]>
Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* $Id: netjet.c,v 1.29.2.4 2004/02/11 13:21:34 keil Exp $ |
2 | * | |
3 | * low level stuff for Traverse Technologie NETJet ISDN cards | |
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 | * Thanks to Traverse Technologies Australia for documents and information | |
12 | * | |
13 | * 16-Apr-2002 - led code added - Guy Ellis (guy@traverse.com.au) | |
14 | * | |
15 | */ | |
16 | ||
17 | #include <linux/init.h> | |
18 | #include "hisax.h" | |
19 | #include "isac.h" | |
20 | #include "hscx.h" | |
21 | #include "isdnl1.h" | |
22 | #include <linux/pci.h> | |
23 | #include <linux/interrupt.h> | |
24 | #include <linux/ppp_defs.h> | |
25 | #include <asm/io.h> | |
26 | #include "netjet.h" | |
27 | ||
1da177e4 LT |
28 | /* Interface functions */ |
29 | ||
30 | u_char | |
31 | NETjet_ReadIC(struct IsdnCardState *cs, u_char offset) | |
32 | { | |
33 | u_char ret; | |
34 | ||
35 | cs->hw.njet.auxd &= 0xfc; | |
36 | cs->hw.njet.auxd |= (offset>>4) & 3; | |
37 | byteout(cs->hw.njet.auxa, cs->hw.njet.auxd); | |
38 | ret = bytein(cs->hw.njet.isac + ((offset & 0xf)<<2)); | |
39 | return(ret); | |
40 | } | |
41 | ||
42 | void | |
43 | NETjet_WriteIC(struct IsdnCardState *cs, u_char offset, u_char value) | |
44 | { | |
45 | cs->hw.njet.auxd &= 0xfc; | |
46 | cs->hw.njet.auxd |= (offset>>4) & 3; | |
47 | byteout(cs->hw.njet.auxa, cs->hw.njet.auxd); | |
48 | byteout(cs->hw.njet.isac + ((offset & 0xf)<<2), value); | |
49 | } | |
50 | ||
51 | void | |
52 | NETjet_ReadICfifo(struct IsdnCardState *cs, u_char *data, int size) | |
53 | { | |
54 | cs->hw.njet.auxd &= 0xfc; | |
55 | byteout(cs->hw.njet.auxa, cs->hw.njet.auxd); | |
56 | insb(cs->hw.njet.isac, data, size); | |
57 | } | |
58 | ||
59 | void | |
60 | NETjet_WriteICfifo(struct IsdnCardState *cs, u_char *data, int size) | |
61 | { | |
62 | cs->hw.njet.auxd &= 0xfc; | |
63 | byteout(cs->hw.njet.auxa, cs->hw.njet.auxd); | |
64 | outsb(cs->hw.njet.isac, data, size); | |
65 | } | |
66 | ||
672c3fd9 | 67 | static void fill_mem(struct BCState *bcs, u_int *pos, u_int cnt, int chan, u_char fill) |
1da177e4 LT |
68 | { |
69 | u_int mask=0x000000ff, val = 0, *p=pos; | |
70 | u_int i; | |
71 | ||
72 | val |= fill; | |
73 | if (chan) { | |
74 | val <<= 8; | |
75 | mask <<= 8; | |
76 | } | |
77 | mask ^= 0xffffffff; | |
78 | for (i=0; i<cnt; i++) { | |
79 | *p &= mask; | |
80 | *p++ |= val; | |
81 | if (p > bcs->hw.tiger.s_end) | |
82 | p = bcs->hw.tiger.send; | |
83 | } | |
84 | } | |
85 | ||
672c3fd9 | 86 | static void |
1da177e4 LT |
87 | mode_tiger(struct BCState *bcs, int mode, int bc) |
88 | { | |
89 | struct IsdnCardState *cs = bcs->cs; | |
90 | u_char led; | |
91 | ||
92 | if (cs->debug & L1_DEB_HSCX) | |
93 | debugl1(cs, "Tiger mode %d bchan %d/%d", | |
94 | mode, bc, bcs->channel); | |
95 | bcs->mode = mode; | |
96 | bcs->channel = bc; | |
97 | switch (mode) { | |
98 | case (L1_MODE_NULL): | |
99 | fill_mem(bcs, bcs->hw.tiger.send, | |
100 | NETJET_DMA_TXSIZE, bc, 0xff); | |
101 | if (cs->debug & L1_DEB_HSCX) | |
102 | debugl1(cs, "Tiger stat rec %d/%d send %d", | |
103 | bcs->hw.tiger.r_tot, bcs->hw.tiger.r_err, | |
104 | bcs->hw.tiger.s_tot); | |
105 | if ((cs->bcs[0].mode == L1_MODE_NULL) && | |
106 | (cs->bcs[1].mode == L1_MODE_NULL)) { | |
107 | cs->hw.njet.dmactrl = 0; | |
108 | byteout(cs->hw.njet.base + NETJET_DMACTRL, | |
109 | cs->hw.njet.dmactrl); | |
110 | byteout(cs->hw.njet.base + NETJET_IRQMASK0, 0); | |
111 | } | |
112 | if (cs->typ == ISDN_CTYPE_NETJET_S) | |
113 | { | |
114 | // led off | |
115 | led = bc & 0x01; | |
116 | led = 0x01 << (6 + led); // convert to mask | |
117 | led = ~led; | |
118 | cs->hw.njet.auxd &= led; | |
119 | byteout(cs->hw.njet.auxa, cs->hw.njet.auxd); | |
120 | } | |
121 | break; | |
122 | case (L1_MODE_TRANS): | |
123 | break; | |
124 | case (L1_MODE_HDLC_56K): | |
125 | case (L1_MODE_HDLC): | |
126 | fill_mem(bcs, bcs->hw.tiger.send, | |
127 | NETJET_DMA_TXSIZE, bc, 0xff); | |
128 | bcs->hw.tiger.r_state = HDLC_ZERO_SEARCH; | |
129 | bcs->hw.tiger.r_tot = 0; | |
130 | bcs->hw.tiger.r_bitcnt = 0; | |
131 | bcs->hw.tiger.r_one = 0; | |
132 | bcs->hw.tiger.r_err = 0; | |
133 | bcs->hw.tiger.s_tot = 0; | |
134 | if (! cs->hw.njet.dmactrl) { | |
135 | fill_mem(bcs, bcs->hw.tiger.send, | |
136 | NETJET_DMA_TXSIZE, !bc, 0xff); | |
137 | cs->hw.njet.dmactrl = 1; | |
138 | byteout(cs->hw.njet.base + NETJET_DMACTRL, | |
139 | cs->hw.njet.dmactrl); | |
140 | byteout(cs->hw.njet.base + NETJET_IRQMASK0, 0x0f); | |
141 | /* was 0x3f now 0x0f for TJ300 and TJ320 GE 13/07/00 */ | |
142 | } | |
143 | bcs->hw.tiger.sendp = bcs->hw.tiger.send; | |
144 | bcs->hw.tiger.free = NETJET_DMA_TXSIZE; | |
145 | test_and_set_bit(BC_FLG_EMPTY, &bcs->Flag); | |
146 | if (cs->typ == ISDN_CTYPE_NETJET_S) | |
147 | { | |
148 | // led on | |
149 | led = bc & 0x01; | |
150 | led = 0x01 << (6 + led); // convert to mask | |
151 | cs->hw.njet.auxd |= led; | |
152 | byteout(cs->hw.njet.auxa, cs->hw.njet.auxd); | |
153 | } | |
154 | break; | |
155 | } | |
156 | if (cs->debug & L1_DEB_HSCX) | |
157 | debugl1(cs, "tiger: set %x %x %x %x/%x pulse=%d", | |
158 | bytein(cs->hw.njet.base + NETJET_DMACTRL), | |
159 | bytein(cs->hw.njet.base + NETJET_IRQMASK0), | |
160 | bytein(cs->hw.njet.base + NETJET_IRQSTAT0), | |
161 | inl(cs->hw.njet.base + NETJET_DMA_READ_ADR), | |
162 | inl(cs->hw.njet.base + NETJET_DMA_WRITE_ADR), | |
163 | bytein(cs->hw.njet.base + NETJET_PULSE_CNT)); | |
164 | } | |
165 | ||
166 | static void printframe(struct IsdnCardState *cs, u_char *buf, int count, char *s) { | |
167 | char tmp[128]; | |
168 | char *t = tmp; | |
169 | int i=count,j; | |
170 | u_char *p = buf; | |
171 | ||
172 | t += sprintf(t, "tiger %s(%4d)", s, count); | |
173 | while (i>0) { | |
174 | if (i>16) | |
175 | j=16; | |
176 | else | |
177 | j=i; | |
178 | QuickHex(t, p, j); | |
179 | debugl1(cs, tmp); | |
180 | p += j; | |
181 | i -= j; | |
182 | t = tmp; | |
183 | t += sprintf(t, "tiger %s ", s); | |
184 | } | |
185 | } | |
186 | ||
187 | // macro for 64k | |
188 | ||
189 | #define MAKE_RAW_BYTE for (j=0; j<8; j++) { \ | |
190 | bitcnt++;\ | |
191 | s_val >>= 1;\ | |
192 | if (val & 1) {\ | |
193 | s_one++;\ | |
194 | s_val |= 0x80;\ | |
195 | } else {\ | |
196 | s_one = 0;\ | |
197 | s_val &= 0x7f;\ | |
198 | }\ | |
199 | if (bitcnt==8) {\ | |
200 | bcs->hw.tiger.sendbuf[s_cnt++] = s_val;\ | |
201 | bitcnt = 0;\ | |
202 | }\ | |
203 | if (s_one == 5) {\ | |
204 | s_val >>= 1;\ | |
205 | s_val &= 0x7f;\ | |
206 | bitcnt++;\ | |
207 | s_one = 0;\ | |
208 | }\ | |
209 | if (bitcnt==8) {\ | |
210 | bcs->hw.tiger.sendbuf[s_cnt++] = s_val;\ | |
211 | bitcnt = 0;\ | |
212 | }\ | |
213 | val >>= 1;\ | |
214 | } | |
215 | ||
216 | static int make_raw_data(struct BCState *bcs) { | |
217 | // this make_raw is for 64k | |
218 | register u_int i,s_cnt=0; | |
219 | register u_char j; | |
220 | register u_char val; | |
221 | register u_char s_one = 0; | |
222 | register u_char s_val = 0; | |
223 | register u_char bitcnt = 0; | |
224 | u_int fcs; | |
225 | ||
226 | if (!bcs->tx_skb) { | |
227 | debugl1(bcs->cs, "tiger make_raw: NULL skb"); | |
228 | return(1); | |
229 | } | |
230 | bcs->hw.tiger.sendbuf[s_cnt++] = HDLC_FLAG_VALUE; | |
231 | fcs = PPP_INITFCS; | |
232 | for (i=0; i<bcs->tx_skb->len; i++) { | |
233 | val = bcs->tx_skb->data[i]; | |
234 | fcs = PPP_FCS (fcs, val); | |
235 | MAKE_RAW_BYTE; | |
236 | } | |
237 | fcs ^= 0xffff; | |
238 | val = fcs & 0xff; | |
239 | MAKE_RAW_BYTE; | |
240 | val = (fcs>>8) & 0xff; | |
241 | MAKE_RAW_BYTE; | |
242 | val = HDLC_FLAG_VALUE; | |
243 | for (j=0; j<8; j++) { | |
244 | bitcnt++; | |
245 | s_val >>= 1; | |
246 | if (val & 1) | |
247 | s_val |= 0x80; | |
248 | else | |
249 | s_val &= 0x7f; | |
250 | if (bitcnt==8) { | |
251 | bcs->hw.tiger.sendbuf[s_cnt++] = s_val; | |
252 | bitcnt = 0; | |
253 | } | |
254 | val >>= 1; | |
255 | } | |
256 | if (bcs->cs->debug & L1_DEB_HSCX) | |
257 | debugl1(bcs->cs,"tiger make_raw: in %ld out %d.%d", | |
258 | bcs->tx_skb->len, s_cnt, bitcnt); | |
259 | if (bitcnt) { | |
260 | while (8>bitcnt++) { | |
261 | s_val >>= 1; | |
262 | s_val |= 0x80; | |
263 | } | |
264 | bcs->hw.tiger.sendbuf[s_cnt++] = s_val; | |
265 | bcs->hw.tiger.sendbuf[s_cnt++] = 0xff; // NJ<->NJ thoughput bug fix | |
266 | } | |
267 | bcs->hw.tiger.sendcnt = s_cnt; | |
268 | bcs->tx_cnt -= bcs->tx_skb->len; | |
269 | bcs->hw.tiger.sp = bcs->hw.tiger.sendbuf; | |
270 | return(0); | |
271 | } | |
272 | ||
273 | // macro for 56k | |
274 | ||
275 | #define MAKE_RAW_BYTE_56K for (j=0; j<8; j++) { \ | |
276 | bitcnt++;\ | |
277 | s_val >>= 1;\ | |
278 | if (val & 1) {\ | |
279 | s_one++;\ | |
280 | s_val |= 0x80;\ | |
281 | } else {\ | |
282 | s_one = 0;\ | |
283 | s_val &= 0x7f;\ | |
284 | }\ | |
285 | if (bitcnt==7) {\ | |
286 | s_val >>= 1;\ | |
287 | s_val |= 0x80;\ | |
288 | bcs->hw.tiger.sendbuf[s_cnt++] = s_val;\ | |
289 | bitcnt = 0;\ | |
290 | }\ | |
291 | if (s_one == 5) {\ | |
292 | s_val >>= 1;\ | |
293 | s_val &= 0x7f;\ | |
294 | bitcnt++;\ | |
295 | s_one = 0;\ | |
296 | }\ | |
297 | if (bitcnt==7) {\ | |
298 | s_val >>= 1;\ | |
299 | s_val |= 0x80;\ | |
300 | bcs->hw.tiger.sendbuf[s_cnt++] = s_val;\ | |
301 | bitcnt = 0;\ | |
302 | }\ | |
303 | val >>= 1;\ | |
304 | } | |
305 | ||
306 | static int make_raw_data_56k(struct BCState *bcs) { | |
307 | // this make_raw is for 56k | |
308 | register u_int i,s_cnt=0; | |
309 | register u_char j; | |
310 | register u_char val; | |
311 | register u_char s_one = 0; | |
312 | register u_char s_val = 0; | |
313 | register u_char bitcnt = 0; | |
314 | u_int fcs; | |
315 | ||
316 | if (!bcs->tx_skb) { | |
317 | debugl1(bcs->cs, "tiger make_raw_56k: NULL skb"); | |
318 | return(1); | |
319 | } | |
320 | val = HDLC_FLAG_VALUE; | |
321 | for (j=0; j<8; j++) { | |
322 | bitcnt++; | |
323 | s_val >>= 1; | |
324 | if (val & 1) | |
325 | s_val |= 0x80; | |
326 | else | |
327 | s_val &= 0x7f; | |
328 | if (bitcnt==7) { | |
329 | s_val >>= 1; | |
330 | s_val |= 0x80; | |
331 | bcs->hw.tiger.sendbuf[s_cnt++] = s_val; | |
332 | bitcnt = 0; | |
333 | } | |
334 | val >>= 1; | |
335 | }; | |
336 | fcs = PPP_INITFCS; | |
337 | for (i=0; i<bcs->tx_skb->len; i++) { | |
338 | val = bcs->tx_skb->data[i]; | |
339 | fcs = PPP_FCS (fcs, val); | |
340 | MAKE_RAW_BYTE_56K; | |
341 | } | |
342 | fcs ^= 0xffff; | |
343 | val = fcs & 0xff; | |
344 | MAKE_RAW_BYTE_56K; | |
345 | val = (fcs>>8) & 0xff; | |
346 | MAKE_RAW_BYTE_56K; | |
347 | val = HDLC_FLAG_VALUE; | |
348 | for (j=0; j<8; j++) { | |
349 | bitcnt++; | |
350 | s_val >>= 1; | |
351 | if (val & 1) | |
352 | s_val |= 0x80; | |
353 | else | |
354 | s_val &= 0x7f; | |
355 | if (bitcnt==7) { | |
356 | s_val >>= 1; | |
357 | s_val |= 0x80; | |
358 | bcs->hw.tiger.sendbuf[s_cnt++] = s_val; | |
359 | bitcnt = 0; | |
360 | } | |
361 | val >>= 1; | |
362 | } | |
363 | if (bcs->cs->debug & L1_DEB_HSCX) | |
364 | debugl1(bcs->cs,"tiger make_raw_56k: in %ld out %d.%d", | |
365 | bcs->tx_skb->len, s_cnt, bitcnt); | |
366 | if (bitcnt) { | |
367 | while (8>bitcnt++) { | |
368 | s_val >>= 1; | |
369 | s_val |= 0x80; | |
370 | } | |
371 | bcs->hw.tiger.sendbuf[s_cnt++] = s_val; | |
372 | bcs->hw.tiger.sendbuf[s_cnt++] = 0xff; // NJ<->NJ thoughput bug fix | |
373 | } | |
374 | bcs->hw.tiger.sendcnt = s_cnt; | |
375 | bcs->tx_cnt -= bcs->tx_skb->len; | |
376 | bcs->hw.tiger.sp = bcs->hw.tiger.sendbuf; | |
377 | return(0); | |
378 | } | |
379 | ||
380 | static void got_frame(struct BCState *bcs, int count) { | |
381 | struct sk_buff *skb; | |
382 | ||
383 | if (!(skb = dev_alloc_skb(count))) | |
384 | printk(KERN_WARNING "TIGER: receive out of memory\n"); | |
385 | else { | |
386 | memcpy(skb_put(skb, count), bcs->hw.tiger.rcvbuf, count); | |
387 | skb_queue_tail(&bcs->rqueue, skb); | |
388 | } | |
389 | test_and_set_bit(B_RCVBUFREADY, &bcs->event); | |
390 | schedule_work(&bcs->tqueue); | |
391 | ||
392 | if (bcs->cs->debug & L1_DEB_RECEIVE_FRAME) | |
393 | printframe(bcs->cs, bcs->hw.tiger.rcvbuf, count, "rec"); | |
394 | } | |
395 | ||
396 | ||
397 | ||
398 | static void read_raw(struct BCState *bcs, u_int *buf, int cnt){ | |
399 | int i; | |
400 | register u_char j; | |
401 | register u_char val; | |
402 | u_int *pend = bcs->hw.tiger.rec +NETJET_DMA_RXSIZE -1; | |
403 | register u_char state = bcs->hw.tiger.r_state; | |
404 | register u_char r_one = bcs->hw.tiger.r_one; | |
405 | register u_char r_val = bcs->hw.tiger.r_val; | |
406 | register u_int bitcnt = bcs->hw.tiger.r_bitcnt; | |
407 | u_int *p = buf; | |
408 | int bits; | |
409 | u_char mask; | |
410 | ||
411 | if (bcs->mode == L1_MODE_HDLC) { // it's 64k | |
412 | mask = 0xff; | |
413 | bits = 8; | |
414 | } | |
415 | else { // it's 56K | |
416 | mask = 0x7f; | |
417 | bits = 7; | |
418 | }; | |
419 | for (i=0;i<cnt;i++) { | |
420 | val = bcs->channel ? ((*p>>8) & 0xff) : (*p & 0xff); | |
421 | p++; | |
422 | if (p > pend) | |
423 | p = bcs->hw.tiger.rec; | |
424 | if ((val & mask) == mask) { | |
425 | state = HDLC_ZERO_SEARCH; | |
426 | bcs->hw.tiger.r_tot++; | |
427 | bitcnt = 0; | |
428 | r_one = 0; | |
429 | continue; | |
430 | } | |
431 | for (j=0;j<bits;j++) { | |
432 | if (state == HDLC_ZERO_SEARCH) { | |
433 | if (val & 1) { | |
434 | r_one++; | |
435 | } else { | |
436 | r_one=0; | |
437 | state= HDLC_FLAG_SEARCH; | |
438 | if (bcs->cs->debug & L1_DEB_HSCX) | |
439 | debugl1(bcs->cs,"tiger read_raw: zBit(%d,%d,%d) %x", | |
440 | bcs->hw.tiger.r_tot,i,j,val); | |
441 | } | |
442 | } else if (state == HDLC_FLAG_SEARCH) { | |
443 | if (val & 1) { | |
444 | r_one++; | |
445 | if (r_one>6) { | |
446 | state=HDLC_ZERO_SEARCH; | |
447 | } | |
448 | } else { | |
449 | if (r_one==6) { | |
450 | bitcnt=0; | |
451 | r_val=0; | |
452 | state=HDLC_FLAG_FOUND; | |
453 | if (bcs->cs->debug & L1_DEB_HSCX) | |
454 | debugl1(bcs->cs,"tiger read_raw: flag(%d,%d,%d) %x", | |
455 | bcs->hw.tiger.r_tot,i,j,val); | |
456 | } | |
457 | r_one=0; | |
458 | } | |
459 | } else if (state == HDLC_FLAG_FOUND) { | |
460 | if (val & 1) { | |
461 | r_one++; | |
462 | if (r_one>6) { | |
463 | state=HDLC_ZERO_SEARCH; | |
464 | } else { | |
465 | r_val >>= 1; | |
466 | r_val |= 0x80; | |
467 | bitcnt++; | |
468 | } | |
469 | } else { | |
470 | if (r_one==6) { | |
471 | bitcnt=0; | |
472 | r_val=0; | |
473 | r_one=0; | |
474 | val >>= 1; | |
475 | continue; | |
476 | } else if (r_one!=5) { | |
477 | r_val >>= 1; | |
478 | r_val &= 0x7f; | |
479 | bitcnt++; | |
480 | } | |
481 | r_one=0; | |
482 | } | |
483 | if ((state != HDLC_ZERO_SEARCH) && | |
484 | !(bitcnt & 7)) { | |
485 | state=HDLC_FRAME_FOUND; | |
486 | bcs->hw.tiger.r_fcs = PPP_INITFCS; | |
487 | bcs->hw.tiger.rcvbuf[0] = r_val; | |
488 | bcs->hw.tiger.r_fcs = PPP_FCS (bcs->hw.tiger.r_fcs, r_val); | |
489 | if (bcs->cs->debug & L1_DEB_HSCX) | |
490 | debugl1(bcs->cs,"tiger read_raw: byte1(%d,%d,%d) rval %x val %x i %x", | |
491 | bcs->hw.tiger.r_tot,i,j,r_val,val, | |
492 | bcs->cs->hw.njet.irqstat0); | |
493 | } | |
494 | } else if (state == HDLC_FRAME_FOUND) { | |
495 | if (val & 1) { | |
496 | r_one++; | |
497 | if (r_one>6) { | |
498 | state=HDLC_ZERO_SEARCH; | |
499 | bitcnt=0; | |
500 | } else { | |
501 | r_val >>= 1; | |
502 | r_val |= 0x80; | |
503 | bitcnt++; | |
504 | } | |
505 | } else { | |
506 | if (r_one==6) { | |
507 | r_val=0; | |
508 | r_one=0; | |
509 | bitcnt++; | |
510 | if (bitcnt & 7) { | |
511 | debugl1(bcs->cs, "tiger: frame not byte aligned"); | |
512 | state=HDLC_FLAG_SEARCH; | |
513 | bcs->hw.tiger.r_err++; | |
514 | #ifdef ERROR_STATISTIC | |
515 | bcs->err_inv++; | |
516 | #endif | |
517 | } else { | |
518 | if (bcs->cs->debug & L1_DEB_HSCX) | |
519 | debugl1(bcs->cs,"tiger frame end(%d,%d): fcs(%x) i %x", | |
520 | i,j,bcs->hw.tiger.r_fcs, bcs->cs->hw.njet.irqstat0); | |
521 | if (bcs->hw.tiger.r_fcs == PPP_GOODFCS) { | |
522 | got_frame(bcs, (bitcnt>>3)-3); | |
523 | } else { | |
524 | if (bcs->cs->debug) { | |
525 | debugl1(bcs->cs, "tiger FCS error"); | |
526 | printframe(bcs->cs, bcs->hw.tiger.rcvbuf, | |
527 | (bitcnt>>3)-1, "rec"); | |
528 | bcs->hw.tiger.r_err++; | |
529 | } | |
530 | #ifdef ERROR_STATISTIC | |
531 | bcs->err_crc++; | |
532 | #endif | |
533 | } | |
534 | state=HDLC_FLAG_FOUND; | |
535 | } | |
536 | bitcnt=0; | |
537 | } else if (r_one==5) { | |
538 | val >>= 1; | |
539 | r_one=0; | |
540 | continue; | |
541 | } else { | |
542 | r_val >>= 1; | |
543 | r_val &= 0x7f; | |
544 | bitcnt++; | |
545 | } | |
546 | r_one=0; | |
547 | } | |
548 | if ((state == HDLC_FRAME_FOUND) && | |
549 | !(bitcnt & 7)) { | |
550 | if ((bitcnt>>3)>=HSCX_BUFMAX) { | |
551 | debugl1(bcs->cs, "tiger: frame too big"); | |
552 | r_val=0; | |
553 | state=HDLC_FLAG_SEARCH; | |
554 | bcs->hw.tiger.r_err++; | |
555 | #ifdef ERROR_STATISTIC | |
556 | bcs->err_inv++; | |
557 | #endif | |
558 | } else { | |
559 | bcs->hw.tiger.rcvbuf[(bitcnt>>3)-1] = r_val; | |
560 | bcs->hw.tiger.r_fcs = | |
561 | PPP_FCS (bcs->hw.tiger.r_fcs, r_val); | |
562 | } | |
563 | } | |
564 | } | |
565 | val >>= 1; | |
566 | } | |
567 | bcs->hw.tiger.r_tot++; | |
568 | } | |
569 | bcs->hw.tiger.r_state = state; | |
570 | bcs->hw.tiger.r_one = r_one; | |
571 | bcs->hw.tiger.r_val = r_val; | |
572 | bcs->hw.tiger.r_bitcnt = bitcnt; | |
573 | } | |
574 | ||
575 | void read_tiger(struct IsdnCardState *cs) { | |
576 | u_int *p; | |
577 | int cnt = NETJET_DMA_RXSIZE/2; | |
578 | ||
579 | if ((cs->hw.njet.irqstat0 & cs->hw.njet.last_is0) & NETJET_IRQM0_READ) { | |
580 | debugl1(cs,"tiger warn read double dma %x/%x", | |
581 | cs->hw.njet.irqstat0, cs->hw.njet.last_is0); | |
582 | #ifdef ERROR_STATISTIC | |
583 | if (cs->bcs[0].mode) | |
584 | cs->bcs[0].err_rdo++; | |
585 | if (cs->bcs[1].mode) | |
586 | cs->bcs[1].err_rdo++; | |
587 | #endif | |
588 | return; | |
589 | } else { | |
590 | cs->hw.njet.last_is0 &= ~NETJET_IRQM0_READ; | |
591 | cs->hw.njet.last_is0 |= (cs->hw.njet.irqstat0 & NETJET_IRQM0_READ); | |
592 | } | |
593 | if (cs->hw.njet.irqstat0 & NETJET_IRQM0_READ_1) | |
594 | p = cs->bcs[0].hw.tiger.rec + NETJET_DMA_RXSIZE - 1; | |
595 | else | |
596 | p = cs->bcs[0].hw.tiger.rec + cnt - 1; | |
597 | if ((cs->bcs[0].mode == L1_MODE_HDLC) || (cs->bcs[0].mode == L1_MODE_HDLC_56K)) | |
598 | read_raw(cs->bcs, p, cnt); | |
599 | ||
600 | if ((cs->bcs[1].mode == L1_MODE_HDLC) || (cs->bcs[1].mode == L1_MODE_HDLC_56K)) | |
601 | read_raw(cs->bcs + 1, p, cnt); | |
602 | cs->hw.njet.irqstat0 &= ~NETJET_IRQM0_READ; | |
603 | } | |
604 | ||
605 | static void write_raw(struct BCState *bcs, u_int *buf, int cnt); | |
606 | ||
607 | void netjet_fill_dma(struct BCState *bcs) | |
608 | { | |
609 | register u_int *p, *sp; | |
610 | register int cnt; | |
611 | ||
612 | if (!bcs->tx_skb) | |
613 | return; | |
614 | if (bcs->cs->debug & L1_DEB_HSCX) | |
615 | debugl1(bcs->cs,"tiger fill_dma1: c%d %4x", bcs->channel, | |
616 | bcs->Flag); | |
617 | if (test_and_set_bit(BC_FLG_BUSY, &bcs->Flag)) | |
618 | return; | |
619 | if (bcs->mode == L1_MODE_HDLC) { // it's 64k | |
620 | if (make_raw_data(bcs)) | |
621 | return; | |
622 | } | |
623 | else { // it's 56k | |
624 | if (make_raw_data_56k(bcs)) | |
625 | return; | |
626 | }; | |
627 | if (bcs->cs->debug & L1_DEB_HSCX) | |
628 | debugl1(bcs->cs,"tiger fill_dma2: c%d %4x", bcs->channel, | |
629 | bcs->Flag); | |
630 | if (test_and_clear_bit(BC_FLG_NOFRAME, &bcs->Flag)) { | |
631 | write_raw(bcs, bcs->hw.tiger.sendp, bcs->hw.tiger.free); | |
632 | } else if (test_and_clear_bit(BC_FLG_HALF, &bcs->Flag)) { | |
633 | p = bus_to_virt(inl(bcs->cs->hw.njet.base + NETJET_DMA_READ_ADR)); | |
634 | sp = bcs->hw.tiger.sendp; | |
635 | if (p == bcs->hw.tiger.s_end) | |
636 | p = bcs->hw.tiger.send -1; | |
637 | if (sp == bcs->hw.tiger.s_end) | |
638 | sp = bcs->hw.tiger.send -1; | |
639 | cnt = p - sp; | |
640 | if (cnt <0) { | |
641 | write_raw(bcs, bcs->hw.tiger.sendp, bcs->hw.tiger.free); | |
642 | } else { | |
643 | p++; | |
644 | cnt++; | |
645 | if (p > bcs->hw.tiger.s_end) | |
646 | p = bcs->hw.tiger.send; | |
647 | p++; | |
648 | cnt++; | |
649 | if (p > bcs->hw.tiger.s_end) | |
650 | p = bcs->hw.tiger.send; | |
651 | write_raw(bcs, p, bcs->hw.tiger.free - cnt); | |
652 | } | |
653 | } else if (test_and_clear_bit(BC_FLG_EMPTY, &bcs->Flag)) { | |
654 | p = bus_to_virt(inl(bcs->cs->hw.njet.base + NETJET_DMA_READ_ADR)); | |
655 | cnt = bcs->hw.tiger.s_end - p; | |
656 | if (cnt < 2) { | |
657 | p = bcs->hw.tiger.send + 1; | |
658 | cnt = NETJET_DMA_TXSIZE/2 - 2; | |
659 | } else { | |
660 | p++; | |
661 | p++; | |
662 | if (cnt <= (NETJET_DMA_TXSIZE/2)) | |
663 | cnt += NETJET_DMA_TXSIZE/2; | |
664 | cnt--; | |
665 | cnt--; | |
666 | } | |
667 | write_raw(bcs, p, cnt); | |
668 | } | |
669 | if (bcs->cs->debug & L1_DEB_HSCX) | |
670 | debugl1(bcs->cs,"tiger fill_dma3: c%d %4x", bcs->channel, | |
671 | bcs->Flag); | |
672 | } | |
673 | ||
674 | static void write_raw(struct BCState *bcs, u_int *buf, int cnt) { | |
675 | u_int mask, val, *p=buf; | |
676 | u_int i, s_cnt; | |
677 | ||
678 | if (cnt <= 0) | |
679 | return; | |
680 | if (test_bit(BC_FLG_BUSY, &bcs->Flag)) { | |
681 | if (bcs->hw.tiger.sendcnt> cnt) { | |
682 | s_cnt = cnt; | |
683 | bcs->hw.tiger.sendcnt -= cnt; | |
684 | } else { | |
685 | s_cnt = bcs->hw.tiger.sendcnt; | |
686 | bcs->hw.tiger.sendcnt = 0; | |
687 | } | |
688 | if (bcs->channel) | |
689 | mask = 0xffff00ff; | |
690 | else | |
691 | mask = 0xffffff00; | |
692 | for (i=0; i<s_cnt; i++) { | |
693 | val = bcs->channel ? ((bcs->hw.tiger.sp[i] <<8) & 0xff00) : | |
694 | (bcs->hw.tiger.sp[i]); | |
695 | *p &= mask; | |
696 | *p++ |= val; | |
697 | if (p>bcs->hw.tiger.s_end) | |
698 | p = bcs->hw.tiger.send; | |
699 | } | |
700 | bcs->hw.tiger.s_tot += s_cnt; | |
701 | if (bcs->cs->debug & L1_DEB_HSCX) | |
702 | debugl1(bcs->cs,"tiger write_raw: c%d %p-%p %d/%d %d %x", bcs->channel, | |
703 | buf, p, s_cnt, cnt, | |
704 | bcs->hw.tiger.sendcnt, bcs->cs->hw.njet.irqstat0); | |
705 | if (bcs->cs->debug & L1_DEB_HSCX_FIFO) | |
706 | printframe(bcs->cs, bcs->hw.tiger.sp, s_cnt, "snd"); | |
707 | bcs->hw.tiger.sp += s_cnt; | |
708 | bcs->hw.tiger.sendp = p; | |
709 | if (!bcs->hw.tiger.sendcnt) { | |
710 | if (!bcs->tx_skb) { | |
711 | debugl1(bcs->cs,"tiger write_raw: NULL skb s_cnt %d", s_cnt); | |
712 | } else { | |
713 | if (test_bit(FLG_LLI_L1WAKEUP,&bcs->st->lli.flag) && | |
714 | (PACKET_NOACK != bcs->tx_skb->pkt_type)) { | |
715 | u_long flags; | |
716 | spin_lock_irqsave(&bcs->aclock, flags); | |
717 | bcs->ackcnt += bcs->tx_skb->len; | |
718 | spin_unlock_irqrestore(&bcs->aclock, flags); | |
719 | schedule_event(bcs, B_ACKPENDING); | |
720 | } | |
721 | dev_kfree_skb_any(bcs->tx_skb); | |
722 | bcs->tx_skb = NULL; | |
723 | } | |
724 | test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); | |
725 | bcs->hw.tiger.free = cnt - s_cnt; | |
726 | if (bcs->hw.tiger.free > (NETJET_DMA_TXSIZE/2)) | |
727 | test_and_set_bit(BC_FLG_HALF, &bcs->Flag); | |
728 | else { | |
729 | test_and_clear_bit(BC_FLG_HALF, &bcs->Flag); | |
730 | test_and_set_bit(BC_FLG_NOFRAME, &bcs->Flag); | |
731 | } | |
732 | if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) { | |
733 | netjet_fill_dma(bcs); | |
734 | } else { | |
735 | mask ^= 0xffffffff; | |
736 | if (s_cnt < cnt) { | |
737 | for (i=s_cnt; i<cnt;i++) { | |
738 | *p++ |= mask; | |
739 | if (p>bcs->hw.tiger.s_end) | |
740 | p = bcs->hw.tiger.send; | |
741 | } | |
742 | if (bcs->cs->debug & L1_DEB_HSCX) | |
743 | debugl1(bcs->cs, "tiger write_raw: fill rest %d", | |
744 | cnt - s_cnt); | |
745 | } | |
746 | test_and_set_bit(B_XMTBUFREADY, &bcs->event); | |
747 | schedule_work(&bcs->tqueue); | |
748 | } | |
749 | } | |
750 | } else if (test_and_clear_bit(BC_FLG_NOFRAME, &bcs->Flag)) { | |
751 | test_and_set_bit(BC_FLG_HALF, &bcs->Flag); | |
752 | fill_mem(bcs, buf, cnt, bcs->channel, 0xff); | |
753 | bcs->hw.tiger.free += cnt; | |
754 | if (bcs->cs->debug & L1_DEB_HSCX) | |
755 | debugl1(bcs->cs,"tiger write_raw: fill half"); | |
756 | } else if (test_and_clear_bit(BC_FLG_HALF, &bcs->Flag)) { | |
757 | test_and_set_bit(BC_FLG_EMPTY, &bcs->Flag); | |
758 | fill_mem(bcs, buf, cnt, bcs->channel, 0xff); | |
759 | if (bcs->cs->debug & L1_DEB_HSCX) | |
760 | debugl1(bcs->cs,"tiger write_raw: fill full"); | |
761 | } | |
762 | } | |
763 | ||
764 | void write_tiger(struct IsdnCardState *cs) { | |
765 | u_int *p, cnt = NETJET_DMA_TXSIZE/2; | |
766 | ||
767 | if ((cs->hw.njet.irqstat0 & cs->hw.njet.last_is0) & NETJET_IRQM0_WRITE) { | |
768 | debugl1(cs,"tiger warn write double dma %x/%x", | |
769 | cs->hw.njet.irqstat0, cs->hw.njet.last_is0); | |
770 | #ifdef ERROR_STATISTIC | |
771 | if (cs->bcs[0].mode) | |
772 | cs->bcs[0].err_tx++; | |
773 | if (cs->bcs[1].mode) | |
774 | cs->bcs[1].err_tx++; | |
775 | #endif | |
776 | return; | |
777 | } else { | |
778 | cs->hw.njet.last_is0 &= ~NETJET_IRQM0_WRITE; | |
779 | cs->hw.njet.last_is0 |= (cs->hw.njet.irqstat0 & NETJET_IRQM0_WRITE); | |
780 | } | |
781 | if (cs->hw.njet.irqstat0 & NETJET_IRQM0_WRITE_1) | |
782 | p = cs->bcs[0].hw.tiger.send + NETJET_DMA_TXSIZE - 1; | |
783 | else | |
784 | p = cs->bcs[0].hw.tiger.send + cnt - 1; | |
785 | if ((cs->bcs[0].mode == L1_MODE_HDLC) || (cs->bcs[0].mode == L1_MODE_HDLC_56K)) | |
786 | write_raw(cs->bcs, p, cnt); | |
787 | if ((cs->bcs[1].mode == L1_MODE_HDLC) || (cs->bcs[1].mode == L1_MODE_HDLC_56K)) | |
788 | write_raw(cs->bcs + 1, p, cnt); | |
789 | cs->hw.njet.irqstat0 &= ~NETJET_IRQM0_WRITE; | |
790 | } | |
791 | ||
792 | static void | |
793 | tiger_l2l1(struct PStack *st, int pr, void *arg) | |
794 | { | |
795 | struct BCState *bcs = st->l1.bcs; | |
796 | struct sk_buff *skb = arg; | |
797 | u_long flags; | |
798 | ||
799 | switch (pr) { | |
800 | case (PH_DATA | REQUEST): | |
801 | spin_lock_irqsave(&bcs->cs->lock, flags); | |
802 | if (bcs->tx_skb) { | |
803 | skb_queue_tail(&bcs->squeue, skb); | |
804 | } else { | |
805 | bcs->tx_skb = skb; | |
806 | bcs->cs->BC_Send_Data(bcs); | |
807 | } | |
808 | spin_unlock_irqrestore(&bcs->cs->lock, flags); | |
809 | break; | |
810 | case (PH_PULL | INDICATION): | |
811 | spin_lock_irqsave(&bcs->cs->lock, flags); | |
812 | if (bcs->tx_skb) { | |
813 | printk(KERN_WARNING "tiger_l2l1: this shouldn't happen\n"); | |
814 | } else { | |
815 | bcs->tx_skb = skb; | |
816 | bcs->cs->BC_Send_Data(bcs); | |
817 | } | |
818 | spin_unlock_irqrestore(&bcs->cs->lock, flags); | |
819 | break; | |
820 | case (PH_PULL | REQUEST): | |
821 | if (!bcs->tx_skb) { | |
822 | test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags); | |
823 | st->l1.l1l2(st, PH_PULL | CONFIRM, NULL); | |
824 | } else | |
825 | test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags); | |
826 | break; | |
827 | case (PH_ACTIVATE | REQUEST): | |
828 | spin_lock_irqsave(&bcs->cs->lock, flags); | |
829 | test_and_set_bit(BC_FLG_ACTIV, &bcs->Flag); | |
830 | mode_tiger(bcs, st->l1.mode, st->l1.bc); | |
831 | /* 2001/10/04 Christoph Ersfeld, Formula-n Europe AG */ | |
832 | spin_unlock_irqrestore(&bcs->cs->lock, flags); | |
833 | bcs->cs->cardmsg(bcs->cs, MDL_BC_ASSIGN, (void *)(&st->l1.bc)); | |
834 | l1_msg_b(st, pr, arg); | |
835 | break; | |
836 | case (PH_DEACTIVATE | REQUEST): | |
837 | /* 2001/10/04 Christoph Ersfeld, Formula-n Europe AG */ | |
838 | bcs->cs->cardmsg(bcs->cs, MDL_BC_RELEASE, (void *)(&st->l1.bc)); | |
839 | l1_msg_b(st, pr, arg); | |
840 | break; | |
841 | case (PH_DEACTIVATE | CONFIRM): | |
842 | spin_lock_irqsave(&bcs->cs->lock, flags); | |
843 | test_and_clear_bit(BC_FLG_ACTIV, &bcs->Flag); | |
844 | test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); | |
845 | mode_tiger(bcs, 0, st->l1.bc); | |
846 | spin_unlock_irqrestore(&bcs->cs->lock, flags); | |
847 | st->l1.l1l2(st, PH_DEACTIVATE | CONFIRM, NULL); | |
848 | break; | |
849 | } | |
850 | } | |
851 | ||
852 | ||
672c3fd9 | 853 | static void |
1da177e4 LT |
854 | close_tigerstate(struct BCState *bcs) |
855 | { | |
856 | mode_tiger(bcs, 0, bcs->channel); | |
857 | if (test_and_clear_bit(BC_FLG_INIT, &bcs->Flag)) { | |
3c7208f2 JJ |
858 | kfree(bcs->hw.tiger.rcvbuf); |
859 | bcs->hw.tiger.rcvbuf = NULL; | |
860 | kfree(bcs->hw.tiger.sendbuf); | |
861 | bcs->hw.tiger.sendbuf = NULL; | |
1da177e4 LT |
862 | skb_queue_purge(&bcs->rqueue); |
863 | skb_queue_purge(&bcs->squeue); | |
864 | if (bcs->tx_skb) { | |
865 | dev_kfree_skb_any(bcs->tx_skb); | |
866 | bcs->tx_skb = NULL; | |
867 | test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); | |
868 | } | |
869 | } | |
870 | } | |
871 | ||
872 | static int | |
873 | open_tigerstate(struct IsdnCardState *cs, struct BCState *bcs) | |
874 | { | |
875 | if (!test_and_set_bit(BC_FLG_INIT, &bcs->Flag)) { | |
876 | if (!(bcs->hw.tiger.rcvbuf = kmalloc(HSCX_BUFMAX, GFP_ATOMIC))) { | |
877 | printk(KERN_WARNING | |
878 | "HiSax: No memory for tiger.rcvbuf\n"); | |
879 | return (1); | |
880 | } | |
881 | if (!(bcs->hw.tiger.sendbuf = kmalloc(RAW_BUFMAX, GFP_ATOMIC))) { | |
882 | printk(KERN_WARNING | |
883 | "HiSax: No memory for tiger.sendbuf\n"); | |
884 | return (1); | |
885 | } | |
886 | skb_queue_head_init(&bcs->rqueue); | |
887 | skb_queue_head_init(&bcs->squeue); | |
888 | } | |
889 | bcs->tx_skb = NULL; | |
890 | bcs->hw.tiger.sendcnt = 0; | |
891 | test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); | |
892 | bcs->event = 0; | |
893 | bcs->tx_cnt = 0; | |
894 | return (0); | |
895 | } | |
896 | ||
672c3fd9 | 897 | static int |
1da177e4 LT |
898 | setstack_tiger(struct PStack *st, struct BCState *bcs) |
899 | { | |
900 | bcs->channel = st->l1.bc; | |
901 | if (open_tigerstate(st->l1.hardware, bcs)) | |
902 | return (-1); | |
903 | st->l1.bcs = bcs; | |
904 | st->l2.l2l1 = tiger_l2l1; | |
905 | setstack_manager(st); | |
906 | bcs->st = st; | |
907 | setstack_l1_B(st); | |
908 | return (0); | |
909 | } | |
910 | ||
911 | ||
67eb5db5 | 912 | void |
1da177e4 LT |
913 | inittiger(struct IsdnCardState *cs) |
914 | { | |
915 | if (!(cs->bcs[0].hw.tiger.send = kmalloc(NETJET_DMA_TXSIZE * sizeof(unsigned int), | |
916 | GFP_KERNEL | GFP_DMA))) { | |
917 | printk(KERN_WARNING | |
918 | "HiSax: No memory for tiger.send\n"); | |
919 | return; | |
920 | } | |
921 | cs->bcs[0].hw.tiger.s_irq = cs->bcs[0].hw.tiger.send + NETJET_DMA_TXSIZE/2 - 1; | |
922 | cs->bcs[0].hw.tiger.s_end = cs->bcs[0].hw.tiger.send + NETJET_DMA_TXSIZE - 1; | |
923 | cs->bcs[1].hw.tiger.send = cs->bcs[0].hw.tiger.send; | |
924 | cs->bcs[1].hw.tiger.s_irq = cs->bcs[0].hw.tiger.s_irq; | |
925 | cs->bcs[1].hw.tiger.s_end = cs->bcs[0].hw.tiger.s_end; | |
926 | ||
927 | memset(cs->bcs[0].hw.tiger.send, 0xff, NETJET_DMA_TXSIZE * sizeof(unsigned int)); | |
928 | debugl1(cs, "tiger: send buf %p - %p", cs->bcs[0].hw.tiger.send, | |
929 | cs->bcs[0].hw.tiger.send + NETJET_DMA_TXSIZE - 1); | |
930 | outl(virt_to_bus(cs->bcs[0].hw.tiger.send), | |
931 | cs->hw.njet.base + NETJET_DMA_READ_START); | |
932 | outl(virt_to_bus(cs->bcs[0].hw.tiger.s_irq), | |
933 | cs->hw.njet.base + NETJET_DMA_READ_IRQ); | |
934 | outl(virt_to_bus(cs->bcs[0].hw.tiger.s_end), | |
935 | cs->hw.njet.base + NETJET_DMA_READ_END); | |
936 | if (!(cs->bcs[0].hw.tiger.rec = kmalloc(NETJET_DMA_RXSIZE * sizeof(unsigned int), | |
937 | GFP_KERNEL | GFP_DMA))) { | |
938 | printk(KERN_WARNING | |
939 | "HiSax: No memory for tiger.rec\n"); | |
940 | return; | |
941 | } | |
942 | debugl1(cs, "tiger: rec buf %p - %p", cs->bcs[0].hw.tiger.rec, | |
943 | cs->bcs[0].hw.tiger.rec + NETJET_DMA_RXSIZE - 1); | |
944 | cs->bcs[1].hw.tiger.rec = cs->bcs[0].hw.tiger.rec; | |
945 | memset(cs->bcs[0].hw.tiger.rec, 0xff, NETJET_DMA_RXSIZE * sizeof(unsigned int)); | |
946 | outl(virt_to_bus(cs->bcs[0].hw.tiger.rec), | |
947 | cs->hw.njet.base + NETJET_DMA_WRITE_START); | |
948 | outl(virt_to_bus(cs->bcs[0].hw.tiger.rec + NETJET_DMA_RXSIZE/2 - 1), | |
949 | cs->hw.njet.base + NETJET_DMA_WRITE_IRQ); | |
950 | outl(virt_to_bus(cs->bcs[0].hw.tiger.rec + NETJET_DMA_RXSIZE - 1), | |
951 | cs->hw.njet.base + NETJET_DMA_WRITE_END); | |
952 | debugl1(cs, "tiger: dmacfg %x/%x pulse=%d", | |
953 | inl(cs->hw.njet.base + NETJET_DMA_WRITE_ADR), | |
954 | inl(cs->hw.njet.base + NETJET_DMA_READ_ADR), | |
955 | bytein(cs->hw.njet.base + NETJET_PULSE_CNT)); | |
956 | cs->hw.njet.last_is0 = 0; | |
957 | cs->bcs[0].BC_SetStack = setstack_tiger; | |
958 | cs->bcs[1].BC_SetStack = setstack_tiger; | |
959 | cs->bcs[0].BC_Close = close_tigerstate; | |
960 | cs->bcs[1].BC_Close = close_tigerstate; | |
961 | } | |
962 | ||
672c3fd9 | 963 | static void |
1da177e4 LT |
964 | releasetiger(struct IsdnCardState *cs) |
965 | { | |
3c7208f2 JJ |
966 | kfree(cs->bcs[0].hw.tiger.send); |
967 | cs->bcs[0].hw.tiger.send = NULL; | |
968 | cs->bcs[1].hw.tiger.send = NULL; | |
969 | kfree(cs->bcs[0].hw.tiger.rec); | |
970 | cs->bcs[0].hw.tiger.rec = NULL; | |
971 | cs->bcs[1].hw.tiger.rec = NULL; | |
1da177e4 LT |
972 | } |
973 | ||
974 | void | |
975 | release_io_netjet(struct IsdnCardState *cs) | |
976 | { | |
977 | byteout(cs->hw.njet.base + NETJET_IRQMASK0, 0); | |
978 | byteout(cs->hw.njet.base + NETJET_IRQMASK1, 0); | |
979 | releasetiger(cs); | |
980 | release_region(cs->hw.njet.base, 256); | |
981 | } | |
982 |