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