File: /usr/src/linux/drivers/isdn/hisax/hscx_irq.c

1     /* $Id: hscx_irq.c,v 1.16.6.1 2001/02/16 16:43:27 kai Exp $
2      *
3      * hscx_irq.c     low level b-channel stuff for Siemens HSCX
4      *
5      * Author     Karsten Keil (keil@isdn4linux.de)
6      *
7      * This is an include file for fast inline IRQ stuff
8      *
9      * This file is (c) under GNU General Public License
10      *
11      */
12     
13     
14     static inline void
15     waitforCEC(struct IsdnCardState *cs, int hscx)
16     {
17     	int to = 50;
18     
19     	while ((READHSCX(cs, hscx, HSCX_STAR) & 0x04) && to) {
20     		udelay(1);
21     		to--;
22     	}
23     	if (!to)
24     		printk(KERN_WARNING "HiSax: waitforCEC timeout\n");
25     }
26     
27     
28     static inline void
29     waitforXFW(struct IsdnCardState *cs, int hscx)
30     {
31     	int to = 50;
32     
33     	while ((!(READHSCX(cs, hscx, HSCX_STAR) & 0x44) == 0x40) && to) {
34     		udelay(1);
35     		to--;
36     	}
37     	if (!to)
38     		printk(KERN_WARNING "HiSax: waitforXFW timeout\n");
39     }
40     
41     static inline void
42     WriteHSCXCMDR(struct IsdnCardState *cs, int hscx, u_char data)
43     {
44     	long flags;
45     
46     	save_flags(flags);
47     	cli();
48     	waitforCEC(cs, hscx);
49     	WRITEHSCX(cs, hscx, HSCX_CMDR, data);
50     	restore_flags(flags);
51     }
52     
53     
54     
55     static void
56     hscx_empty_fifo(struct BCState *bcs, int count)
57     {
58     	u_char *ptr;
59     	struct IsdnCardState *cs = bcs->cs;
60     	long flags;
61     
62     	if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO))
63     		debugl1(cs, "hscx_empty_fifo");
64     
65     	if (bcs->hw.hscx.rcvidx + count > HSCX_BUFMAX) {
66     		if (cs->debug & L1_DEB_WARN)
67     			debugl1(cs, "hscx_empty_fifo: incoming packet too large");
68     		WriteHSCXCMDR(cs, bcs->hw.hscx.hscx, 0x80);
69     		bcs->hw.hscx.rcvidx = 0;
70     		return;
71     	}
72     	ptr = bcs->hw.hscx.rcvbuf + bcs->hw.hscx.rcvidx;
73     	bcs->hw.hscx.rcvidx += count;
74     	save_flags(flags);
75     	cli();
76     	READHSCXFIFO(cs, bcs->hw.hscx.hscx, ptr, count);
77     	WriteHSCXCMDR(cs, bcs->hw.hscx.hscx, 0x80);
78     	restore_flags(flags);
79     	if (cs->debug & L1_DEB_HSCX_FIFO) {
80     		char *t = bcs->blog;
81     
82     		t += sprintf(t, "hscx_empty_fifo %c cnt %d",
83     			     bcs->hw.hscx.hscx ? 'B' : 'A', count);
84     		QuickHex(t, ptr, count);
85     		debugl1(cs, bcs->blog);
86     	}
87     }
88     
89     static void
90     hscx_fill_fifo(struct BCState *bcs)
91     {
92     	struct IsdnCardState *cs = bcs->cs;
93     	int more, count;
94     	int fifo_size = test_bit(HW_IPAC, &cs->HW_Flags)? 64: 32;
95     	u_char *ptr;
96     	long flags;
97     
98     
99     	if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO))
100     		debugl1(cs, "hscx_fill_fifo");
101     
102     	if (!bcs->tx_skb)
103     		return;
104     	if (bcs->tx_skb->len <= 0)
105     		return;
106     
107     	more = (bcs->mode == L1_MODE_TRANS) ? 1 : 0;
108     	if (bcs->tx_skb->len > fifo_size) {
109     		more = !0;
110     		count = fifo_size;
111     	} else
112     		count = bcs->tx_skb->len;
113     
114     	waitforXFW(cs, bcs->hw.hscx.hscx);
115     	save_flags(flags);
116     	cli();
117     	ptr = bcs->tx_skb->data;
118     	skb_pull(bcs->tx_skb, count);
119     	bcs->tx_cnt -= count;
120     	bcs->hw.hscx.count += count;
121     	WRITEHSCXFIFO(cs, bcs->hw.hscx.hscx, ptr, count);
122     	WriteHSCXCMDR(cs, bcs->hw.hscx.hscx, more ? 0x8 : 0xa);
123     	restore_flags(flags);
124     	if (cs->debug & L1_DEB_HSCX_FIFO) {
125     		char *t = bcs->blog;
126     
127     		t += sprintf(t, "hscx_fill_fifo %c cnt %d",
128     			     bcs->hw.hscx.hscx ? 'B' : 'A', count);
129     		QuickHex(t, ptr, count);
130     		debugl1(cs, bcs->blog);
131     	}
132     }
133     
134     static inline void
135     hscx_interrupt(struct IsdnCardState *cs, u_char val, u_char hscx)
136     {
137     	u_char r;
138     	struct BCState *bcs = cs->bcs + hscx;
139     	struct sk_buff *skb;
140     	int fifo_size = test_bit(HW_IPAC, &cs->HW_Flags)? 64: 32;
141     	int count;
142     
143     	if (!test_bit(BC_FLG_INIT, &bcs->Flag))
144     		return;
145     
146     	if (val & 0x80) {	/* RME */
147     		r = READHSCX(cs, hscx, HSCX_RSTA);
148     		if ((r & 0xf0) != 0xa0) {
149     			if (!(r & 0x80)) {
150     				if (cs->debug & L1_DEB_WARN)
151     					debugl1(cs, "HSCX invalid frame");
152     #ifdef ERROR_STATISTIC
153     				bcs->err_inv++;
154     #endif
155     			}
156     			if ((r & 0x40) && bcs->mode) {
157     				if (cs->debug & L1_DEB_WARN)
158     					debugl1(cs, "HSCX RDO mode=%d",
159     						bcs->mode);
160     #ifdef ERROR_STATISTIC
161     				bcs->err_rdo++;
162     #endif
163     			}
164     			if (!(r & 0x20)) {
165     				if (cs->debug & L1_DEB_WARN)
166     					debugl1(cs, "HSCX CRC error");
167     #ifdef ERROR_STATISTIC
168     				bcs->err_crc++;
169     #endif
170     			}
171     			WriteHSCXCMDR(cs, hscx, 0x80);
172     		} else {
173     			count = READHSCX(cs, hscx, HSCX_RBCL) & (
174     				test_bit(HW_IPAC, &cs->HW_Flags)? 0x3f: 0x1f);
175     			if (count == 0)
176     				count = fifo_size;
177     			hscx_empty_fifo(bcs, count);
178     			if ((count = bcs->hw.hscx.rcvidx - 1) > 0) {
179     				if (cs->debug & L1_DEB_HSCX_FIFO)
180     					debugl1(cs, "HX Frame %d", count);
181     				if (!(skb = dev_alloc_skb(count)))
182     					printk(KERN_WARNING "HSCX: receive out of memory\n");
183     				else {
184     					memcpy(skb_put(skb, count), bcs->hw.hscx.rcvbuf, count);
185     					skb_queue_tail(&bcs->rqueue, skb);
186     				}
187     			}
188     		}
189     		bcs->hw.hscx.rcvidx = 0;
190     		hscx_sched_event(bcs, B_RCVBUFREADY);
191     	}
192     	if (val & 0x40) {	/* RPF */
193     		hscx_empty_fifo(bcs, fifo_size);
194     		if (bcs->mode == L1_MODE_TRANS) {
195     			/* receive audio data */
196     			if (!(skb = dev_alloc_skb(fifo_size)))
197     				printk(KERN_WARNING "HiSax: receive out of memory\n");
198     			else {
199     				memcpy(skb_put(skb, fifo_size), bcs->hw.hscx.rcvbuf, fifo_size);
200     				skb_queue_tail(&bcs->rqueue, skb);
201     			}
202     			bcs->hw.hscx.rcvidx = 0;
203     			hscx_sched_event(bcs, B_RCVBUFREADY);
204     		}
205     	}
206     	if (val & 0x10) {	/* XPR */
207     		if (bcs->tx_skb) {
208     			if (bcs->tx_skb->len) {
209     				hscx_fill_fifo(bcs);
210     				return;
211     			} else {
212     				if (bcs->st->lli.l1writewakeup &&
213     					(PACKET_NOACK != bcs->tx_skb->pkt_type))
214     					bcs->st->lli.l1writewakeup(bcs->st, bcs->hw.hscx.count);
215     				dev_kfree_skb_irq(bcs->tx_skb);
216     				bcs->hw.hscx.count = 0; 
217     				bcs->tx_skb = NULL;
218     			}
219     		}
220     		if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) {
221     			bcs->hw.hscx.count = 0;
222     			test_and_set_bit(BC_FLG_BUSY, &bcs->Flag);
223     			hscx_fill_fifo(bcs);
224     		} else {
225     			test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
226     			hscx_sched_event(bcs, B_XMTBUFREADY);
227     		}
228     	}
229     }
230     
231     static inline void
232     hscx_int_main(struct IsdnCardState *cs, u_char val)
233     {
234     
235     	u_char exval;
236     	struct BCState *bcs;
237     
238     	if (val & 0x01) {
239     		bcs = cs->bcs + 1;
240     		exval = READHSCX(cs, 1, HSCX_EXIR);
241     		if (exval & 0x40) {
242     			if (bcs->mode == 1)
243     				hscx_fill_fifo(bcs);
244     			else {
245     #ifdef ERROR_STATISTIC
246     				bcs->err_tx++;
247     #endif
248     				/* Here we lost an TX interrupt, so
249     				   * restart transmitting the whole frame.
250     				 */
251     				if (bcs->tx_skb) {
252     					skb_push(bcs->tx_skb, bcs->hw.hscx.count);
253     					bcs->tx_cnt += bcs->hw.hscx.count;
254     					bcs->hw.hscx.count = 0;
255     				}
256     				WriteHSCXCMDR(cs, bcs->hw.hscx.hscx, 0x01);
257     				if (cs->debug & L1_DEB_WARN)
258     					debugl1(cs, "HSCX B EXIR %x Lost TX", exval);
259     			}
260     		} else if (cs->debug & L1_DEB_HSCX)
261     			debugl1(cs, "HSCX B EXIR %x", exval);
262     	}
263     	if (val & 0xf8) {
264     		if (cs->debug & L1_DEB_HSCX)
265     			debugl1(cs, "HSCX B interrupt %x", val);
266     		hscx_interrupt(cs, val, 1);
267     	}
268     	if (val & 0x02) {
269     		bcs = cs->bcs;
270     		exval = READHSCX(cs, 0, HSCX_EXIR);
271     		if (exval & 0x40) {
272     			if (bcs->mode == L1_MODE_TRANS)
273     				hscx_fill_fifo(bcs);
274     			else {
275     				/* Here we lost an TX interrupt, so
276     				   * restart transmitting the whole frame.
277     				 */
278     #ifdef ERROR_STATISTIC
279     				bcs->err_tx++;
280     #endif
281     				if (bcs->tx_skb) {
282     					skb_push(bcs->tx_skb, bcs->hw.hscx.count);
283     					bcs->tx_cnt += bcs->hw.hscx.count;
284     					bcs->hw.hscx.count = 0;
285     				}
286     				WriteHSCXCMDR(cs, bcs->hw.hscx.hscx, 0x01);
287     				if (cs->debug & L1_DEB_WARN)
288     					debugl1(cs, "HSCX A EXIR %x Lost TX", exval);
289     			}
290     		} else if (cs->debug & L1_DEB_HSCX)
291     			debugl1(cs, "HSCX A EXIR %x", exval);
292     	}
293     	if (val & 0x04) {
294     		exval = READHSCX(cs, 0, HSCX_ISTA);
295     		if (cs->debug & L1_DEB_HSCX)
296     			debugl1(cs, "HSCX A interrupt %x", exval);
297     		hscx_interrupt(cs, exval, 0);
298     	}
299     }
300