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 <info@formula-n.de> 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 64static void Amd7930_new_ph(struct IsdnCardState *cs); 65 66static 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 101static void /* macro wWordAMD */ 102WriteWordAmd7930(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 109static WORD /* macro rWordAMD */ 110ReadWordAmd7930(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 128static void 129Amd7930_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 140static 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 */ 154static BYTE stateHelper[] = { 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 }; 155 156 157 158 159static void 160Amd7930_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 168static void 169Amd7930_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 235static void 236Amd7930_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 270static void 271Amd7930_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, "%s", 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 344static void 345Amd7930_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, "%s", cs->dlog); 410 } 411 /* AMD interrupts on */ 412 AmdIrqOn(cs); 413} 414 415 416void 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 557static void 558Amd7930_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 REQUEST"); //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 669static void 670setstack_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 680static void 681DC_Close_Amd7930(struct IsdnCardState *cs) { 682 if (cs->debug & L1_DEB_ISAC) 683 debugl1(cs, "Amd7930: DC_Close called"); 684} 685 686 687static void 688dbusy_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 747void 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 789void setup_Amd7930(struct IsdnCardState *cs) 790{ 791 INIT_WORK(&cs->tqueue, Amd7930_bh); 792 cs->dbusytimer.function = (void *) dbusy_timer_handler; 793 cs->dbusytimer.data = (long) cs; 794 init_timer(&cs->dbusytimer); 795} 796