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/hfc_sx.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/hfc_sx.c')
-rw-r--r-- | drivers/isdn/hisax/hfc_sx.c | 1521 |
1 files changed, 1521 insertions, 0 deletions
diff --git a/drivers/isdn/hisax/hfc_sx.c b/drivers/isdn/hisax/hfc_sx.c new file mode 100644 index 000000000000..a307fcb6c634 --- /dev/null +++ b/drivers/isdn/hisax/hfc_sx.c | |||
@@ -0,0 +1,1521 @@ | |||
1 | /* $Id: hfc_sx.c,v 1.12.2.5 2004/02/11 13:21:33 keil Exp $ | ||
2 | * | ||
3 | * level driver for Cologne Chip Designs hfc-s+/sp based cards | ||
4 | * | ||
5 | * Author Werner Cornelius | ||
6 | * based on existing driver for CCD HFC PCI cards | ||
7 | * Copyright by Werner Cornelius <werner@isdn4linux.de> | ||
8 | * | ||
9 | * This software may be used and distributed according to the terms | ||
10 | * of the GNU General Public License, incorporated herein by reference. | ||
11 | * | ||
12 | */ | ||
13 | |||
14 | #include <linux/init.h> | ||
15 | #include "hisax.h" | ||
16 | #include "hfc_sx.h" | ||
17 | #include "isdnl1.h" | ||
18 | #include <linux/interrupt.h> | ||
19 | #include <linux/isapnp.h> | ||
20 | |||
21 | extern const char *CardType[]; | ||
22 | |||
23 | static const char *hfcsx_revision = "$Revision: 1.12.2.5 $"; | ||
24 | |||
25 | /***************************************/ | ||
26 | /* IRQ-table for CCDs demo board */ | ||
27 | /* IRQs 6,5,10,11,12,15 are supported */ | ||
28 | /***************************************/ | ||
29 | |||
30 | /* Teles 16.3c Vendor Id TAG2620, Version 1.0, Vendor version 2.1 | ||
31 | * | ||
32 | * Thanks to Uwe Wisniewski | ||
33 | * | ||
34 | * ISA-SLOT Signal PIN | ||
35 | * B25 IRQ3 92 IRQ_G | ||
36 | * B23 IRQ5 94 IRQ_A | ||
37 | * B4 IRQ2/9 95 IRQ_B | ||
38 | * D3 IRQ10 96 IRQ_C | ||
39 | * D4 IRQ11 97 IRQ_D | ||
40 | * D5 IRQ12 98 IRQ_E | ||
41 | * D6 IRQ15 99 IRQ_F | ||
42 | */ | ||
43 | |||
44 | #undef CCD_DEMO_BOARD | ||
45 | #ifdef CCD_DEMO_BOARD | ||
46 | static u_char ccd_sp_irqtab[16] = { | ||
47 | 0,0,0,0,0,2,1,0,0,0,3,4,5,0,0,6 | ||
48 | }; | ||
49 | #else /* Teles 16.3c */ | ||
50 | static u_char ccd_sp_irqtab[16] = { | ||
51 | 0,0,0,7,0,1,0,0,0,2,3,4,5,0,0,6 | ||
52 | }; | ||
53 | #endif | ||
54 | #define NT_T1_COUNT 20 /* number of 3.125ms interrupts for G2 timeout */ | ||
55 | |||
56 | #define byteout(addr,val) outb(val,addr) | ||
57 | #define bytein(addr) inb(addr) | ||
58 | |||
59 | /******************************/ | ||
60 | /* In/Out access to registers */ | ||
61 | /******************************/ | ||
62 | static inline void | ||
63 | Write_hfc(struct IsdnCardState *cs, u_char regnum, u_char val) | ||
64 | { | ||
65 | byteout(cs->hw.hfcsx.base+1, regnum); | ||
66 | byteout(cs->hw.hfcsx.base, val); | ||
67 | } | ||
68 | |||
69 | static inline u_char | ||
70 | Read_hfc(struct IsdnCardState *cs, u_char regnum) | ||
71 | { | ||
72 | u_char ret; | ||
73 | |||
74 | byteout(cs->hw.hfcsx.base+1, regnum); | ||
75 | ret = bytein(cs->hw.hfcsx.base); | ||
76 | return(ret); | ||
77 | } | ||
78 | |||
79 | |||
80 | /**************************************************/ | ||
81 | /* select a fifo and remember which one for reuse */ | ||
82 | /**************************************************/ | ||
83 | static void | ||
84 | fifo_select(struct IsdnCardState *cs, u_char fifo) | ||
85 | { | ||
86 | if (fifo == cs->hw.hfcsx.last_fifo) | ||
87 | return; /* still valid */ | ||
88 | |||
89 | byteout(cs->hw.hfcsx.base+1, HFCSX_FIF_SEL); | ||
90 | byteout(cs->hw.hfcsx.base, fifo); | ||
91 | while (bytein(cs->hw.hfcsx.base+1) & 1); /* wait for busy */ | ||
92 | udelay(4); | ||
93 | byteout(cs->hw.hfcsx.base, fifo); | ||
94 | while (bytein(cs->hw.hfcsx.base+1) & 1); /* wait for busy */ | ||
95 | } | ||
96 | |||
97 | /******************************************/ | ||
98 | /* reset the specified fifo to defaults. */ | ||
99 | /* If its a send fifo init needed markers */ | ||
100 | /******************************************/ | ||
101 | static void | ||
102 | reset_fifo(struct IsdnCardState *cs, u_char fifo) | ||
103 | { | ||
104 | fifo_select(cs, fifo); /* first select the fifo */ | ||
105 | byteout(cs->hw.hfcsx.base+1, HFCSX_CIRM); | ||
106 | byteout(cs->hw.hfcsx.base, cs->hw.hfcsx.cirm | 0x80); /* reset cmd */ | ||
107 | udelay(1); | ||
108 | while (bytein(cs->hw.hfcsx.base+1) & 1); /* wait for busy */ | ||
109 | } | ||
110 | |||
111 | |||
112 | /*************************************************************/ | ||
113 | /* write_fifo writes the skb contents to the desired fifo */ | ||
114 | /* if no space is available or an error occurs 0 is returned */ | ||
115 | /* the skb is not released in any way. */ | ||
116 | /*************************************************************/ | ||
117 | static int | ||
118 | write_fifo(struct IsdnCardState *cs, struct sk_buff *skb, u_char fifo, int trans_max) | ||
119 | { | ||
120 | unsigned short *msp; | ||
121 | int fifo_size, count, z1, z2; | ||
122 | u_char f_msk, f1, f2, *src; | ||
123 | |||
124 | if (skb->len <= 0) return(0); | ||
125 | if (fifo & 1) return(0); /* no write fifo */ | ||
126 | |||
127 | fifo_select(cs, fifo); | ||
128 | if (fifo & 4) { | ||
129 | fifo_size = D_FIFO_SIZE; /* D-channel */ | ||
130 | f_msk = MAX_D_FRAMES; | ||
131 | if (trans_max) return(0); /* only HDLC */ | ||
132 | } | ||
133 | else { | ||
134 | fifo_size = cs->hw.hfcsx.b_fifo_size; /* B-channel */ | ||
135 | f_msk = MAX_B_FRAMES; | ||
136 | } | ||
137 | |||
138 | z1 = Read_hfc(cs, HFCSX_FIF_Z1H); | ||
139 | z1 = ((z1 << 8) | Read_hfc(cs, HFCSX_FIF_Z1L)); | ||
140 | |||
141 | /* Check for transparent mode */ | ||
142 | if (trans_max) { | ||
143 | z2 = Read_hfc(cs, HFCSX_FIF_Z2H); | ||
144 | z2 = ((z2 << 8) | Read_hfc(cs, HFCSX_FIF_Z2L)); | ||
145 | count = z2 - z1; | ||
146 | if (count <= 0) | ||
147 | count += fifo_size; /* free bytes */ | ||
148 | if (count < skb->len+1) return(0); /* no room */ | ||
149 | count = fifo_size - count; /* bytes still not send */ | ||
150 | if (count > 2 * trans_max) return(0); /* delay to long */ | ||
151 | count = skb->len; | ||
152 | src = skb->data; | ||
153 | while (count--) | ||
154 | Write_hfc(cs, HFCSX_FIF_DWR, *src++); | ||
155 | return(1); /* success */ | ||
156 | } | ||
157 | |||
158 | msp = ((struct hfcsx_extra *)(cs->hw.hfcsx.extra))->marker; | ||
159 | msp += (((fifo >> 1) & 3) * (MAX_B_FRAMES+1)); | ||
160 | f1 = Read_hfc(cs, HFCSX_FIF_F1) & f_msk; | ||
161 | f2 = Read_hfc(cs, HFCSX_FIF_F2) & f_msk; | ||
162 | |||
163 | count = f1 - f2; /* frame count actually buffered */ | ||
164 | if (count < 0) | ||
165 | count += (f_msk + 1); /* if wrap around */ | ||
166 | if (count > f_msk-1) { | ||
167 | if (cs->debug & L1_DEB_ISAC_FIFO) | ||
168 | debugl1(cs, "hfcsx_write_fifo %d more as %d frames",fifo,f_msk-1); | ||
169 | return(0); | ||
170 | } | ||
171 | |||
172 | *(msp + f1) = z1; /* remember marker */ | ||
173 | |||
174 | if (cs->debug & L1_DEB_ISAC_FIFO) | ||
175 | debugl1(cs, "hfcsx_write_fifo %d f1(%x) f2(%x) z1(f1)(%x)", | ||
176 | fifo, f1, f2, z1); | ||
177 | /* now determine free bytes in FIFO buffer */ | ||
178 | count = *(msp + f2) - z1; | ||
179 | if (count <= 0) | ||
180 | count += fifo_size; /* count now contains available bytes */ | ||
181 | |||
182 | if (cs->debug & L1_DEB_ISAC_FIFO) | ||
183 | debugl1(cs, "hfcsx_write_fifo %d count(%ld/%d)", | ||
184 | fifo, skb->len, count); | ||
185 | if (count < skb->len) { | ||
186 | if (cs->debug & L1_DEB_ISAC_FIFO) | ||
187 | debugl1(cs, "hfcsx_write_fifo %d no fifo mem", fifo); | ||
188 | return(0); | ||
189 | } | ||
190 | |||
191 | count = skb->len; /* get frame len */ | ||
192 | src = skb->data; /* source pointer */ | ||
193 | while (count--) | ||
194 | Write_hfc(cs, HFCSX_FIF_DWR, *src++); | ||
195 | |||
196 | Read_hfc(cs, HFCSX_FIF_INCF1); /* increment F1 */ | ||
197 | udelay(1); | ||
198 | while (bytein(cs->hw.hfcsx.base+1) & 1); /* wait for busy */ | ||
199 | return(1); | ||
200 | } | ||
201 | |||
202 | /***************************************************************/ | ||
203 | /* read_fifo reads data to an skb from the desired fifo */ | ||
204 | /* if no data is available or an error occurs NULL is returned */ | ||
205 | /* the skb is not released in any way. */ | ||
206 | /***************************************************************/ | ||
207 | static struct sk_buff * | ||
208 | read_fifo(struct IsdnCardState *cs, u_char fifo, int trans_max) | ||
209 | { int fifo_size, count, z1, z2; | ||
210 | u_char f_msk, f1, f2, *dst; | ||
211 | struct sk_buff *skb; | ||
212 | |||
213 | if (!(fifo & 1)) return(NULL); /* no read fifo */ | ||
214 | fifo_select(cs, fifo); | ||
215 | if (fifo & 4) { | ||
216 | fifo_size = D_FIFO_SIZE; /* D-channel */ | ||
217 | f_msk = MAX_D_FRAMES; | ||
218 | if (trans_max) return(NULL); /* only hdlc */ | ||
219 | } | ||
220 | else { | ||
221 | fifo_size = cs->hw.hfcsx.b_fifo_size; /* B-channel */ | ||
222 | f_msk = MAX_B_FRAMES; | ||
223 | } | ||
224 | |||
225 | /* transparent mode */ | ||
226 | if (trans_max) { | ||
227 | z1 = Read_hfc(cs, HFCSX_FIF_Z1H); | ||
228 | z1 = ((z1 << 8) | Read_hfc(cs, HFCSX_FIF_Z1L)); | ||
229 | z2 = Read_hfc(cs, HFCSX_FIF_Z2H); | ||
230 | z2 = ((z2 << 8) | Read_hfc(cs, HFCSX_FIF_Z2L)); | ||
231 | /* now determine bytes in actual FIFO buffer */ | ||
232 | count = z1 - z2; | ||
233 | if (count <= 0) | ||
234 | count += fifo_size; /* count now contains buffered bytes */ | ||
235 | count++; | ||
236 | if (count > trans_max) | ||
237 | count = trans_max; /* limit length */ | ||
238 | if ((skb = dev_alloc_skb(count))) { | ||
239 | dst = skb_put(skb, count); | ||
240 | while (count--) | ||
241 | *dst++ = Read_hfc(cs, HFCSX_FIF_DRD); | ||
242 | return(skb); | ||
243 | } | ||
244 | else return(NULL); /* no memory */ | ||
245 | } | ||
246 | |||
247 | do { | ||
248 | f1 = Read_hfc(cs, HFCSX_FIF_F1) & f_msk; | ||
249 | f2 = Read_hfc(cs, HFCSX_FIF_F2) & f_msk; | ||
250 | |||
251 | if (f1 == f2) return(NULL); /* no frame available */ | ||
252 | |||
253 | z1 = Read_hfc(cs, HFCSX_FIF_Z1H); | ||
254 | z1 = ((z1 << 8) | Read_hfc(cs, HFCSX_FIF_Z1L)); | ||
255 | z2 = Read_hfc(cs, HFCSX_FIF_Z2H); | ||
256 | z2 = ((z2 << 8) | Read_hfc(cs, HFCSX_FIF_Z2L)); | ||
257 | |||
258 | if (cs->debug & L1_DEB_ISAC_FIFO) | ||
259 | debugl1(cs, "hfcsx_read_fifo %d f1(%x) f2(%x) z1(f2)(%x) z2(f2)(%x)", | ||
260 | fifo, f1, f2, z1, z2); | ||
261 | /* now determine bytes in actual FIFO buffer */ | ||
262 | count = z1 - z2; | ||
263 | if (count <= 0) | ||
264 | count += fifo_size; /* count now contains buffered bytes */ | ||
265 | count++; | ||
266 | |||
267 | if (cs->debug & L1_DEB_ISAC_FIFO) | ||
268 | debugl1(cs, "hfcsx_read_fifo %d count %ld)", | ||
269 | fifo, count); | ||
270 | |||
271 | if ((count > fifo_size) || (count < 4)) { | ||
272 | if (cs->debug & L1_DEB_WARN) | ||
273 | debugl1(cs, "hfcsx_read_fifo %d paket inv. len %d ", fifo , count); | ||
274 | while (count) { | ||
275 | count--; /* empty fifo */ | ||
276 | Read_hfc(cs, HFCSX_FIF_DRD); | ||
277 | } | ||
278 | skb = NULL; | ||
279 | } else | ||
280 | if ((skb = dev_alloc_skb(count - 3))) { | ||
281 | count -= 3; | ||
282 | dst = skb_put(skb, count); | ||
283 | |||
284 | while (count--) | ||
285 | *dst++ = Read_hfc(cs, HFCSX_FIF_DRD); | ||
286 | |||
287 | Read_hfc(cs, HFCSX_FIF_DRD); /* CRC 1 */ | ||
288 | Read_hfc(cs, HFCSX_FIF_DRD); /* CRC 2 */ | ||
289 | if (Read_hfc(cs, HFCSX_FIF_DRD)) { | ||
290 | dev_kfree_skb_irq(skb); | ||
291 | if (cs->debug & L1_DEB_ISAC_FIFO) | ||
292 | debugl1(cs, "hfcsx_read_fifo %d crc error", fifo); | ||
293 | skb = NULL; | ||
294 | } | ||
295 | } else { | ||
296 | printk(KERN_WARNING "HFC-SX: receive out of memory\n"); | ||
297 | return(NULL); | ||
298 | } | ||
299 | |||
300 | Read_hfc(cs, HFCSX_FIF_INCF2); /* increment F2 */ | ||
301 | udelay(1); | ||
302 | while (bytein(cs->hw.hfcsx.base+1) & 1); /* wait for busy */ | ||
303 | udelay(1); | ||
304 | } while (!skb); /* retry in case of crc error */ | ||
305 | return(skb); | ||
306 | } | ||
307 | |||
308 | /******************************************/ | ||
309 | /* free hardware resources used by driver */ | ||
310 | /******************************************/ | ||
311 | void | ||
312 | release_io_hfcsx(struct IsdnCardState *cs) | ||
313 | { | ||
314 | cs->hw.hfcsx.int_m2 = 0; /* interrupt output off ! */ | ||
315 | Write_hfc(cs, HFCSX_INT_M2, cs->hw.hfcsx.int_m2); | ||
316 | Write_hfc(cs, HFCSX_CIRM, HFCSX_RESET); /* Reset On */ | ||
317 | msleep(30); /* Timeout 30ms */ | ||
318 | Write_hfc(cs, HFCSX_CIRM, 0); /* Reset Off */ | ||
319 | del_timer(&cs->hw.hfcsx.timer); | ||
320 | release_region(cs->hw.hfcsx.base, 2); /* release IO-Block */ | ||
321 | kfree(cs->hw.hfcsx.extra); | ||
322 | cs->hw.hfcsx.extra = NULL; | ||
323 | } | ||
324 | |||
325 | /**********************************************************/ | ||
326 | /* set_fifo_size determines the size of the RAM and FIFOs */ | ||
327 | /* returning 0 -> need to reset the chip again. */ | ||
328 | /**********************************************************/ | ||
329 | static int set_fifo_size(struct IsdnCardState *cs) | ||
330 | { | ||
331 | |||
332 | if (cs->hw.hfcsx.b_fifo_size) return(1); /* already determined */ | ||
333 | |||
334 | if ((cs->hw.hfcsx.chip >> 4) == 9) { | ||
335 | cs->hw.hfcsx.b_fifo_size = B_FIFO_SIZE_32K; | ||
336 | return(1); | ||
337 | } | ||
338 | |||
339 | cs->hw.hfcsx.b_fifo_size = B_FIFO_SIZE_8K; | ||
340 | cs->hw.hfcsx.cirm |= 0x10; /* only 8K of ram */ | ||
341 | return(0); | ||
342 | |||
343 | } | ||
344 | |||
345 | /********************************************************************************/ | ||
346 | /* function called to reset the HFC SX chip. A complete software reset of chip */ | ||
347 | /* and fifos is done. */ | ||
348 | /********************************************************************************/ | ||
349 | static void | ||
350 | reset_hfcsx(struct IsdnCardState *cs) | ||
351 | { | ||
352 | cs->hw.hfcsx.int_m2 = 0; /* interrupt output off ! */ | ||
353 | Write_hfc(cs, HFCSX_INT_M2, cs->hw.hfcsx.int_m2); | ||
354 | |||
355 | printk(KERN_INFO "HFC_SX: resetting card\n"); | ||
356 | while (1) { | ||
357 | Write_hfc(cs, HFCSX_CIRM, HFCSX_RESET | cs->hw.hfcsx.cirm ); /* Reset */ | ||
358 | mdelay(30); | ||
359 | Write_hfc(cs, HFCSX_CIRM, cs->hw.hfcsx.cirm); /* Reset Off */ | ||
360 | mdelay(20); | ||
361 | if (Read_hfc(cs, HFCSX_STATUS) & 2) | ||
362 | printk(KERN_WARNING "HFC-SX init bit busy\n"); | ||
363 | cs->hw.hfcsx.last_fifo = 0xff; /* invalidate */ | ||
364 | if (!set_fifo_size(cs)) continue; | ||
365 | break; | ||
366 | } | ||
367 | |||
368 | cs->hw.hfcsx.trm = 0 + HFCSX_BTRANS_THRESMASK; /* no echo connect , threshold */ | ||
369 | Write_hfc(cs, HFCSX_TRM, cs->hw.hfcsx.trm); | ||
370 | |||
371 | Write_hfc(cs, HFCSX_CLKDEL, 0x0e); /* ST-Bit delay for TE-Mode */ | ||
372 | cs->hw.hfcsx.sctrl_e = HFCSX_AUTO_AWAKE; | ||
373 | Write_hfc(cs, HFCSX_SCTRL_E, cs->hw.hfcsx.sctrl_e); /* S/T Auto awake */ | ||
374 | cs->hw.hfcsx.bswapped = 0; /* no exchange */ | ||
375 | cs->hw.hfcsx.nt_mode = 0; /* we are in TE mode */ | ||
376 | cs->hw.hfcsx.ctmt = HFCSX_TIM3_125 | HFCSX_AUTO_TIMER; | ||
377 | Write_hfc(cs, HFCSX_CTMT, cs->hw.hfcsx.ctmt); | ||
378 | |||
379 | cs->hw.hfcsx.int_m1 = HFCSX_INTS_DTRANS | HFCSX_INTS_DREC | | ||
380 | HFCSX_INTS_L1STATE | HFCSX_INTS_TIMER; | ||
381 | Write_hfc(cs, HFCSX_INT_M1, cs->hw.hfcsx.int_m1); | ||
382 | |||
383 | /* Clear already pending ints */ | ||
384 | if (Read_hfc(cs, HFCSX_INT_S1)); | ||
385 | |||
386 | Write_hfc(cs, HFCSX_STATES, HFCSX_LOAD_STATE | 2); /* HFC ST 2 */ | ||
387 | udelay(10); | ||
388 | Write_hfc(cs, HFCSX_STATES, 2); /* HFC ST 2 */ | ||
389 | cs->hw.hfcsx.mst_m = HFCSX_MASTER; /* HFC Master Mode */ | ||
390 | |||
391 | Write_hfc(cs, HFCSX_MST_MODE, cs->hw.hfcsx.mst_m); | ||
392 | cs->hw.hfcsx.sctrl = 0x40; /* set tx_lo mode, error in datasheet ! */ | ||
393 | Write_hfc(cs, HFCSX_SCTRL, cs->hw.hfcsx.sctrl); | ||
394 | cs->hw.hfcsx.sctrl_r = 0; | ||
395 | Write_hfc(cs, HFCSX_SCTRL_R, cs->hw.hfcsx.sctrl_r); | ||
396 | |||
397 | /* Init GCI/IOM2 in master mode */ | ||
398 | /* Slots 0 and 1 are set for B-chan 1 and 2 */ | ||
399 | /* D- and monitor/CI channel are not enabled */ | ||
400 | /* STIO1 is used as output for data, B1+B2 from ST->IOM+HFC */ | ||
401 | /* STIO2 is used as data input, B1+B2 from IOM->ST */ | ||
402 | /* ST B-channel send disabled -> continous 1s */ | ||
403 | /* The IOM slots are always enabled */ | ||
404 | cs->hw.hfcsx.conn = 0x36; /* set data flow directions */ | ||
405 | Write_hfc(cs, HFCSX_CONNECT, cs->hw.hfcsx.conn); | ||
406 | Write_hfc(cs, HFCSX_B1_SSL, 0x80); /* B1-Slot 0 STIO1 out enabled */ | ||
407 | Write_hfc(cs, HFCSX_B2_SSL, 0x81); /* B2-Slot 1 STIO1 out enabled */ | ||
408 | Write_hfc(cs, HFCSX_B1_RSL, 0x80); /* B1-Slot 0 STIO2 in enabled */ | ||
409 | Write_hfc(cs, HFCSX_B2_RSL, 0x81); /* B2-Slot 1 STIO2 in enabled */ | ||
410 | |||
411 | /* Finally enable IRQ output */ | ||
412 | cs->hw.hfcsx.int_m2 = HFCSX_IRQ_ENABLE; | ||
413 | Write_hfc(cs, HFCSX_INT_M2, cs->hw.hfcsx.int_m2); | ||
414 | if (Read_hfc(cs, HFCSX_INT_S2)); | ||
415 | } | ||
416 | |||
417 | /***************************************************/ | ||
418 | /* Timer function called when kernel timer expires */ | ||
419 | /***************************************************/ | ||
420 | static void | ||
421 | hfcsx_Timer(struct IsdnCardState *cs) | ||
422 | { | ||
423 | cs->hw.hfcsx.timer.expires = jiffies + 75; | ||
424 | /* WD RESET */ | ||
425 | /* WriteReg(cs, HFCD_DATA, HFCD_CTMT, cs->hw.hfcsx.ctmt | 0x80); | ||
426 | add_timer(&cs->hw.hfcsx.timer); | ||
427 | */ | ||
428 | } | ||
429 | |||
430 | /************************************************/ | ||
431 | /* select a b-channel entry matching and active */ | ||
432 | /************************************************/ | ||
433 | static | ||
434 | struct BCState * | ||
435 | Sel_BCS(struct IsdnCardState *cs, int channel) | ||
436 | { | ||
437 | if (cs->bcs[0].mode && (cs->bcs[0].channel == channel)) | ||
438 | return (&cs->bcs[0]); | ||
439 | else if (cs->bcs[1].mode && (cs->bcs[1].channel == channel)) | ||
440 | return (&cs->bcs[1]); | ||
441 | else | ||
442 | return (NULL); | ||
443 | } | ||
444 | |||
445 | /*******************************/ | ||
446 | /* D-channel receive procedure */ | ||
447 | /*******************************/ | ||
448 | static | ||
449 | int | ||
450 | receive_dmsg(struct IsdnCardState *cs) | ||
451 | { | ||
452 | struct sk_buff *skb; | ||
453 | int count = 5; | ||
454 | |||
455 | if (test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { | ||
456 | debugl1(cs, "rec_dmsg blocked"); | ||
457 | return (1); | ||
458 | } | ||
459 | |||
460 | do { | ||
461 | skb = read_fifo(cs, HFCSX_SEL_D_RX, 0); | ||
462 | if (skb) { | ||
463 | skb_queue_tail(&cs->rq, skb); | ||
464 | schedule_event(cs, D_RCVBUFREADY); | ||
465 | } | ||
466 | } while (--count && skb); | ||
467 | |||
468 | test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); | ||
469 | return (1); | ||
470 | } | ||
471 | |||
472 | /**********************************/ | ||
473 | /* B-channel main receive routine */ | ||
474 | /**********************************/ | ||
475 | void | ||
476 | main_rec_hfcsx(struct BCState *bcs) | ||
477 | { | ||
478 | struct IsdnCardState *cs = bcs->cs; | ||
479 | int count = 5; | ||
480 | struct sk_buff *skb; | ||
481 | |||
482 | Begin: | ||
483 | count--; | ||
484 | if (test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { | ||
485 | debugl1(cs, "rec_data %d blocked", bcs->channel); | ||
486 | return; | ||
487 | } | ||
488 | skb = read_fifo(cs, ((bcs->channel) && (!cs->hw.hfcsx.bswapped)) ? | ||
489 | HFCSX_SEL_B2_RX : HFCSX_SEL_B1_RX, | ||
490 | (bcs->mode == L1_MODE_TRANS) ? | ||
491 | HFCSX_BTRANS_THRESHOLD : 0); | ||
492 | |||
493 | if (skb) { | ||
494 | skb_queue_tail(&bcs->rqueue, skb); | ||
495 | schedule_event(bcs, B_RCVBUFREADY); | ||
496 | } | ||
497 | |||
498 | test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); | ||
499 | if (count && skb) | ||
500 | goto Begin; | ||
501 | return; | ||
502 | } | ||
503 | |||
504 | /**************************/ | ||
505 | /* D-channel send routine */ | ||
506 | /**************************/ | ||
507 | static void | ||
508 | hfcsx_fill_dfifo(struct IsdnCardState *cs) | ||
509 | { | ||
510 | if (!cs->tx_skb) | ||
511 | return; | ||
512 | if (cs->tx_skb->len <= 0) | ||
513 | return; | ||
514 | |||
515 | if (write_fifo(cs, cs->tx_skb, HFCSX_SEL_D_TX, 0)) { | ||
516 | dev_kfree_skb_any(cs->tx_skb); | ||
517 | cs->tx_skb = NULL; | ||
518 | } | ||
519 | return; | ||
520 | } | ||
521 | |||
522 | /**************************/ | ||
523 | /* B-channel send routine */ | ||
524 | /**************************/ | ||
525 | static void | ||
526 | hfcsx_fill_fifo(struct BCState *bcs) | ||
527 | { | ||
528 | struct IsdnCardState *cs = bcs->cs; | ||
529 | |||
530 | if (!bcs->tx_skb) | ||
531 | return; | ||
532 | if (bcs->tx_skb->len <= 0) | ||
533 | return; | ||
534 | |||
535 | if (write_fifo(cs, bcs->tx_skb, | ||
536 | ((bcs->channel) && (!cs->hw.hfcsx.bswapped)) ? | ||
537 | HFCSX_SEL_B2_TX : HFCSX_SEL_B1_TX, | ||
538 | (bcs->mode == L1_MODE_TRANS) ? | ||
539 | HFCSX_BTRANS_THRESHOLD : 0)) { | ||
540 | |||
541 | bcs->tx_cnt -= bcs->tx_skb->len; | ||
542 | if (test_bit(FLG_LLI_L1WAKEUP,&bcs->st->lli.flag) && | ||
543 | (PACKET_NOACK != bcs->tx_skb->pkt_type)) { | ||
544 | u_long flags; | ||
545 | spin_lock_irqsave(&bcs->aclock, flags); | ||
546 | bcs->ackcnt += bcs->tx_skb->len; | ||
547 | spin_unlock_irqrestore(&bcs->aclock, flags); | ||
548 | schedule_event(bcs, B_ACKPENDING); | ||
549 | } | ||
550 | dev_kfree_skb_any(bcs->tx_skb); | ||
551 | bcs->tx_skb = NULL; | ||
552 | test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); | ||
553 | } | ||
554 | } | ||
555 | |||
556 | /**********************************************/ | ||
557 | /* D-channel l1 state call for leased NT-mode */ | ||
558 | /**********************************************/ | ||
559 | static void | ||
560 | dch_nt_l2l1(struct PStack *st, int pr, void *arg) | ||
561 | { | ||
562 | struct IsdnCardState *cs = (struct IsdnCardState *) st->l1.hardware; | ||
563 | |||
564 | switch (pr) { | ||
565 | case (PH_DATA | REQUEST): | ||
566 | case (PH_PULL | REQUEST): | ||
567 | case (PH_PULL | INDICATION): | ||
568 | st->l1.l1hw(st, pr, arg); | ||
569 | break; | ||
570 | case (PH_ACTIVATE | REQUEST): | ||
571 | st->l1.l1l2(st, PH_ACTIVATE | CONFIRM, NULL); | ||
572 | break; | ||
573 | case (PH_TESTLOOP | REQUEST): | ||
574 | if (1 & (long) arg) | ||
575 | debugl1(cs, "PH_TEST_LOOP B1"); | ||
576 | if (2 & (long) arg) | ||
577 | debugl1(cs, "PH_TEST_LOOP B2"); | ||
578 | if (!(3 & (long) arg)) | ||
579 | debugl1(cs, "PH_TEST_LOOP DISABLED"); | ||
580 | st->l1.l1hw(st, HW_TESTLOOP | REQUEST, arg); | ||
581 | break; | ||
582 | default: | ||
583 | if (cs->debug) | ||
584 | debugl1(cs, "dch_nt_l2l1 msg %04X unhandled", pr); | ||
585 | break; | ||
586 | } | ||
587 | } | ||
588 | |||
589 | |||
590 | |||
591 | /***********************/ | ||
592 | /* set/reset echo mode */ | ||
593 | /***********************/ | ||
594 | static int | ||
595 | hfcsx_auxcmd(struct IsdnCardState *cs, isdn_ctrl * ic) | ||
596 | { | ||
597 | unsigned long flags; | ||
598 | int i = *(unsigned int *) ic->parm.num; | ||
599 | |||
600 | if ((ic->arg == 98) && | ||
601 | (!(cs->hw.hfcsx.int_m1 & (HFCSX_INTS_B2TRANS + HFCSX_INTS_B2REC + HFCSX_INTS_B1TRANS + HFCSX_INTS_B1REC)))) { | ||
602 | spin_lock_irqsave(&cs->lock, flags); | ||
603 | Write_hfc(cs, HFCSX_STATES, HFCSX_LOAD_STATE | 0); /* HFC ST G0 */ | ||
604 | udelay(10); | ||
605 | cs->hw.hfcsx.sctrl |= SCTRL_MODE_NT; | ||
606 | Write_hfc(cs, HFCSX_SCTRL, cs->hw.hfcsx.sctrl); /* set NT-mode */ | ||
607 | udelay(10); | ||
608 | Write_hfc(cs, HFCSX_STATES, HFCSX_LOAD_STATE | 1); /* HFC ST G1 */ | ||
609 | udelay(10); | ||
610 | Write_hfc(cs, HFCSX_STATES, 1 | HFCSX_ACTIVATE | HFCSX_DO_ACTION); | ||
611 | cs->dc.hfcsx.ph_state = 1; | ||
612 | cs->hw.hfcsx.nt_mode = 1; | ||
613 | cs->hw.hfcsx.nt_timer = 0; | ||
614 | spin_unlock_irqrestore(&cs->lock, flags); | ||
615 | cs->stlist->l2.l2l1 = dch_nt_l2l1; | ||
616 | debugl1(cs, "NT mode activated"); | ||
617 | return (0); | ||
618 | } | ||
619 | if ((cs->chanlimit > 1) || (cs->hw.hfcsx.bswapped) || | ||
620 | (cs->hw.hfcsx.nt_mode) || (ic->arg != 12)) | ||
621 | return (-EINVAL); | ||
622 | |||
623 | if (i) { | ||
624 | cs->logecho = 1; | ||
625 | cs->hw.hfcsx.trm |= 0x20; /* enable echo chan */ | ||
626 | cs->hw.hfcsx.int_m1 |= HFCSX_INTS_B2REC; | ||
627 | /* reset Channel !!!!! */ | ||
628 | } else { | ||
629 | cs->logecho = 0; | ||
630 | cs->hw.hfcsx.trm &= ~0x20; /* disable echo chan */ | ||
631 | cs->hw.hfcsx.int_m1 &= ~HFCSX_INTS_B2REC; | ||
632 | } | ||
633 | cs->hw.hfcsx.sctrl_r &= ~SCTRL_B2_ENA; | ||
634 | cs->hw.hfcsx.sctrl &= ~SCTRL_B2_ENA; | ||
635 | cs->hw.hfcsx.conn |= 0x10; /* B2-IOM -> B2-ST */ | ||
636 | cs->hw.hfcsx.ctmt &= ~2; | ||
637 | spin_lock_irqsave(&cs->lock, flags); | ||
638 | Write_hfc(cs, HFCSX_CTMT, cs->hw.hfcsx.ctmt); | ||
639 | Write_hfc(cs, HFCSX_SCTRL_R, cs->hw.hfcsx.sctrl_r); | ||
640 | Write_hfc(cs, HFCSX_SCTRL, cs->hw.hfcsx.sctrl); | ||
641 | Write_hfc(cs, HFCSX_CONNECT, cs->hw.hfcsx.conn); | ||
642 | Write_hfc(cs, HFCSX_TRM, cs->hw.hfcsx.trm); | ||
643 | Write_hfc(cs, HFCSX_INT_M1, cs->hw.hfcsx.int_m1); | ||
644 | spin_unlock_irqrestore(&cs->lock, flags); | ||
645 | return (0); | ||
646 | } /* hfcsx_auxcmd */ | ||
647 | |||
648 | /*****************************/ | ||
649 | /* E-channel receive routine */ | ||
650 | /*****************************/ | ||
651 | static void | ||
652 | receive_emsg(struct IsdnCardState *cs) | ||
653 | { | ||
654 | int count = 5; | ||
655 | u_char *ptr; | ||
656 | struct sk_buff *skb; | ||
657 | |||
658 | if (test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { | ||
659 | debugl1(cs, "echo_rec_data blocked"); | ||
660 | return; | ||
661 | } | ||
662 | do { | ||
663 | skb = read_fifo(cs, HFCSX_SEL_B2_RX, 0); | ||
664 | if (skb) { | ||
665 | if (cs->debug & DEB_DLOG_HEX) { | ||
666 | ptr = cs->dlog; | ||
667 | if ((skb->len) < MAX_DLOG_SPACE / 3 - 10) { | ||
668 | *ptr++ = 'E'; | ||
669 | *ptr++ = 'C'; | ||
670 | *ptr++ = 'H'; | ||
671 | *ptr++ = 'O'; | ||
672 | *ptr++ = ':'; | ||
673 | ptr += QuickHex(ptr, skb->data, skb->len); | ||
674 | ptr--; | ||
675 | *ptr++ = '\n'; | ||
676 | *ptr = 0; | ||
677 | HiSax_putstatus(cs, NULL, cs->dlog); | ||
678 | } else | ||
679 | HiSax_putstatus(cs, "LogEcho: ", "warning Frame too big (%d)", skb->len); | ||
680 | } | ||
681 | dev_kfree_skb_any(skb); | ||
682 | } | ||
683 | } while (--count && skb); | ||
684 | |||
685 | test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); | ||
686 | return; | ||
687 | } /* receive_emsg */ | ||
688 | |||
689 | |||
690 | /*********************/ | ||
691 | /* Interrupt handler */ | ||
692 | /*********************/ | ||
693 | static irqreturn_t | ||
694 | hfcsx_interrupt(int intno, void *dev_id, struct pt_regs *regs) | ||
695 | { | ||
696 | struct IsdnCardState *cs = dev_id; | ||
697 | u_char exval; | ||
698 | struct BCState *bcs; | ||
699 | int count = 15; | ||
700 | u_long flags; | ||
701 | u_char val, stat; | ||
702 | |||
703 | if (!(cs->hw.hfcsx.int_m2 & 0x08)) | ||
704 | return IRQ_NONE; /* not initialised */ | ||
705 | |||
706 | spin_lock_irqsave(&cs->lock, flags); | ||
707 | if (HFCSX_ANYINT & (stat = Read_hfc(cs, HFCSX_STATUS))) { | ||
708 | val = Read_hfc(cs, HFCSX_INT_S1); | ||
709 | if (cs->debug & L1_DEB_ISAC) | ||
710 | debugl1(cs, "HFC-SX: stat(%02x) s1(%02x)", stat, val); | ||
711 | } else { | ||
712 | spin_unlock_irqrestore(&cs->lock, flags); | ||
713 | return IRQ_NONE; | ||
714 | } | ||
715 | if (cs->debug & L1_DEB_ISAC) | ||
716 | debugl1(cs, "HFC-SX irq %x %s", val, | ||
717 | test_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags) ? | ||
718 | "locked" : "unlocked"); | ||
719 | val &= cs->hw.hfcsx.int_m1; | ||
720 | if (val & 0x40) { /* state machine irq */ | ||
721 | exval = Read_hfc(cs, HFCSX_STATES) & 0xf; | ||
722 | if (cs->debug & L1_DEB_ISAC) | ||
723 | debugl1(cs, "ph_state chg %d->%d", cs->dc.hfcsx.ph_state, | ||
724 | exval); | ||
725 | cs->dc.hfcsx.ph_state = exval; | ||
726 | schedule_event(cs, D_L1STATECHANGE); | ||
727 | val &= ~0x40; | ||
728 | } | ||
729 | if (val & 0x80) { /* timer irq */ | ||
730 | if (cs->hw.hfcsx.nt_mode) { | ||
731 | if ((--cs->hw.hfcsx.nt_timer) < 0) | ||
732 | schedule_event(cs, D_L1STATECHANGE); | ||
733 | } | ||
734 | val &= ~0x80; | ||
735 | Write_hfc(cs, HFCSX_CTMT, cs->hw.hfcsx.ctmt | HFCSX_CLTIMER); | ||
736 | } | ||
737 | while (val) { | ||
738 | if (test_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { | ||
739 | cs->hw.hfcsx.int_s1 |= val; | ||
740 | spin_unlock_irqrestore(&cs->lock, flags); | ||
741 | return IRQ_HANDLED; | ||
742 | } | ||
743 | if (cs->hw.hfcsx.int_s1 & 0x18) { | ||
744 | exval = val; | ||
745 | val = cs->hw.hfcsx.int_s1; | ||
746 | cs->hw.hfcsx.int_s1 = exval; | ||
747 | } | ||
748 | if (val & 0x08) { | ||
749 | if (!(bcs = Sel_BCS(cs, cs->hw.hfcsx.bswapped ? 1 : 0))) { | ||
750 | if (cs->debug) | ||
751 | debugl1(cs, "hfcsx spurious 0x08 IRQ"); | ||
752 | } else | ||
753 | main_rec_hfcsx(bcs); | ||
754 | } | ||
755 | if (val & 0x10) { | ||
756 | if (cs->logecho) | ||
757 | receive_emsg(cs); | ||
758 | else if (!(bcs = Sel_BCS(cs, 1))) { | ||
759 | if (cs->debug) | ||
760 | debugl1(cs, "hfcsx spurious 0x10 IRQ"); | ||
761 | } else | ||
762 | main_rec_hfcsx(bcs); | ||
763 | } | ||
764 | if (val & 0x01) { | ||
765 | if (!(bcs = Sel_BCS(cs, cs->hw.hfcsx.bswapped ? 1 : 0))) { | ||
766 | if (cs->debug) | ||
767 | debugl1(cs, "hfcsx spurious 0x01 IRQ"); | ||
768 | } else { | ||
769 | if (bcs->tx_skb) { | ||
770 | if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { | ||
771 | hfcsx_fill_fifo(bcs); | ||
772 | test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); | ||
773 | } else | ||
774 | debugl1(cs, "fill_data %d blocked", bcs->channel); | ||
775 | } else { | ||
776 | if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) { | ||
777 | if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { | ||
778 | hfcsx_fill_fifo(bcs); | ||
779 | test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); | ||
780 | } else | ||
781 | debugl1(cs, "fill_data %d blocked", bcs->channel); | ||
782 | } else { | ||
783 | schedule_event(bcs, B_XMTBUFREADY); | ||
784 | } | ||
785 | } | ||
786 | } | ||
787 | } | ||
788 | if (val & 0x02) { | ||
789 | if (!(bcs = Sel_BCS(cs, 1))) { | ||
790 | if (cs->debug) | ||
791 | debugl1(cs, "hfcsx spurious 0x02 IRQ"); | ||
792 | } else { | ||
793 | if (bcs->tx_skb) { | ||
794 | if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { | ||
795 | hfcsx_fill_fifo(bcs); | ||
796 | test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); | ||
797 | } else | ||
798 | debugl1(cs, "fill_data %d blocked", bcs->channel); | ||
799 | } else { | ||
800 | if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) { | ||
801 | if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { | ||
802 | hfcsx_fill_fifo(bcs); | ||
803 | test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); | ||
804 | } else | ||
805 | debugl1(cs, "fill_data %d blocked", bcs->channel); | ||
806 | } else { | ||
807 | schedule_event(bcs, B_XMTBUFREADY); | ||
808 | } | ||
809 | } | ||
810 | } | ||
811 | } | ||
812 | if (val & 0x20) { /* receive dframe */ | ||
813 | receive_dmsg(cs); | ||
814 | } | ||
815 | if (val & 0x04) { /* dframe transmitted */ | ||
816 | if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) | ||
817 | del_timer(&cs->dbusytimer); | ||
818 | if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags)) | ||
819 | schedule_event(cs, D_CLEARBUSY); | ||
820 | if (cs->tx_skb) { | ||
821 | if (cs->tx_skb->len) { | ||
822 | if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { | ||
823 | hfcsx_fill_dfifo(cs); | ||
824 | test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); | ||
825 | } else { | ||
826 | debugl1(cs, "hfcsx_fill_dfifo irq blocked"); | ||
827 | } | ||
828 | goto afterXPR; | ||
829 | } else { | ||
830 | dev_kfree_skb_irq(cs->tx_skb); | ||
831 | cs->tx_cnt = 0; | ||
832 | cs->tx_skb = NULL; | ||
833 | } | ||
834 | } | ||
835 | if ((cs->tx_skb = skb_dequeue(&cs->sq))) { | ||
836 | cs->tx_cnt = 0; | ||
837 | if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { | ||
838 | hfcsx_fill_dfifo(cs); | ||
839 | test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); | ||
840 | } else { | ||
841 | debugl1(cs, "hfcsx_fill_dfifo irq blocked"); | ||
842 | } | ||
843 | } else | ||
844 | schedule_event(cs, D_XMTBUFREADY); | ||
845 | } | ||
846 | afterXPR: | ||
847 | if (cs->hw.hfcsx.int_s1 && count--) { | ||
848 | val = cs->hw.hfcsx.int_s1; | ||
849 | cs->hw.hfcsx.int_s1 = 0; | ||
850 | if (cs->debug & L1_DEB_ISAC) | ||
851 | debugl1(cs, "HFC-SX irq %x loop %d", val, 15 - count); | ||
852 | } else | ||
853 | val = 0; | ||
854 | } | ||
855 | spin_unlock_irqrestore(&cs->lock, flags); | ||
856 | return IRQ_HANDLED; | ||
857 | } | ||
858 | |||
859 | /********************************************************************/ | ||
860 | /* timer callback for D-chan busy resolution. Currently no function */ | ||
861 | /********************************************************************/ | ||
862 | static void | ||
863 | hfcsx_dbusy_timer(struct IsdnCardState *cs) | ||
864 | { | ||
865 | } | ||
866 | |||
867 | /*************************************/ | ||
868 | /* Layer 1 D-channel hardware access */ | ||
869 | /*************************************/ | ||
870 | static void | ||
871 | HFCSX_l1hw(struct PStack *st, int pr, void *arg) | ||
872 | { | ||
873 | struct IsdnCardState *cs = (struct IsdnCardState *) st->l1.hardware; | ||
874 | struct sk_buff *skb = arg; | ||
875 | u_long flags; | ||
876 | |||
877 | switch (pr) { | ||
878 | case (PH_DATA | REQUEST): | ||
879 | if (cs->debug & DEB_DLOG_HEX) | ||
880 | LogFrame(cs, skb->data, skb->len); | ||
881 | if (cs->debug & DEB_DLOG_VERBOSE) | ||
882 | dlogframe(cs, skb, 0); | ||
883 | spin_lock_irqsave(&cs->lock, flags); | ||
884 | if (cs->tx_skb) { | ||
885 | skb_queue_tail(&cs->sq, skb); | ||
886 | #ifdef L2FRAME_DEBUG /* psa */ | ||
887 | if (cs->debug & L1_DEB_LAPD) | ||
888 | Logl2Frame(cs, skb, "PH_DATA Queued", 0); | ||
889 | #endif | ||
890 | } else { | ||
891 | cs->tx_skb = skb; | ||
892 | cs->tx_cnt = 0; | ||
893 | #ifdef L2FRAME_DEBUG /* psa */ | ||
894 | if (cs->debug & L1_DEB_LAPD) | ||
895 | Logl2Frame(cs, skb, "PH_DATA", 0); | ||
896 | #endif | ||
897 | if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { | ||
898 | hfcsx_fill_dfifo(cs); | ||
899 | test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); | ||
900 | } else | ||
901 | debugl1(cs, "hfcsx_fill_dfifo blocked"); | ||
902 | |||
903 | } | ||
904 | spin_unlock_irqrestore(&cs->lock, flags); | ||
905 | break; | ||
906 | case (PH_PULL | INDICATION): | ||
907 | spin_lock_irqsave(&cs->lock, flags); | ||
908 | if (cs->tx_skb) { | ||
909 | if (cs->debug & L1_DEB_WARN) | ||
910 | debugl1(cs, " l2l1 tx_skb exist this shouldn't happen"); | ||
911 | skb_queue_tail(&cs->sq, skb); | ||
912 | spin_unlock_irqrestore(&cs->lock, flags); | ||
913 | break; | ||
914 | } | ||
915 | if (cs->debug & DEB_DLOG_HEX) | ||
916 | LogFrame(cs, skb->data, skb->len); | ||
917 | if (cs->debug & DEB_DLOG_VERBOSE) | ||
918 | dlogframe(cs, skb, 0); | ||
919 | cs->tx_skb = skb; | ||
920 | cs->tx_cnt = 0; | ||
921 | #ifdef L2FRAME_DEBUG /* psa */ | ||
922 | if (cs->debug & L1_DEB_LAPD) | ||
923 | Logl2Frame(cs, skb, "PH_DATA_PULLED", 0); | ||
924 | #endif | ||
925 | if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { | ||
926 | hfcsx_fill_dfifo(cs); | ||
927 | test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); | ||
928 | } else | ||
929 | debugl1(cs, "hfcsx_fill_dfifo blocked"); | ||
930 | spin_unlock_irqrestore(&cs->lock, flags); | ||
931 | break; | ||
932 | case (PH_PULL | REQUEST): | ||
933 | #ifdef L2FRAME_DEBUG /* psa */ | ||
934 | if (cs->debug & L1_DEB_LAPD) | ||
935 | debugl1(cs, "-> PH_REQUEST_PULL"); | ||
936 | #endif | ||
937 | if (!cs->tx_skb) { | ||
938 | test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags); | ||
939 | st->l1.l1l2(st, PH_PULL | CONFIRM, NULL); | ||
940 | } else | ||
941 | test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags); | ||
942 | break; | ||
943 | case (HW_RESET | REQUEST): | ||
944 | spin_lock_irqsave(&cs->lock, flags); | ||
945 | Write_hfc(cs, HFCSX_STATES, HFCSX_LOAD_STATE | 3); /* HFC ST 3 */ | ||
946 | udelay(6); | ||
947 | Write_hfc(cs, HFCSX_STATES, 3); /* HFC ST 2 */ | ||
948 | cs->hw.hfcsx.mst_m |= HFCSX_MASTER; | ||
949 | Write_hfc(cs, HFCSX_MST_MODE, cs->hw.hfcsx.mst_m); | ||
950 | Write_hfc(cs, HFCSX_STATES, HFCSX_ACTIVATE | HFCSX_DO_ACTION); | ||
951 | spin_unlock_irqrestore(&cs->lock, flags); | ||
952 | l1_msg(cs, HW_POWERUP | CONFIRM, NULL); | ||
953 | break; | ||
954 | case (HW_ENABLE | REQUEST): | ||
955 | spin_lock_irqsave(&cs->lock, flags); | ||
956 | Write_hfc(cs, HFCSX_STATES, HFCSX_ACTIVATE | HFCSX_DO_ACTION); | ||
957 | spin_unlock_irqrestore(&cs->lock, flags); | ||
958 | break; | ||
959 | case (HW_DEACTIVATE | REQUEST): | ||
960 | spin_lock_irqsave(&cs->lock, flags); | ||
961 | cs->hw.hfcsx.mst_m &= ~HFCSX_MASTER; | ||
962 | Write_hfc(cs, HFCSX_MST_MODE, cs->hw.hfcsx.mst_m); | ||
963 | spin_unlock_irqrestore(&cs->lock, flags); | ||
964 | break; | ||
965 | case (HW_INFO3 | REQUEST): | ||
966 | spin_lock_irqsave(&cs->lock, flags); | ||
967 | cs->hw.hfcsx.mst_m |= HFCSX_MASTER; | ||
968 | Write_hfc(cs, HFCSX_MST_MODE, cs->hw.hfcsx.mst_m); | ||
969 | spin_unlock_irqrestore(&cs->lock, flags); | ||
970 | break; | ||
971 | case (HW_TESTLOOP | REQUEST): | ||
972 | spin_lock_irqsave(&cs->lock, flags); | ||
973 | switch ((int) arg) { | ||
974 | case (1): | ||
975 | Write_hfc(cs, HFCSX_B1_SSL, 0x80); /* tx slot */ | ||
976 | Write_hfc(cs, HFCSX_B1_RSL, 0x80); /* rx slot */ | ||
977 | cs->hw.hfcsx.conn = (cs->hw.hfcsx.conn & ~7) | 1; | ||
978 | Write_hfc(cs, HFCSX_CONNECT, cs->hw.hfcsx.conn); | ||
979 | break; | ||
980 | case (2): | ||
981 | Write_hfc(cs, HFCSX_B2_SSL, 0x81); /* tx slot */ | ||
982 | Write_hfc(cs, HFCSX_B2_RSL, 0x81); /* rx slot */ | ||
983 | cs->hw.hfcsx.conn = (cs->hw.hfcsx.conn & ~0x38) | 0x08; | ||
984 | Write_hfc(cs, HFCSX_CONNECT, cs->hw.hfcsx.conn); | ||
985 | break; | ||
986 | default: | ||
987 | spin_unlock_irqrestore(&cs->lock, flags); | ||
988 | if (cs->debug & L1_DEB_WARN) | ||
989 | debugl1(cs, "hfcsx_l1hw loop invalid %4x", (int) arg); | ||
990 | return; | ||
991 | } | ||
992 | cs->hw.hfcsx.trm |= 0x80; /* enable IOM-loop */ | ||
993 | Write_hfc(cs, HFCSX_TRM, cs->hw.hfcsx.trm); | ||
994 | spin_unlock_irqrestore(&cs->lock, flags); | ||
995 | break; | ||
996 | default: | ||
997 | if (cs->debug & L1_DEB_WARN) | ||
998 | debugl1(cs, "hfcsx_l1hw unknown pr %4x", pr); | ||
999 | break; | ||
1000 | } | ||
1001 | } | ||
1002 | |||
1003 | /***********************************************/ | ||
1004 | /* called during init setting l1 stack pointer */ | ||
1005 | /***********************************************/ | ||
1006 | void | ||
1007 | setstack_hfcsx(struct PStack *st, struct IsdnCardState *cs) | ||
1008 | { | ||
1009 | st->l1.l1hw = HFCSX_l1hw; | ||
1010 | } | ||
1011 | |||
1012 | /**************************************/ | ||
1013 | /* send B-channel data if not blocked */ | ||
1014 | /**************************************/ | ||
1015 | static void | ||
1016 | hfcsx_send_data(struct BCState *bcs) | ||
1017 | { | ||
1018 | struct IsdnCardState *cs = bcs->cs; | ||
1019 | |||
1020 | if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { | ||
1021 | hfcsx_fill_fifo(bcs); | ||
1022 | test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); | ||
1023 | } else | ||
1024 | debugl1(cs, "send_data %d blocked", bcs->channel); | ||
1025 | } | ||
1026 | |||
1027 | /***************************************************************/ | ||
1028 | /* activate/deactivate hardware for selected channels and mode */ | ||
1029 | /***************************************************************/ | ||
1030 | void | ||
1031 | mode_hfcsx(struct BCState *bcs, int mode, int bc) | ||
1032 | { | ||
1033 | struct IsdnCardState *cs = bcs->cs; | ||
1034 | int fifo2; | ||
1035 | |||
1036 | if (cs->debug & L1_DEB_HSCX) | ||
1037 | debugl1(cs, "HFCSX bchannel mode %d bchan %d/%d", | ||
1038 | mode, bc, bcs->channel); | ||
1039 | bcs->mode = mode; | ||
1040 | bcs->channel = bc; | ||
1041 | fifo2 = bc; | ||
1042 | if (cs->chanlimit > 1) { | ||
1043 | cs->hw.hfcsx.bswapped = 0; /* B1 and B2 normal mode */ | ||
1044 | cs->hw.hfcsx.sctrl_e &= ~0x80; | ||
1045 | } else { | ||
1046 | if (bc) { | ||
1047 | if (mode != L1_MODE_NULL) { | ||
1048 | cs->hw.hfcsx.bswapped = 1; /* B1 and B2 exchanged */ | ||
1049 | cs->hw.hfcsx.sctrl_e |= 0x80; | ||
1050 | } else { | ||
1051 | cs->hw.hfcsx.bswapped = 0; /* B1 and B2 normal mode */ | ||
1052 | cs->hw.hfcsx.sctrl_e &= ~0x80; | ||
1053 | } | ||
1054 | fifo2 = 0; | ||
1055 | } else { | ||
1056 | cs->hw.hfcsx.bswapped = 0; /* B1 and B2 normal mode */ | ||
1057 | cs->hw.hfcsx.sctrl_e &= ~0x80; | ||
1058 | } | ||
1059 | } | ||
1060 | switch (mode) { | ||
1061 | case (L1_MODE_NULL): | ||
1062 | if (bc) { | ||
1063 | cs->hw.hfcsx.sctrl &= ~SCTRL_B2_ENA; | ||
1064 | cs->hw.hfcsx.sctrl_r &= ~SCTRL_B2_ENA; | ||
1065 | } else { | ||
1066 | cs->hw.hfcsx.sctrl &= ~SCTRL_B1_ENA; | ||
1067 | cs->hw.hfcsx.sctrl_r &= ~SCTRL_B1_ENA; | ||
1068 | } | ||
1069 | if (fifo2) { | ||
1070 | cs->hw.hfcsx.int_m1 &= ~(HFCSX_INTS_B2TRANS + HFCSX_INTS_B2REC); | ||
1071 | } else { | ||
1072 | cs->hw.hfcsx.int_m1 &= ~(HFCSX_INTS_B1TRANS + HFCSX_INTS_B1REC); | ||
1073 | } | ||
1074 | break; | ||
1075 | case (L1_MODE_TRANS): | ||
1076 | if (bc) { | ||
1077 | cs->hw.hfcsx.sctrl |= SCTRL_B2_ENA; | ||
1078 | cs->hw.hfcsx.sctrl_r |= SCTRL_B2_ENA; | ||
1079 | } else { | ||
1080 | cs->hw.hfcsx.sctrl |= SCTRL_B1_ENA; | ||
1081 | cs->hw.hfcsx.sctrl_r |= SCTRL_B1_ENA; | ||
1082 | } | ||
1083 | if (fifo2) { | ||
1084 | cs->hw.hfcsx.int_m1 |= (HFCSX_INTS_B2TRANS + HFCSX_INTS_B2REC); | ||
1085 | cs->hw.hfcsx.ctmt |= 2; | ||
1086 | cs->hw.hfcsx.conn &= ~0x18; | ||
1087 | } else { | ||
1088 | cs->hw.hfcsx.int_m1 |= (HFCSX_INTS_B1TRANS + HFCSX_INTS_B1REC); | ||
1089 | cs->hw.hfcsx.ctmt |= 1; | ||
1090 | cs->hw.hfcsx.conn &= ~0x03; | ||
1091 | } | ||
1092 | break; | ||
1093 | case (L1_MODE_HDLC): | ||
1094 | if (bc) { | ||
1095 | cs->hw.hfcsx.sctrl |= SCTRL_B2_ENA; | ||
1096 | cs->hw.hfcsx.sctrl_r |= SCTRL_B2_ENA; | ||
1097 | } else { | ||
1098 | cs->hw.hfcsx.sctrl |= SCTRL_B1_ENA; | ||
1099 | cs->hw.hfcsx.sctrl_r |= SCTRL_B1_ENA; | ||
1100 | } | ||
1101 | if (fifo2) { | ||
1102 | cs->hw.hfcsx.int_m1 |= (HFCSX_INTS_B2TRANS + HFCSX_INTS_B2REC); | ||
1103 | cs->hw.hfcsx.ctmt &= ~2; | ||
1104 | cs->hw.hfcsx.conn &= ~0x18; | ||
1105 | } else { | ||
1106 | cs->hw.hfcsx.int_m1 |= (HFCSX_INTS_B1TRANS + HFCSX_INTS_B1REC); | ||
1107 | cs->hw.hfcsx.ctmt &= ~1; | ||
1108 | cs->hw.hfcsx.conn &= ~0x03; | ||
1109 | } | ||
1110 | break; | ||
1111 | case (L1_MODE_EXTRN): | ||
1112 | if (bc) { | ||
1113 | cs->hw.hfcsx.conn |= 0x10; | ||
1114 | cs->hw.hfcsx.sctrl |= SCTRL_B2_ENA; | ||
1115 | cs->hw.hfcsx.sctrl_r |= SCTRL_B2_ENA; | ||
1116 | cs->hw.hfcsx.int_m1 &= ~(HFCSX_INTS_B2TRANS + HFCSX_INTS_B2REC); | ||
1117 | } else { | ||
1118 | cs->hw.hfcsx.conn |= 0x02; | ||
1119 | cs->hw.hfcsx.sctrl |= SCTRL_B1_ENA; | ||
1120 | cs->hw.hfcsx.sctrl_r |= SCTRL_B1_ENA; | ||
1121 | cs->hw.hfcsx.int_m1 &= ~(HFCSX_INTS_B1TRANS + HFCSX_INTS_B1REC); | ||
1122 | } | ||
1123 | break; | ||
1124 | } | ||
1125 | Write_hfc(cs, HFCSX_SCTRL_E, cs->hw.hfcsx.sctrl_e); | ||
1126 | Write_hfc(cs, HFCSX_INT_M1, cs->hw.hfcsx.int_m1); | ||
1127 | Write_hfc(cs, HFCSX_SCTRL, cs->hw.hfcsx.sctrl); | ||
1128 | Write_hfc(cs, HFCSX_SCTRL_R, cs->hw.hfcsx.sctrl_r); | ||
1129 | Write_hfc(cs, HFCSX_CTMT, cs->hw.hfcsx.ctmt); | ||
1130 | Write_hfc(cs, HFCSX_CONNECT, cs->hw.hfcsx.conn); | ||
1131 | if (mode != L1_MODE_EXTRN) { | ||
1132 | reset_fifo(cs, fifo2 ? HFCSX_SEL_B2_RX : HFCSX_SEL_B1_RX); | ||
1133 | reset_fifo(cs, fifo2 ? HFCSX_SEL_B2_TX : HFCSX_SEL_B1_TX); | ||
1134 | } | ||
1135 | } | ||
1136 | |||
1137 | /******************************/ | ||
1138 | /* Layer2 -> Layer 1 Transfer */ | ||
1139 | /******************************/ | ||
1140 | static void | ||
1141 | hfcsx_l2l1(struct PStack *st, int pr, void *arg) | ||
1142 | { | ||
1143 | struct BCState *bcs = st->l1.bcs; | ||
1144 | struct sk_buff *skb = arg; | ||
1145 | u_long flags; | ||
1146 | |||
1147 | switch (pr) { | ||
1148 | case (PH_DATA | REQUEST): | ||
1149 | spin_lock_irqsave(&bcs->cs->lock, flags); | ||
1150 | if (bcs->tx_skb) { | ||
1151 | skb_queue_tail(&bcs->squeue, skb); | ||
1152 | } else { | ||
1153 | bcs->tx_skb = skb; | ||
1154 | // test_and_set_bit(BC_FLG_BUSY, &bcs->Flag); | ||
1155 | bcs->cs->BC_Send_Data(bcs); | ||
1156 | } | ||
1157 | spin_unlock_irqrestore(&bcs->cs->lock, flags); | ||
1158 | break; | ||
1159 | case (PH_PULL | INDICATION): | ||
1160 | spin_lock_irqsave(&bcs->cs->lock, flags); | ||
1161 | if (bcs->tx_skb) { | ||
1162 | printk(KERN_WARNING "hfc_l2l1: this shouldn't happen\n"); | ||
1163 | } else { | ||
1164 | // test_and_set_bit(BC_FLG_BUSY, &bcs->Flag); | ||
1165 | bcs->tx_skb = skb; | ||
1166 | bcs->cs->BC_Send_Data(bcs); | ||
1167 | } | ||
1168 | spin_unlock_irqrestore(&bcs->cs->lock, flags); | ||
1169 | break; | ||
1170 | case (PH_PULL | REQUEST): | ||
1171 | if (!bcs->tx_skb) { | ||
1172 | test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags); | ||
1173 | st->l1.l1l2(st, PH_PULL | CONFIRM, NULL); | ||
1174 | } else | ||
1175 | test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags); | ||
1176 | break; | ||
1177 | case (PH_ACTIVATE | REQUEST): | ||
1178 | spin_lock_irqsave(&bcs->cs->lock, flags); | ||
1179 | test_and_set_bit(BC_FLG_ACTIV, &bcs->Flag); | ||
1180 | mode_hfcsx(bcs, st->l1.mode, st->l1.bc); | ||
1181 | spin_unlock_irqrestore(&bcs->cs->lock, flags); | ||
1182 | l1_msg_b(st, pr, arg); | ||
1183 | break; | ||
1184 | case (PH_DEACTIVATE | REQUEST): | ||
1185 | l1_msg_b(st, pr, arg); | ||
1186 | break; | ||
1187 | case (PH_DEACTIVATE | CONFIRM): | ||
1188 | spin_lock_irqsave(&bcs->cs->lock, flags); | ||
1189 | test_and_clear_bit(BC_FLG_ACTIV, &bcs->Flag); | ||
1190 | test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); | ||
1191 | mode_hfcsx(bcs, 0, st->l1.bc); | ||
1192 | spin_unlock_irqrestore(&bcs->cs->lock, flags); | ||
1193 | st->l1.l1l2(st, PH_DEACTIVATE | CONFIRM, NULL); | ||
1194 | break; | ||
1195 | } | ||
1196 | } | ||
1197 | |||
1198 | /******************************************/ | ||
1199 | /* deactivate B-channel access and queues */ | ||
1200 | /******************************************/ | ||
1201 | static void | ||
1202 | close_hfcsx(struct BCState *bcs) | ||
1203 | { | ||
1204 | mode_hfcsx(bcs, 0, bcs->channel); | ||
1205 | if (test_and_clear_bit(BC_FLG_INIT, &bcs->Flag)) { | ||
1206 | skb_queue_purge(&bcs->rqueue); | ||
1207 | skb_queue_purge(&bcs->squeue); | ||
1208 | if (bcs->tx_skb) { | ||
1209 | dev_kfree_skb_any(bcs->tx_skb); | ||
1210 | bcs->tx_skb = NULL; | ||
1211 | test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); | ||
1212 | } | ||
1213 | } | ||
1214 | } | ||
1215 | |||
1216 | /*************************************/ | ||
1217 | /* init B-channel queues and control */ | ||
1218 | /*************************************/ | ||
1219 | static int | ||
1220 | open_hfcsxstate(struct IsdnCardState *cs, struct BCState *bcs) | ||
1221 | { | ||
1222 | if (!test_and_set_bit(BC_FLG_INIT, &bcs->Flag)) { | ||
1223 | skb_queue_head_init(&bcs->rqueue); | ||
1224 | skb_queue_head_init(&bcs->squeue); | ||
1225 | } | ||
1226 | bcs->tx_skb = NULL; | ||
1227 | test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); | ||
1228 | bcs->event = 0; | ||
1229 | bcs->tx_cnt = 0; | ||
1230 | return (0); | ||
1231 | } | ||
1232 | |||
1233 | /*********************************/ | ||
1234 | /* inits the stack for B-channel */ | ||
1235 | /*********************************/ | ||
1236 | static int | ||
1237 | setstack_2b(struct PStack *st, struct BCState *bcs) | ||
1238 | { | ||
1239 | bcs->channel = st->l1.bc; | ||
1240 | if (open_hfcsxstate(st->l1.hardware, bcs)) | ||
1241 | return (-1); | ||
1242 | st->l1.bcs = bcs; | ||
1243 | st->l2.l2l1 = hfcsx_l2l1; | ||
1244 | setstack_manager(st); | ||
1245 | bcs->st = st; | ||
1246 | setstack_l1_B(st); | ||
1247 | return (0); | ||
1248 | } | ||
1249 | |||
1250 | /***************************/ | ||
1251 | /* handle L1 state changes */ | ||
1252 | /***************************/ | ||
1253 | static void | ||
1254 | hfcsx_bh(struct IsdnCardState *cs) | ||
1255 | { | ||
1256 | u_long flags; | ||
1257 | |||
1258 | if (!cs) | ||
1259 | return; | ||
1260 | if (test_and_clear_bit(D_L1STATECHANGE, &cs->event)) { | ||
1261 | if (!cs->hw.hfcsx.nt_mode) | ||
1262 | switch (cs->dc.hfcsx.ph_state) { | ||
1263 | case (0): | ||
1264 | l1_msg(cs, HW_RESET | INDICATION, NULL); | ||
1265 | break; | ||
1266 | case (3): | ||
1267 | l1_msg(cs, HW_DEACTIVATE | INDICATION, NULL); | ||
1268 | break; | ||
1269 | case (8): | ||
1270 | l1_msg(cs, HW_RSYNC | INDICATION, NULL); | ||
1271 | break; | ||
1272 | case (6): | ||
1273 | l1_msg(cs, HW_INFO2 | INDICATION, NULL); | ||
1274 | break; | ||
1275 | case (7): | ||
1276 | l1_msg(cs, HW_INFO4_P8 | INDICATION, NULL); | ||
1277 | break; | ||
1278 | default: | ||
1279 | break; | ||
1280 | } else { | ||
1281 | switch (cs->dc.hfcsx.ph_state) { | ||
1282 | case (2): | ||
1283 | spin_lock_irqsave(&cs->lock, flags); | ||
1284 | if (cs->hw.hfcsx.nt_timer < 0) { | ||
1285 | cs->hw.hfcsx.nt_timer = 0; | ||
1286 | cs->hw.hfcsx.int_m1 &= ~HFCSX_INTS_TIMER; | ||
1287 | Write_hfc(cs, HFCSX_INT_M1, cs->hw.hfcsx.int_m1); | ||
1288 | /* Clear already pending ints */ | ||
1289 | if (Read_hfc(cs, HFCSX_INT_S1)); | ||
1290 | |||
1291 | Write_hfc(cs, HFCSX_STATES, 4 | HFCSX_LOAD_STATE); | ||
1292 | udelay(10); | ||
1293 | Write_hfc(cs, HFCSX_STATES, 4); | ||
1294 | cs->dc.hfcsx.ph_state = 4; | ||
1295 | } else { | ||
1296 | cs->hw.hfcsx.int_m1 |= HFCSX_INTS_TIMER; | ||
1297 | Write_hfc(cs, HFCSX_INT_M1, cs->hw.hfcsx.int_m1); | ||
1298 | cs->hw.hfcsx.ctmt &= ~HFCSX_AUTO_TIMER; | ||
1299 | cs->hw.hfcsx.ctmt |= HFCSX_TIM3_125; | ||
1300 | Write_hfc(cs, HFCSX_CTMT, cs->hw.hfcsx.ctmt | HFCSX_CLTIMER); | ||
1301 | Write_hfc(cs, HFCSX_CTMT, cs->hw.hfcsx.ctmt | HFCSX_CLTIMER); | ||
1302 | cs->hw.hfcsx.nt_timer = NT_T1_COUNT; | ||
1303 | Write_hfc(cs, HFCSX_STATES, 2 | HFCSX_NT_G2_G3); /* allow G2 -> G3 transition */ | ||
1304 | } | ||
1305 | spin_unlock_irqrestore(&cs->lock, flags); | ||
1306 | break; | ||
1307 | case (1): | ||
1308 | case (3): | ||
1309 | case (4): | ||
1310 | spin_lock_irqsave(&cs->lock, flags); | ||
1311 | cs->hw.hfcsx.nt_timer = 0; | ||
1312 | cs->hw.hfcsx.int_m1 &= ~HFCSX_INTS_TIMER; | ||
1313 | Write_hfc(cs, HFCSX_INT_M1, cs->hw.hfcsx.int_m1); | ||
1314 | spin_unlock_irqrestore(&cs->lock, flags); | ||
1315 | break; | ||
1316 | default: | ||
1317 | break; | ||
1318 | } | ||
1319 | } | ||
1320 | } | ||
1321 | if (test_and_clear_bit(D_RCVBUFREADY, &cs->event)) | ||
1322 | DChannel_proc_rcv(cs); | ||
1323 | if (test_and_clear_bit(D_XMTBUFREADY, &cs->event)) | ||
1324 | DChannel_proc_xmt(cs); | ||
1325 | } | ||
1326 | |||
1327 | |||
1328 | /********************************/ | ||
1329 | /* called for card init message */ | ||
1330 | /********************************/ | ||
1331 | void __devinit | ||
1332 | inithfcsx(struct IsdnCardState *cs) | ||
1333 | { | ||
1334 | cs->setstack_d = setstack_hfcsx; | ||
1335 | cs->BC_Send_Data = &hfcsx_send_data; | ||
1336 | cs->bcs[0].BC_SetStack = setstack_2b; | ||
1337 | cs->bcs[1].BC_SetStack = setstack_2b; | ||
1338 | cs->bcs[0].BC_Close = close_hfcsx; | ||
1339 | cs->bcs[1].BC_Close = close_hfcsx; | ||
1340 | mode_hfcsx(cs->bcs, 0, 0); | ||
1341 | mode_hfcsx(cs->bcs + 1, 0, 1); | ||
1342 | } | ||
1343 | |||
1344 | |||
1345 | |||
1346 | /*******************************************/ | ||
1347 | /* handle card messages from control layer */ | ||
1348 | /*******************************************/ | ||
1349 | static int | ||
1350 | hfcsx_card_msg(struct IsdnCardState *cs, int mt, void *arg) | ||
1351 | { | ||
1352 | u_long flags; | ||
1353 | |||
1354 | if (cs->debug & L1_DEB_ISAC) | ||
1355 | debugl1(cs, "HFCSX: card_msg %x", mt); | ||
1356 | switch (mt) { | ||
1357 | case CARD_RESET: | ||
1358 | spin_lock_irqsave(&cs->lock, flags); | ||
1359 | reset_hfcsx(cs); | ||
1360 | spin_unlock_irqrestore(&cs->lock, flags); | ||
1361 | return (0); | ||
1362 | case CARD_RELEASE: | ||
1363 | release_io_hfcsx(cs); | ||
1364 | return (0); | ||
1365 | case CARD_INIT: | ||
1366 | spin_lock_irqsave(&cs->lock, flags); | ||
1367 | inithfcsx(cs); | ||
1368 | spin_unlock_irqrestore(&cs->lock, flags); | ||
1369 | msleep(80); /* Timeout 80ms */ | ||
1370 | /* now switch timer interrupt off */ | ||
1371 | spin_lock_irqsave(&cs->lock, flags); | ||
1372 | cs->hw.hfcsx.int_m1 &= ~HFCSX_INTS_TIMER; | ||
1373 | Write_hfc(cs, HFCSX_INT_M1, cs->hw.hfcsx.int_m1); | ||
1374 | /* reinit mode reg */ | ||
1375 | Write_hfc(cs, HFCSX_MST_MODE, cs->hw.hfcsx.mst_m); | ||
1376 | spin_unlock_irqrestore(&cs->lock, flags); | ||
1377 | return (0); | ||
1378 | case CARD_TEST: | ||
1379 | return (0); | ||
1380 | } | ||
1381 | return (0); | ||
1382 | } | ||
1383 | |||
1384 | #ifdef __ISAPNP__ | ||
1385 | static struct isapnp_device_id hfc_ids[] __devinitdata = { | ||
1386 | { ISAPNP_VENDOR('T', 'A', 'G'), ISAPNP_FUNCTION(0x2620), | ||
1387 | ISAPNP_VENDOR('T', 'A', 'G'), ISAPNP_FUNCTION(0x2620), | ||
1388 | (unsigned long) "Teles 16.3c2" }, | ||
1389 | { 0, } | ||
1390 | }; | ||
1391 | |||
1392 | static struct isapnp_device_id *ipid __devinitdata = &hfc_ids[0]; | ||
1393 | static struct pnp_card *pnp_c __devinitdata = NULL; | ||
1394 | #endif | ||
1395 | |||
1396 | int __devinit | ||
1397 | setup_hfcsx(struct IsdnCard *card) | ||
1398 | { | ||
1399 | struct IsdnCardState *cs = card->cs; | ||
1400 | char tmp[64]; | ||
1401 | |||
1402 | strcpy(tmp, hfcsx_revision); | ||
1403 | printk(KERN_INFO "HiSax: HFC-SX driver Rev. %s\n", HiSax_getrev(tmp)); | ||
1404 | #ifdef __ISAPNP__ | ||
1405 | if (!card->para[1] && isapnp_present()) { | ||
1406 | struct pnp_dev *pnp_d; | ||
1407 | while(ipid->card_vendor) { | ||
1408 | if ((pnp_c = pnp_find_card(ipid->card_vendor, | ||
1409 | ipid->card_device, pnp_c))) { | ||
1410 | pnp_d = NULL; | ||
1411 | if ((pnp_d = pnp_find_dev(pnp_c, | ||
1412 | ipid->vendor, ipid->function, pnp_d))) { | ||
1413 | int err; | ||
1414 | |||
1415 | printk(KERN_INFO "HiSax: %s detected\n", | ||
1416 | (char *)ipid->driver_data); | ||
1417 | pnp_disable_dev(pnp_d); | ||
1418 | err = pnp_activate_dev(pnp_d); | ||
1419 | if (err<0) { | ||
1420 | printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n", | ||
1421 | __FUNCTION__, err); | ||
1422 | return(0); | ||
1423 | } | ||
1424 | card->para[1] = pnp_port_start(pnp_d, 0); | ||
1425 | card->para[0] = pnp_irq(pnp_d, 0); | ||
1426 | if (!card->para[0] || !card->para[1]) { | ||
1427 | printk(KERN_ERR "HFC PnP:some resources are missing %ld/%lx\n", | ||
1428 | card->para[0], card->para[1]); | ||
1429 | pnp_disable_dev(pnp_d); | ||
1430 | return(0); | ||
1431 | } | ||
1432 | break; | ||
1433 | } else { | ||
1434 | printk(KERN_ERR "HFC PnP: PnP error card found, no device\n"); | ||
1435 | } | ||
1436 | } | ||
1437 | ipid++; | ||
1438 | pnp_c = NULL; | ||
1439 | } | ||
1440 | if (!ipid->card_vendor) { | ||
1441 | printk(KERN_INFO "HFC PnP: no ISAPnP card found\n"); | ||
1442 | return(0); | ||
1443 | } | ||
1444 | } | ||
1445 | #endif | ||
1446 | cs->hw.hfcsx.base = card->para[1] & 0xfffe; | ||
1447 | cs->irq = card->para[0]; | ||
1448 | cs->hw.hfcsx.int_s1 = 0; | ||
1449 | cs->dc.hfcsx.ph_state = 0; | ||
1450 | cs->hw.hfcsx.fifo = 255; | ||
1451 | if ((cs->typ == ISDN_CTYPE_HFC_SX) || | ||
1452 | (cs->typ == ISDN_CTYPE_HFC_SP_PCMCIA)) { | ||
1453 | if ((!cs->hw.hfcsx.base) || !request_region(cs->hw.hfcsx.base, 2, "HFCSX isdn")) { | ||
1454 | printk(KERN_WARNING | ||
1455 | "HiSax: HFC-SX io-base %#lx already in use\n", | ||
1456 | cs->hw.hfcsx.base); | ||
1457 | return(0); | ||
1458 | } | ||
1459 | byteout(cs->hw.hfcsx.base, cs->hw.hfcsx.base & 0xFF); | ||
1460 | byteout(cs->hw.hfcsx.base + 1, | ||
1461 | ((cs->hw.hfcsx.base >> 8) & 3) | 0x54); | ||
1462 | udelay(10); | ||
1463 | cs->hw.hfcsx.chip = Read_hfc(cs,HFCSX_CHIP_ID); | ||
1464 | switch (cs->hw.hfcsx.chip >> 4) { | ||
1465 | case 1: | ||
1466 | tmp[0] ='+'; | ||
1467 | break; | ||
1468 | case 9: | ||
1469 | tmp[0] ='P'; | ||
1470 | break; | ||
1471 | default: | ||
1472 | printk(KERN_WARNING | ||
1473 | "HFC-SX: invalid chip id 0x%x\n", | ||
1474 | cs->hw.hfcsx.chip >> 4); | ||
1475 | release_region(cs->hw.hfcsx.base, 2); | ||
1476 | return(0); | ||
1477 | } | ||
1478 | if (!ccd_sp_irqtab[cs->irq & 0xF]) { | ||
1479 | printk(KERN_WARNING | ||
1480 | "HFC_SX: invalid irq %d specified\n",cs->irq & 0xF); | ||
1481 | release_region(cs->hw.hfcsx.base, 2); | ||
1482 | return(0); | ||
1483 | } | ||
1484 | if (!(cs->hw.hfcsx.extra = (void *) | ||
1485 | kmalloc(sizeof(struct hfcsx_extra), GFP_ATOMIC))) { | ||
1486 | release_region(cs->hw.hfcsx.base, 2); | ||
1487 | printk(KERN_WARNING "HFC-SX: unable to allocate memory\n"); | ||
1488 | return(0); | ||
1489 | } | ||
1490 | printk(KERN_INFO "HFC-S%c chip detected at base 0x%x IRQ %d HZ %d\n", | ||
1491 | tmp[0], (u_int) cs->hw.hfcsx.base, cs->irq, HZ); | ||
1492 | cs->hw.hfcsx.int_m2 = 0; /* disable alle interrupts */ | ||
1493 | cs->hw.hfcsx.int_m1 = 0; | ||
1494 | Write_hfc(cs, HFCSX_INT_M1, cs->hw.hfcsx.int_m1); | ||
1495 | Write_hfc(cs, HFCSX_INT_M2, cs->hw.hfcsx.int_m2); | ||
1496 | } else | ||
1497 | return (0); /* no valid card type */ | ||
1498 | |||
1499 | cs->dbusytimer.function = (void *) hfcsx_dbusy_timer; | ||
1500 | cs->dbusytimer.data = (long) cs; | ||
1501 | init_timer(&cs->dbusytimer); | ||
1502 | INIT_WORK(&cs->tqueue, (void *)(void *) hfcsx_bh, cs); | ||
1503 | cs->readisac = NULL; | ||
1504 | cs->writeisac = NULL; | ||
1505 | cs->readisacfifo = NULL; | ||
1506 | cs->writeisacfifo = NULL; | ||
1507 | cs->BC_Read_Reg = NULL; | ||
1508 | cs->BC_Write_Reg = NULL; | ||
1509 | cs->irq_func = &hfcsx_interrupt; | ||
1510 | |||
1511 | cs->hw.hfcsx.timer.function = (void *) hfcsx_Timer; | ||
1512 | cs->hw.hfcsx.timer.data = (long) cs; | ||
1513 | cs->hw.hfcsx.b_fifo_size = 0; /* fifo size still unknown */ | ||
1514 | cs->hw.hfcsx.cirm = ccd_sp_irqtab[cs->irq & 0xF]; /* RAM not evaluated */ | ||
1515 | init_timer(&cs->hw.hfcsx.timer); | ||
1516 | |||
1517 | reset_hfcsx(cs); | ||
1518 | cs->cardmsg = &hfcsx_card_msg; | ||
1519 | cs->auxcmd = &hfcsx_auxcmd; | ||
1520 | return (1); | ||
1521 | } | ||