Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/drivers/isdn/hisax/hscx_irq.c
15115 views
1
/* $Id: hscx_irq.c,v 1.18.2.3 2004/02/11 13:21:34 keil Exp $
2
*
3
* low level b-channel stuff for Siemens HSCX
4
*
5
* Author Karsten Keil
6
* Copyright by Karsten Keil <[email protected]>
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
* This is an include file for fast inline IRQ stuff
12
*
13
*/
14
15
16
static inline void
17
waitforCEC(struct IsdnCardState *cs, int hscx)
18
{
19
int to = 50;
20
21
while ((READHSCX(cs, hscx, HSCX_STAR) & 0x04) && to) {
22
udelay(1);
23
to--;
24
}
25
if (!to)
26
printk(KERN_WARNING "HiSax: waitforCEC timeout\n");
27
}
28
29
30
static inline void
31
waitforXFW(struct IsdnCardState *cs, int hscx)
32
{
33
int to = 50;
34
35
while (((READHSCX(cs, hscx, HSCX_STAR) & 0x44) != 0x40) && to) {
36
udelay(1);
37
to--;
38
}
39
if (!to)
40
printk(KERN_WARNING "HiSax: waitforXFW timeout\n");
41
}
42
43
static inline void
44
WriteHSCXCMDR(struct IsdnCardState *cs, int hscx, u_char data)
45
{
46
waitforCEC(cs, hscx);
47
WRITEHSCX(cs, hscx, HSCX_CMDR, data);
48
}
49
50
51
52
static void
53
hscx_empty_fifo(struct BCState *bcs, int count)
54
{
55
u_char *ptr;
56
struct IsdnCardState *cs = bcs->cs;
57
58
if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO))
59
debugl1(cs, "hscx_empty_fifo");
60
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;
66
return;
67
}
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) {
73
char *t = bcs->blog;
74
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);
79
}
80
}
81
82
static void
83
hscx_fill_fifo(struct BCState *bcs)
84
{
85
struct IsdnCardState *cs = bcs->cs;
86
int more, count;
87
int fifo_size = test_bit(HW_IPAC, &cs->HW_Flags)? 64: 32;
88
u_char *ptr;
89
90
if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO))
91
debugl1(cs, "hscx_fill_fifo");
92
93
if (!bcs->tx_skb)
94
return;
95
if (bcs->tx_skb->len <= 0)
96
return;
97
98
more = (bcs->mode == L1_MODE_TRANS) ? 1 : 0;
99
if (bcs->tx_skb->len > fifo_size) {
100
more = !0;
101
count = fifo_size;
102
} else
103
count = bcs->tx_skb->len;
104
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) {
113
char *t = bcs->blog;
114
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);
119
}
120
}
121
122
static void
123
hscx_interrupt(struct IsdnCardState *cs, u_char val, u_char hscx)
124
{
125
u_char r;
126
struct BCState *bcs = cs->bcs + hscx;
127
struct sk_buff *skb;
128
int fifo_size = test_bit(HW_IPAC, &cs->HW_Flags)? 64: 32;
129
int count;
130
131
if (!test_bit(BC_FLG_INIT, &bcs->Flag))
132
return;
133
134
if (val & 0x80) { /* RME */
135
r = READHSCX(cs, hscx, HSCX_RSTA);
136
if ((r & 0xf0) != 0xa0) {
137
if (!(r & 0x80)) {
138
if (cs->debug & L1_DEB_WARN)
139
debugl1(cs, "HSCX invalid frame");
140
#ifdef ERROR_STATISTIC
141
bcs->err_inv++;
142
#endif
143
}
144
if ((r & 0x40) && bcs->mode) {
145
if (cs->debug & L1_DEB_WARN)
146
debugl1(cs, "HSCX RDO mode=%d",
147
bcs->mode);
148
#ifdef ERROR_STATISTIC
149
bcs->err_rdo++;
150
#endif
151
}
152
if (!(r & 0x20)) {
153
if (cs->debug & L1_DEB_WARN)
154
debugl1(cs, "HSCX CRC error");
155
#ifdef ERROR_STATISTIC
156
bcs->err_crc++;
157
#endif
158
}
159
WriteHSCXCMDR(cs, hscx, 0x80);
160
} else {
161
count = READHSCX(cs, hscx, HSCX_RBCL) & (
162
test_bit(HW_IPAC, &cs->HW_Flags)? 0x3f: 0x1f);
163
if (count == 0)
164
count = fifo_size;
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");
171
else {
172
memcpy(skb_put(skb, count), bcs->hw.hscx.rcvbuf, count);
173
skb_queue_tail(&bcs->rqueue, skb);
174
}
175
}
176
}
177
bcs->hw.hscx.rcvidx = 0;
178
schedule_event(bcs, B_RCVBUFREADY);
179
}
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");
186
else {
187
memcpy(skb_put(skb, fifo_size), bcs->hw.hscx.rcvbuf, fifo_size);
188
skb_queue_tail(&bcs->rqueue, skb);
189
}
190
bcs->hw.hscx.rcvidx = 0;
191
schedule_event(bcs, B_RCVBUFREADY);
192
}
193
}
194
if (val & 0x10) { /* XPR */
195
if (bcs->tx_skb) {
196
if (bcs->tx_skb->len) {
197
hscx_fill_fifo(bcs);
198
return;
199
} else {
200
if (test_bit(FLG_LLI_L1WAKEUP,&bcs->st->lli.flag) &&
201
(PACKET_NOACK != bcs->tx_skb->pkt_type)) {
202
u_long flags;
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);
207
}
208
dev_kfree_skb_irq(bcs->tx_skb);
209
bcs->hw.hscx.count = 0;
210
bcs->tx_skb = NULL;
211
}
212
}
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);
216
hscx_fill_fifo(bcs);
217
} else {
218
test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
219
schedule_event(bcs, B_XMTBUFREADY);
220
}
221
}
222
}
223
224
static void
225
hscx_int_main(struct IsdnCardState *cs, u_char val)
226
{
227
228
u_char exval;
229
struct BCState *bcs;
230
231
if (val & 0x01) {
232
bcs = cs->bcs + 1;
233
exval = READHSCX(cs, 1, HSCX_EXIR);
234
if (exval & 0x40) {
235
if (bcs->mode == 1)
236
hscx_fill_fifo(bcs);
237
else {
238
#ifdef ERROR_STATISTIC
239
bcs->err_tx++;
240
#endif
241
/* Here we lost an TX interrupt, so
242
* restart transmitting the whole frame.
243
*/
244
if (bcs->tx_skb) {
245
skb_push(bcs->tx_skb, bcs->hw.hscx.count);
246
bcs->tx_cnt += bcs->hw.hscx.count;
247
bcs->hw.hscx.count = 0;
248
}
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);
252
}
253
} else if (cs->debug & L1_DEB_HSCX)
254
debugl1(cs, "HSCX B EXIR %x", exval);
255
}
256
if (val & 0xf8) {
257
if (cs->debug & L1_DEB_HSCX)
258
debugl1(cs, "HSCX B interrupt %x", val);
259
hscx_interrupt(cs, val, 1);
260
}
261
if (val & 0x02) {
262
bcs = cs->bcs;
263
exval = READHSCX(cs, 0, HSCX_EXIR);
264
if (exval & 0x40) {
265
if (bcs->mode == L1_MODE_TRANS)
266
hscx_fill_fifo(bcs);
267
else {
268
/* Here we lost an TX interrupt, so
269
* restart transmitting the whole frame.
270
*/
271
#ifdef ERROR_STATISTIC
272
bcs->err_tx++;
273
#endif
274
if (bcs->tx_skb) {
275
skb_push(bcs->tx_skb, bcs->hw.hscx.count);
276
bcs->tx_cnt += bcs->hw.hscx.count;
277
bcs->hw.hscx.count = 0;
278
}
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);
282
}
283
} else if (cs->debug & L1_DEB_HSCX)
284
debugl1(cs, "HSCX A EXIR %x", exval);
285
}
286
if (val & 0x04) {
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);
291
}
292
}
293
294