Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/drivers/isdn/hisax/amd7930_fn.c
15115 views
1
/* gerdes_amd7930.c,v 0.99 2001/10/02
2
*
3
* gerdes_amd7930.c Amd 79C30A and 79C32A specific routines
4
* (based on HiSax driver by Karsten Keil)
5
*
6
* Author Christoph Ersfeld <[email protected]>
7
* Formula-n Europe AG (www.formula-n.com)
8
* previously Gerdes AG
9
*
10
*
11
* This file is (c) under GNU PUBLIC LICENSE
12
*
13
*
14
* Notes:
15
* Version 0.99 is the first release of this driver and there are
16
* certainly a few bugs.
17
*
18
* Please don't report any malfunction to me without sending
19
* (compressed) debug-logs.
20
* It would be nearly impossible to retrace it.
21
*
22
* Log D-channel-processing as follows:
23
*
24
* 1. Load hisax with card-specific parameters, this example ist for
25
* Formula-n enter:now ISDN PCI and compatible
26
* (f.e. Gerdes Power ISDN PCI)
27
*
28
* modprobe hisax type=41 protocol=2 id=gerdes
29
*
30
* if you chose an other value for id, you need to modify the
31
* code below, too.
32
*
33
* 2. set debug-level
34
*
35
* hisaxctrl gerdes 1 0x3ff
36
* hisaxctrl gerdes 11 0x4f
37
* cat /dev/isdnctrl >> ~/log &
38
*
39
* Please take also a look into /var/log/messages if there is
40
* anything importand concerning HISAX.
41
*
42
*
43
* Credits:
44
* Programming the driver for Formula-n enter:now ISDN PCI and
45
* necessary this driver for the used Amd 7930 D-channel-controller
46
* was spnsored by Formula-n Europe AG.
47
* Thanks to Karsten Keil and Petr Novak, who gave me support in
48
* Hisax-specific questions.
49
* I want so say special thanks to Carl-Friedrich Braun, who had to
50
* answer a lot of questions about generally ISDN and about handling
51
* of the Amd-Chip.
52
*
53
*/
54
55
56
#include "hisax.h"
57
#include "isdnl1.h"
58
#include "isac.h"
59
#include "amd7930_fn.h"
60
#include <linux/interrupt.h>
61
#include <linux/init.h>
62
#include <linux/gfp.h>
63
64
static void Amd7930_new_ph(struct IsdnCardState *cs);
65
66
static WORD initAMD[] = {
67
0x0100,
68
69
0x00A5, 3, 0x01, 0x40, 0x58, // LPR, LMR1, LMR2
70
0x0086, 1, 0x0B, // DMR1 (D-Buffer TH-Interrupts on)
71
0x0087, 1, 0xFF, // DMR2
72
0x0092, 1, 0x03, // EFCR (extended mode d-channel-fifo on)
73
0x0090, 4, 0xFE, 0xFF, 0x02, 0x0F, // FRAR4, SRAR4, DMR3, DMR4 (address recognition )
74
0x0084, 2, 0x80, 0x00, // DRLR
75
0x00C0, 1, 0x47, // PPCR1
76
0x00C8, 1, 0x01, // PPCR2
77
78
0x0102,
79
0x0107,
80
0x01A1, 1,
81
0x0121, 1,
82
0x0189, 2,
83
84
0x0045, 4, 0x61, 0x72, 0x00, 0x00, // MCR1, MCR2, MCR3, MCR4
85
0x0063, 2, 0x08, 0x08, // GX
86
0x0064, 2, 0x08, 0x08, // GR
87
0x0065, 2, 0x99, 0x00, // GER
88
0x0066, 2, 0x7C, 0x8B, // STG
89
0x0067, 2, 0x00, 0x00, // FTGR1, FTGR2
90
0x0068, 2, 0x20, 0x20, // ATGR1, ATGR2
91
0x0069, 1, 0x4F, // MMR1
92
0x006A, 1, 0x00, // MMR2
93
0x006C, 1, 0x40, // MMR3
94
0x0021, 1, 0x02, // INIT
95
0x00A3, 1, 0x40, // LMR1
96
97
0xFFFF
98
};
99
100
101
static void /* macro wWordAMD */
102
WriteWordAmd7930(struct IsdnCardState *cs, BYTE reg, WORD val)
103
{
104
wByteAMD(cs, 0x00, reg);
105
wByteAMD(cs, 0x01, LOBYTE(val));
106
wByteAMD(cs, 0x01, HIBYTE(val));
107
}
108
109
static WORD /* macro rWordAMD */
110
ReadWordAmd7930(struct IsdnCardState *cs, BYTE reg)
111
{
112
WORD res;
113
/* direct access register */
114
if(reg < 8) {
115
res = rByteAMD(cs, reg);
116
res += 256*rByteAMD(cs, reg);
117
}
118
/* indirect access register */
119
else {
120
wByteAMD(cs, 0x00, reg);
121
res = rByteAMD(cs, 0x01);
122
res += 256*rByteAMD(cs, 0x01);
123
}
124
return (res);
125
}
126
127
128
static void
129
Amd7930_ph_command(struct IsdnCardState *cs, u_char command, char *s)
130
{
131
if (cs->debug & L1_DEB_ISAC)
132
debugl1(cs, "AMD7930: %s: ph_command 0x%02X", s, command);
133
134
cs->dc.amd7930.lmr1 = command;
135
wByteAMD(cs, 0xA3, command);
136
}
137
138
139
140
static BYTE i430States[] = {
141
// to reset F3 F4 F5 F6 F7 F8 AR from
142
0x01, 0x02, 0x00, 0x00, 0x00, 0x07, 0x05, 0x00, // init
143
0x01, 0x02, 0x00, 0x00, 0x00, 0x07, 0x05, 0x00, // reset
144
0x01, 0x02, 0x00, 0x00, 0x00, 0x09, 0x05, 0x04, // F3
145
0x01, 0x02, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, // F4
146
0x01, 0x02, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, // F5
147
0x01, 0x03, 0x00, 0x00, 0x00, 0x06, 0x05, 0x00, // F6
148
0x11, 0x13, 0x00, 0x00, 0x1B, 0x00, 0x15, 0x00, // F7
149
0x01, 0x03, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, // F8
150
0x01, 0x03, 0x00, 0x00, 0x00, 0x09, 0x00, 0x0A}; // AR
151
152
153
/* Row init - reset F3 F4 F5 F6 F7 F8 AR */
154
static BYTE stateHelper[] = { 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 };
155
156
157
158
159
static void
160
Amd7930_get_state(struct IsdnCardState *cs) {
161
BYTE lsr = rByteAMD(cs, 0xA1);
162
cs->dc.amd7930.ph_state = (lsr & 0x7) + 2;
163
Amd7930_new_ph(cs);
164
}
165
166
167
168
static void
169
Amd7930_new_ph(struct IsdnCardState *cs)
170
{
171
u_char index = stateHelper[cs->dc.amd7930.old_state]*8 + stateHelper[cs->dc.amd7930.ph_state]-1;
172
u_char message = i430States[index];
173
174
if (cs->debug & L1_DEB_ISAC)
175
debugl1(cs, "AMD7930: new_ph %d, old_ph %d, message %d, index %d",
176
cs->dc.amd7930.ph_state, cs->dc.amd7930.old_state, message & 0x0f, index);
177
178
cs->dc.amd7930.old_state = cs->dc.amd7930.ph_state;
179
180
/* abort transmit if nessesary */
181
if ((message & 0xf0) && (cs->tx_skb)) {
182
wByteAMD(cs, 0x21, 0xC2);
183
wByteAMD(cs, 0x21, 0x02);
184
}
185
186
switch (message & 0x0f) {
187
188
case (1):
189
l1_msg(cs, HW_RESET | INDICATION, NULL);
190
Amd7930_get_state(cs);
191
break;
192
case (2): /* init, Card starts in F3 */
193
l1_msg(cs, HW_DEACTIVATE | CONFIRM, NULL);
194
break;
195
case (3):
196
l1_msg(cs, HW_DEACTIVATE | INDICATION, NULL);
197
break;
198
case (4):
199
l1_msg(cs, HW_POWERUP | CONFIRM, NULL);
200
Amd7930_ph_command(cs, 0x50, "HW_ENABLE REQUEST");
201
break;
202
case (5):
203
l1_msg(cs, HW_RSYNC | INDICATION, NULL);
204
break;
205
case (6):
206
l1_msg(cs, HW_INFO4_P8 | INDICATION, NULL);
207
break;
208
case (7): /* init, Card starts in F7 */
209
l1_msg(cs, HW_RSYNC | INDICATION, NULL);
210
l1_msg(cs, HW_INFO4_P8 | INDICATION, NULL);
211
break;
212
case (8):
213
l1_msg(cs, HW_POWERUP | CONFIRM, NULL);
214
/* fall through */
215
case (9):
216
Amd7930_ph_command(cs, 0x40, "HW_ENABLE REQ cleared if set");
217
l1_msg(cs, HW_RSYNC | INDICATION, NULL);
218
l1_msg(cs, HW_INFO2 | INDICATION, NULL);
219
l1_msg(cs, HW_INFO4_P8 | INDICATION, NULL);
220
break;
221
case (10):
222
Amd7930_ph_command(cs, 0x40, "T3 expired, HW_ENABLE REQ cleared");
223
cs->dc.amd7930.old_state = 3;
224
break;
225
case (11):
226
l1_msg(cs, HW_INFO2 | INDICATION, NULL);
227
break;
228
default:
229
break;
230
}
231
}
232
233
234
235
static void
236
Amd7930_bh(struct work_struct *work)
237
{
238
struct IsdnCardState *cs =
239
container_of(work, struct IsdnCardState, tqueue);
240
struct PStack *stptr;
241
242
if (test_and_clear_bit(D_CLEARBUSY, &cs->event)) {
243
if (cs->debug)
244
debugl1(cs, "Amd7930: bh, D-Channel Busy cleared");
245
stptr = cs->stlist;
246
while (stptr != NULL) {
247
stptr->l1.l1l2(stptr, PH_PAUSE | CONFIRM, NULL);
248
stptr = stptr->next;
249
}
250
}
251
if (test_and_clear_bit(D_L1STATECHANGE, &cs->event)) {
252
if (cs->debug & L1_DEB_ISAC)
253
debugl1(cs, "AMD7930: bh, D_L1STATECHANGE");
254
Amd7930_new_ph(cs);
255
}
256
257
if (test_and_clear_bit(D_RCVBUFREADY, &cs->event)) {
258
if (cs->debug & L1_DEB_ISAC)
259
debugl1(cs, "AMD7930: bh, D_RCVBUFREADY");
260
DChannel_proc_rcv(cs);
261
}
262
263
if (test_and_clear_bit(D_XMTBUFREADY, &cs->event)) {
264
if (cs->debug & L1_DEB_ISAC)
265
debugl1(cs, "AMD7930: bh, D_XMTBUFREADY");
266
DChannel_proc_xmt(cs);
267
}
268
}
269
270
static void
271
Amd7930_empty_Dfifo(struct IsdnCardState *cs, int flag)
272
{
273
274
BYTE stat, der;
275
BYTE *ptr;
276
struct sk_buff *skb;
277
278
279
if ((cs->debug & L1_DEB_ISAC) && !(cs->debug & L1_DEB_ISAC_FIFO))
280
debugl1(cs, "Amd7930: empty_Dfifo");
281
282
283
ptr = cs->rcvbuf + cs->rcvidx;
284
285
/* AMD interrupts off */
286
AmdIrqOff(cs);
287
288
/* read D-Channel-Fifo*/
289
stat = rByteAMD(cs, 0x07); // DSR2
290
291
/* while Data in Fifo ... */
292
while ( (stat & 2) && ((ptr-cs->rcvbuf) < MAX_DFRAME_LEN_L1) ) {
293
*ptr = rByteAMD(cs, 0x04); // DCRB
294
ptr++;
295
stat = rByteAMD(cs, 0x07); // DSR2
296
cs->rcvidx = ptr - cs->rcvbuf;
297
298
/* Paket ready? */
299
if (stat & 1) {
300
301
der = rWordAMD(cs, 0x03);
302
303
/* no errors, packet ok */
304
if(!der && !flag) {
305
rWordAMD(cs, 0x89); // clear DRCR
306
307
if ((cs->rcvidx) > 0) {
308
if (!(skb = alloc_skb(cs->rcvidx, GFP_ATOMIC)))
309
printk(KERN_WARNING "HiSax: Amd7930: empty_Dfifo, D receive out of memory!\n");
310
else {
311
/* Debugging */
312
if (cs->debug & L1_DEB_ISAC_FIFO) {
313
char *t = cs->dlog;
314
315
t += sprintf(t, "Amd7930: empty_Dfifo cnt: %d |", cs->rcvidx);
316
QuickHex(t, cs->rcvbuf, cs->rcvidx);
317
debugl1(cs, cs->dlog);
318
}
319
/* moves received data in sk-buffer */
320
memcpy(skb_put(skb, cs->rcvidx), cs->rcvbuf, cs->rcvidx);
321
skb_queue_tail(&cs->rq, skb);
322
}
323
}
324
325
}
326
/* throw damaged packets away, reset receive-buffer, indicate RX */
327
ptr = cs->rcvbuf;
328
cs->rcvidx = 0;
329
schedule_event(cs, D_RCVBUFREADY);
330
}
331
}
332
/* Packet to long, overflow */
333
if(cs->rcvidx >= MAX_DFRAME_LEN_L1) {
334
if (cs->debug & L1_DEB_WARN)
335
debugl1(cs, "AMD7930: empty_Dfifo L2-Framelength overrun");
336
cs->rcvidx = 0;
337
return;
338
}
339
/* AMD interrupts on */
340
AmdIrqOn(cs);
341
}
342
343
344
static void
345
Amd7930_fill_Dfifo(struct IsdnCardState *cs)
346
{
347
348
WORD dtcrr, dtcrw, len, count;
349
BYTE txstat, dmr3;
350
BYTE *ptr, *deb_ptr;
351
352
if ((cs->debug & L1_DEB_ISAC) && !(cs->debug & L1_DEB_ISAC_FIFO))
353
debugl1(cs, "Amd7930: fill_Dfifo");
354
355
if ((!cs->tx_skb) || (cs->tx_skb->len <= 0))
356
return;
357
358
dtcrw = 0;
359
if(!cs->dc.amd7930.tx_xmtlen)
360
/* new Frame */
361
len = dtcrw = cs->tx_skb->len;
362
/* continue frame */
363
else len = cs->dc.amd7930.tx_xmtlen;
364
365
366
/* AMD interrupts off */
367
AmdIrqOff(cs);
368
369
deb_ptr = ptr = cs->tx_skb->data;
370
371
/* while free place in tx-fifo available and data in sk-buffer */
372
txstat = 0x10;
373
while((txstat & 0x10) && (cs->tx_cnt < len)) {
374
wByteAMD(cs, 0x04, *ptr);
375
ptr++;
376
cs->tx_cnt++;
377
txstat= rByteAMD(cs, 0x07);
378
}
379
count = ptr - cs->tx_skb->data;
380
skb_pull(cs->tx_skb, count);
381
382
383
dtcrr = rWordAMD(cs, 0x85); // DTCR
384
dmr3 = rByteAMD(cs, 0x8E);
385
386
if (cs->debug & L1_DEB_ISAC) {
387
debugl1(cs, "Amd7930: fill_Dfifo, DMR3: 0x%02X, DTCR read: 0x%04X write: 0x%02X 0x%02X", dmr3, dtcrr, LOBYTE(dtcrw), HIBYTE(dtcrw));
388
}
389
390
/* writeing of dtcrw starts transmit */
391
if(!cs->dc.amd7930.tx_xmtlen) {
392
wWordAMD(cs, 0x85, dtcrw);
393
cs->dc.amd7930.tx_xmtlen = dtcrw;
394
}
395
396
if (test_and_set_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) {
397
debugl1(cs, "Amd7930: fill_Dfifo dbusytimer running");
398
del_timer(&cs->dbusytimer);
399
}
400
init_timer(&cs->dbusytimer);
401
cs->dbusytimer.expires = jiffies + ((DBUSY_TIMER_VALUE * HZ) / 1000);
402
add_timer(&cs->dbusytimer);
403
404
if (cs->debug & L1_DEB_ISAC_FIFO) {
405
char *t = cs->dlog;
406
407
t += sprintf(t, "Amd7930: fill_Dfifo cnt: %d |", count);
408
QuickHex(t, deb_ptr, count);
409
debugl1(cs, cs->dlog);
410
}
411
/* AMD interrupts on */
412
AmdIrqOn(cs);
413
}
414
415
416
void Amd7930_interrupt(struct IsdnCardState *cs, BYTE irflags)
417
{
418
BYTE dsr1, dsr2, lsr;
419
WORD der;
420
421
while (irflags)
422
{
423
424
dsr1 = rByteAMD(cs, 0x02);
425
der = rWordAMD(cs, 0x03);
426
dsr2 = rByteAMD(cs, 0x07);
427
lsr = rByteAMD(cs, 0xA1);
428
429
if (cs->debug & L1_DEB_ISAC)
430
debugl1(cs, "Amd7930: interrupt: flags: 0x%02X, DSR1: 0x%02X, DSR2: 0x%02X, LSR: 0x%02X, DER=0x%04X", irflags, dsr1, dsr2, lsr, der);
431
432
/* D error -> read DER and DSR2 bit 2 */
433
if (der || (dsr2 & 4)) {
434
435
if (cs->debug & L1_DEB_WARN)
436
debugl1(cs, "Amd7930: interrupt: D error DER=0x%04X", der);
437
438
/* RX, TX abort if collision detected */
439
if (der & 2) {
440
wByteAMD(cs, 0x21, 0xC2);
441
wByteAMD(cs, 0x21, 0x02);
442
if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))
443
del_timer(&cs->dbusytimer);
444
if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags))
445
schedule_event(cs, D_CLEARBUSY);
446
/* restart frame */
447
if (cs->tx_skb) {
448
skb_push(cs->tx_skb, cs->tx_cnt);
449
cs->tx_cnt = 0;
450
cs->dc.amd7930.tx_xmtlen = 0;
451
Amd7930_fill_Dfifo(cs);
452
} else {
453
printk(KERN_WARNING "HiSax: Amd7930 D-Collision, no skb\n");
454
debugl1(cs, "Amd7930: interrupt: D-Collision, no skb");
455
}
456
}
457
/* remove damaged data from fifo */
458
Amd7930_empty_Dfifo(cs, 1);
459
460
if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))
461
del_timer(&cs->dbusytimer);
462
if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags))
463
schedule_event(cs, D_CLEARBUSY);
464
/* restart TX-Frame */
465
if (cs->tx_skb) {
466
skb_push(cs->tx_skb, cs->tx_cnt);
467
cs->tx_cnt = 0;
468
cs->dc.amd7930.tx_xmtlen = 0;
469
Amd7930_fill_Dfifo(cs);
470
}
471
}
472
473
/* D TX FIFO empty -> fill */
474
if (irflags & 1) {
475
if (cs->debug & L1_DEB_ISAC)
476
debugl1(cs, "Amd7930: interrupt: clear Timer and fill D-TX-FIFO if data");
477
478
/* AMD interrupts off */
479
AmdIrqOff(cs);
480
481
if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))
482
del_timer(&cs->dbusytimer);
483
if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags))
484
schedule_event(cs, D_CLEARBUSY);
485
if (cs->tx_skb) {
486
if (cs->tx_skb->len)
487
Amd7930_fill_Dfifo(cs);
488
}
489
/* AMD interrupts on */
490
AmdIrqOn(cs);
491
}
492
493
494
/* D RX FIFO full or tiny packet in Fifo -> empty */
495
if ((irflags & 2) || (dsr1 & 2)) {
496
if (cs->debug & L1_DEB_ISAC)
497
debugl1(cs, "Amd7930: interrupt: empty D-FIFO");
498
Amd7930_empty_Dfifo(cs, 0);
499
}
500
501
502
/* D-Frame transmit complete */
503
if (dsr1 & 64) {
504
if (cs->debug & L1_DEB_ISAC) {
505
debugl1(cs, "Amd7930: interrupt: transmit packet ready");
506
}
507
/* AMD interrupts off */
508
AmdIrqOff(cs);
509
510
if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))
511
del_timer(&cs->dbusytimer);
512
if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags))
513
schedule_event(cs, D_CLEARBUSY);
514
515
if (cs->tx_skb) {
516
if (cs->debug & L1_DEB_ISAC)
517
debugl1(cs, "Amd7930: interrupt: TX-Packet ready, freeing skb");
518
dev_kfree_skb_irq(cs->tx_skb);
519
cs->tx_cnt = 0;
520
cs->dc.amd7930.tx_xmtlen=0;
521
cs->tx_skb = NULL;
522
}
523
if ((cs->tx_skb = skb_dequeue(&cs->sq))) {
524
if (cs->debug & L1_DEB_ISAC)
525
debugl1(cs, "Amd7930: interrupt: TX-Packet ready, next packet dequeued");
526
cs->tx_cnt = 0;
527
cs->dc.amd7930.tx_xmtlen=0;
528
Amd7930_fill_Dfifo(cs);
529
}
530
else
531
schedule_event(cs, D_XMTBUFREADY);
532
/* AMD interrupts on */
533
AmdIrqOn(cs);
534
}
535
536
/* LIU status interrupt -> read LSR, check statechanges */
537
if (lsr & 0x38) {
538
/* AMD interrupts off */
539
AmdIrqOff(cs);
540
541
if (cs->debug & L1_DEB_ISAC)
542
debugl1(cs, "Amd: interrupt: LSR=0x%02X, LIU is in state %d", lsr, ((lsr & 0x7) +2));
543
544
cs->dc.amd7930.ph_state = (lsr & 0x7) + 2;
545
546
schedule_event(cs, D_L1STATECHANGE);
547
/* AMD interrupts on */
548
AmdIrqOn(cs);
549
}
550
551
/* reads Interrupt-Register again. If there is a new interrupt-flag: restart handler */
552
irflags = rByteAMD(cs, 0x00);
553
}
554
555
}
556
557
static void
558
Amd7930_l1hw(struct PStack *st, int pr, void *arg)
559
{
560
struct IsdnCardState *cs = (struct IsdnCardState *) st->l1.hardware;
561
struct sk_buff *skb = arg;
562
u_long flags;
563
564
if (cs->debug & L1_DEB_ISAC)
565
debugl1(cs, "Amd7930: l1hw called, pr: 0x%04X", pr);
566
567
switch (pr) {
568
case (PH_DATA | REQUEST):
569
if (cs->debug & DEB_DLOG_HEX)
570
LogFrame(cs, skb->data, skb->len);
571
if (cs->debug & DEB_DLOG_VERBOSE)
572
dlogframe(cs, skb, 0);
573
spin_lock_irqsave(&cs->lock, flags);
574
if (cs->tx_skb) {
575
skb_queue_tail(&cs->sq, skb);
576
#ifdef L2FRAME_DEBUG /* psa */
577
if (cs->debug & L1_DEB_LAPD)
578
Logl2Frame(cs, skb, "Amd7930: l1hw: PH_DATA Queued", 0);
579
#endif
580
} else {
581
cs->tx_skb = skb;
582
cs->tx_cnt = 0;
583
cs->dc.amd7930.tx_xmtlen=0;
584
#ifdef L2FRAME_DEBUG /* psa */
585
if (cs->debug & L1_DEB_LAPD)
586
Logl2Frame(cs, skb, "Amd7930: l1hw: PH_DATA", 0);
587
#endif
588
Amd7930_fill_Dfifo(cs);
589
}
590
spin_unlock_irqrestore(&cs->lock, flags);
591
break;
592
case (PH_PULL | INDICATION):
593
spin_lock_irqsave(&cs->lock, flags);
594
if (cs->tx_skb) {
595
if (cs->debug & L1_DEB_WARN)
596
debugl1(cs, "Amd7930: l1hw: l2l1 tx_skb exist this shouldn't happen");
597
skb_queue_tail(&cs->sq, skb);
598
spin_unlock_irqrestore(&cs->lock, flags);
599
break;
600
}
601
if (cs->debug & DEB_DLOG_HEX)
602
LogFrame(cs, skb->data, skb->len);
603
if (cs->debug & DEB_DLOG_VERBOSE)
604
dlogframe(cs, skb, 0);
605
cs->tx_skb = skb;
606
cs->tx_cnt = 0;
607
cs->dc.amd7930.tx_xmtlen=0;
608
#ifdef L2FRAME_DEBUG /* psa */
609
if (cs->debug & L1_DEB_LAPD)
610
Logl2Frame(cs, skb, "Amd7930: l1hw: PH_DATA_PULLED", 0);
611
#endif
612
Amd7930_fill_Dfifo(cs);
613
spin_unlock_irqrestore(&cs->lock, flags);
614
break;
615
case (PH_PULL | REQUEST):
616
#ifdef L2FRAME_DEBUG /* psa */
617
if (cs->debug & L1_DEB_LAPD)
618
debugl1(cs, "Amd7930: l1hw: -> PH_REQUEST_PULL, skb: %s", (cs->tx_skb)? "yes":"no");
619
#endif
620
if (!cs->tx_skb) {
621
test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
622
st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
623
} else
624
test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
625
break;
626
case (HW_RESET | REQUEST):
627
spin_lock_irqsave(&cs->lock, flags);
628
if ((cs->dc.amd7930.ph_state == 8)) {
629
/* b-channels off, PH-AR cleared
630
* change to F3 */
631
Amd7930_ph_command(cs, 0x20, "HW_RESET REQEST"); //LMR1 bit 5
632
spin_unlock_irqrestore(&cs->lock, flags);
633
} else {
634
Amd7930_ph_command(cs, 0x40, "HW_RESET REQUEST");
635
cs->dc.amd7930.ph_state = 2;
636
spin_unlock_irqrestore(&cs->lock, flags);
637
Amd7930_new_ph(cs);
638
}
639
break;
640
case (HW_ENABLE | REQUEST):
641
cs->dc.amd7930.ph_state = 9;
642
Amd7930_new_ph(cs);
643
break;
644
case (HW_INFO3 | REQUEST):
645
// automatic
646
break;
647
case (HW_TESTLOOP | REQUEST):
648
/* not implemented yet */
649
break;
650
case (HW_DEACTIVATE | RESPONSE):
651
skb_queue_purge(&cs->rq);
652
skb_queue_purge(&cs->sq);
653
if (cs->tx_skb) {
654
dev_kfree_skb(cs->tx_skb);
655
cs->tx_skb = NULL;
656
}
657
if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))
658
del_timer(&cs->dbusytimer);
659
if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags))
660
schedule_event(cs, D_CLEARBUSY);
661
break;
662
default:
663
if (cs->debug & L1_DEB_WARN)
664
debugl1(cs, "Amd7930: l1hw: unknown %04x", pr);
665
break;
666
}
667
}
668
669
static void
670
setstack_Amd7930(struct PStack *st, struct IsdnCardState *cs)
671
{
672
673
if (cs->debug & L1_DEB_ISAC)
674
debugl1(cs, "Amd7930: setstack called");
675
676
st->l1.l1hw = Amd7930_l1hw;
677
}
678
679
680
static void
681
DC_Close_Amd7930(struct IsdnCardState *cs) {
682
if (cs->debug & L1_DEB_ISAC)
683
debugl1(cs, "Amd7930: DC_Close called");
684
}
685
686
687
static void
688
dbusy_timer_handler(struct IsdnCardState *cs)
689
{
690
u_long flags;
691
struct PStack *stptr;
692
WORD dtcr, der;
693
BYTE dsr1, dsr2;
694
695
696
if (cs->debug & L1_DEB_ISAC)
697
debugl1(cs, "Amd7930: dbusy_timer expired!");
698
699
if (test_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) {
700
spin_lock_irqsave(&cs->lock, flags);
701
/* D Transmit Byte Count Register:
702
* Counts down packet's number of Bytes, 0 if packet ready */
703
dtcr = rWordAMD(cs, 0x85);
704
dsr1 = rByteAMD(cs, 0x02);
705
dsr2 = rByteAMD(cs, 0x07);
706
der = rWordAMD(cs, 0x03);
707
708
if (cs->debug & L1_DEB_ISAC)
709
debugl1(cs, "Amd7930: dbusy_timer_handler: DSR1=0x%02X, DSR2=0x%02X, DER=0x%04X, cs->tx_skb->len=%u, tx_stat=%u, dtcr=%u, cs->tx_cnt=%u", dsr1, dsr2, der, cs->tx_skb->len, cs->dc.amd7930.tx_xmtlen, dtcr, cs->tx_cnt);
710
711
if ((cs->dc.amd7930.tx_xmtlen - dtcr) < cs->tx_cnt) { /* D-Channel Busy */
712
test_and_set_bit(FLG_L1_DBUSY, &cs->HW_Flags);
713
stptr = cs->stlist;
714
spin_unlock_irqrestore(&cs->lock, flags);
715
while (stptr != NULL) {
716
stptr->l1.l1l2(stptr, PH_PAUSE | INDICATION, NULL);
717
stptr = stptr->next;
718
}
719
720
} else {
721
/* discard frame; reset transceiver */
722
test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags);
723
if (cs->tx_skb) {
724
dev_kfree_skb_any(cs->tx_skb);
725
cs->tx_cnt = 0;
726
cs->tx_skb = NULL;
727
cs->dc.amd7930.tx_xmtlen = 0;
728
} else {
729
printk(KERN_WARNING "HiSax: Amd7930: D-Channel Busy no skb\n");
730
debugl1(cs, "Amd7930: D-Channel Busy no skb");
731
732
}
733
/* Transmitter reset, abort transmit */
734
wByteAMD(cs, 0x21, 0x82);
735
wByteAMD(cs, 0x21, 0x02);
736
spin_unlock_irqrestore(&cs->lock, flags);
737
cs->irq_func(cs->irq, cs);
738
739
if (cs->debug & L1_DEB_ISAC)
740
debugl1(cs, "Amd7930: dbusy_timer_handler: Transmitter reset");
741
}
742
}
743
}
744
745
746
747
void Amd7930_init(struct IsdnCardState *cs)
748
{
749
WORD *ptr;
750
BYTE cmd, cnt;
751
752
if (cs->debug & L1_DEB_ISAC)
753
debugl1(cs, "Amd7930: initamd called");
754
755
cs->dc.amd7930.tx_xmtlen = 0;
756
cs->dc.amd7930.old_state = 0;
757
cs->dc.amd7930.lmr1 = 0x40;
758
cs->dc.amd7930.ph_command = Amd7930_ph_command;
759
cs->setstack_d = setstack_Amd7930;
760
cs->DC_Close = DC_Close_Amd7930;
761
762
/* AMD Initialisation */
763
for (ptr = initAMD; *ptr != 0xFFFF; ) {
764
cmd = LOBYTE(*ptr);
765
766
/* read */
767
if (*ptr++ >= 0x100) {
768
if (cmd < 8)
769
/* reset register */
770
rByteAMD(cs, cmd);
771
else {
772
wByteAMD(cs, 0x00, cmd);
773
for (cnt = *ptr++; cnt > 0; cnt--)
774
rByteAMD(cs, 0x01);
775
}
776
}
777
/* write */
778
else if (cmd < 8)
779
wByteAMD(cs, cmd, LOBYTE(*ptr++));
780
781
else {
782
wByteAMD(cs, 0x00, cmd);
783
for (cnt = *ptr++; cnt > 0; cnt--)
784
wByteAMD(cs, 0x01, LOBYTE(*ptr++));
785
}
786
}
787
}
788
789
void __devinit
790
setup_Amd7930(struct IsdnCardState *cs)
791
{
792
INIT_WORK(&cs->tqueue, Amd7930_bh);
793
cs->dbusytimer.function = (void *) dbusy_timer_handler;
794
cs->dbusytimer.data = (long) cs;
795
init_timer(&cs->dbusytimer);
796
}
797
798