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/icc.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/icc.c')
-rw-r--r-- | drivers/isdn/hisax/icc.c | 685 |
1 files changed, 685 insertions, 0 deletions
diff --git a/drivers/isdn/hisax/icc.c b/drivers/isdn/hisax/icc.c new file mode 100644 index 000000000000..dcf31f83c600 --- /dev/null +++ b/drivers/isdn/hisax/icc.c | |||
@@ -0,0 +1,685 @@ | |||
1 | /* $Id: icc.c,v 1.8.2.3 2004/01/13 14:31:25 keil Exp $ | ||
2 | * | ||
3 | * ICC specific routines | ||
4 | * | ||
5 | * Author Matt Henderson & Guy Ellis | ||
6 | * Copyright by Traverse Technologies Pty Ltd, www.travers.com.au | ||
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 | * 1999.6.25 Initial implementation of routines for Siemens ISDN | ||
12 | * Communication Controller PEB 2070 based on the ISAC routines | ||
13 | * written by Karsten Keil. | ||
14 | * | ||
15 | */ | ||
16 | |||
17 | #include <linux/init.h> | ||
18 | #include "hisax.h" | ||
19 | #include "icc.h" | ||
20 | // #include "arcofi.h" | ||
21 | #include "isdnl1.h" | ||
22 | #include <linux/interrupt.h> | ||
23 | |||
24 | #define DBUSY_TIMER_VALUE 80 | ||
25 | #define ARCOFI_USE 0 | ||
26 | |||
27 | static char *ICCVer[] __initdata = | ||
28 | {"2070 A1/A3", "2070 B1", "2070 B2/B3", "2070 V2.4"}; | ||
29 | |||
30 | void __init | ||
31 | ICCVersion(struct IsdnCardState *cs, char *s) | ||
32 | { | ||
33 | int val; | ||
34 | |||
35 | val = cs->readisac(cs, ICC_RBCH); | ||
36 | printk(KERN_INFO "%s ICC version (%x): %s\n", s, val, ICCVer[(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, ICC_CIX0, (command << 2) | 3); | ||
45 | } | ||
46 | |||
47 | |||
48 | static void | ||
49 | icc_new_ph(struct IsdnCardState *cs) | ||
50 | { | ||
51 | switch (cs->dc.icc.ph_state) { | ||
52 | case (ICC_IND_EI1): | ||
53 | ph_command(cs, ICC_CMD_DI); | ||
54 | l1_msg(cs, HW_RESET | INDICATION, NULL); | ||
55 | break; | ||
56 | case (ICC_IND_DC): | ||
57 | l1_msg(cs, HW_DEACTIVATE | CONFIRM, NULL); | ||
58 | break; | ||
59 | case (ICC_IND_DR): | ||
60 | l1_msg(cs, HW_DEACTIVATE | INDICATION, NULL); | ||
61 | break; | ||
62 | case (ICC_IND_PU): | ||
63 | l1_msg(cs, HW_POWERUP | CONFIRM, NULL); | ||
64 | break; | ||
65 | case (ICC_IND_FJ): | ||
66 | l1_msg(cs, HW_RSYNC | INDICATION, NULL); | ||
67 | break; | ||
68 | case (ICC_IND_AR): | ||
69 | l1_msg(cs, HW_INFO2 | INDICATION, NULL); | ||
70 | break; | ||
71 | case (ICC_IND_AI): | ||
72 | l1_msg(cs, HW_INFO4 | INDICATION, NULL); | ||
73 | break; | ||
74 | default: | ||
75 | break; | ||
76 | } | ||
77 | } | ||
78 | |||
79 | static void | ||
80 | icc_bh(struct IsdnCardState *cs) | ||
81 | { | ||
82 | struct PStack *stptr; | ||
83 | |||
84 | if (!cs) | ||
85 | return; | ||
86 | if (test_and_clear_bit(D_CLEARBUSY, &cs->event)) { | ||
87 | if (cs->debug) | ||
88 | debugl1(cs, "D-Channel Busy cleared"); | ||
89 | stptr = cs->stlist; | ||
90 | while (stptr != NULL) { | ||
91 | stptr->l1.l1l2(stptr, PH_PAUSE | CONFIRM, NULL); | ||
92 | stptr = stptr->next; | ||
93 | } | ||
94 | } | ||
95 | if (test_and_clear_bit(D_L1STATECHANGE, &cs->event)) | ||
96 | icc_new_ph(cs); | ||
97 | if (test_and_clear_bit(D_RCVBUFREADY, &cs->event)) | ||
98 | DChannel_proc_rcv(cs); | ||
99 | if (test_and_clear_bit(D_XMTBUFREADY, &cs->event)) | ||
100 | DChannel_proc_xmt(cs); | ||
101 | #if ARCOFI_USE | ||
102 | if (!test_bit(HW_ARCOFI, &cs->HW_Flags)) | ||
103 | return; | ||
104 | if (test_and_clear_bit(D_RX_MON1, &cs->event)) | ||
105 | arcofi_fsm(cs, ARCOFI_RX_END, NULL); | ||
106 | if (test_and_clear_bit(D_TX_MON1, &cs->event)) | ||
107 | arcofi_fsm(cs, ARCOFI_TX_END, NULL); | ||
108 | #endif | ||
109 | } | ||
110 | |||
111 | void | ||
112 | icc_empty_fifo(struct IsdnCardState *cs, int count) | ||
113 | { | ||
114 | u_char *ptr; | ||
115 | |||
116 | if ((cs->debug & L1_DEB_ISAC) && !(cs->debug & L1_DEB_ISAC_FIFO)) | ||
117 | debugl1(cs, "icc_empty_fifo"); | ||
118 | |||
119 | if ((cs->rcvidx + count) >= MAX_DFRAME_LEN_L1) { | ||
120 | if (cs->debug & L1_DEB_WARN) | ||
121 | debugl1(cs, "icc_empty_fifo overrun %d", | ||
122 | cs->rcvidx + count); | ||
123 | cs->writeisac(cs, ICC_CMDR, 0x80); | ||
124 | cs->rcvidx = 0; | ||
125 | return; | ||
126 | } | ||
127 | ptr = cs->rcvbuf + cs->rcvidx; | ||
128 | cs->rcvidx += count; | ||
129 | cs->readisacfifo(cs, ptr, count); | ||
130 | cs->writeisac(cs, ICC_CMDR, 0x80); | ||
131 | if (cs->debug & L1_DEB_ISAC_FIFO) { | ||
132 | char *t = cs->dlog; | ||
133 | |||
134 | t += sprintf(t, "icc_empty_fifo cnt %d", count); | ||
135 | QuickHex(t, ptr, count); | ||
136 | debugl1(cs, cs->dlog); | ||
137 | } | ||
138 | } | ||
139 | |||
140 | static void | ||
141 | icc_fill_fifo(struct IsdnCardState *cs) | ||
142 | { | ||
143 | int count, more; | ||
144 | u_char *ptr; | ||
145 | |||
146 | if ((cs->debug & L1_DEB_ISAC) && !(cs->debug & L1_DEB_ISAC_FIFO)) | ||
147 | debugl1(cs, "icc_fill_fifo"); | ||
148 | |||
149 | if (!cs->tx_skb) | ||
150 | return; | ||
151 | |||
152 | count = cs->tx_skb->len; | ||
153 | if (count <= 0) | ||
154 | return; | ||
155 | |||
156 | more = 0; | ||
157 | if (count > 32) { | ||
158 | more = !0; | ||
159 | count = 32; | ||
160 | } | ||
161 | ptr = cs->tx_skb->data; | ||
162 | skb_pull(cs->tx_skb, count); | ||
163 | cs->tx_cnt += count; | ||
164 | cs->writeisacfifo(cs, ptr, count); | ||
165 | cs->writeisac(cs, ICC_CMDR, more ? 0x8 : 0xa); | ||
166 | if (test_and_set_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) { | ||
167 | debugl1(cs, "icc_fill_fifo dbusytimer running"); | ||
168 | del_timer(&cs->dbusytimer); | ||
169 | } | ||
170 | init_timer(&cs->dbusytimer); | ||
171 | cs->dbusytimer.expires = jiffies + ((DBUSY_TIMER_VALUE * HZ)/1000); | ||
172 | add_timer(&cs->dbusytimer); | ||
173 | if (cs->debug & L1_DEB_ISAC_FIFO) { | ||
174 | char *t = cs->dlog; | ||
175 | |||
176 | t += sprintf(t, "icc_fill_fifo cnt %d", count); | ||
177 | QuickHex(t, ptr, count); | ||
178 | debugl1(cs, cs->dlog); | ||
179 | } | ||
180 | } | ||
181 | |||
182 | void | ||
183 | icc_interrupt(struct IsdnCardState *cs, u_char val) | ||
184 | { | ||
185 | u_char exval, v1; | ||
186 | struct sk_buff *skb; | ||
187 | unsigned int count; | ||
188 | |||
189 | if (cs->debug & L1_DEB_ISAC) | ||
190 | debugl1(cs, "ICC interrupt %x", val); | ||
191 | if (val & 0x80) { /* RME */ | ||
192 | exval = cs->readisac(cs, ICC_RSTA); | ||
193 | if ((exval & 0x70) != 0x20) { | ||
194 | if (exval & 0x40) { | ||
195 | if (cs->debug & L1_DEB_WARN) | ||
196 | debugl1(cs, "ICC RDO"); | ||
197 | #ifdef ERROR_STATISTIC | ||
198 | cs->err_rx++; | ||
199 | #endif | ||
200 | } | ||
201 | if (!(exval & 0x20)) { | ||
202 | if (cs->debug & L1_DEB_WARN) | ||
203 | debugl1(cs, "ICC CRC error"); | ||
204 | #ifdef ERROR_STATISTIC | ||
205 | cs->err_crc++; | ||
206 | #endif | ||
207 | } | ||
208 | cs->writeisac(cs, ICC_CMDR, 0x80); | ||
209 | } else { | ||
210 | count = cs->readisac(cs, ICC_RBCL) & 0x1f; | ||
211 | if (count == 0) | ||
212 | count = 32; | ||
213 | icc_empty_fifo(cs, count); | ||
214 | if ((count = cs->rcvidx) > 0) { | ||
215 | cs->rcvidx = 0; | ||
216 | if (!(skb = alloc_skb(count, GFP_ATOMIC))) | ||
217 | printk(KERN_WARNING "HiSax: D receive out of memory\n"); | ||
218 | else { | ||
219 | memcpy(skb_put(skb, count), cs->rcvbuf, count); | ||
220 | skb_queue_tail(&cs->rq, skb); | ||
221 | } | ||
222 | } | ||
223 | } | ||
224 | cs->rcvidx = 0; | ||
225 | schedule_event(cs, D_RCVBUFREADY); | ||
226 | } | ||
227 | if (val & 0x40) { /* RPF */ | ||
228 | icc_empty_fifo(cs, 32); | ||
229 | } | ||
230 | if (val & 0x20) { /* RSC */ | ||
231 | /* never */ | ||
232 | if (cs->debug & L1_DEB_WARN) | ||
233 | debugl1(cs, "ICC RSC interrupt"); | ||
234 | } | ||
235 | if (val & 0x10) { /* XPR */ | ||
236 | if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) | ||
237 | del_timer(&cs->dbusytimer); | ||
238 | if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags)) | ||
239 | schedule_event(cs, D_CLEARBUSY); | ||
240 | if (cs->tx_skb) { | ||
241 | if (cs->tx_skb->len) { | ||
242 | icc_fill_fifo(cs); | ||
243 | goto afterXPR; | ||
244 | } else { | ||
245 | dev_kfree_skb_irq(cs->tx_skb); | ||
246 | cs->tx_cnt = 0; | ||
247 | cs->tx_skb = NULL; | ||
248 | } | ||
249 | } | ||
250 | if ((cs->tx_skb = skb_dequeue(&cs->sq))) { | ||
251 | cs->tx_cnt = 0; | ||
252 | icc_fill_fifo(cs); | ||
253 | } else | ||
254 | schedule_event(cs, D_XMTBUFREADY); | ||
255 | } | ||
256 | afterXPR: | ||
257 | if (val & 0x04) { /* CISQ */ | ||
258 | exval = cs->readisac(cs, ICC_CIR0); | ||
259 | if (cs->debug & L1_DEB_ISAC) | ||
260 | debugl1(cs, "ICC CIR0 %02X", exval ); | ||
261 | if (exval & 2) { | ||
262 | cs->dc.icc.ph_state = (exval >> 2) & 0xf; | ||
263 | if (cs->debug & L1_DEB_ISAC) | ||
264 | debugl1(cs, "ph_state change %x", cs->dc.icc.ph_state); | ||
265 | schedule_event(cs, D_L1STATECHANGE); | ||
266 | } | ||
267 | if (exval & 1) { | ||
268 | exval = cs->readisac(cs, ICC_CIR1); | ||
269 | if (cs->debug & L1_DEB_ISAC) | ||
270 | debugl1(cs, "ICC CIR1 %02X", exval ); | ||
271 | } | ||
272 | } | ||
273 | if (val & 0x02) { /* SIN */ | ||
274 | /* never */ | ||
275 | if (cs->debug & L1_DEB_WARN) | ||
276 | debugl1(cs, "ICC SIN interrupt"); | ||
277 | } | ||
278 | if (val & 0x01) { /* EXI */ | ||
279 | exval = cs->readisac(cs, ICC_EXIR); | ||
280 | if (cs->debug & L1_DEB_WARN) | ||
281 | debugl1(cs, "ICC EXIR %02x", exval); | ||
282 | if (exval & 0x80) { /* XMR */ | ||
283 | debugl1(cs, "ICC XMR"); | ||
284 | printk(KERN_WARNING "HiSax: ICC XMR\n"); | ||
285 | } | ||
286 | if (exval & 0x40) { /* XDU */ | ||
287 | debugl1(cs, "ICC XDU"); | ||
288 | printk(KERN_WARNING "HiSax: ICC XDU\n"); | ||
289 | #ifdef ERROR_STATISTIC | ||
290 | cs->err_tx++; | ||
291 | #endif | ||
292 | if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) | ||
293 | del_timer(&cs->dbusytimer); | ||
294 | if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags)) | ||
295 | schedule_event(cs, D_CLEARBUSY); | ||
296 | if (cs->tx_skb) { /* Restart frame */ | ||
297 | skb_push(cs->tx_skb, cs->tx_cnt); | ||
298 | cs->tx_cnt = 0; | ||
299 | icc_fill_fifo(cs); | ||
300 | } else { | ||
301 | printk(KERN_WARNING "HiSax: ICC XDU no skb\n"); | ||
302 | debugl1(cs, "ICC XDU no skb"); | ||
303 | } | ||
304 | } | ||
305 | if (exval & 0x04) { /* MOS */ | ||
306 | v1 = cs->readisac(cs, ICC_MOSR); | ||
307 | if (cs->debug & L1_DEB_MONITOR) | ||
308 | debugl1(cs, "ICC MOSR %02x", v1); | ||
309 | #if ARCOFI_USE | ||
310 | if (v1 & 0x08) { | ||
311 | if (!cs->dc.icc.mon_rx) { | ||
312 | if (!(cs->dc.icc.mon_rx = kmalloc(MAX_MON_FRAME, GFP_ATOMIC))) { | ||
313 | if (cs->debug & L1_DEB_WARN) | ||
314 | debugl1(cs, "ICC MON RX out of memory!"); | ||
315 | cs->dc.icc.mocr &= 0xf0; | ||
316 | cs->dc.icc.mocr |= 0x0a; | ||
317 | cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr); | ||
318 | goto afterMONR0; | ||
319 | } else | ||
320 | cs->dc.icc.mon_rxp = 0; | ||
321 | } | ||
322 | if (cs->dc.icc.mon_rxp >= MAX_MON_FRAME) { | ||
323 | cs->dc.icc.mocr &= 0xf0; | ||
324 | cs->dc.icc.mocr |= 0x0a; | ||
325 | cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr); | ||
326 | cs->dc.icc.mon_rxp = 0; | ||
327 | if (cs->debug & L1_DEB_WARN) | ||
328 | debugl1(cs, "ICC MON RX overflow!"); | ||
329 | goto afterMONR0; | ||
330 | } | ||
331 | cs->dc.icc.mon_rx[cs->dc.icc.mon_rxp++] = cs->readisac(cs, ICC_MOR0); | ||
332 | if (cs->debug & L1_DEB_MONITOR) | ||
333 | debugl1(cs, "ICC MOR0 %02x", cs->dc.icc.mon_rx[cs->dc.icc.mon_rxp -1]); | ||
334 | if (cs->dc.icc.mon_rxp == 1) { | ||
335 | cs->dc.icc.mocr |= 0x04; | ||
336 | cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr); | ||
337 | } | ||
338 | } | ||
339 | afterMONR0: | ||
340 | if (v1 & 0x80) { | ||
341 | if (!cs->dc.icc.mon_rx) { | ||
342 | if (!(cs->dc.icc.mon_rx = kmalloc(MAX_MON_FRAME, GFP_ATOMIC))) { | ||
343 | if (cs->debug & L1_DEB_WARN) | ||
344 | debugl1(cs, "ICC MON RX out of memory!"); | ||
345 | cs->dc.icc.mocr &= 0x0f; | ||
346 | cs->dc.icc.mocr |= 0xa0; | ||
347 | cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr); | ||
348 | goto afterMONR1; | ||
349 | } else | ||
350 | cs->dc.icc.mon_rxp = 0; | ||
351 | } | ||
352 | if (cs->dc.icc.mon_rxp >= MAX_MON_FRAME) { | ||
353 | cs->dc.icc.mocr &= 0x0f; | ||
354 | cs->dc.icc.mocr |= 0xa0; | ||
355 | cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr); | ||
356 | cs->dc.icc.mon_rxp = 0; | ||
357 | if (cs->debug & L1_DEB_WARN) | ||
358 | debugl1(cs, "ICC MON RX overflow!"); | ||
359 | goto afterMONR1; | ||
360 | } | ||
361 | cs->dc.icc.mon_rx[cs->dc.icc.mon_rxp++] = cs->readisac(cs, ICC_MOR1); | ||
362 | if (cs->debug & L1_DEB_MONITOR) | ||
363 | debugl1(cs, "ICC MOR1 %02x", cs->dc.icc.mon_rx[cs->dc.icc.mon_rxp -1]); | ||
364 | cs->dc.icc.mocr |= 0x40; | ||
365 | cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr); | ||
366 | } | ||
367 | afterMONR1: | ||
368 | if (v1 & 0x04) { | ||
369 | cs->dc.icc.mocr &= 0xf0; | ||
370 | cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr); | ||
371 | cs->dc.icc.mocr |= 0x0a; | ||
372 | cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr); | ||
373 | schedule_event(cs, D_RX_MON0); | ||
374 | } | ||
375 | if (v1 & 0x40) { | ||
376 | cs->dc.icc.mocr &= 0x0f; | ||
377 | cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr); | ||
378 | cs->dc.icc.mocr |= 0xa0; | ||
379 | cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr); | ||
380 | schedule_event(cs, D_RX_MON1); | ||
381 | } | ||
382 | if (v1 & 0x02) { | ||
383 | if ((!cs->dc.icc.mon_tx) || (cs->dc.icc.mon_txc && | ||
384 | (cs->dc.icc.mon_txp >= cs->dc.icc.mon_txc) && | ||
385 | !(v1 & 0x08))) { | ||
386 | cs->dc.icc.mocr &= 0xf0; | ||
387 | cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr); | ||
388 | cs->dc.icc.mocr |= 0x0a; | ||
389 | cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr); | ||
390 | if (cs->dc.icc.mon_txc && | ||
391 | (cs->dc.icc.mon_txp >= cs->dc.icc.mon_txc)) | ||
392 | schedule_event(cs, D_TX_MON0); | ||
393 | goto AfterMOX0; | ||
394 | } | ||
395 | if (cs->dc.icc.mon_txc && (cs->dc.icc.mon_txp >= cs->dc.icc.mon_txc)) { | ||
396 | schedule_event(cs, D_TX_MON0); | ||
397 | goto AfterMOX0; | ||
398 | } | ||
399 | cs->writeisac(cs, ICC_MOX0, | ||
400 | cs->dc.icc.mon_tx[cs->dc.icc.mon_txp++]); | ||
401 | if (cs->debug & L1_DEB_MONITOR) | ||
402 | debugl1(cs, "ICC %02x -> MOX0", cs->dc.icc.mon_tx[cs->dc.icc.mon_txp -1]); | ||
403 | } | ||
404 | AfterMOX0: | ||
405 | if (v1 & 0x20) { | ||
406 | if ((!cs->dc.icc.mon_tx) || (cs->dc.icc.mon_txc && | ||
407 | (cs->dc.icc.mon_txp >= cs->dc.icc.mon_txc) && | ||
408 | !(v1 & 0x80))) { | ||
409 | cs->dc.icc.mocr &= 0x0f; | ||
410 | cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr); | ||
411 | cs->dc.icc.mocr |= 0xa0; | ||
412 | cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr); | ||
413 | if (cs->dc.icc.mon_txc && | ||
414 | (cs->dc.icc.mon_txp >= cs->dc.icc.mon_txc)) | ||
415 | schedule_event(cs, D_TX_MON1); | ||
416 | goto AfterMOX1; | ||
417 | } | ||
418 | if (cs->dc.icc.mon_txc && (cs->dc.icc.mon_txp >= cs->dc.icc.mon_txc)) { | ||
419 | schedule_event(cs, D_TX_MON1); | ||
420 | goto AfterMOX1; | ||
421 | } | ||
422 | cs->writeisac(cs, ICC_MOX1, | ||
423 | cs->dc.icc.mon_tx[cs->dc.icc.mon_txp++]); | ||
424 | if (cs->debug & L1_DEB_MONITOR) | ||
425 | debugl1(cs, "ICC %02x -> MOX1", cs->dc.icc.mon_tx[cs->dc.icc.mon_txp -1]); | ||
426 | } | ||
427 | AfterMOX1: | ||
428 | #endif | ||
429 | } | ||
430 | } | ||
431 | } | ||
432 | |||
433 | static void | ||
434 | ICC_l1hw(struct PStack *st, int pr, void *arg) | ||
435 | { | ||
436 | struct IsdnCardState *cs = (struct IsdnCardState *) st->l1.hardware; | ||
437 | struct sk_buff *skb = arg; | ||
438 | u_long flags; | ||
439 | int val; | ||
440 | |||
441 | switch (pr) { | ||
442 | case (PH_DATA |REQUEST): | ||
443 | if (cs->debug & DEB_DLOG_HEX) | ||
444 | LogFrame(cs, skb->data, skb->len); | ||
445 | if (cs->debug & DEB_DLOG_VERBOSE) | ||
446 | dlogframe(cs, skb, 0); | ||
447 | spin_lock_irqsave(&cs->lock, flags); | ||
448 | if (cs->tx_skb) { | ||
449 | skb_queue_tail(&cs->sq, skb); | ||
450 | #ifdef L2FRAME_DEBUG /* psa */ | ||
451 | if (cs->debug & L1_DEB_LAPD) | ||
452 | Logl2Frame(cs, skb, "PH_DATA Queued", 0); | ||
453 | #endif | ||
454 | } else { | ||
455 | cs->tx_skb = skb; | ||
456 | cs->tx_cnt = 0; | ||
457 | #ifdef L2FRAME_DEBUG /* psa */ | ||
458 | if (cs->debug & L1_DEB_LAPD) | ||
459 | Logl2Frame(cs, skb, "PH_DATA", 0); | ||
460 | #endif | ||
461 | icc_fill_fifo(cs); | ||
462 | } | ||
463 | spin_unlock_irqrestore(&cs->lock, flags); | ||
464 | break; | ||
465 | case (PH_PULL |INDICATION): | ||
466 | spin_lock_irqsave(&cs->lock, flags); | ||
467 | if (cs->tx_skb) { | ||
468 | if (cs->debug & L1_DEB_WARN) | ||
469 | debugl1(cs, " l2l1 tx_skb exist this shouldn't happen"); | ||
470 | skb_queue_tail(&cs->sq, skb); | ||
471 | break; | ||
472 | } | ||
473 | if (cs->debug & DEB_DLOG_HEX) | ||
474 | LogFrame(cs, skb->data, skb->len); | ||
475 | if (cs->debug & DEB_DLOG_VERBOSE) | ||
476 | dlogframe(cs, skb, 0); | ||
477 | cs->tx_skb = skb; | ||
478 | cs->tx_cnt = 0; | ||
479 | #ifdef L2FRAME_DEBUG /* psa */ | ||
480 | if (cs->debug & L1_DEB_LAPD) | ||
481 | Logl2Frame(cs, skb, "PH_DATA_PULLED", 0); | ||
482 | #endif | ||
483 | icc_fill_fifo(cs); | ||
484 | spin_unlock_irqrestore(&cs->lock, flags); | ||
485 | break; | ||
486 | case (PH_PULL | REQUEST): | ||
487 | #ifdef L2FRAME_DEBUG /* psa */ | ||
488 | if (cs->debug & L1_DEB_LAPD) | ||
489 | debugl1(cs, "-> PH_REQUEST_PULL"); | ||
490 | #endif | ||
491 | if (!cs->tx_skb) { | ||
492 | test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags); | ||
493 | st->l1.l1l2(st, PH_PULL | CONFIRM, NULL); | ||
494 | } else | ||
495 | test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags); | ||
496 | break; | ||
497 | case (HW_RESET | REQUEST): | ||
498 | spin_lock_irqsave(&cs->lock, flags); | ||
499 | if ((cs->dc.icc.ph_state == ICC_IND_EI1) || | ||
500 | (cs->dc.icc.ph_state == ICC_IND_DR)) | ||
501 | ph_command(cs, ICC_CMD_DI); | ||
502 | else | ||
503 | ph_command(cs, ICC_CMD_RES); | ||
504 | spin_unlock_irqrestore(&cs->lock, flags); | ||
505 | break; | ||
506 | case (HW_ENABLE | REQUEST): | ||
507 | spin_lock_irqsave(&cs->lock, flags); | ||
508 | ph_command(cs, ICC_CMD_DI); | ||
509 | spin_unlock_irqrestore(&cs->lock, flags); | ||
510 | break; | ||
511 | case (HW_INFO1 | REQUEST): | ||
512 | spin_lock_irqsave(&cs->lock, flags); | ||
513 | ph_command(cs, ICC_CMD_AR); | ||
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, ICC_CMD_AI); | ||
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, ICC_SPCR, 0xa); | ||
532 | cs->writeisac(cs, ICC_ADF1, 0x2); | ||
533 | } else { | ||
534 | cs->writeisac(cs, ICC_SPCR, val); | ||
535 | cs->writeisac(cs, ICC_ADF1, 0xa); | ||
536 | } | ||
537 | } else { | ||
538 | /* IOM 2 Mode */ | ||
539 | cs->writeisac(cs, ICC_SPCR, val); | ||
540 | if (val) | ||
541 | cs->writeisac(cs, ICC_ADF1, 0x8); | ||
542 | else | ||
543 | cs->writeisac(cs, ICC_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, "icc_l1hw unknown %04x", pr); | ||
562 | break; | ||
563 | } | ||
564 | } | ||
565 | |||
566 | void | ||
567 | setstack_icc(struct PStack *st, struct IsdnCardState *cs) | ||
568 | { | ||
569 | st->l1.l1hw = ICC_l1hw; | ||
570 | } | ||
571 | |||
572 | void | ||
573 | DC_Close_icc(struct IsdnCardState *cs) { | ||
574 | if (cs->dc.icc.mon_rx) { | ||
575 | kfree(cs->dc.icc.mon_rx); | ||
576 | cs->dc.icc.mon_rx = NULL; | ||
577 | } | ||
578 | if (cs->dc.icc.mon_tx) { | ||
579 | kfree(cs->dc.icc.mon_tx); | ||
580 | cs->dc.icc.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, ICC_RBCH); | ||
592 | star = cs->readisac(cs, ICC_STAR); | ||
593 | if (cs->debug) | ||
594 | debugl1(cs, "D-Channel Busy RBCH %02x STAR %02x", | ||
595 | rbch, star); | ||
596 | if (rbch & ICC_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: ICC D-Channel Busy no skb\n"); | ||
612 | debugl1(cs, "D-Channel Busy no skb"); | ||
613 | } | ||
614 | cs->writeisac(cs, ICC_CMDR, 0x01); /* Transmitter reset */ | ||
615 | cs->irq_func(cs->irq, cs, NULL); | ||
616 | } | ||
617 | } | ||
618 | } | ||
619 | |||
620 | void __init | ||
621 | initicc(struct IsdnCardState *cs) | ||
622 | { | ||
623 | cs->setstack_d = setstack_icc; | ||
624 | cs->DC_Close = DC_Close_icc; | ||
625 | cs->dc.icc.mon_tx = NULL; | ||
626 | cs->dc.icc.mon_rx = NULL; | ||
627 | cs->writeisac(cs, ICC_MASK, 0xff); | ||
628 | cs->dc.icc.mocr = 0xaa; | ||
629 | if (test_bit(HW_IOM1, &cs->HW_Flags)) { | ||
630 | /* IOM 1 Mode */ | ||
631 | cs->writeisac(cs, ICC_ADF2, 0x0); | ||
632 | cs->writeisac(cs, ICC_SPCR, 0xa); | ||
633 | cs->writeisac(cs, ICC_ADF1, 0x2); | ||
634 | cs->writeisac(cs, ICC_STCR, 0x70); | ||
635 | cs->writeisac(cs, ICC_MODE, 0xc9); | ||
636 | } else { | ||
637 | /* IOM 2 Mode */ | ||
638 | if (!cs->dc.icc.adf2) | ||
639 | cs->dc.icc.adf2 = 0x80; | ||
640 | cs->writeisac(cs, ICC_ADF2, cs->dc.icc.adf2); | ||
641 | cs->writeisac(cs, ICC_SQXR, 0xa0); | ||
642 | cs->writeisac(cs, ICC_SPCR, 0x20); | ||
643 | cs->writeisac(cs, ICC_STCR, 0x70); | ||
644 | cs->writeisac(cs, ICC_MODE, 0xca); | ||
645 | cs->writeisac(cs, ICC_TIMR, 0x00); | ||
646 | cs->writeisac(cs, ICC_ADF1, 0x20); | ||
647 | } | ||
648 | ph_command(cs, ICC_CMD_RES); | ||
649 | cs->writeisac(cs, ICC_MASK, 0x0); | ||
650 | ph_command(cs, ICC_CMD_DI); | ||
651 | } | ||
652 | |||
653 | void __init | ||
654 | clear_pending_icc_ints(struct IsdnCardState *cs) | ||
655 | { | ||
656 | int val, eval; | ||
657 | |||
658 | val = cs->readisac(cs, ICC_STAR); | ||
659 | debugl1(cs, "ICC STAR %x", val); | ||
660 | val = cs->readisac(cs, ICC_MODE); | ||
661 | debugl1(cs, "ICC MODE %x", val); | ||
662 | val = cs->readisac(cs, ICC_ADF2); | ||
663 | debugl1(cs, "ICC ADF2 %x", val); | ||
664 | val = cs->readisac(cs, ICC_ISTA); | ||
665 | debugl1(cs, "ICC ISTA %x", val); | ||
666 | if (val & 0x01) { | ||
667 | eval = cs->readisac(cs, ICC_EXIR); | ||
668 | debugl1(cs, "ICC EXIR %x", eval); | ||
669 | } | ||
670 | val = cs->readisac(cs, ICC_CIR0); | ||
671 | debugl1(cs, "ICC CIR0 %x", val); | ||
672 | cs->dc.icc.ph_state = (val >> 2) & 0xf; | ||
673 | schedule_event(cs, D_L1STATECHANGE); | ||
674 | /* Disable all IRQ */ | ||
675 | cs->writeisac(cs, ICC_MASK, 0xFF); | ||
676 | } | ||
677 | |||
678 | void __devinit | ||
679 | setup_icc(struct IsdnCardState *cs) | ||
680 | { | ||
681 | INIT_WORK(&cs->tqueue, (void *)(void *) icc_bh, cs); | ||
682 | cs->dbusytimer.function = (void *) dbusy_timer_handler; | ||
683 | cs->dbusytimer.data = (long) cs; | ||
684 | init_timer(&cs->dbusytimer); | ||
685 | } | ||