Annotation of sys/dev/ic/rlnsubr.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: rlnsubr.c,v 1.5 2002/03/14 01:26:55 millert Exp $ */
! 2: /*
! 3: * David Leonard <d@openbsd.org>, 1999. Public Domain.
! 4: *
! 5: * Low level card protocol access to the Proxim RangeLAN2 wireless
! 6: * network adaptor.
! 7: *
! 8: * Information and ideas gleaned from
! 9: * - disassembly of Dave Koberstein's <davek@komacke.com> Linux driver
! 10: * (which is built with Proxim source),
! 11: * - Yoichi Shinoda's <shinoda@cs.washington.edu> BSDI driver, and
! 12: * - Geoff Voelker's <voelker@cs.washington.edu> Linux port of the same.
! 13: */
! 14:
! 15: #include <sys/param.h>
! 16: #include <sys/systm.h>
! 17: #include <sys/mbuf.h>
! 18: #include <sys/socket.h>
! 19: #include <sys/ioctl.h>
! 20: #include <sys/syslog.h>
! 21: #include <sys/device.h>
! 22: #include <sys/queue.h>
! 23: #include <sys/proc.h>
! 24: #include <sys/kernel.h>
! 25:
! 26: #include <net/if.h>
! 27:
! 28: #ifdef INET
! 29: #include <netinet/in.h>
! 30: #include <netinet/if_ether.h>
! 31: #endif
! 32:
! 33: #include <machine/bus.h>
! 34: #include <machine/intr.h>
! 35:
! 36: #include <dev/ic/rln.h>
! 37: #include <dev/ic/rlnvar.h>
! 38: #include <dev/ic/rlnreg.h>
! 39: #include <dev/ic/rlncmd.h>
! 40:
! 41: static int rln_tx_request(struct rln_softc *, u_int16_t);
! 42: static int rln_tx_end(struct rln_softc *);
! 43:
! 44: /*
! 45: * Disables or enables interrupts from the card. Returns the old
! 46: * interrupt-enable state.
! 47: */
! 48: int
! 49: rln_enable(sc, enable)
! 50: struct rln_softc * sc;
! 51: int enable;
! 52: {
! 53: int s;
! 54: int was_enabled;
! 55:
! 56: s = splhigh();
! 57: was_enabled = (sc->sc_intsel & RLN_INTSEL_ENABLE) ? 1 : 0;
! 58: if (enable != was_enabled) {
! 59: if (enable)
! 60: sc->sc_intsel |= RLN_INTSEL_ENABLE;
! 61: else
! 62: sc->sc_intsel &=~RLN_INTSEL_ENABLE;
! 63: _rln_register_write_1(sc, RLN_REG_INTSEL, sc->sc_intsel);
! 64: }
! 65: splx(s);
! 66: return (was_enabled);
! 67: }
! 68:
! 69: /*
! 70: * Perform a hard reset of the card. Determines bus width (8 or
! 71: * 16 bit), if sc->sc_width is unset. Returns 0 on success.
! 72: * Note: takes about 200ms at splhigh, meaning this is an expensive call,
! 73: * but normal (error-free) operation of the card will not need more than
! 74: * two resets - one at probe time, and the other when the interface is
! 75: * brought up.
! 76: */
! 77: int
! 78: rln_reset(sc)
! 79: struct rln_softc * sc;
! 80: {
! 81: int s;
! 82: int i;
! 83: int status;
! 84: u_int8_t op = 0x00;
! 85:
! 86: s = splhigh();
! 87: dprintf(" R[");
! 88: if (sc->sc_cardtype & (RLN_CTYPE_UISA | RLN_CTYPE_ONE_PIECE))
! 89: op = 0x04;
! 90: if (rln_status_read(sc) & RLN_STATUS_WAKEUP) {
! 91: rln_control_write(sc, op);
! 92: rln_control_write(sc, op | RLN_CONTROL_RESET);
! 93: dprintf(" 7ms");
! 94: DELAY(7000);
! 95: rln_control_write(sc, op);
! 96: dprintf(" 7ms");
! 97: DELAY(7000);
! 98: }
! 99: rln_control_write(sc, op);
! 100: rln_control_write(sc, op);
! 101: rln_control_write(sc, op | RLN_CONTROL_BIT3);
! 102: dprintf(" 67ms");
! 103: DELAY(67000);
! 104: rln_status_write(sc, 0x00);
! 105: if (sc->sc_cardtype & (RLN_CTYPE_UISA | RLN_CTYPE_ONE_PIECE))
! 106: rln_control_write(sc, 0x38);
! 107: /* RLN_CONTROL_BIT3 | RLN_CONTROL_RESET | RLN_CONTROL_16BIT */
! 108: else
! 109: rln_control_write(sc, 0x2c);
! 110: /* RLN_CONTROL_BIT3 | RLN_CONTROL_BIT2 | RLN_CONTROL_16BIT */
! 111: dprintf(" 67ms");
! 112: DELAY(67000);
! 113: rln_data_write_2(sc, 0xaa55);
! 114: rln_status_write(sc, 0x5a);
! 115: splx(s);
! 116: for (i = 0; i < 200 * 10; i++) { /* Proxim says 200. */
! 117: if ((status = rln_status_read(sc)) == 0x5a)
! 118: break;
! 119: DELAY(1000);
! 120: }
! 121: dprintf(" (%dms)", i);
! 122: s = splhigh();
! 123: if (status != 0x5a) {
! 124: splx(s);
! 125: /* Only winge if bus width not yet probed */
! 126: if (sc->sc_width != 0)
! 127: printf("%s: reset timeout\n", sc->sc_dev.dv_xname);
! 128: dprintf("]=-1");
! 129: return (-1);
! 130: }
! 131: if (sc->sc_width == 8) {
! 132: if (sc->sc_cardtype & (RLN_CTYPE_UISA | RLN_CTYPE_ONE_PIECE))
! 133: rln_control_write(sc, RLN_CONTROL_BIT3);
! 134: else
! 135: rln_control_write(sc, RLN_CONTROL_BIT3 |
! 136: RLN_CONTROL_BIT2);
! 137: rln_data_write_1(sc, 0x20);
! 138: } else if (sc->sc_width == 16) {
! 139: rln_data_write_2(sc, 0x0000);
! 140: } else {
! 141: if (rln_data_read_2(sc) == 0x55aa) {
! 142: rln_data_write_2(sc, 0x0000);
! 143: sc->sc_width = 16;
! 144: } else {
! 145: if (sc->sc_cardtype & (RLN_CTYPE_UISA |
! 146: RLN_CTYPE_ONE_PIECE))
! 147: rln_control_write(sc, RLN_CONTROL_BIT3);
! 148: else
! 149: rln_control_write(sc, RLN_CONTROL_BIT3 |
! 150: RLN_CONTROL_BIT2);
! 151: rln_data_write_1(sc, 0x20);
! 152: sc->sc_width = 8;
! 153: }
! 154: /* printf("%s: %d bit bus\n", sc->sc_dev.dv_xname,
! 155: sc->sc_width); */
! 156: }
! 157: rln_status_write(sc, 0x00);
! 158: sc->sc_intsel = 0;
! 159: rln_intsel_write(sc, sc->sc_irq);
! 160: splx(s);
! 161: dprintf("]");
! 162: return (0);
! 163: }
! 164:
! 165: /*
! 166: * Sets the new 'wakeup' state. Returns the old wakeup state.
! 167: * The special state value RLN_WAKEUP_SET should be used to wake the
! 168: * card up. The card can be partially put to sleep (presumably to save
! 169: * power) by sending it the 'Standby' command.
! 170: */
! 171: u_int8_t
! 172: rln_wakeup(sc, wnew)
! 173: struct rln_softc * sc;
! 174: u_int8_t wnew;
! 175: {
! 176: u_int8_t wold, s;
! 177: int i;
! 178:
! 179: /* Save what the last-written values were. */
! 180: wold = (sc->sc_status & RLN_STATUS_WAKEUP) |
! 181: (sc->sc_control & RLN_CONTROL_RESET);
! 182:
! 183: if (wnew == RLN_WAKEUP_SET) {
! 184: /* SetWakeupBit() */
! 185: dprintf(" Ws[");
! 186: rln_status_set(sc, RLN_STATUS_WAKEUP);
! 187: if (0/*LLDInactivityTimeOut &&
! 188: (sc->sc_cardtype & RLN_CTYPE_OEM)*/) {
! 189: dprintf (" 167ms");
! 190: DELAY(167000);
! 191: } else {
! 192: dprintf (" .1ms");
! 193: DELAY(100);
! 194: }
! 195: s = rln_status_read(sc);
! 196: rln_control_set(sc, RLN_CONTROL_RESET);
! 197: if ((s & RLN_STATUS_WAKEUP) != 0)
! 198: for (i = 0; i < 9; i++) {
! 199: dprintf(" 2ms");
! 200: DELAY(2000);
! 201: rln_status_set(sc, RLN_STATUS_WAKEUP);
! 202: }
! 203: dprintf("]");
! 204: } else {
! 205: /* ClearWakeupBit() */
! 206: dprintf(" Wc[");
! 207: if ((wnew & RLN_STATUS_WAKEUP) == 0)
! 208: rln_status_clear(sc, RLN_STATUS_WAKEUP);
! 209: if ((wnew & RLN_CONTROL_RESET) == 0)
! 210: rln_control_clear(sc, RLN_CONTROL_RESET);
! 211: dprintf("]");
! 212: }
! 213: return (wold);
! 214: }
! 215:
! 216: /*
! 217: * Performs the first (request) stage of transmitting a command message
! 218: * to the card. 'len' is the expected length of the message is needed.
! 219: * Returns: 0 on success
! 220: * 1 on timeout
! 221: * 2 on NAK (card busy, and will need a rln_clear_nak() after 100ms)
! 222: */
! 223: static int
! 224: rln_tx_request(sc, len)
! 225: struct rln_softc * sc;
! 226: u_int16_t len;
! 227: {
! 228: /* TxRequest() */
! 229: int s;
! 230: int i;
! 231: u_int8_t status;
! 232:
! 233: /* u_int8_t w; */
! 234: /* w = rln_wakeup(sc, RLN_WAKEUP_SET); */
! 235:
! 236: dprintf(" Tr[");
! 237: if (sc->sc_width == 16) {
! 238: rln_status_tx_write(sc, RLN_STATUS_TX_HILEN_AVAIL);
! 239: rln_data_write_2(sc, len);
! 240: rln_status_tx_int(sc);
! 241:
! 242: s = spl0();
! 243: for (i = 0; i < 600; i++) {
! 244: status = rln_status_tx_read(sc);
! 245: if (status == RLN_STATUS_TX_HILEN_ACCEPT ||
! 246: status == RLN_STATUS_TX_ERROR)
! 247: break;
! 248: DELAY(1000);
! 249: }
! 250: splx(s);
! 251: dprintf(" %dms", i);
! 252: if (status == RLN_STATUS_TX_HILEN_ACCEPT)
! 253: goto success;
! 254: if (status == RLN_STATUS_TX_ERROR)
! 255: goto error;
! 256: } else if (sc->sc_width == 8) {
! 257: rln_status_tx_write(sc, RLN_STATUS_TX_LOLEN_AVAIL);
! 258: rln_data_write_1(sc, len & 0xff);
! 259: rln_status_tx_int(sc);
! 260: s = spl0();
! 261: for (i = 0; i < 6800; i++) {
! 262: status = rln_status_tx_read(sc);
! 263: if (status == RLN_STATUS_TX_LOLEN_ACCEPT)
! 264: break;
! 265: DELAY(1000);
! 266: }
! 267: splx(s);
! 268: dprintf(" %dms", i);
! 269: if (status == RLN_STATUS_TX_LOLEN_ACCEPT) {
! 270: rln_data_write_1(sc, (len >> 8) & 0xff);
! 271: rln_status_tx_write(sc, RLN_STATUS_TX_HILEN_AVAIL);
! 272: s = spl0();
! 273: for (i = 0; i < 600; i++) {
! 274: status = rln_status_tx_read(sc);
! 275: if (status == RLN_STATUS_TX_HILEN_ACCEPT ||
! 276: status == RLN_STATUS_TX_ERROR)
! 277: break;
! 278: DELAY(1000);
! 279: }
! 280: splx(s);
! 281: dprintf(" %dms", i);
! 282: if (status == RLN_STATUS_TX_HILEN_ACCEPT)
! 283: goto success;
! 284: if (status == RLN_STATUS_TX_ERROR)
! 285: goto error;
! 286: }
! 287: }
! 288: #ifdef DIAGNOSTIC
! 289: else
! 290: panic("rln: bus width");
! 291: #endif
! 292:
! 293: printf("%s: tx_request timed out, status 0x%02x",
! 294: sc->sc_dev.dv_xname, status);
! 295: dprintf("]=(1)");
! 296: return (1);
! 297:
! 298: error:
! 299: /* Will need to clear nak within 100 ms. */
! 300: dprintf("]=2");
! 301: #ifdef DIAGNOSTIC
! 302: printf("%s: tx protocol fault (nak)\n", sc->sc_dev.dv_xname);
! 303: #endif
! 304: return (2);
! 305:
! 306: success:
! 307: /* rln_wakeup(sc, w); */
! 308: dprintf("]=0");
! 309: return (0);
! 310: }
! 311:
! 312: /*
! 313: * Performs the third (and final) stage of transmitting a command
! 314: * message to the card.
! 315: * Returns: 0 on command success.
! 316: * non-zero on failure (card will need reset)
! 317: */
! 318: static int
! 319: rln_tx_end(sc)
! 320: struct rln_softc * sc;
! 321: {
! 322: /* EndOfTx() */
! 323: int i;
! 324: int s;
! 325: u_int8_t status;
! 326:
! 327: dprintf(" Te[");
! 328: s = spl0();
! 329: for (i = 0; i < 600; i++) {
! 330: status = rln_status_tx_read(sc);
! 331: if (status == RLN_STATUS_TX_XFR_COMPLETE)
! 332: break;
! 333: DELAY(1000);
! 334: }
! 335: splx(s);
! 336: if (status == RLN_STATUS_TX_XFR_COMPLETE) {
! 337: rln_status_tx_write(sc, RLN_STATUS_TX_IDLE);
! 338: dprintf("]=0");
! 339: return (0);
! 340: } else {
! 341: printf("%s: tx cmd failed (%02x)\n", sc->sc_dev.dv_xname,
! 342: status);
! 343: rln_need_reset(sc);
! 344: dprintf("]=-1");
! 345: return (-1);
! 346: }
! 347: }
! 348:
! 349: /*
! 350: * Performs first (request) stage of receiving a message from the card.
! 351: * Returns: 0 on failure,
! 352: * n>0 on success, where 'n' is the length of the message
! 353: */
! 354:
! 355: int
! 356: rln_rx_request(sc, timeo)
! 357: struct rln_softc * sc;
! 358: int timeo; /* milliseconds */
! 359: {
! 360: /* RxRequest */
! 361: int s;
! 362: int len = 0;
! 363: int i;
! 364: u_int8_t status;
! 365: u_int8_t hi, lo;
! 366:
! 367: dprintf(" Rr[");
! 368: status = rln_status_rx_read(sc);
! 369:
! 370: /* Short wait for states 1|5|6. */
! 371: s = spl0();
! 372: for (i = 0; i < timeo; i++) {
! 373: if (status == RLN_STATUS_RX_LOLEN_AVAIL ||
! 374: status == RLN_STATUS_RX_HILEN_AVAIL ||
! 375: status == RLN_STATUS_RX_ERROR)
! 376: break;
! 377: DELAY(1000);
! 378: status = rln_status_rx_read(sc);
! 379: }
! 380: splx(s);
! 381: dprintf(" (%dms)",i);
! 382:
! 383: if (sc->sc_width == 16) {
! 384: if (status != RLN_STATUS_RX_HILEN_AVAIL)
! 385: goto badstatus_quiet;
! 386: /* Read 2 octets. */
! 387: len = rln_data_read_2(sc);
! 388: } else if (sc->sc_width == 8) {
! 389: if (status != RLN_STATUS_RX_LOLEN_AVAIL)
! 390: goto badstatus_quiet;
! 391: /* Read low octet. */
! 392: lo = rln_data_read_1(sc);
! 393: rln_status_rx_write(sc, RLN_STATUS_RX_LOLEN_ACCEPT);
! 394: rln_status_rx_int(sc);
! 395: s = spl0();
! 396: for (i = 0; i < 600; i++) {
! 397: status = rln_status_rx_read(sc);
! 398: if (status == RLN_STATUS_RX_HILEN_AVAIL)
! 399: break;
! 400: DELAY(1000);
! 401: }
! 402: splx(s);
! 403: if (status != RLN_STATUS_RX_HILEN_AVAIL)
! 404: goto badstatus;
! 405: /* Read high octet. */
! 406: hi = rln_data_read_1(sc);
! 407: len = lo | (hi << 8);
! 408: }
! 409: #ifdef DIAGNOSTIC
! 410: else
! 411: panic("rln: bus width %d", sc->sc_width);
! 412: #endif
! 413:
! 414: dprintf(" len=%d]", len);
! 415: return (len);
! 416:
! 417: badstatus:
! 418: printf("%s: rx_request timed out, status %02x\n",
! 419: sc->sc_dev.dv_xname, status);
! 420: badstatus_quiet:
! 421: if (status == RLN_STATUS_RX_ERROR)
! 422: printf("%s: rx protocol error (nak)\n", sc->sc_dev.dv_xname);
! 423: dprintf("]");
! 424: return (-1);
! 425: }
! 426:
! 427: /* Performs part of the second (transfer) stage of receiving a data message. */
! 428: void
! 429: rln_rx_pdata(sc, buf, len, pd)
! 430: struct rln_softc * sc;
! 431: void * buf;
! 432: int len;
! 433: struct rln_pdata * pd;
! 434: {
! 435: char * data = (char *)buf;
! 436:
! 437: if (pd->p_nremain) {
! 438: *data++ = pd->p_data;
! 439: if (--len == 0)
! 440: return;
! 441: }
! 442:
! 443: pd->p_nremain = 0;
! 444:
! 445: if (sc->sc_width == 16) {
! 446: /* Round down to the closest even multiple. */
! 447: rln_data_read_multi_2(sc, data, len / 2);
! 448: #ifdef RLNDEBUG_REG
! 449: dprintf(" D>");
! 450: dprinthex(data, len);
! 451: #endif
! 452: if (len & 1) {
! 453: /* Read the last octet plus a bit extra. */
! 454: union {
! 455: u_int16_t w;
! 456: u_int8_t b[2];
! 457: } u;
! 458:
! 459: u.w = rln_data_read_2(sc);
! 460: data[len - 1] = u.b[0];
! 461: pd->p_data = u.b[1];
! 462: pd->p_nremain = 1;
! 463: #ifdef RLNDEBUG_REG
! 464: dprintf(" D>{%02x%02x}", u.b[0], u.b[1]);
! 465: #endif
! 466: }
! 467: } else if (sc->sc_width == 8) {
! 468: rln_data_read_multi_1(sc, data, len);
! 469: #ifdef RLNDEBUG_REG
! 470: dprintf(" D>");
! 471: dprinthex(data, len);
! 472: #endif
! 473: if (len & 1) {
! 474: /* Must read multiples of two. */
! 475: pd->p_data = rln_data_read_1(sc);
! 476: pd->p_nremain = 1;
! 477: #ifdef RLNDEBUG_REG
! 478: dprintf(" D>{%02x}", pd->p_data);
! 479: #endif
! 480: }
! 481: }
! 482:
! 483: }
! 484:
! 485: int
! 486: rln_rx_data(sc, buf, len)
! 487: struct rln_softc * sc;
! 488: void * buf;
! 489: int len;
! 490: {
! 491: /* RxData() */
! 492: struct rln_pdata pd = { 0, 0 };
! 493: int s;
! 494: int i;
! 495: u_int8_t status;
! 496:
! 497: dprintf(" Rd[");
! 498: rln_status_rx_write(sc, RLN_STATUS_RX_HILEN_ACCEPT);
! 499: rln_status_rx_int(sc);
! 500: s = spl0();
! 501: for (i = 0; i < 600; i++) {
! 502: status = rln_status_rx_read(sc);
! 503: if (status == RLN_STATUS_RX_XFR)
! 504: break;
! 505: DELAY(1000);
! 506: }
! 507: splx(s);
! 508: if (status != RLN_STATUS_RX_XFR) {
! 509: dprintf("]=-1");
! 510: return (-1);
! 511: }
! 512:
! 513: rln_rx_pdata(sc, buf, len, &pd);
! 514: #ifdef DIAGNOSTIC
! 515: /* We should have nothing left over. */
! 516: if (pd.p_nremain || len & 1)
! 517: panic("rln_rx_data: leftover");
! 518: #endif
! 519:
! 520: dprintf("]=0");
! 521: return (0);
! 522: }
! 523:
! 524: void
! 525: rln_rx_end(sc)
! 526: struct rln_softc * sc;
! 527: {
! 528: /* EndOfRx() */
! 529:
! 530: dprintf(" Re[");
! 531: rln_status_rx_write(sc, RLN_STATUS_RX_XFR_COMPLETE);
! 532: rln_status_rx_int(sc);
! 533: /* rln_wakeup(sc, 0); */
! 534: dprintf("]");
! 535: }
! 536:
! 537: /* Clear a transmission NAK from the card. */
! 538: void
! 539: rln_clear_nak(sc)
! 540: struct rln_softc * sc;
! 541: {
! 542: /* ClearNAK() */
! 543:
! 544: rln_status_tx_write(sc, RLN_STATUS_CLRNAK);
! 545: rln_status_tx_int(sc);
! 546: }
! 547:
! 548: /*
! 549: * Send a command message to the card. Returns;
! 550: * 2: NAK
! 551: * -1: failure
! 552: * 0: success
! 553: */
! 554: int
! 555: rln_msg_tx_start(sc, buf, pktlen, state)
! 556: struct rln_softc * sc;
! 557: void * buf;
! 558: int pktlen;
! 559: struct rln_msg_tx_state * state;
! 560: {
! 561: struct rln_mm_cmd * cmd = (struct rln_mm_cmd *)buf;
! 562: int ret;
! 563:
! 564: state->ien = rln_enable(sc, 0);
! 565: state->pd.p_nremain = 0;
! 566:
! 567: if (!(cmd->cmd_letter == 'A' && cmd->cmd_fn == 6)) /* Standby. */
! 568: state->w = rln_wakeup(sc, RLN_WAKEUP_SET);
! 569: else
! 570: state->w = RLN_WAKEUP_NOCHANGE;
! 571:
! 572: ret = rln_tx_request(sc, pktlen);
! 573: if (ret == 2) {
! 574: rln_clear_nak(sc);
! 575: if (sc->sc_cardtype & RLN_CTYPE_OEM)
! 576: rln_need_reset(sc);
! 577: ret = 2;
! 578: }
! 579: else if (ret == 1) {
! 580: /* Timeout. */
! 581: rln_status_tx_write(sc, RLN_STATUS_TX_XFR);
! 582: ret = -1;
! 583: }
! 584: return (ret);
! 585: }
! 586:
! 587: void
! 588: rln_msg_tx_data(sc, buf, len, state)
! 589: struct rln_softc * sc;
! 590: void * buf;
! 591: u_int16_t len;
! 592: struct rln_msg_tx_state * state;
! 593: {
! 594: char * data = (char *)buf;
! 595:
! 596: if (sc->sc_width == 16 && state->pd.p_nremain) {
! 597: /* XXX htons() needed? */
! 598: union {
! 599: u_int8_t b[2];
! 600: u_int16_t w;
! 601: } u;
! 602:
! 603: u.b[0] = state->pd.p_data;
! 604: if (len) {
! 605: u.b[1] = *data++;
! 606: len--;
! 607: } else
! 608: u.b[1] = '\0';
! 609: #ifdef RLNDEBUG_REG
! 610: dprintf(" D<%02x%02x", u.b[0], u.b[1]);
! 611: #endif
! 612: rln_data_write_2(sc, u.w);
! 613: state->pd.p_nremain = 0;
! 614: }
! 615:
! 616: if (len) {
! 617: if (sc->sc_width == 16) {
! 618: if (len >= 2)
! 619: rln_data_write_multi_2(sc, buf, len / 2);
! 620: if (len & 1) {
! 621: state->pd.p_nremain = 1;
! 622: state->pd.p_data = data[len - 1];
! 623: }
! 624: } else if (sc->sc_width == 8)
! 625: rln_data_write_multi_1(sc, buf, len);
! 626: #ifdef DIAGNOSTIC
! 627: else
! 628: panic("rln_msg_tx_data width %d", sc->sc_width);
! 629: #endif
! 630: #ifdef RLNDEBUG_REG
! 631: dprintf(" D<");
! 632: dprinthex(data, len);
! 633: #endif
! 634: }
! 635: }
! 636:
! 637:
! 638: int
! 639: rln_msg_tx_end(sc, state)
! 640: struct rln_softc * sc;
! 641: struct rln_msg_tx_state * state;
! 642: {
! 643: int ret;
! 644:
! 645: /* Flush the tx buffer. */
! 646: if (state->pd.p_nremain)
! 647: rln_msg_tx_data(sc, NULL, 0, state);
! 648:
! 649: #ifdef DIAGNOSTIC
! 650: if (state->pd.p_nremain)
! 651: panic("rln_msg_tx_end remain %d", state->pd.p_nremain);
! 652: #endif
! 653: ret = rln_tx_end(sc);
! 654: if (sc->sc_arpcom.ac_if.if_flags & IFF_OACTIVE)
! 655: state->w = RLN_WAKEUP_NOCHANGE;
! 656: rln_wakeup(sc, state->w);
! 657: rln_enable(sc, state->ien);
! 658: return (ret);
! 659: }
! 660:
! 661: /* Return the next unique sequence number to use for a transmitted command */
! 662: u_int8_t
! 663: rln_newseq(sc)
! 664: struct rln_softc * sc;
! 665: {
! 666: int s;
! 667: u_int8_t seq;
! 668:
! 669: s = splhigh();
! 670: seq = sc->sc_pktseq++;
! 671: if (sc->sc_pktseq > RLN_MAXSEQ)
! 672: sc->sc_pktseq = 0;
! 673: splx(s);
! 674: return (seq);
! 675: }
! 676:
! 677: /*
! 678: * Transmit a command message to, and (optionally) receive a response
! 679: * message from the card. Each transmitted message has a sequence
! 680: * number, and corresponding reply messages have the same sequence
! 681: * number. We use the sequence numbers to index the mailboxes so
! 682: * that rlnsoftintr() can signal this routine when it has serviced
! 683: * and correctly received a response.
! 684: */
! 685:
! 686: int
! 687: rln_msg_txrx(sc, tx, txlen, rx, rxlen)
! 688: struct rln_softc * sc;
! 689: void * tx;
! 690: int txlen;
! 691: void * rx;
! 692: int rxlen;
! 693: {
! 694: struct rln_mm_cmd * txc = (struct rln_mm_cmd *)tx;
! 695: struct rln_mm_cmd * rxc = (struct rln_mm_cmd *)rx;
! 696: struct rln_msg_tx_state state;
! 697: int ien;
! 698: int ret;
! 699:
! 700: #ifdef DIAGNOSTIC
! 701: if (rx != NULL && rxlen < sizeof *rxc)
! 702: panic("rln_msg_txrx");
! 703: #endif
! 704:
! 705: txc->cmd_seq = rln_newseq(sc);
! 706:
! 707: #ifdef RLNDUMP
! 708: printf("%s: send %c%d seq %d data ", sc->sc_dev.dv_xname,
! 709: txc->cmd_letter, txc->cmd_fn, txc->cmd_seq);
! 710: RLNDUMPHEX(txc, sizeof *txc);
! 711: printf(":");
! 712: RLNDUMPHEX((char *)tx + sizeof *txc, txlen - sizeof *txc);
! 713: printf("\n");
! 714: #endif
! 715:
! 716: if (rx != NULL)
! 717: if (rln_mbox_create(sc, txc->cmd_seq, rx, rxlen) < 0)
! 718: /* Mailbox collision. */
! 719: return (-1);
! 720:
! 721: /* Start the transfer. */
! 722: if ((ret = rln_msg_tx_start(sc, tx, txlen, &state))) {
! 723: if (rx != NULL)
! 724: rln_mbox_wait(sc, txc->cmd_seq, -1);
! 725: return (ret);
! 726: }
! 727:
! 728: /* Always send an even number of octets. */
! 729: rln_msg_tx_data(sc, tx, (txlen + 1) & ~1, &state);
! 730:
! 731: /* End the transmission. */
! 732: if ((ret = rln_msg_tx_end(sc, &state))) {
! 733: /* Destroy mailbox. */
! 734: if (rx != NULL)
! 735: rln_mbox_wait(sc, txc->cmd_seq, -1);
! 736: return (ret);
! 737: }
! 738:
! 739: /* Don't wait for reply if there is nowhere to put it. */
! 740: if (rx == NULL)
! 741: return (0);
! 742:
! 743: /* Enable interrupts if not already. */
! 744: ien = rln_enable(sc, 1);
! 745:
! 746: /* Wait for the reply message. */
! 747: if (rln_mbox_wait(sc, txc->cmd_seq, 4000) <= 0) {
! 748: printf("%s: lost message %c%d seq %d\n", sc->sc_dev.dv_xname,
! 749: txc->cmd_letter, txc->cmd_fn, txc->cmd_seq);
! 750: rln_enable(sc, ien);
! 751: return (-1);
! 752: }
! 753: rln_enable(sc, ien);
! 754:
! 755: #ifdef RLNDUMP
! 756: printf("%s: recv %c%d seq %d data ", sc->sc_dev.dv_xname,
! 757: rxc->cmd_letter, rxc->cmd_fn, rxc->cmd_seq);
! 758: RLNDUMPHEX(rxc, sizeof *rxc);
! 759: printf(":");
! 760: RLNDUMPHEX(((char *)rx) + sizeof *rxc, rxlen - sizeof *rxc);
! 761: printf("\n");
! 762: #endif
! 763:
! 764: /* Check for errors in the received message. */
! 765: if (rxc->cmd_error & 0x80) {
! 766: printf("%s: command error 0x%02x command %c%d\n",
! 767: sc->sc_dev.dv_xname,
! 768: rxc->cmd_error & ~0x80,
! 769: rxc->cmd_letter, rxc->cmd_fn);
! 770: return (-1);
! 771: }
! 772:
! 773: return (0);
! 774: }
! 775:
! 776: /*
! 777: * Mailboxes provide a simple way to tell the interrupt
! 778: * service routine that someone is expecting a reply message.
! 779: * Mailboxes are identified by the message sequence number
! 780: * and also hold a pointer to storage supplied by the waiter.
! 781: * The interrupt service routine signals the mailbox when it
! 782: * gets the reply message.
! 783: */
! 784:
! 785: /* Create a mailbox for filling. */
! 786: int
! 787: rln_mbox_create(sc, seq, buf, len)
! 788: struct rln_softc * sc;
! 789: u_int8_t seq;
! 790: void * buf;
! 791: size_t len;
! 792: {
! 793: int s;
! 794: struct rln_mbox * mb = &sc->sc_mbox[seq];
! 795:
! 796: dprintf(" <create %d", seq);
! 797:
! 798: #ifdef DIAGNOSTIC
! 799: if (seq > RLN_NMBOX)
! 800: panic("mbox create");
! 801: #endif
! 802:
! 803: s = splhigh();
! 804: if (mb->mb_state != RLNMBOX_VOID) {
! 805: #ifdef DIAGNOSTIC
! 806: printf("mbox collision");
! 807: #endif
! 808: splx(s);
! 809: return (-1);
! 810: }
! 811: mb->mb_buf = buf;
! 812: mb->mb_len = len;
! 813: mb->mb_actlen = 0;
! 814: mb->mb_state = RLNMBOX_EMPTY;
! 815: dprintf(" empty>");
! 816: splx(s);
! 817: return (0);
! 818: }
! 819:
! 820:
! 821: /* Wait for a mailbox to be filled. */
! 822: int
! 823: rln_mbox_wait(sc, seq, timeo)
! 824: struct rln_softc * sc;
! 825: u_int8_t seq;
! 826: int timeo;
! 827: {
! 828: int i;
! 829: int s;
! 830: int ret;
! 831: volatile struct rln_mbox * mb = &sc->sc_mbox[seq];
! 832:
! 833: dprintf(" <wait %d", seq);
! 834:
! 835: #ifdef DIAGNOSTIC
! 836: if (seq > RLN_NMBOX)
! 837: panic("mbox wait");
! 838: #endif
! 839:
! 840: #if defined(RLN_TSLEEP)
! 841: if (!cold) {
! 842: tsleep((void *)mb, PRIBIO, "rlnmbox", hz * timeo / 1000);
! 843: if (mb->mb_state == RLNMBOX_FILLING) {
! 844: /* Must wait until filled. */
! 845: s = spl0();
! 846: while (mb->mb_state == RLNMBOX_FILLING)
! 847: ;
! 848: splx(s);
! 849: }
! 850: } else {
! 851: /* Autoconfiguration - spin at spl0. */
! 852: #endif
! 853: s = spl0();
! 854: i = 0;
! 855: while (mb->mb_state == RLNMBOX_EMPTY && i < timeo) {
! 856: DELAY(1000);
! 857: i++;
! 858: }
! 859: if (i)
! 860: dprintf(" %dms", i);
! 861: while (mb->mb_state == RLNMBOX_FILLING)
! 862: ;
! 863: splx(s);
! 864: #if defined(RLN_TSLEEP)
! 865: }
! 866: #endif
! 867:
! 868: s = splhigh();
! 869:
! 870: #ifdef DIAGNOSTIC
! 871: if (mb->mb_state != RLNMBOX_EMPTY && mb->mb_state != RLNMBOX_FILLED)
! 872: panic("mbox wait %d", mb->mb_state);
! 873: #endif
! 874: ret = mb->mb_actlen;
! 875: mb->mb_state = RLNMBOX_VOID;
! 876: dprintf(" void>=%d", ret);
! 877: splx(s);
! 878: return (ret);
! 879: }
! 880:
! 881: /* Lock a mailbox for filling. */
! 882: int
! 883: rln_mbox_lock(sc, seq, bufp, lenp)
! 884: struct rln_softc * sc;
! 885: u_int8_t seq;
! 886: void ** bufp;
! 887: size_t * lenp;
! 888: {
! 889: int s;
! 890: struct rln_mbox * mb = &sc->sc_mbox[seq];
! 891:
! 892: dprintf(" <lock %d", seq);
! 893:
! 894: s = splhigh();
! 895: #ifdef DIAGNOSTIC
! 896: if (seq > RLN_NMBOX)
! 897: panic("mbox lock");
! 898: #endif
! 899: if (mb->mb_state != RLNMBOX_EMPTY) {
! 900: splx(s);
! 901: dprintf(" ?>");
! 902: return (-1);
! 903: }
! 904:
! 905: mb->mb_state = RLNMBOX_FILLING;
! 906: dprintf(" filling>");
! 907: *bufp = mb->mb_buf;
! 908: *lenp = mb->mb_len;
! 909:
! 910: splx(s);
! 911: return (0);
! 912: }
! 913:
! 914: /* Unlock a mailbox and inform the waiter of the actual number of octets. */
! 915: void
! 916: rln_mbox_unlock(sc, seq, actlen)
! 917: struct rln_softc * sc;
! 918: u_int8_t seq;
! 919: size_t actlen;
! 920: {
! 921: int s;
! 922: struct rln_mbox * mb = &sc->sc_mbox[seq];
! 923:
! 924: dprintf(" <unlock %d", seq);
! 925:
! 926: s = splhigh();
! 927: #ifdef DIAGNOSTIC
! 928: if (seq > RLN_NMBOX)
! 929: panic("mbox unlock seq");
! 930: if (mb->mb_state != RLNMBOX_FILLING)
! 931: panic("mbox unlock");
! 932: #endif
! 933: mb->mb_state = RLNMBOX_FILLED;
! 934: dprintf(" filled>");
! 935: mb->mb_actlen = actlen;
! 936: #if defined(RLN_TSLEEP)
! 937: wakeup(mb);
! 938: #endif
! 939: splx(s);
! 940: }
! 941:
CVSweb