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
, 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
, 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 memcpy(skb_put(skb
, count
), bcs
->hw
.hscx
.rcvbuf
, count
);
173 skb_queue_tail(&bcs
->rqueue
, skb
);
177 bcs
->hw
.hscx
.rcvidx
= 0;
178 schedule_event(bcs
, B_RCVBUFREADY
);
180 if (val
& 0x40) { /* RPF */
181 hscx_empty_fifo(bcs
, fifo_size
);
182 if (bcs
->mode
== L1_MODE_TRANS
) {
183 /* receive audio data */
184 if (!(skb
= dev_alloc_skb(fifo_size
)))
185 printk(KERN_WARNING
"HiSax: receive out of memory\n");
187 memcpy(skb_put(skb
, fifo_size
), bcs
->hw
.hscx
.rcvbuf
, fifo_size
);
188 skb_queue_tail(&bcs
->rqueue
, skb
);
190 bcs
->hw
.hscx
.rcvidx
= 0;
191 schedule_event(bcs
, B_RCVBUFREADY
);
194 if (val
& 0x10) { /* XPR */
196 if (bcs
->tx_skb
->len
) {
200 if (test_bit(FLG_LLI_L1WAKEUP
,&bcs
->st
->lli
.flag
) &&
201 (PACKET_NOACK
!= bcs
->tx_skb
->pkt_type
)) {
203 spin_lock_irqsave(&bcs
->aclock
, flags
);
204 bcs
->ackcnt
+= bcs
->hw
.hscx
.count
;
205 spin_unlock_irqrestore(&bcs
->aclock
, flags
);
206 schedule_event(bcs
, B_ACKPENDING
);
208 dev_kfree_skb_irq(bcs
->tx_skb
);
209 bcs
->hw
.hscx
.count
= 0;
213 if ((bcs
->tx_skb
= skb_dequeue(&bcs
->squeue
))) {
214 bcs
->hw
.hscx
.count
= 0;
215 test_and_set_bit(BC_FLG_BUSY
, &bcs
->Flag
);
218 test_and_clear_bit(BC_FLG_BUSY
, &bcs
->Flag
);
219 schedule_event(bcs
, B_XMTBUFREADY
);
225 hscx_int_main(struct IsdnCardState
*cs
, u_char val
)
233 exval
= READHSCX(cs
, 1, HSCX_EXIR
);
238 #ifdef ERROR_STATISTIC
241 /* Here we lost an TX interrupt, so
242 * restart transmitting the whole frame.
245 skb_push(bcs
->tx_skb
, bcs
->hw
.hscx
.count
);
246 bcs
->tx_cnt
+= bcs
->hw
.hscx
.count
;
247 bcs
->hw
.hscx
.count
= 0;
249 WriteHSCXCMDR(cs
, bcs
->hw
.hscx
.hscx
, 0x01);
250 if (cs
->debug
& L1_DEB_WARN
)
251 debugl1(cs
, "HSCX B EXIR %x Lost TX", exval
);
253 } else if (cs
->debug
& L1_DEB_HSCX
)
254 debugl1(cs
, "HSCX B EXIR %x", exval
);
257 if (cs
->debug
& L1_DEB_HSCX
)
258 debugl1(cs
, "HSCX B interrupt %x", val
);
259 hscx_interrupt(cs
, val
, 1);
263 exval
= READHSCX(cs
, 0, HSCX_EXIR
);
265 if (bcs
->mode
== L1_MODE_TRANS
)
268 /* Here we lost an TX interrupt, so
269 * restart transmitting the whole frame.
271 #ifdef ERROR_STATISTIC
275 skb_push(bcs
->tx_skb
, bcs
->hw
.hscx
.count
);
276 bcs
->tx_cnt
+= bcs
->hw
.hscx
.count
;
277 bcs
->hw
.hscx
.count
= 0;
279 WriteHSCXCMDR(cs
, bcs
->hw
.hscx
.hscx
, 0x01);
280 if (cs
->debug
& L1_DEB_WARN
)
281 debugl1(cs
, "HSCX A EXIR %x Lost TX", exval
);
283 } else if (cs
->debug
& L1_DEB_HSCX
)
284 debugl1(cs
, "HSCX A EXIR %x", exval
);
287 exval
= READHSCX(cs
, 0, HSCX_ISTA
);
288 if (cs
->debug
& L1_DEB_HSCX
)
289 debugl1(cs
, "HSCX A interrupt %x", exval
);
290 hscx_interrupt(cs
, exval
, 0);