1 /* $NetBSD: if_le.c,v 1.1 1997/02/04 03:52:28 thorpej Exp $ */ 2 3 /* 4 * Copyright (c) 1993 Adam Glass 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by Adam Glass. 18 * 4. The name of the Author may not be used to endorse or promote products 19 * derived from this software without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY Adam Glass ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 34 #include <sys/param.h> 35 #include <sys/types.h> 36 37 #include <netinet/in.h> 38 #include <netinet/in_systm.h> 39 40 #include <lib/libsa/netif.h> 41 42 #include <hp300/stand/common/device.h> 43 #include <hp300/stand/common/if_lereg.h> 44 #include <hp300/stand/common/samachdep.h> 45 46 #ifndef NLE 47 #define NLE 1 48 #endif 49 50 #ifdef LE_DEBUG 51 int le_debug = 0; 52 #endif 53 54 #define ETHER_MIN_LEN 64 55 #define ETHER_MAX_LEN 1518 56 #define ETHER_ADDR_LEN 6 57 58 int le_probe(); 59 int le_match(); 60 void le_init(); 61 int le_get(); 62 int le_put(); 63 void le_end(); 64 65 struct le_sel { 66 int le_id; 67 int le_regs; 68 int le_mem; 69 int le_nvram; 70 int le_heat; 71 int le_bonus; 72 } le0conf[] = { 73 /* offsets for: ID REGS MEM NVRAM le_heat le_bonus*/ 74 { 0, 0x4000, 0x8000, 0xC008, 1, 10 } 75 }; 76 77 extern struct netif_stats le_stats[]; 78 79 struct netif_dif le_ifs[] = { 80 /* dif_unit dif_nsel dif_stats dif_private */ 81 { 0, NENTS(le0conf), &le_stats[0], le0conf, }, 82 }; 83 84 struct netif_stats le_stats[NENTS(le_ifs)]; 85 86 struct netif_driver le_driver = { 87 "le", /* netif_bname */ 88 le_match, /* netif_match */ 89 le_probe, /* netif_probe */ 90 le_init, /* netif_init */ 91 le_get, /* netif_get */ 92 le_put, /* netif_put */ 93 le_end, /* netif_end */ 94 le_ifs, /* netif_ifs */ 95 NENTS(le_ifs) /* netif_nifs */ 96 }; 97 98 struct le_softc { 99 struct lereg0 *sc_r0; /* DIO registers */ 100 struct lereg1 *sc_r1; /* LANCE registers */ 101 void *sc_mem; 102 struct init_block *sc_init; 103 struct mds *sc_rd, *sc_td; 104 u_char *sc_rbuf, *sc_tbuf; 105 int sc_next_rd, sc_next_td; 106 u_char sc_addr[ETHER_ADDR_LEN]; 107 } le_softc[NLE]; 108 109 static inline void 110 lewrcsr(sc, port, val) 111 struct le_softc *sc; 112 register u_short port; 113 register u_short val; 114 { 115 register struct lereg0 *ler0 = sc->sc_r0; 116 register struct lereg1 *ler1 = sc->sc_r1; 117 118 do { 119 ler1->ler1_rap = port; 120 } while ((ler0->ler0_status & LE_ACK) == 0); 121 do { 122 ler1->ler1_rdp = val; 123 } while ((ler0->ler0_status & LE_ACK) == 0); 124 } 125 126 static inline u_short 127 lerdcsr(sc, port) 128 struct le_softc *sc; 129 register u_short port; 130 { 131 register struct lereg0 *ler0 = sc->sc_r0; 132 register struct lereg1 *ler1 = sc->sc_r1; 133 register u_short val; 134 135 do { 136 ler1->ler1_rap = port; 137 } while ((ler0->ler0_status & LE_ACK) == 0); 138 do { 139 val = ler1->ler1_rdp; 140 } while ((ler0->ler0_status & LE_ACK) == 0); 141 return (val); 142 } 143 144 leinit() 145 { 146 extern struct hp_hw sc_table[]; 147 register struct hp_hw *hw; 148 struct le_softc *sc; 149 struct le_sel *sels; 150 register int i, n; 151 char *cp; 152 153 i = 0; 154 155 for (hw = sc_table; i < NLE && hw < &sc_table[MAXCTLRS]; hw++) { 156 #ifdef LE_DEBUG 157 if (le_debug) 158 printf("found type %x\n", hw->hw_type); 159 #endif 160 161 #if 0 162 if (!HW_ISDEV(hw, D_LAN)) 163 continue; 164 #endif 165 166 sels = (struct le_sel *)le_ifs[i].dif_private; 167 168 sc = &le_softc[i]; 169 sc->sc_r0 = (struct lereg0 *)(sels->le_id + (int)hw->hw_kva); 170 171 if (sc->sc_r0->ler0_id != LEID) 172 continue; 173 174 sc->sc_r1 = (struct lereg1 *)(sels->le_regs + (int)hw->hw_kva); 175 sc->sc_mem = (struct lereg2 *)(sels->le_mem + (int)hw->hw_kva); 176 177 #ifdef LE_DEBUG 178 if (le_debug) 179 printf("le%d: DIO=%x regs=%x mem=%x\n", 180 i, sc->sc_r0, sc->sc_r1, sc->sc_mem); 181 #endif 182 183 /* 184 * Read the ethernet address off the board, one nibble at a time. 185 */ 186 cp = (char *)(sels->le_nvram + (int)hw->hw_kva); 187 for (n = 0; n < sizeof(sc->sc_addr); n++) { 188 sc->sc_addr[n] = (*++cp & 0xF) << 4; 189 cp++; 190 sc->sc_addr[n] |= *++cp & 0xF; 191 cp++; 192 } 193 #ifdef LE_DEBUG 194 if (le_debug) 195 printf("le%d at sc%d physical address %s\n", 196 i, hw->hw_sc, ether_sprintf(sc->sc_addr)); 197 #endif 198 hw->hw_pa = (caddr_t) i; /* XXX for autoconfig */ 199 i++; 200 } 201 } 202 203 int 204 le_match(nif, machdep_hint) 205 struct netif *nif; 206 void *machdep_hint; 207 { 208 struct le_sel *sels; 209 char *name = machdep_hint; 210 int rv = 0; 211 212 if (nif->nif_sel < le_ifs[nif->nif_unit].dif_nsel) { 213 sels = (struct le_sel *)le_ifs[nif->nif_unit].dif_private; 214 rv = sels[nif->nif_sel].le_heat; 215 if (name && !strncmp(le_driver.netif_bname, name, 2)) 216 rv += sels[nif->nif_sel].le_bonus; 217 } 218 #ifdef LE_DEBUG 219 if (le_debug) 220 printf("le%d: sel %d --> %d\n", nif->nif_unit, nif->nif_sel, 221 rv); 222 #endif 223 return rv; 224 } 225 226 le_probe(nif, machdep_hint) 227 struct netif *nif; 228 void *machdep_hint; 229 { 230 char *cp; 231 int i; 232 233 /* the set unit is the current unit */ 234 #ifdef LE_DEBUG 235 if (le_debug) 236 printf("le%d.%d: le_probe called\n", nif->nif_unit, nif->nif_sel); 237 #endif 238 /* XXX reset controller */ 239 return 0; 240 } 241 242 #ifdef MEM_SUMMARY 243 void le_mem_summary(unit) 244 { 245 struct lereg1 *ler1 = le_softc.sc_r1; 246 struct lereg2 *ler2 = le_softc.sc_r2; 247 register int i; 248 249 printf("le%d: ler1 = %x\n", unit, ler1); 250 printf("le%d: ler2 = %x\n", unit, ler2); 251 252 #if 0 253 ler1->ler1_rap = LE_CSR0; 254 ler1->ler1_rdp = LE_STOP; 255 printf("le%d: csr0 = %x\n", unit, ler1->ler1_rdp); 256 ler1->ler1_rap = LE_CSR1; 257 printf("le%d: csr1 = %x\n", unit, ler1->ler1_rdp); 258 ler1->ler1_rap = LE_CSR2; 259 printf("le%d: csr2 = %x\n", unit, ler1->ler1_rdp); 260 ler1->ler1_rap = LE_CSR3; 261 printf("le%d: csr3 = %x\n", unit, ler1->ler1_rdp); 262 #endif 263 printf("le%d: ladrf[0] = %x\n", unit, ler2->ler2_ladrf[0]); 264 printf("le%d: ladrf[1] = %x\n", unit, ler2->ler2_ladrf[1]); 265 printf("le%d: ler2_rdra = %x\n", unit, ler2->ler2_rdra); 266 printf("le%d: ler2_rlen = %x\n", unit, ler2->ler2_rlen); 267 printf("le%d: ler2_tdra = %x\n", unit, ler2->ler2_tdra); 268 printf("le%d: ler2_tlen = %x\n", unit, ler2->ler2_tlen); 269 270 for (i = 0; i < LERBUF; i++) { 271 printf("le%d: ler2_rmd[%d].rmd0 (ladr) = %x\n", unit, i, 272 ler2->ler2_rmd[i].rmd0); 273 printf("le%d: ler2_rmd[%d].rmd1 = %x\n", unit, i, 274 ler2->ler2_rmd[i].rmd1); 275 printf("le%d: ler2_rmd[%d].rmd2 (-bcnt) = %x\n", unit, i, 276 ler2->ler2_rmd[i].rmd2); 277 printf("le%d: ler2_rmd[%d].rmd3 (mcnt) = %x\n", unit, i, 278 ler2->ler2_rmd[i].rmd3); 279 printf("le%d: ler2_rbuf[%d] addr = %x\n", unit, i, 280 &ler2->ler2_rbuf[i]); 281 } 282 for (i = 0; i < LETBUF; i++) { 283 printf("le%d: ler2_tmd[%d].tmd0 = %x\n", unit, i, 284 ler2->ler2_tmd[i].tmd0); 285 printf("le%d: ler2_tmd[%d].tmd1 = %x\n", unit, i, 286 ler2->ler2_tmd[i].tmd1); 287 printf("le%d: ler2_tmd[%d].tmd2 (bcnt) = %x\n", unit, i, 288 ler2->ler2_tmd[i].tmd2); 289 printf("le%d: ler2_tmd[%d].tmd3 = %x\n", unit, i, 290 ler2->ler2_tmd[i].tmd3); 291 printf("le%d: ler2_tbuf[%d] addr = %x\n", unit, i, 292 &ler2->ler2_tbuf[i]); 293 } 294 } 295 #else 296 #define le_mem_summary(u) 297 #endif 298 299 void 300 le_error(unit, str, stat) 301 int unit; 302 char *str; 303 u_short stat; 304 { 305 306 if (stat & LE_BABL) 307 panic("le%d: been babbling, found by '%s'\n", unit, str); 308 if (stat & LE_CERR) 309 le_stats[unit].collision_error++; 310 if (stat & LE_MISS) 311 le_stats[unit].missed++; 312 if (stat & LE_MERR) { 313 printf("le%d: memory error in '%s'\n", unit, str); 314 le_mem_summary(unit); 315 panic("bye"); 316 } 317 } 318 319 #define LANCE_ADDR(sc, a) \ 320 ((u_long)(a) - (u_long)sc->sc_mem) 321 322 /* LANCE initialization block set up. */ 323 void 324 lememinit(sc) 325 register struct le_softc *sc; 326 { 327 int i; 328 void *mem; 329 u_long a; 330 331 /* 332 * At this point we assume that the memory allocated to the Lance is 333 * quadword aligned. If it isn't then the initialisation is going 334 * fail later on. 335 */ 336 mem = sc->sc_mem; 337 338 sc->sc_init = mem; 339 sc->sc_init->mode = LE_NORMAL; 340 for (i = 0; i < ETHER_ADDR_LEN; i++) 341 sc->sc_init->padr[i] = sc->sc_addr[i^1]; 342 sc->sc_init->ladrf[0] = sc->sc_init->ladrf[1] = 0; 343 mem += sizeof(struct init_block); 344 345 sc->sc_rd = mem; 346 a = LANCE_ADDR(sc, mem); 347 sc->sc_init->rdra = a; 348 sc->sc_init->rlen = ((a >> 16) & 0xff) | (RLEN << 13); 349 mem += NRBUF * sizeof(struct mds); 350 351 sc->sc_td = mem; 352 a = LANCE_ADDR(sc, mem); 353 sc->sc_init->tdra = a; 354 sc->sc_init->tlen = ((a >> 16) & 0xff) | (TLEN << 13); 355 mem += NTBUF * sizeof(struct mds); 356 357 /* 358 * Set up receive ring descriptors. 359 */ 360 sc->sc_rbuf = mem; 361 for (i = 0; i < NRBUF; i++) { 362 a = LANCE_ADDR(sc, mem); 363 sc->sc_rd[i].addr = a; 364 sc->sc_rd[i].flags = ((a >> 16) & 0xff) | LE_OWN; 365 sc->sc_rd[i].bcnt = -BUFSIZE; 366 sc->sc_rd[i].mcnt = 0; 367 mem += BUFSIZE; 368 } 369 370 /* 371 * Set up transmit ring descriptors. 372 */ 373 sc->sc_tbuf = mem; 374 for (i = 0; i < NTBUF; i++) { 375 a = LANCE_ADDR(sc, mem); 376 sc->sc_td[i].addr = a; 377 sc->sc_td[i].flags = ((a >> 16) & 0xff); 378 sc->sc_td[i].bcnt = 0xf000; 379 sc->sc_td[i].mcnt = 0; 380 mem += BUFSIZE; 381 } 382 } 383 384 void 385 le_reset(unit, myea) 386 int unit; 387 u_char *myea; 388 { 389 struct le_softc *sc = &le_softc[unit]; 390 u_long a; 391 int timo = 100000, stat, i; 392 393 #ifdef LE_DEBUG 394 if (le_debug) { 395 printf("le%d: le_reset called\n", unit); 396 printf(" r0=%x, r1=%x, mem=%x, addr=%x:%x:%x:%x:%x:%x\n", 397 sc->sc_r0, sc->sc_r1, sc->sc_mem, 398 sc->sc_addr[0], sc->sc_addr[1], sc->sc_addr[2], 399 sc->sc_addr[3], sc->sc_addr[4], sc->sc_addr[5]); 400 } 401 #endif 402 lewrcsr(sc, 0, LE_STOP); 403 for (timo = 1000; timo; timo--); 404 405 sc->sc_next_rd = sc->sc_next_td = 0; 406 407 /* Set up LANCE init block. */ 408 lememinit(sc); 409 410 if (myea) 411 bcopy(sc->sc_addr, myea, ETHER_ADDR_LEN); 412 413 /* Turn on byte swapping. */ 414 lewrcsr(sc, 3, LE_BSWP); 415 416 /* Give LANCE the physical address of its init block. */ 417 a = LANCE_ADDR(sc, sc->sc_init); 418 lewrcsr(sc, 1, a); 419 lewrcsr(sc, 2, (a >> 16) & 0xff); 420 421 #ifdef LE_DEBUG 422 if (le_debug) 423 printf("le%d: before init\n", unit); 424 #endif 425 426 /* Try to initialize the LANCE. */ 427 lewrcsr(sc, 0, LE_INIT); 428 429 /* Wait for initialization to finish. */ 430 for (timo = 100000; timo; timo--) 431 if (lerdcsr(sc, 0) & LE_IDON) 432 break; 433 434 if (lerdcsr(sc, 0) & LE_IDON) { 435 /* Start the LANCE. */ 436 lewrcsr(sc, 0, LE_INEA | LE_STRT | LE_IDON); 437 } else 438 printf("le%d: card failed to initialize\n", unit); 439 440 #ifdef LE_DEBUG 441 if (le_debug) 442 printf("le%d: after init\n", unit); 443 #endif 444 445 le_mem_summary(unit); 446 } 447 448 int 449 le_poll(desc, pkt, len) 450 struct iodesc *desc; 451 void *pkt; 452 int len; 453 { 454 struct netif *nif = desc->io_netif; 455 int unit = /*nif->nif_unit*/0; 456 struct le_softc *sc = &le_softc[unit]; 457 volatile struct lereg0 *ler0 = sc->sc_r0; 458 volatile struct lereg1 *ler1 = sc->sc_r1; 459 int length; 460 volatile struct mds *cdm; 461 register int stat; 462 463 #ifdef LE_DEBUG 464 if (/*le_debug*/0) 465 printf("le%d: le_poll called. next_rd=%d\n", unit, sc->sc_next_rd); 466 #endif 467 stat = lerdcsr(sc, 0); 468 lewrcsr(sc, 0, stat & (LE_BABL | LE_MISS | LE_MERR | LE_RINT)); 469 cdm = &sc->sc_rd[sc->sc_next_rd]; 470 if (cdm->flags & LE_OWN) 471 return 0; 472 #ifdef LE_DEBUG 473 if (le_debug) { 474 printf("next_rd %d\n", sc->sc_next_rd); 475 printf("cdm->flags %x\n", cdm->flags); 476 printf("cdm->bcnt %x, cdm->mcnt %x\n", cdm->bcnt, cdm->mcnt); 477 printf("cdm->rbuf msg %d buf %d\n", cdm->mcnt, -cdm->bcnt ); 478 } 479 #endif 480 if (stat & (LE_BABL | LE_CERR | LE_MISS | LE_MERR)) 481 le_error(unit, "le_poll", stat); 482 if (cdm->flags & (LE_FRAM | LE_OFLO | LE_CRC | LE_RBUFF)) { 483 printf("le%d_poll: rmd status 0x%x\n", unit, cdm->flags); 484 length = 0; 485 goto cleanup; 486 } 487 if ((cdm->flags & (LE_STP|LE_ENP)) != (LE_STP|LE_ENP)) 488 panic("le_poll: chained packet\n"); 489 490 length = cdm->mcnt; 491 #ifdef LE_DEBUG 492 if (le_debug) 493 printf("le_poll: length %d\n", length); 494 #endif 495 if (length >= BUFSIZE) { 496 length = 0; 497 panic("csr0 when bad things happen: %x\n", stat); 498 goto cleanup; 499 } 500 if (!length) 501 goto cleanup; 502 length -= 4; 503 504 if (length > 0) { 505 /* 506 * If the length of the packet is greater than the size of the 507 * buffer, we have to truncate it, to avoid Bad Things. 508 * XXX Is this the right thing to do? 509 */ 510 if (length > len) 511 length = len; 512 513 bcopy(sc->sc_rbuf + (BUFSIZE * sc->sc_next_rd), pkt, length); 514 } 515 516 cleanup: 517 cdm->mcnt = 0; 518 cdm->flags |= LE_OWN; 519 if (++sc->sc_next_rd >= NRBUF) 520 sc->sc_next_rd = 0; 521 #ifdef LE_DEBUG 522 if (le_debug) 523 printf("new next_rd %d\n", sc->sc_next_rd); 524 #endif 525 526 return length; 527 } 528 529 int 530 le_put(desc, pkt, len) 531 struct iodesc *desc; 532 void *pkt; 533 int len; 534 { 535 struct netif *nif = desc->io_netif; 536 int unit = /*nif->nif_unit*/0; 537 struct le_softc *sc = &le_softc[unit]; 538 volatile struct lereg0 *ler0 = sc->sc_r0; 539 volatile struct lereg1 *ler1 = sc->sc_r1; 540 volatile struct mds *cdm; 541 int timo, i, stat; 542 543 le_put_loop: 544 timo = 100000; 545 546 #ifdef LE_DEBUG 547 if (le_debug) 548 printf("le%d: le_put called. next_td=%d\n", unit, sc->sc_next_td); 549 #endif 550 stat = lerdcsr(sc, 0); 551 lewrcsr(sc, 0, stat & (LE_BABL | LE_MISS | LE_MERR | LE_TINT)); 552 if (stat & (LE_BABL | LE_CERR | LE_MISS | LE_MERR)) 553 le_error(unit, "le_put(way before xmit)", stat); 554 cdm = &sc->sc_td[sc->sc_next_td]; 555 i = 0; 556 #if 0 557 while (cdm->flags & LE_OWN) { 558 if ((i % 100) == 0) 559 printf("le%d: output buffer busy - flags=%x\n", 560 unit, cdm->flags); 561 if (i++ > 500) break; 562 } 563 if (cdm->flags & LE_OWN) 564 getchar(); 565 #else 566 while (cdm->flags & LE_OWN); 567 #endif 568 bcopy(pkt, sc->sc_tbuf + (BUFSIZE * sc->sc_next_td), len); 569 if (len < ETHER_MIN_LEN) 570 cdm->bcnt = -ETHER_MIN_LEN; 571 else 572 cdm->bcnt = -len; 573 cdm->mcnt = 0; 574 cdm->flags |= LE_OWN | LE_STP | LE_ENP; 575 stat = lerdcsr(sc, 0); 576 if (stat & (LE_BABL | LE_CERR | LE_MISS | LE_MERR)) 577 le_error(unit, "le_put(before xmit)", stat); 578 lewrcsr(sc, 0, LE_TDMD); 579 stat = lerdcsr(sc, 0); 580 if (stat & (LE_BABL | LE_CERR | LE_MISS | LE_MERR)) 581 le_error(unit, "le_put(after xmit)", stat); 582 do { 583 if (--timo == 0) { 584 printf("le%d: transmit timeout, stat = 0x%x\n", 585 unit, stat); 586 if (stat & LE_SERR) 587 le_error(unit, "le_put(timeout)", stat); 588 if (stat & LE_INIT) { 589 printf("le%d: reset and retry packet\n"); 590 lewrcsr(sc, 0, LE_TINT); /* sanity */ 591 le_init(); 592 goto le_put_loop; 593 } 594 break; 595 } 596 stat = lerdcsr(sc, 0); 597 } while ((stat & LE_TINT) == 0); 598 lewrcsr(sc, 0, LE_TINT); 599 if (stat & (LE_BABL |/* LE_CERR |*/ LE_MISS | LE_MERR)) { 600 printf("le_put: xmit error, buf %d\n", sc->sc_next_td); 601 le_error(unit, "le_put(xmit error)", stat); 602 } 603 if (++sc->sc_next_td >= NTBUF) 604 sc->sc_next_td = 0; 605 if (cdm->flags & LE_DEF) 606 le_stats[unit].deferred++; 607 if (cdm->flags & LE_ONE) 608 le_stats[unit].collisions++; 609 if (cdm->flags & LE_MORE) 610 le_stats[unit].collisions+=2; 611 if (cdm->flags & LE_ERR) { 612 printf("le%d: transmit error, error = 0x%x\n", unit, 613 cdm->mcnt); 614 return -1; 615 } 616 #ifdef LE_DEBUG 617 if (le_debug) { 618 printf("le%d: le_put() successful: sent %d\n", unit, len); 619 printf("le%d: le_put(): flags: %x mcnt: %x\n", unit, 620 (unsigned int) cdm->flags, 621 (unsigned int) cdm->mcnt); 622 } 623 #endif 624 return len; 625 } 626 627 628 int 629 le_get(desc, pkt, len, timeout) 630 struct iodesc *desc; 631 void *pkt; 632 int len; 633 time_t timeout; 634 { 635 time_t t; 636 int cc; 637 638 t = getsecs(); 639 cc = 0; 640 while (((getsecs() - t) < timeout) && !cc) { 641 cc = le_poll(desc, pkt, len); 642 } 643 return cc; 644 } 645 646 void 647 le_init(desc, machdep_hint) 648 struct iodesc *desc; 649 void *machdep_hint; 650 { 651 struct netif *nif = desc->io_netif; 652 int unit = nif->nif_unit; 653 654 /* Get machine's common ethernet interface. This is done in leinit() */ 655 /* machdep_common_ether(myea); */ 656 leinit(); 657 658 #ifdef LE_DEBUG 659 if (le_debug) 660 printf("le%d: le_init called\n", unit); 661 #endif 662 unit = 0; 663 le_reset(unit, desc->myea); 664 } 665 666 void 667 le_end(nif) 668 struct netif *nif; 669 { 670 int unit = nif->nif_unit; 671 672 #ifdef LE_DEBUG 673 if (le_debug) 674 printf("le%d: le_end called\n", unit); 675 #endif 676 677 lewrcsr(&le_softc[unit], 0, LE_STOP); 678 } 679