User: | Jiri Slaby |
Error type: | Leaving function in locked state |
Error type description: | Some lock is not unlocked on all paths of a function, so it is leaked |
File location: | drivers/isdn/hisax/amd7930_fn.c |
Line in file: | 667 |
Project: | Linux Kernel |
Project version: | 2.6.28 |
Tools: |
Stanse
(1.2)
Undetermined 1 |
Entered: | 2012-03-02 21:35:17 UTC |
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 63static void Amd7930_new_ph(struct IsdnCardState *cs); 64 65static WORD initAMD[] = { 66 0x0100, 67 68 0x00A5, 3, 0x01, 0x40, 0x58, // LPR, LMR1, LMR2 69 0x0086, 1, 0x0B, // DMR1 (D-Buffer TH-Interrupts on) 70 0x0087, 1, 0xFF, // DMR2 71 0x0092, 1, 0x03, // EFCR (extended mode d-channel-fifo on) 72 0x0090, 4, 0xFE, 0xFF, 0x02, 0x0F, // FRAR4, SRAR4, DMR3, DMR4 (address recognition ) 73 0x0084, 2, 0x80, 0x00, // DRLR 74 0x00C0, 1, 0x47, // PPCR1 75 0x00C8, 1, 0x01, // PPCR2 76 77 0x0102, 78 0x0107, 79 0x01A1, 1, 80 0x0121, 1, 81 0x0189, 2, 82 83 0x0045, 4, 0x61, 0x72, 0x00, 0x00, // MCR1, MCR2, MCR3, MCR4 84 0x0063, 2, 0x08, 0x08, // GX 85 0x0064, 2, 0x08, 0x08, // GR 86 0x0065, 2, 0x99, 0x00, // GER 87 0x0066, 2, 0x7C, 0x8B, // STG 88 0x0067, 2, 0x00, 0x00, // FTGR1, FTGR2 89 0x0068, 2, 0x20, 0x20, // ATGR1, ATGR2 90 0x0069, 1, 0x4F, // MMR1 91 0x006A, 1, 0x00, // MMR2 92 0x006C, 1, 0x40, // MMR3 93 0x0021, 1, 0x02, // INIT 94 0x00A3, 1, 0x40, // LMR1 95 96 0xFFFF 97}; 98 99 100static void /* macro wWordAMD */ 101WriteWordAmd7930(struct IsdnCardState *cs, BYTE reg, WORD val) 102{ 103 wByteAMD(cs, 0x00, reg); 104 wByteAMD(cs, 0x01, LOBYTE(val)); 105 wByteAMD(cs, 0x01, HIBYTE(val)); 106} 107 108static WORD /* macro rWordAMD */ 109ReadWordAmd7930(struct IsdnCardState *cs, BYTE reg) 110{ 111 WORD res; 112 /* direct access register */ 113 if(reg < 8) { 114 res = rByteAMD(cs, reg); 115 res += 256*rByteAMD(cs, reg); 116 } 117 /* indirect access register */ 118 else { 119 wByteAMD(cs, 0x00, reg); 120 res = rByteAMD(cs, 0x01); 121 res += 256*rByteAMD(cs, 0x01); 122 } 123 return (res); 124} 125 126 127static void 128Amd7930_ph_command(struct IsdnCardState *cs, u_char command, char *s) 129{ 130 if (cs->debug & L1_DEB_ISAC) 131 debugl1(cs, "AMD7930: %s: ph_command 0x%02X", s, command); 132 133 cs->dc.amd7930.lmr1 = command; 134 wByteAMD(cs, 0xA3, command); 135} 136 137 138 139static BYTE i430States[] = { 140// to reset F3 F4 F5 F6 F7 F8 AR from 141 0x01, 0x02, 0x00, 0x00, 0x00, 0x07, 0x05, 0x00, // init 142 0x01, 0x02, 0x00, 0x00, 0x00, 0x07, 0x05, 0x00, // reset 143 0x01, 0x02, 0x00, 0x00, 0x00, 0x09, 0x05, 0x04, // F3 144 0x01, 0x02, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, // F4 145 0x01, 0x02, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, // F5 146 0x01, 0x03, 0x00, 0x00, 0x00, 0x06, 0x05, 0x00, // F6 147 0x11, 0x13, 0x00, 0x00, 0x1B, 0x00, 0x15, 0x00, // F7 148 0x01, 0x03, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, // F8 149 0x01, 0x03, 0x00, 0x00, 0x00, 0x09, 0x00, 0x0A}; // AR 150 151 152/* Row init - reset F3 F4 F5 F6 F7 F8 AR */ 153static BYTE stateHelper[] = { 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 }; 154 155 156 157 158static void 159Amd7930_get_state(struct IsdnCardState *cs) { 160 BYTE lsr = rByteAMD(cs, 0xA1); 161 cs->dc.amd7930.ph_state = (lsr & 0x7) + 2; 162 Amd7930_new_ph(cs); 163} 164 165 166 167static void 168Amd7930_new_ph(struct IsdnCardState *cs) 169{ 170 u_char index = stateHelper[cs->dc.amd7930.old_state]*8 + stateHelper[cs->dc.amd7930.ph_state]-1; 171 u_char message = i430States[index]; 172 173 if (cs->debug & L1_DEB_ISAC) 174 debugl1(cs, "AMD7930: new_ph %d, old_ph %d, message %d, index %d", 175 cs->dc.amd7930.ph_state, cs->dc.amd7930.old_state, message & 0x0f, index); 176 177 cs->dc.amd7930.old_state = cs->dc.amd7930.ph_state; 178 179 /* abort transmit if nessesary */ 180 if ((message & 0xf0) && (cs->tx_skb)) { 181 wByteAMD(cs, 0x21, 0xC2); 182 wByteAMD(cs, 0x21, 0x02); 183 } 184 185 switch (message & 0x0f) { 186 187 case (1): 188 l1_msg(cs, HW_RESET | INDICATION, NULL); 189 Amd7930_get_state(cs); 190 break; 191 case (2): /* init, Card starts in F3 */ 192 l1_msg(cs, HW_DEACTIVATE | CONFIRM, NULL); 193 break; 194 case (3): 195 l1_msg(cs, HW_DEACTIVATE | INDICATION, NULL); 196 break; 197 case (4): 198 l1_msg(cs, HW_POWERUP | CONFIRM, NULL); 199 Amd7930_ph_command(cs, 0x50, "HW_ENABLE REQUEST"); 200 break; 201 case (5): 202 l1_msg(cs, HW_RSYNC | INDICATION, NULL); 203 break; 204 case (6): 205 l1_msg(cs, HW_INFO4_P8 | INDICATION, NULL); 206 break; 207 case (7): /* init, Card starts in F7 */ 208 l1_msg(cs, HW_RSYNC | INDICATION, NULL); 209 l1_msg(cs, HW_INFO4_P8 | INDICATION, NULL); 210 break; 211 case (8): 212 l1_msg(cs, HW_POWERUP | CONFIRM, NULL); 213 /* fall through */ 214 case (9): 215 Amd7930_ph_command(cs, 0x40, "HW_ENABLE REQ cleared if set"); 216 l1_msg(cs, HW_RSYNC | INDICATION, NULL); 217 l1_msg(cs, HW_INFO2 | INDICATION, NULL); 218 l1_msg(cs, HW_INFO4_P8 | INDICATION, NULL); 219 break; 220 case (10): 221 Amd7930_ph_command(cs, 0x40, "T3 expired, HW_ENABLE REQ cleared"); 222 cs->dc.amd7930.old_state = 3; 223 break; 224 case (11): 225 l1_msg(cs, HW_INFO2 | INDICATION, NULL); 226 break; 227 default: 228 break; 229 } 230} 231 232 233 234static void 235Amd7930_bh(struct work_struct *work) 236{ 237 struct IsdnCardState *cs = 238 container_of(work, struct IsdnCardState, tqueue); 239 struct PStack *stptr; 240 241 if (!cs) 242 return; 243 if (test_and_clear_bit(D_CLEARBUSY, &cs->event)) { 244 if (cs->debug) 245 debugl1(cs, "Amd7930: bh, D-Channel Busy cleared"); 246 stptr = cs->stlist; 247 while (stptr != NULL) { 248 stptr->l1.l1l2(stptr, PH_PAUSE | CONFIRM, NULL); 249 stptr = stptr->next; 250 } 251 } 252 if (test_and_clear_bit(D_L1STATECHANGE, &cs->event)) { 253 if (cs->debug & L1_DEB_ISAC) 254 debugl1(cs, "AMD7930: bh, D_L1STATECHANGE"); 255 Amd7930_new_ph(cs); 256 } 257 258 if (test_and_clear_bit(D_RCVBUFREADY, &cs->event)) { 259 if (cs->debug & L1_DEB_ISAC) 260 debugl1(cs, "AMD7930: bh, D_RCVBUFREADY"); 261 DChannel_proc_rcv(cs); 262 } 263 264 if (test_and_clear_bit(D_XMTBUFREADY, &cs->event)) { 265 if (cs->debug & L1_DEB_ISAC) 266 debugl1(cs, "AMD7930: bh, D_XMTBUFREADY"); 267 DChannel_proc_xmt(cs); 268 } 269} 270 271static void 272Amd7930_empty_Dfifo(struct IsdnCardState *cs, int flag) 273{ 274 275 BYTE stat, der; 276 BYTE *ptr; 277 struct sk_buff *skb; 278 279 280 if ((cs->debug & L1_DEB_ISAC) && !(cs->debug & L1_DEB_ISAC_FIFO)) 281 debugl1(cs, "Amd7930: empty_Dfifo"); 282 283 284 ptr = cs->rcvbuf + cs->rcvidx; 285 286 /* AMD interrupts off */ 287 AmdIrqOff(cs); 288 289 /* read D-Channel-Fifo*/ 290 stat = rByteAMD(cs, 0x07); // DSR2 291 292 /* while Data in Fifo ... */ 293 while ( (stat & 2) && ((ptr-cs->rcvbuf) < MAX_DFRAME_LEN_L1) ) { 294 *ptr = rByteAMD(cs, 0x04); // DCRB 295 ptr++; 296 stat = rByteAMD(cs, 0x07); // DSR2 297 cs->rcvidx = ptr - cs->rcvbuf; 298 299 /* Paket ready? */ 300 if (stat & 1) { 301 302 der = rWordAMD(cs, 0x03); 303 304 /* no errors, packet ok */ 305 if(!der && !flag) { 306 rWordAMD(cs, 0x89); // clear DRCR 307 308 if ((cs->rcvidx) > 0) { 309 if (!(skb = alloc_skb(cs->rcvidx, GFP_ATOMIC))) 310 printk(KERN_WARNING "HiSax: Amd7930: empty_Dfifo, D receive out of memory!\n"); 311 else { 312 /* Debugging */ 313 if (cs->debug & L1_DEB_ISAC_FIFO) { 314 char *t = cs->dlog; 315 316 t += sprintf(t, "Amd7930: empty_Dfifo cnt: %d |", cs->rcvidx); 317 QuickHex(t, cs->rcvbuf, cs->rcvidx); 318 debugl1(cs, cs->dlog); 319 } 320 /* moves received data in sk-buffer */ 321 memcpy(skb_put(skb, cs->rcvidx), cs->rcvbuf, cs->rcvidx); 322 skb_queue_tail(&cs->rq, skb); 323 } 324 } 325 326 } 327 /* throw damaged packets away, reset receive-buffer, indicate RX */ 328 ptr = cs->rcvbuf; 329 cs->rcvidx = 0; 330 schedule_event(cs, D_RCVBUFREADY); 331 } 332 } 333 /* Packet to long, overflow */ 334 if(cs->rcvidx >= MAX_DFRAME_LEN_L1) { 335 if (cs->debug & L1_DEB_WARN) 336 debugl1(cs, "AMD7930: empty_Dfifo L2-Framelength overrun"); 337 cs->rcvidx = 0; 338 return; 339 } 340 /* AMD interrupts on */ 341 AmdIrqOn(cs); 342} 343 344 345static void 346Amd7930_fill_Dfifo(struct IsdnCardState *cs) 347{ 348 349 WORD dtcrr, dtcrw, len, count; 350 BYTE txstat, dmr3; 351 BYTE *ptr, *deb_ptr; 352 353 if ((cs->debug & L1_DEB_ISAC) && !(cs->debug & L1_DEB_ISAC_FIFO)) 354 debugl1(cs, "Amd7930: fill_Dfifo"); 355 356 if ((!cs->tx_skb) || (cs->tx_skb->len <= 0)) 357 return; 358 359 dtcrw = 0; 360 if(!cs->dc.amd7930.tx_xmtlen) 361 /* new Frame */ 362 len = dtcrw = cs->tx_skb->len; 363 /* continue frame */ 364 else len = cs->dc.amd7930.tx_xmtlen; 365 366 367 /* AMD interrupts off */ 368 AmdIrqOff(cs); 369 370 deb_ptr = ptr = cs->tx_skb->data; 371 372 /* while free place in tx-fifo available and data in sk-buffer */ 373 txstat = 0x10; 374 while((txstat & 0x10) && (cs->tx_cnt < len)) { 375 wByteAMD(cs, 0x04, *ptr); 376 ptr++; 377 cs->tx_cnt++; 378 txstat= rByteAMD(cs, 0x07); 379 } 380 count = ptr - cs->tx_skb->data; 381 skb_pull(cs->tx_skb, count); 382 383 384 dtcrr = rWordAMD(cs, 0x85); // DTCR 385 dmr3 = rByteAMD(cs, 0x8E); 386 387 if (cs->debug & L1_DEB_ISAC) { 388 debugl1(cs, "Amd7930: fill_Dfifo, DMR3: 0x%02X, DTCR read: 0x%04X write: 0x%02X 0x%02X", dmr3, dtcrr, LOBYTE(dtcrw), HIBYTE(dtcrw)); 389 } 390 391 /* writeing of dtcrw starts transmit */ 392 if(!cs->dc.amd7930.tx_xmtlen) { 393 wWordAMD(cs, 0x85, dtcrw); 394 cs->dc.amd7930.tx_xmtlen = dtcrw; 395 } 396 397 if (test_and_set_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) { 398 debugl1(cs, "Amd7930: fill_Dfifo dbusytimer running"); 399 del_timer(&cs->dbusytimer); 400 } 401 init_timer(&cs->dbusytimer); 402 cs->dbusytimer.expires = jiffies + ((DBUSY_TIMER_VALUE * HZ) / 1000); 403 add_timer(&cs->dbusytimer); 404 405 if (cs->debug & L1_DEB_ISAC_FIFO) { 406 char *t = cs->dlog; 407 408 t += sprintf(t, "Amd7930: fill_Dfifo cnt: %d |", count); 409 QuickHex(t, deb_ptr, count); 410 debugl1(cs, cs->dlog); 411 } 412 /* AMD interrupts on */ 413 AmdIrqOn(cs); 414} 415 416 417void Amd7930_interrupt(struct IsdnCardState *cs, BYTE irflags) 418{ 419 BYTE dsr1, dsr2, lsr; 420 WORD der; 421 422 while (irflags) 423 { 424 425 dsr1 = rByteAMD(cs, 0x02); 426 der = rWordAMD(cs, 0x03); 427 dsr2 = rByteAMD(cs, 0x07); 428 lsr = rByteAMD(cs, 0xA1); 429 430 if (cs->debug & L1_DEB_ISAC) 431 debugl1(cs, "Amd7930: interrupt: flags: 0x%02X, DSR1: 0x%02X, DSR2: 0x%02X, LSR: 0x%02X, DER=0x%04X", irflags, dsr1, dsr2, lsr, der); 432 433 /* D error -> read DER and DSR2 bit 2 */ 434 if (der || (dsr2 & 4)) { 435 436 if (cs->debug & L1_DEB_WARN) 437 debugl1(cs, "Amd7930: interrupt: D error DER=0x%04X", der); 438 439 /* RX, TX abort if collision detected */ 440 if (der & 2) { 441 wByteAMD(cs, 0x21, 0xC2); 442 wByteAMD(cs, 0x21, 0x02); 443 if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) 444 del_timer(&cs->dbusytimer); 445 if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags)) 446 schedule_event(cs, D_CLEARBUSY); 447 /* restart frame */ 448 if (cs->tx_skb) { 449 skb_push(cs->tx_skb, cs->tx_cnt); 450 cs->tx_cnt = 0; 451 cs->dc.amd7930.tx_xmtlen = 0; 452 Amd7930_fill_Dfifo(cs); 453 } else { 454 printk(KERN_WARNING "HiSax: Amd7930 D-Collision, no skb\n"); 455 debugl1(cs, "Amd7930: interrupt: D-Collision, no skb"); 456 } 457 } 458 /* remove damaged data from fifo */ 459 Amd7930_empty_Dfifo(cs, 1); 460 461 if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) 462 del_timer(&cs->dbusytimer); 463 if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags)) 464 schedule_event(cs, D_CLEARBUSY); 465 /* restart TX-Frame */ 466 if (cs->tx_skb) { 467 skb_push(cs->tx_skb, cs->tx_cnt); 468 cs->tx_cnt = 0; 469 cs->dc.amd7930.tx_xmtlen = 0; 470 Amd7930_fill_Dfifo(cs); 471 } 472 } 473 474 /* D TX FIFO empty -> fill */ 475 if (irflags & 1) { 476 if (cs->debug & L1_DEB_ISAC) 477 debugl1(cs, "Amd7930: interrupt: clear Timer and fill D-TX-FIFO if data"); 478 479 /* AMD interrupts off */ 480 AmdIrqOff(cs); 481 482 if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) 483 del_timer(&cs->dbusytimer); 484 if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags)) 485 schedule_event(cs, D_CLEARBUSY); 486 if (cs->tx_skb) { 487 if (cs->tx_skb->len) 488 Amd7930_fill_Dfifo(cs); 489 } 490 /* AMD interrupts on */ 491 AmdIrqOn(cs); 492 } 493 494 495 /* D RX FIFO full or tiny packet in Fifo -> empty */ 496 if ((irflags & 2) || (dsr1 & 2)) { 497 if (cs->debug & L1_DEB_ISAC) 498 debugl1(cs, "Amd7930: interrupt: empty D-FIFO"); 499 Amd7930_empty_Dfifo(cs, 0); 500 } 501 502 503 /* D-Frame transmit complete */ 504 if (dsr1 & 64) { 505 if (cs->debug & L1_DEB_ISAC) { 506 debugl1(cs, "Amd7930: interrupt: transmit packet ready"); 507 } 508 /* AMD interrupts off */ 509 AmdIrqOff(cs); 510 511 if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) 512 del_timer(&cs->dbusytimer); 513 if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags)) 514 schedule_event(cs, D_CLEARBUSY); 515 516 if (cs->tx_skb) { 517 if (cs->debug & L1_DEB_ISAC) 518 debugl1(cs, "Amd7930: interrupt: TX-Packet ready, freeing skb"); 519 dev_kfree_skb_irq(cs->tx_skb); 520 cs->tx_cnt = 0; 521 cs->dc.amd7930.tx_xmtlen=0; 522 cs->tx_skb = NULL; 523 } 524 if ((cs->tx_skb = skb_dequeue(&cs->sq))) { 525 if (cs->debug & L1_DEB_ISAC) 526 debugl1(cs, "Amd7930: interrupt: TX-Packet ready, next packet dequeued"); 527 cs->tx_cnt = 0; 528 cs->dc.amd7930.tx_xmtlen=0; 529 Amd7930_fill_Dfifo(cs); 530 } 531 else 532 schedule_event(cs, D_XMTBUFREADY); 533 /* AMD interrupts on */ 534 AmdIrqOn(cs); 535 } 536 537 /* LIU status interrupt -> read LSR, check statechanges */ 538 if (lsr & 0x38) { 539 /* AMD interrupts off */ 540 AmdIrqOff(cs); 541 542 if (cs->debug & L1_DEB_ISAC) 543 debugl1(cs, "Amd: interrupt: LSR=0x%02X, LIU is in state %d", lsr, ((lsr & 0x7) +2)); 544 545 cs->dc.amd7930.ph_state = (lsr & 0x7) + 2; 546 547 schedule_event(cs, D_L1STATECHANGE); 548 /* AMD interrupts on */ 549 AmdIrqOn(cs); 550 } 551 552 /* reads Interrupt-Register again. If there is a new interrupt-flag: restart handler */ 553 irflags = rByteAMD(cs, 0x00); 554 } 555 556} 557 558static void 559Amd7930_l1hw(struct PStack *st, int pr, void *arg) 560{ 561 struct IsdnCardState *cs = (struct IsdnCardState *) st->l1.hardware; 562 struct sk_buff *skb = arg; 563 u_long flags; 564 565 if (cs->debug & L1_DEB_ISAC) 566 debugl1(cs, "Amd7930: l1hw called, pr: 0x%04X", pr); 567 568 switch (pr) { 569 case (PH_DATA | REQUEST): 570 if (cs->debug & DEB_DLOG_HEX) 571 LogFrame(cs, skb->data, skb->len); 572 if (cs->debug & DEB_DLOG_VERBOSE) 573 dlogframe(cs, skb, 0); 574 spin_lock_irqsave(&cs->lock, flags); 575 if (cs->tx_skb) { 576 skb_queue_tail(&cs->sq, skb); 577#ifdef L2FRAME_DEBUG /* psa */ 578 if (cs->debug & L1_DEB_LAPD) 579 Logl2Frame(cs, skb, "Amd7930: l1hw: PH_DATA Queued", 0); 580#endif 581 } else { 582 cs->tx_skb = skb; 583 cs->tx_cnt = 0; 584 cs->dc.amd7930.tx_xmtlen=0; 585#ifdef L2FRAME_DEBUG /* psa */ 586 if (cs->debug & L1_DEB_LAPD) 587 Logl2Frame(cs, skb, "Amd7930: l1hw: PH_DATA", 0); 588#endif 589 Amd7930_fill_Dfifo(cs); 590 } 591 spin_unlock_irqrestore(&cs->lock, flags); 592 break; 593 case (PH_PULL | INDICATION): 594 spin_lock_irqsave(&cs->lock, flags); 595 if (cs->tx_skb) { 596 if (cs->debug & L1_DEB_WARN) 597 debugl1(cs, "Amd7930: l1hw: l2l1 tx_skb exist this shouldn't happen"); 598 skb_queue_tail(&cs->sq, skb); 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 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 __devinit 790setup_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}