Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/drivers/isdn/hisax/hisax_isac.c
15115 views
1
/*
2
* Driver for ISAC-S and ISAC-SX
3
* ISDN Subscriber Access Controller for Terminals
4
*
5
* Author Kai Germaschewski
6
* Copyright 2001 by Kai Germaschewski <[email protected]>
7
* 2001 by Karsten Keil <[email protected]>
8
*
9
* based upon Karsten Keil's original isac.c driver
10
*
11
* This software may be used and distributed according to the terms
12
* of the GNU General Public License, incorporated herein by reference.
13
*
14
* Thanks to Wizard Computersysteme GmbH, Bremervoerde and
15
* SoHaNet Technology GmbH, Berlin
16
* for supporting the development of this driver
17
*/
18
19
/* TODO:
20
* specifically handle level vs edge triggered?
21
*/
22
23
#include <linux/module.h>
24
#include <linux/gfp.h>
25
#include <linux/init.h>
26
#include <linux/netdevice.h>
27
#include "hisax_isac.h"
28
29
// debugging cruft
30
31
#define __debug_variable debug
32
#include "hisax_debug.h"
33
34
#ifdef CONFIG_HISAX_DEBUG
35
static int debug = 1;
36
module_param(debug, int, 0);
37
38
static char *ISACVer[] = {
39
"2086/2186 V1.1",
40
"2085 B1",
41
"2085 B2",
42
"2085 V2.3"
43
};
44
#endif
45
46
MODULE_AUTHOR("Kai Germaschewski <[email protected]>/Karsten Keil <[email protected]>");
47
MODULE_DESCRIPTION("ISAC/ISAC-SX driver");
48
MODULE_LICENSE("GPL");
49
50
#define DBG_WARN 0x0001
51
#define DBG_IRQ 0x0002
52
#define DBG_L1M 0x0004
53
#define DBG_PR 0x0008
54
#define DBG_RFIFO 0x0100
55
#define DBG_RPACKET 0x0200
56
#define DBG_XFIFO 0x1000
57
#define DBG_XPACKET 0x2000
58
59
// we need to distinguish ISAC-S and ISAC-SX
60
#define TYPE_ISAC 0x00
61
#define TYPE_ISACSX 0x01
62
63
// registers etc.
64
#define ISAC_MASK 0x20
65
#define ISAC_ISTA 0x20
66
#define ISAC_ISTA_EXI 0x01
67
#define ISAC_ISTA_SIN 0x02
68
#define ISAC_ISTA_CISQ 0x04
69
#define ISAC_ISTA_XPR 0x10
70
#define ISAC_ISTA_RSC 0x20
71
#define ISAC_ISTA_RPF 0x40
72
#define ISAC_ISTA_RME 0x80
73
74
#define ISAC_STAR 0x21
75
#define ISAC_CMDR 0x21
76
#define ISAC_CMDR_XRES 0x01
77
#define ISAC_CMDR_XME 0x02
78
#define ISAC_CMDR_XTF 0x08
79
#define ISAC_CMDR_RRES 0x40
80
#define ISAC_CMDR_RMC 0x80
81
82
#define ISAC_EXIR 0x24
83
#define ISAC_EXIR_MOS 0x04
84
#define ISAC_EXIR_XDU 0x40
85
#define ISAC_EXIR_XMR 0x80
86
87
#define ISAC_ADF2 0x39
88
#define ISAC_SPCR 0x30
89
#define ISAC_ADF1 0x38
90
91
#define ISAC_CIR0 0x31
92
#define ISAC_CIX0 0x31
93
#define ISAC_CIR0_CIC0 0x02
94
#define ISAC_CIR0_CIC1 0x01
95
96
#define ISAC_CIR1 0x33
97
#define ISAC_CIX1 0x33
98
#define ISAC_STCR 0x37
99
#define ISAC_MODE 0x22
100
101
#define ISAC_RSTA 0x27
102
#define ISAC_RSTA_RDO 0x40
103
#define ISAC_RSTA_CRC 0x20
104
#define ISAC_RSTA_RAB 0x10
105
106
#define ISAC_RBCL 0x25
107
#define ISAC_RBCH 0x2A
108
#define ISAC_TIMR 0x23
109
#define ISAC_SQXR 0x3b
110
#define ISAC_MOSR 0x3a
111
#define ISAC_MOCR 0x3a
112
#define ISAC_MOR0 0x32
113
#define ISAC_MOX0 0x32
114
#define ISAC_MOR1 0x34
115
#define ISAC_MOX1 0x34
116
117
#define ISAC_RBCH_XAC 0x80
118
119
#define ISAC_CMD_TIM 0x0
120
#define ISAC_CMD_RES 0x1
121
#define ISAC_CMD_SSP 0x2
122
#define ISAC_CMD_SCP 0x3
123
#define ISAC_CMD_AR8 0x8
124
#define ISAC_CMD_AR10 0x9
125
#define ISAC_CMD_ARL 0xa
126
#define ISAC_CMD_DI 0xf
127
128
#define ISACSX_MASK 0x60
129
#define ISACSX_ISTA 0x60
130
#define ISACSX_ISTA_ICD 0x01
131
#define ISACSX_ISTA_CIC 0x10
132
133
#define ISACSX_MASKD 0x20
134
#define ISACSX_ISTAD 0x20
135
#define ISACSX_ISTAD_XDU 0x04
136
#define ISACSX_ISTAD_XMR 0x08
137
#define ISACSX_ISTAD_XPR 0x10
138
#define ISACSX_ISTAD_RFO 0x20
139
#define ISACSX_ISTAD_RPF 0x40
140
#define ISACSX_ISTAD_RME 0x80
141
142
#define ISACSX_CMDRD 0x21
143
#define ISACSX_CMDRD_XRES 0x01
144
#define ISACSX_CMDRD_XME 0x02
145
#define ISACSX_CMDRD_XTF 0x08
146
#define ISACSX_CMDRD_RRES 0x40
147
#define ISACSX_CMDRD_RMC 0x80
148
149
#define ISACSX_MODED 0x22
150
151
#define ISACSX_RBCLD 0x26
152
153
#define ISACSX_RSTAD 0x28
154
#define ISACSX_RSTAD_RAB 0x10
155
#define ISACSX_RSTAD_CRC 0x20
156
#define ISACSX_RSTAD_RDO 0x40
157
#define ISACSX_RSTAD_VFR 0x80
158
159
#define ISACSX_CIR0 0x2e
160
#define ISACSX_CIR0_CIC0 0x08
161
#define ISACSX_CIX0 0x2e
162
163
#define ISACSX_TR_CONF0 0x30
164
165
#define ISACSX_TR_CONF2 0x32
166
167
static struct Fsm l1fsm;
168
169
enum {
170
ST_L1_RESET,
171
ST_L1_F3_PDOWN,
172
ST_L1_F3_PUP,
173
ST_L1_F3_PEND_DEACT,
174
ST_L1_F4,
175
ST_L1_F5,
176
ST_L1_F6,
177
ST_L1_F7,
178
ST_L1_F8,
179
};
180
181
#define L1_STATE_COUNT (ST_L1_F8+1)
182
183
static char *strL1State[] =
184
{
185
"ST_L1_RESET",
186
"ST_L1_F3_PDOWN",
187
"ST_L1_F3_PUP",
188
"ST_L1_F3_PEND_DEACT",
189
"ST_L1_F4",
190
"ST_L1_F5",
191
"ST_L1_F6",
192
"ST_L1_F7",
193
"ST_L1_F8",
194
};
195
196
enum {
197
EV_PH_DR, // 0000
198
EV_PH_RES, // 0001
199
EV_PH_TMA, // 0010
200
EV_PH_SLD, // 0011
201
EV_PH_RSY, // 0100
202
EV_PH_DR6, // 0101
203
EV_PH_EI, // 0110
204
EV_PH_PU, // 0111
205
EV_PH_AR, // 1000
206
EV_PH_9, // 1001
207
EV_PH_ARL, // 1010
208
EV_PH_CVR, // 1011
209
EV_PH_AI8, // 1100
210
EV_PH_AI10, // 1101
211
EV_PH_AIL, // 1110
212
EV_PH_DC, // 1111
213
EV_PH_ACTIVATE_REQ,
214
EV_PH_DEACTIVATE_REQ,
215
EV_TIMER3,
216
};
217
218
#define L1_EVENT_COUNT (EV_TIMER3 + 1)
219
220
static char *strL1Event[] =
221
{
222
"EV_PH_DR", // 0000
223
"EV_PH_RES", // 0001
224
"EV_PH_TMA", // 0010
225
"EV_PH_SLD", // 0011
226
"EV_PH_RSY", // 0100
227
"EV_PH_DR6", // 0101
228
"EV_PH_EI", // 0110
229
"EV_PH_PU", // 0111
230
"EV_PH_AR", // 1000
231
"EV_PH_9", // 1001
232
"EV_PH_ARL", // 1010
233
"EV_PH_CVR", // 1011
234
"EV_PH_AI8", // 1100
235
"EV_PH_AI10", // 1101
236
"EV_PH_AIL", // 1110
237
"EV_PH_DC", // 1111
238
"EV_PH_ACTIVATE_REQ",
239
"EV_PH_DEACTIVATE_REQ",
240
"EV_TIMER3",
241
};
242
243
static inline void D_L1L2(struct isac *isac, int pr, void *arg)
244
{
245
struct hisax_if *ifc = (struct hisax_if *) &isac->hisax_d_if;
246
247
DBG(DBG_PR, "pr %#x", pr);
248
ifc->l1l2(ifc, pr, arg);
249
}
250
251
static void ph_command(struct isac *isac, unsigned int command)
252
{
253
DBG(DBG_L1M, "ph_command %#x", command);
254
switch (isac->type) {
255
case TYPE_ISAC:
256
isac->write_isac(isac, ISAC_CIX0, (command << 2) | 3);
257
break;
258
case TYPE_ISACSX:
259
isac->write_isac(isac, ISACSX_CIX0, (command << 4) | (7 << 1));
260
break;
261
}
262
}
263
264
// ----------------------------------------------------------------------
265
266
static void l1_di(struct FsmInst *fi, int event, void *arg)
267
{
268
struct isac *isac = fi->userdata;
269
270
FsmChangeState(fi, ST_L1_RESET);
271
ph_command(isac, ISAC_CMD_DI);
272
}
273
274
static void l1_di_deact_ind(struct FsmInst *fi, int event, void *arg)
275
{
276
struct isac *isac = fi->userdata;
277
278
FsmChangeState(fi, ST_L1_RESET);
279
D_L1L2(isac, PH_DEACTIVATE | INDICATION, NULL);
280
ph_command(isac, ISAC_CMD_DI);
281
}
282
283
static void l1_go_f3pdown(struct FsmInst *fi, int event, void *arg)
284
{
285
FsmChangeState(fi, ST_L1_F3_PDOWN);
286
}
287
288
static void l1_go_f3pend_deact_ind(struct FsmInst *fi, int event, void *arg)
289
{
290
struct isac *isac = fi->userdata;
291
292
FsmChangeState(fi, ST_L1_F3_PEND_DEACT);
293
D_L1L2(isac, PH_DEACTIVATE | INDICATION, NULL);
294
ph_command(isac, ISAC_CMD_DI);
295
}
296
297
static void l1_go_f3pend(struct FsmInst *fi, int event, void *arg)
298
{
299
struct isac *isac = fi->userdata;
300
301
FsmChangeState(fi, ST_L1_F3_PEND_DEACT);
302
ph_command(isac, ISAC_CMD_DI);
303
}
304
305
static void l1_go_f4(struct FsmInst *fi, int event, void *arg)
306
{
307
FsmChangeState(fi, ST_L1_F4);
308
}
309
310
static void l1_go_f5(struct FsmInst *fi, int event, void *arg)
311
{
312
FsmChangeState(fi, ST_L1_F5);
313
}
314
315
static void l1_go_f6(struct FsmInst *fi, int event, void *arg)
316
{
317
FsmChangeState(fi, ST_L1_F6);
318
}
319
320
static void l1_go_f6_deact_ind(struct FsmInst *fi, int event, void *arg)
321
{
322
struct isac *isac = fi->userdata;
323
324
FsmChangeState(fi, ST_L1_F6);
325
D_L1L2(isac, PH_DEACTIVATE | INDICATION, NULL);
326
}
327
328
static void l1_go_f7_act_ind(struct FsmInst *fi, int event, void *arg)
329
{
330
struct isac *isac = fi->userdata;
331
332
FsmDelTimer(&isac->timer, 0);
333
FsmChangeState(fi, ST_L1_F7);
334
ph_command(isac, ISAC_CMD_AR8);
335
D_L1L2(isac, PH_ACTIVATE | INDICATION, NULL);
336
}
337
338
static void l1_go_f8(struct FsmInst *fi, int event, void *arg)
339
{
340
FsmChangeState(fi, ST_L1_F8);
341
}
342
343
static void l1_go_f8_deact_ind(struct FsmInst *fi, int event, void *arg)
344
{
345
struct isac *isac = fi->userdata;
346
347
FsmChangeState(fi, ST_L1_F8);
348
D_L1L2(isac, PH_DEACTIVATE | INDICATION, NULL);
349
}
350
351
static void l1_ar8(struct FsmInst *fi, int event, void *arg)
352
{
353
struct isac *isac = fi->userdata;
354
355
FsmRestartTimer(&isac->timer, TIMER3_VALUE, EV_TIMER3, NULL, 2);
356
ph_command(isac, ISAC_CMD_AR8);
357
}
358
359
static void l1_timer3(struct FsmInst *fi, int event, void *arg)
360
{
361
struct isac *isac = fi->userdata;
362
363
ph_command(isac, ISAC_CMD_DI);
364
D_L1L2(isac, PH_DEACTIVATE | INDICATION, NULL);
365
}
366
367
// state machines according to data sheet PSB 2186 / 3186
368
369
static struct FsmNode L1FnList[] __initdata =
370
{
371
{ST_L1_RESET, EV_PH_RES, l1_di},
372
{ST_L1_RESET, EV_PH_EI, l1_di},
373
{ST_L1_RESET, EV_PH_DC, l1_go_f3pdown},
374
{ST_L1_RESET, EV_PH_AR, l1_go_f6},
375
{ST_L1_RESET, EV_PH_AI8, l1_go_f7_act_ind},
376
377
{ST_L1_F3_PDOWN, EV_PH_RES, l1_di},
378
{ST_L1_F3_PDOWN, EV_PH_EI, l1_di},
379
{ST_L1_F3_PDOWN, EV_PH_AR, l1_go_f6},
380
{ST_L1_F3_PDOWN, EV_PH_RSY, l1_go_f5},
381
{ST_L1_F3_PDOWN, EV_PH_PU, l1_go_f4},
382
{ST_L1_F3_PDOWN, EV_PH_AI8, l1_go_f7_act_ind},
383
{ST_L1_F3_PDOWN, EV_PH_ACTIVATE_REQ, l1_ar8},
384
{ST_L1_F3_PDOWN, EV_TIMER3, l1_timer3},
385
386
{ST_L1_F3_PEND_DEACT, EV_PH_RES, l1_di},
387
{ST_L1_F3_PEND_DEACT, EV_PH_EI, l1_di},
388
{ST_L1_F3_PEND_DEACT, EV_PH_DC, l1_go_f3pdown},
389
{ST_L1_F3_PEND_DEACT, EV_PH_RSY, l1_go_f5},
390
{ST_L1_F3_PEND_DEACT, EV_PH_AR, l1_go_f6},
391
{ST_L1_F3_PEND_DEACT, EV_PH_AI8, l1_go_f7_act_ind},
392
393
{ST_L1_F4, EV_PH_RES, l1_di},
394
{ST_L1_F4, EV_PH_EI, l1_di},
395
{ST_L1_F4, EV_PH_RSY, l1_go_f5},
396
{ST_L1_F4, EV_PH_AI8, l1_go_f7_act_ind},
397
{ST_L1_F4, EV_TIMER3, l1_timer3},
398
{ST_L1_F4, EV_PH_DC, l1_go_f3pdown},
399
400
{ST_L1_F5, EV_PH_RES, l1_di},
401
{ST_L1_F5, EV_PH_EI, l1_di},
402
{ST_L1_F5, EV_PH_AR, l1_go_f6},
403
{ST_L1_F5, EV_PH_AI8, l1_go_f7_act_ind},
404
{ST_L1_F5, EV_TIMER3, l1_timer3},
405
{ST_L1_F5, EV_PH_DR, l1_go_f3pend},
406
{ST_L1_F5, EV_PH_DC, l1_go_f3pdown},
407
408
{ST_L1_F6, EV_PH_RES, l1_di},
409
{ST_L1_F6, EV_PH_EI, l1_di},
410
{ST_L1_F6, EV_PH_RSY, l1_go_f8},
411
{ST_L1_F6, EV_PH_AI8, l1_go_f7_act_ind},
412
{ST_L1_F6, EV_PH_DR6, l1_go_f3pend},
413
{ST_L1_F6, EV_TIMER3, l1_timer3},
414
{ST_L1_F6, EV_PH_DC, l1_go_f3pdown},
415
416
{ST_L1_F7, EV_PH_RES, l1_di_deact_ind},
417
{ST_L1_F7, EV_PH_EI, l1_di_deact_ind},
418
{ST_L1_F7, EV_PH_AR, l1_go_f6_deact_ind},
419
{ST_L1_F7, EV_PH_RSY, l1_go_f8_deact_ind},
420
{ST_L1_F7, EV_PH_DR, l1_go_f3pend_deact_ind},
421
422
{ST_L1_F8, EV_PH_RES, l1_di},
423
{ST_L1_F8, EV_PH_EI, l1_di},
424
{ST_L1_F8, EV_PH_AR, l1_go_f6},
425
{ST_L1_F8, EV_PH_DR, l1_go_f3pend},
426
{ST_L1_F8, EV_PH_AI8, l1_go_f7_act_ind},
427
{ST_L1_F8, EV_TIMER3, l1_timer3},
428
{ST_L1_F8, EV_PH_DC, l1_go_f3pdown},
429
};
430
431
static void l1m_debug(struct FsmInst *fi, char *fmt, ...)
432
{
433
va_list args;
434
char buf[256];
435
436
va_start(args, fmt);
437
vsnprintf(buf, sizeof(buf), fmt, args);
438
DBG(DBG_L1M, "%s", buf);
439
va_end(args);
440
}
441
442
static void isac_version(struct isac *cs)
443
{
444
int val;
445
446
val = cs->read_isac(cs, ISAC_RBCH);
447
DBG(1, "ISAC version (%x): %s", val, ISACVer[(val >> 5) & 3]);
448
}
449
450
static void isac_empty_fifo(struct isac *isac, int count)
451
{
452
// this also works for isacsx, since
453
// CMDR(D) register works the same
454
u_char *ptr;
455
456
DBG(DBG_IRQ, "count %d", count);
457
458
if ((isac->rcvidx + count) >= MAX_DFRAME_LEN_L1) {
459
DBG(DBG_WARN, "overrun %d", isac->rcvidx + count);
460
isac->write_isac(isac, ISAC_CMDR, ISAC_CMDR_RMC);
461
isac->rcvidx = 0;
462
return;
463
}
464
ptr = isac->rcvbuf + isac->rcvidx;
465
isac->rcvidx += count;
466
isac->read_isac_fifo(isac, ptr, count);
467
isac->write_isac(isac, ISAC_CMDR, ISAC_CMDR_RMC);
468
DBG_PACKET(DBG_RFIFO, ptr, count);
469
}
470
471
static void isac_fill_fifo(struct isac *isac)
472
{
473
// this also works for isacsx, since
474
// CMDR(D) register works the same
475
476
int count;
477
unsigned char cmd;
478
u_char *ptr;
479
480
BUG_ON(!isac->tx_skb);
481
482
count = isac->tx_skb->len;
483
BUG_ON(count <= 0);
484
485
DBG(DBG_IRQ, "count %d", count);
486
487
if (count > 0x20) {
488
count = 0x20;
489
cmd = ISAC_CMDR_XTF;
490
} else {
491
cmd = ISAC_CMDR_XTF | ISAC_CMDR_XME;
492
}
493
494
ptr = isac->tx_skb->data;
495
skb_pull(isac->tx_skb, count);
496
isac->tx_cnt += count;
497
DBG_PACKET(DBG_XFIFO, ptr, count);
498
isac->write_isac_fifo(isac, ptr, count);
499
isac->write_isac(isac, ISAC_CMDR, cmd);
500
}
501
502
static void isac_retransmit(struct isac *isac)
503
{
504
if (!isac->tx_skb) {
505
DBG(DBG_WARN, "no skb");
506
return;
507
}
508
skb_push(isac->tx_skb, isac->tx_cnt);
509
isac->tx_cnt = 0;
510
}
511
512
513
static inline void isac_cisq_interrupt(struct isac *isac)
514
{
515
unsigned char val;
516
517
val = isac->read_isac(isac, ISAC_CIR0);
518
DBG(DBG_IRQ, "CIR0 %#x", val);
519
if (val & ISAC_CIR0_CIC0) {
520
DBG(DBG_IRQ, "CODR0 %#x", (val >> 2) & 0xf);
521
FsmEvent(&isac->l1m, (val >> 2) & 0xf, NULL);
522
}
523
if (val & ISAC_CIR0_CIC1) {
524
val = isac->read_isac(isac, ISAC_CIR1);
525
DBG(DBG_WARN, "ISAC CIR1 %#x", val );
526
}
527
}
528
529
static inline void isac_rme_interrupt(struct isac *isac)
530
{
531
unsigned char val;
532
int count;
533
struct sk_buff *skb;
534
535
val = isac->read_isac(isac, ISAC_RSTA);
536
if ((val & (ISAC_RSTA_RDO | ISAC_RSTA_CRC | ISAC_RSTA_RAB) )
537
!= ISAC_RSTA_CRC) {
538
DBG(DBG_WARN, "RSTA %#x, dropped", val);
539
isac->write_isac(isac, ISAC_CMDR, ISAC_CMDR_RMC);
540
goto out;
541
}
542
543
count = isac->read_isac(isac, ISAC_RBCL) & 0x1f;
544
DBG(DBG_IRQ, "RBCL %#x", count);
545
if (count == 0)
546
count = 0x20;
547
548
isac_empty_fifo(isac, count);
549
count = isac->rcvidx;
550
if (count < 1) {
551
DBG(DBG_WARN, "count %d < 1", count);
552
goto out;
553
}
554
555
skb = alloc_skb(count, GFP_ATOMIC);
556
if (!skb) {
557
DBG(DBG_WARN, "no memory, dropping\n");
558
goto out;
559
}
560
memcpy(skb_put(skb, count), isac->rcvbuf, count);
561
DBG_SKB(DBG_RPACKET, skb);
562
D_L1L2(isac, PH_DATA | INDICATION, skb);
563
out:
564
isac->rcvidx = 0;
565
}
566
567
static inline void isac_xpr_interrupt(struct isac *isac)
568
{
569
if (!isac->tx_skb)
570
return;
571
572
if (isac->tx_skb->len > 0) {
573
isac_fill_fifo(isac);
574
return;
575
}
576
dev_kfree_skb_irq(isac->tx_skb);
577
isac->tx_cnt = 0;
578
isac->tx_skb = NULL;
579
D_L1L2(isac, PH_DATA | CONFIRM, NULL);
580
}
581
582
static inline void isac_exi_interrupt(struct isac *isac)
583
{
584
unsigned char val;
585
586
val = isac->read_isac(isac, ISAC_EXIR);
587
DBG(2, "EXIR %#x", val);
588
589
if (val & ISAC_EXIR_XMR) {
590
DBG(DBG_WARN, "ISAC XMR");
591
isac_retransmit(isac);
592
}
593
if (val & ISAC_EXIR_XDU) {
594
DBG(DBG_WARN, "ISAC XDU");
595
isac_retransmit(isac);
596
}
597
if (val & ISAC_EXIR_MOS) { /* MOS */
598
DBG(DBG_WARN, "MOS");
599
val = isac->read_isac(isac, ISAC_MOSR);
600
DBG(2, "ISAC MOSR %#x", val);
601
}
602
}
603
604
void isac_irq(struct isac *isac)
605
{
606
unsigned char val;
607
608
val = isac->read_isac(isac, ISAC_ISTA);
609
DBG(DBG_IRQ, "ISTA %#x", val);
610
611
if (val & ISAC_ISTA_EXI) {
612
DBG(DBG_IRQ, "EXI");
613
isac_exi_interrupt(isac);
614
}
615
if (val & ISAC_ISTA_XPR) {
616
DBG(DBG_IRQ, "XPR");
617
isac_xpr_interrupt(isac);
618
}
619
if (val & ISAC_ISTA_RME) {
620
DBG(DBG_IRQ, "RME");
621
isac_rme_interrupt(isac);
622
}
623
if (val & ISAC_ISTA_RPF) {
624
DBG(DBG_IRQ, "RPF");
625
isac_empty_fifo(isac, 0x20);
626
}
627
if (val & ISAC_ISTA_CISQ) {
628
DBG(DBG_IRQ, "CISQ");
629
isac_cisq_interrupt(isac);
630
}
631
if (val & ISAC_ISTA_RSC) {
632
DBG(DBG_WARN, "RSC");
633
}
634
if (val & ISAC_ISTA_SIN) {
635
DBG(DBG_WARN, "SIN");
636
}
637
isac->write_isac(isac, ISAC_MASK, 0xff);
638
isac->write_isac(isac, ISAC_MASK, 0x00);
639
}
640
641
// ======================================================================
642
643
static inline void isacsx_cic_interrupt(struct isac *isac)
644
{
645
unsigned char val;
646
647
val = isac->read_isac(isac, ISACSX_CIR0);
648
DBG(DBG_IRQ, "CIR0 %#x", val);
649
if (val & ISACSX_CIR0_CIC0) {
650
DBG(DBG_IRQ, "CODR0 %#x", val >> 4);
651
FsmEvent(&isac->l1m, val >> 4, NULL);
652
}
653
}
654
655
static inline void isacsx_rme_interrupt(struct isac *isac)
656
{
657
int count;
658
struct sk_buff *skb;
659
unsigned char val;
660
661
val = isac->read_isac(isac, ISACSX_RSTAD);
662
if ((val & (ISACSX_RSTAD_VFR |
663
ISACSX_RSTAD_RDO |
664
ISACSX_RSTAD_CRC |
665
ISACSX_RSTAD_RAB))
666
!= (ISACSX_RSTAD_VFR | ISACSX_RSTAD_CRC)) {
667
DBG(DBG_WARN, "RSTAD %#x, dropped", val);
668
isac->write_isac(isac, ISACSX_CMDRD, ISACSX_CMDRD_RMC);
669
goto out;
670
}
671
672
count = isac->read_isac(isac, ISACSX_RBCLD) & 0x1f;
673
DBG(DBG_IRQ, "RBCLD %#x", count);
674
if (count == 0)
675
count = 0x20;
676
677
isac_empty_fifo(isac, count);
678
// strip trailing status byte
679
count = isac->rcvidx - 1;
680
if (count < 1) {
681
DBG(DBG_WARN, "count %d < 1", count);
682
goto out;
683
}
684
685
skb = dev_alloc_skb(count);
686
if (!skb) {
687
DBG(DBG_WARN, "no memory, dropping");
688
goto out;
689
}
690
memcpy(skb_put(skb, count), isac->rcvbuf, count);
691
DBG_SKB(DBG_RPACKET, skb);
692
D_L1L2(isac, PH_DATA | INDICATION, skb);
693
out:
694
isac->rcvidx = 0;
695
}
696
697
static inline void isacsx_xpr_interrupt(struct isac *isac)
698
{
699
if (!isac->tx_skb)
700
return;
701
702
if (isac->tx_skb->len > 0) {
703
isac_fill_fifo(isac);
704
return;
705
}
706
dev_kfree_skb_irq(isac->tx_skb);
707
isac->tx_skb = NULL;
708
isac->tx_cnt = 0;
709
D_L1L2(isac, PH_DATA | CONFIRM, NULL);
710
}
711
712
static inline void isacsx_icd_interrupt(struct isac *isac)
713
{
714
unsigned char val;
715
716
val = isac->read_isac(isac, ISACSX_ISTAD);
717
DBG(DBG_IRQ, "ISTAD %#x", val);
718
if (val & ISACSX_ISTAD_XDU) {
719
DBG(DBG_WARN, "ISTAD XDU");
720
isac_retransmit(isac);
721
}
722
if (val & ISACSX_ISTAD_XMR) {
723
DBG(DBG_WARN, "ISTAD XMR");
724
isac_retransmit(isac);
725
}
726
if (val & ISACSX_ISTAD_XPR) {
727
DBG(DBG_IRQ, "ISTAD XPR");
728
isacsx_xpr_interrupt(isac);
729
}
730
if (val & ISACSX_ISTAD_RFO) {
731
DBG(DBG_WARN, "ISTAD RFO");
732
isac->write_isac(isac, ISACSX_CMDRD, ISACSX_CMDRD_RMC);
733
}
734
if (val & ISACSX_ISTAD_RME) {
735
DBG(DBG_IRQ, "ISTAD RME");
736
isacsx_rme_interrupt(isac);
737
}
738
if (val & ISACSX_ISTAD_RPF) {
739
DBG(DBG_IRQ, "ISTAD RPF");
740
isac_empty_fifo(isac, 0x20);
741
}
742
}
743
744
void isacsx_irq(struct isac *isac)
745
{
746
unsigned char val;
747
748
val = isac->read_isac(isac, ISACSX_ISTA);
749
DBG(DBG_IRQ, "ISTA %#x", val);
750
751
if (val & ISACSX_ISTA_ICD)
752
isacsx_icd_interrupt(isac);
753
if (val & ISACSX_ISTA_CIC)
754
isacsx_cic_interrupt(isac);
755
}
756
757
void isac_init(struct isac *isac)
758
{
759
isac->tx_skb = NULL;
760
isac->l1m.fsm = &l1fsm;
761
isac->l1m.state = ST_L1_RESET;
762
#ifdef CONFIG_HISAX_DEBUG
763
isac->l1m.debug = 1;
764
#else
765
isac->l1m.debug = 0;
766
#endif
767
isac->l1m.userdata = isac;
768
isac->l1m.printdebug = l1m_debug;
769
FsmInitTimer(&isac->l1m, &isac->timer);
770
}
771
772
void isac_setup(struct isac *isac)
773
{
774
int val, eval;
775
776
isac->type = TYPE_ISAC;
777
isac_version(isac);
778
779
ph_command(isac, ISAC_CMD_RES);
780
781
isac->write_isac(isac, ISAC_MASK, 0xff);
782
isac->mocr = 0xaa;
783
if (test_bit(ISAC_IOM1, &isac->flags)) {
784
/* IOM 1 Mode */
785
isac->write_isac(isac, ISAC_ADF2, 0x0);
786
isac->write_isac(isac, ISAC_SPCR, 0xa);
787
isac->write_isac(isac, ISAC_ADF1, 0x2);
788
isac->write_isac(isac, ISAC_STCR, 0x70);
789
isac->write_isac(isac, ISAC_MODE, 0xc9);
790
} else {
791
/* IOM 2 Mode */
792
if (!isac->adf2)
793
isac->adf2 = 0x80;
794
isac->write_isac(isac, ISAC_ADF2, isac->adf2);
795
isac->write_isac(isac, ISAC_SQXR, 0x2f);
796
isac->write_isac(isac, ISAC_SPCR, 0x00);
797
isac->write_isac(isac, ISAC_STCR, 0x70);
798
isac->write_isac(isac, ISAC_MODE, 0xc9);
799
isac->write_isac(isac, ISAC_TIMR, 0x00);
800
isac->write_isac(isac, ISAC_ADF1, 0x00);
801
}
802
val = isac->read_isac(isac, ISAC_STAR);
803
DBG(2, "ISAC STAR %x", val);
804
val = isac->read_isac(isac, ISAC_MODE);
805
DBG(2, "ISAC MODE %x", val);
806
val = isac->read_isac(isac, ISAC_ADF2);
807
DBG(2, "ISAC ADF2 %x", val);
808
val = isac->read_isac(isac, ISAC_ISTA);
809
DBG(2, "ISAC ISTA %x", val);
810
if (val & 0x01) {
811
eval = isac->read_isac(isac, ISAC_EXIR);
812
DBG(2, "ISAC EXIR %x", eval);
813
}
814
val = isac->read_isac(isac, ISAC_CIR0);
815
DBG(2, "ISAC CIR0 %x", val);
816
FsmEvent(&isac->l1m, (val >> 2) & 0xf, NULL);
817
818
isac->write_isac(isac, ISAC_MASK, 0x0);
819
// RESET Receiver and Transmitter
820
isac->write_isac(isac, ISAC_CMDR, ISAC_CMDR_XRES | ISAC_CMDR_RRES);
821
}
822
823
void isacsx_setup(struct isac *isac)
824
{
825
isac->type = TYPE_ISACSX;
826
// clear LDD
827
isac->write_isac(isac, ISACSX_TR_CONF0, 0x00);
828
// enable transmitter
829
isac->write_isac(isac, ISACSX_TR_CONF2, 0x00);
830
// transparent mode 0, RAC, stop/go
831
isac->write_isac(isac, ISACSX_MODED, 0xc9);
832
// all HDLC IRQ unmasked
833
isac->write_isac(isac, ISACSX_MASKD, 0x03);
834
// unmask ICD, CID IRQs
835
isac->write_isac(isac, ISACSX_MASK,
836
~(ISACSX_ISTA_ICD | ISACSX_ISTA_CIC));
837
}
838
839
void isac_d_l2l1(struct hisax_if *hisax_d_if, int pr, void *arg)
840
{
841
struct isac *isac = hisax_d_if->priv;
842
struct sk_buff *skb = arg;
843
844
DBG(DBG_PR, "pr %#x", pr);
845
846
switch (pr) {
847
case PH_ACTIVATE | REQUEST:
848
FsmEvent(&isac->l1m, EV_PH_ACTIVATE_REQ, NULL);
849
break;
850
case PH_DEACTIVATE | REQUEST:
851
FsmEvent(&isac->l1m, EV_PH_DEACTIVATE_REQ, NULL);
852
break;
853
case PH_DATA | REQUEST:
854
DBG(DBG_PR, "PH_DATA REQUEST len %d", skb->len);
855
DBG_SKB(DBG_XPACKET, skb);
856
if (isac->l1m.state != ST_L1_F7) {
857
DBG(1, "L1 wrong state %d\n", isac->l1m.state);
858
dev_kfree_skb(skb);
859
break;
860
}
861
BUG_ON(isac->tx_skb);
862
863
isac->tx_skb = skb;
864
isac_fill_fifo(isac);
865
break;
866
}
867
}
868
869
static int __init hisax_isac_init(void)
870
{
871
printk(KERN_INFO "hisax_isac: ISAC-S/ISAC-SX ISDN driver v0.1.0\n");
872
873
l1fsm.state_count = L1_STATE_COUNT;
874
l1fsm.event_count = L1_EVENT_COUNT;
875
l1fsm.strState = strL1State;
876
l1fsm.strEvent = strL1Event;
877
return FsmNew(&l1fsm, L1FnList, ARRAY_SIZE(L1FnList));
878
}
879
880
static void __exit hisax_isac_exit(void)
881
{
882
FsmFree(&l1fsm);
883
}
884
885
EXPORT_SYMBOL(isac_init);
886
EXPORT_SYMBOL(isac_d_l2l1);
887
888
EXPORT_SYMBOL(isacsx_setup);
889
EXPORT_SYMBOL(isacsx_irq);
890
891
EXPORT_SYMBOL(isac_setup);
892
EXPORT_SYMBOL(isac_irq);
893
894
module_init(hisax_isac_init);
895
module_exit(hisax_isac_exit);
896
897