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