1 /* $Id: hscx_irq.c,v 1.18.2.3 2004/02/11 13:21:34 keil Exp $
3 * low level b-channel stuff for Siemens HSCX
6 * Copyright by Karsten Keil <keil@isdn4linux.de>
8 * This software may be used and distributed according to the terms
9 * of the GNU General Public License, incorporated herein by reference.
11 * This is an include file for fast inline IRQ stuff
17 waitforCEC(struct IsdnCardState
*cs
, int hscx
)
21 while ((READHSCX(cs
, hscx
, HSCX_STAR
) & 0x04) && to
) {
26 printk(KERN_WARNING
"HiSax: waitforCEC timeout\n");
31 waitforXFW(struct IsdnCardState
*cs
, int hscx
)
35 while (((READHSCX(cs
, hscx
, HSCX_STAR
) & 0x44) != 0x40) && to
) {
40 printk(KERN_WARNING
"HiSax: waitforXFW timeout\n");
44 WriteHSCXCMDR(struct IsdnCardState
*cs
, int hscx
, u_char data
)
47 WRITEHSCX(cs
, hscx
, HSCX_CMDR
, data
);
53 hscx_empty_fifo(struct BCState
*bcs
, int count
)
56 struct IsdnCardState
*cs
= bcs
->cs
;
58 if ((cs
->debug
& L1_DEB_HSCX
) && !(cs
->debug
& L1_DEB_HSCX_FIFO
))
59 debugl1(cs
, "hscx_empty_fifo");
61 if (bcs
->hw
.hscx
.rcvidx
+ count
> HSCX_BUFMAX
) {
62 if (cs
->debug
& L1_DEB_WARN
)
63 debugl1(cs
, "hscx_empty_fifo: incoming packet too large");
64 WriteHSCXCMDR(cs
, bcs
->hw
.hscx
.hscx
, 0x80);
65 bcs
->hw
.hscx
.rcvidx
= 0;
68 ptr
= bcs
->hw
.hscx
.rcvbuf
+ bcs
->hw
.hscx
.rcvidx
;
69 bcs
->hw
.hscx
.rcvidx
+= count
;
70 READHSCXFIFO(cs
, bcs
->hw
.hscx
.hscx
, ptr
, count
);
71 WriteHSCXCMDR(cs
, bcs
->hw
.hscx
.hscx
, 0x80);
72 if (cs
->debug
& L1_DEB_HSCX_FIFO
) {
75 t
+= sprintf(t
, "hscx_empty_fifo %c cnt %d",
76 bcs
->hw
.hscx
.hscx
? 'B' : 'A', count
);
77 QuickHex(t
, ptr
, count
);
78 debugl1(cs
, "%s", bcs
->blog
);
83 hscx_fill_fifo(struct BCState
*bcs
)
85 struct IsdnCardState
*cs
= bcs
->cs
;
87 int fifo_size
= test_bit(HW_IPAC
, &cs
->HW_Flags
) ? 64 : 32;
90 if ((cs
->debug
& L1_DEB_HSCX
) && !(cs
->debug
& L1_DEB_HSCX_FIFO
))
91 debugl1(cs
, "hscx_fill_fifo");
95 if (bcs
->tx_skb
->len
<= 0)
98 more
= (bcs
->mode
== L1_MODE_TRANS
) ? 1 : 0;
99 if (bcs
->tx_skb
->len
> fifo_size
) {
103 count
= bcs
->tx_skb
->len
;
105 waitforXFW(cs
, bcs
->hw
.hscx
.hscx
);
106 ptr
= bcs
->tx_skb
->data
;
107 skb_pull(bcs
->tx_skb
, count
);
108 bcs
->tx_cnt
-= count
;
109 bcs
->hw
.hscx
.count
+= count
;
110 WRITEHSCXFIFO(cs
, bcs
->hw
.hscx
.hscx
, ptr
, count
);
111 WriteHSCXCMDR(cs
, bcs
->hw
.hscx
.hscx
, more
? 0x8 : 0xa);
112 if (cs
->debug
& L1_DEB_HSCX_FIFO
) {
115 t
+= sprintf(t
, "hscx_fill_fifo %c cnt %d",
116 bcs
->hw
.hscx
.hscx
? 'B' : 'A', count
);
117 QuickHex(t
, ptr
, count
);
118 debugl1(cs
, "%s", bcs
->blog
);
123 hscx_interrupt(struct IsdnCardState
*cs
, u_char val
, u_char hscx
)
126 struct BCState
*bcs
= cs
->bcs
+ hscx
;
128 int fifo_size
= test_bit(HW_IPAC
, &cs
->HW_Flags
) ? 64 : 32;
131 if (!test_bit(BC_FLG_INIT
, &bcs
->Flag
))
134 if (val
& 0x80) { /* RME */
135 r
= READHSCX(cs
, hscx
, HSCX_RSTA
);
136 if ((r
& 0xf0) != 0xa0) {
138 if (cs
->debug
& L1_DEB_WARN
)
139 debugl1(cs
, "HSCX invalid frame");
140 #ifdef ERROR_STATISTIC
144 if ((r
& 0x40) && bcs
->mode
) {
145 if (cs
->debug
& L1_DEB_WARN
)
146 debugl1(cs
, "HSCX RDO mode=%d",
148 #ifdef ERROR_STATISTIC
153 if (cs
->debug
& L1_DEB_WARN
)
154 debugl1(cs
, "HSCX CRC error");
155 #ifdef ERROR_STATISTIC
159 WriteHSCXCMDR(cs
, hscx
, 0x80);
161 count
= READHSCX(cs
, hscx
, HSCX_RBCL
) & (
162 test_bit(HW_IPAC
, &cs
->HW_Flags
) ? 0x3f : 0x1f);
165 hscx_empty_fifo(bcs
, count
);
166 if ((count
= bcs
->hw
.hscx
.rcvidx
- 1) > 0) {
167 if (cs
->debug
& L1_DEB_HSCX_FIFO
)
168 debugl1(cs
, "HX Frame %d", count
);
169 if (!(skb
= dev_alloc_skb(count
)))
170 printk(KERN_WARNING
"HSCX: receive out of memory\n");
172 skb_put_data(skb
, bcs
->hw
.hscx
.rcvbuf
,
174 skb_queue_tail(&bcs
->rqueue
, skb
);
178 bcs
->hw
.hscx
.rcvidx
= 0;
179 schedule_event(bcs
, B_RCVBUFREADY
);
181 if (val
& 0x40) { /* RPF */
182 hscx_empty_fifo(bcs
, fifo_size
);
183 if (bcs
->mode
== L1_MODE_TRANS
) {
184 /* receive audio data */
185 if (!(skb
= dev_alloc_skb(fifo_size
)))
186 printk(KERN_WARNING
"HiSax: receive out of memory\n");
188 skb_put_data(skb
, bcs
->hw
.hscx
.rcvbuf
,
190 skb_queue_tail(&bcs
->rqueue
, skb
);
192 bcs
->hw
.hscx
.rcvidx
= 0;
193 schedule_event(bcs
, B_RCVBUFREADY
);
196 if (val
& 0x10) { /* XPR */
198 if (bcs
->tx_skb
->len
) {
202 if (test_bit(FLG_LLI_L1WAKEUP
, &bcs
->st
->lli
.flag
) &&
203 (PACKET_NOACK
!= bcs
->tx_skb
->pkt_type
)) {
205 spin_lock_irqsave(&bcs
->aclock
, flags
);
206 bcs
->ackcnt
+= bcs
->hw
.hscx
.count
;
207 spin_unlock_irqrestore(&bcs
->aclock
, flags
);
208 schedule_event(bcs
, B_ACKPENDING
);
210 dev_kfree_skb_irq(bcs
->tx_skb
);
211 bcs
->hw
.hscx
.count
= 0;
215 if ((bcs
->tx_skb
= skb_dequeue(&bcs
->squeue
))) {
216 bcs
->hw
.hscx
.count
= 0;
217 test_and_set_bit(BC_FLG_BUSY
, &bcs
->Flag
);
220 test_and_clear_bit(BC_FLG_BUSY
, &bcs
->Flag
);
221 schedule_event(bcs
, B_XMTBUFREADY
);
227 hscx_int_main(struct IsdnCardState
*cs
, u_char val
)
235 exval
= READHSCX(cs
, 1, HSCX_EXIR
);
240 #ifdef ERROR_STATISTIC
243 /* Here we lost an TX interrupt, so
244 * restart transmitting the whole frame.
247 skb_push(bcs
->tx_skb
, bcs
->hw
.hscx
.count
);
248 bcs
->tx_cnt
+= bcs
->hw
.hscx
.count
;
249 bcs
->hw
.hscx
.count
= 0;
251 WriteHSCXCMDR(cs
, bcs
->hw
.hscx
.hscx
, 0x01);
252 if (cs
->debug
& L1_DEB_WARN
)
253 debugl1(cs
, "HSCX B EXIR %x Lost TX", exval
);
255 } else if (cs
->debug
& L1_DEB_HSCX
)
256 debugl1(cs
, "HSCX B EXIR %x", exval
);
259 if (cs
->debug
& L1_DEB_HSCX
)
260 debugl1(cs
, "HSCX B interrupt %x", val
);
261 hscx_interrupt(cs
, val
, 1);
265 exval
= READHSCX(cs
, 0, HSCX_EXIR
);
267 if (bcs
->mode
== L1_MODE_TRANS
)
270 /* Here we lost an TX interrupt, so
271 * restart transmitting the whole frame.
273 #ifdef ERROR_STATISTIC
277 skb_push(bcs
->tx_skb
, bcs
->hw
.hscx
.count
);
278 bcs
->tx_cnt
+= bcs
->hw
.hscx
.count
;
279 bcs
->hw
.hscx
.count
= 0;
281 WriteHSCXCMDR(cs
, bcs
->hw
.hscx
.hscx
, 0x01);
282 if (cs
->debug
& L1_DEB_WARN
)
283 debugl1(cs
, "HSCX A EXIR %x Lost TX", exval
);
285 } else if (cs
->debug
& L1_DEB_HSCX
)
286 debugl1(cs
, "HSCX A EXIR %x", exval
);
289 exval
= READHSCX(cs
, 0, HSCX_ISTA
);
290 if (cs
->debug
& L1_DEB_HSCX
)
291 debugl1(cs
, "HSCX A interrupt %x", exval
);
292 hscx_interrupt(cs
, exval
, 0);