if_le.c revision 1.5 1 /* $NetBSD: if_le.c,v 1.5 2002/09/27 15:36:02 provos 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'", 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");
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", 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