date and time created 90/11/08 19:33:06 by bill
[unix-history] / usr / src / sys / i386 / isa / if_we.c
CommitLineData
11dcaca6
WN
1/*-
2 * Copyright (c) 1990 The Regents of the University of California.
3 * All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley by
6 * Tim L. Tucker
7 *
8 * %sccs.include.noredist.c%
9 *
10 * @(#)if_we.c 5.1 (Berkeley) %G%
11 */
12
13/*
14 * Modification history
15 *
16 * 8/28/89 - Initial version, Tim L Tucker
17 */
18
19#include "wd.h"
20#if NWD > 0
21/*
22 * Western Digital 8003 ethernet/starlan adapter
23 *
24 * Supports the following interface cards:
25 * WD8003E, WD8003EBT, WD8003S, WD8003SBT
26 *
27 * The Western Digital card is one of many AT/MCA ethernet interfaces
28 * based on the National N8390/NS32490 Network Interface chip set.
29 */
30#include "param.h"
31#include "mbuf.h"
32#include "socket.h"
33#include "ioctl.h"
34#include "errno.h"
35#include "syslog.h"
36
37#include "../net/if.h"
38#include "../net/netisr.h"
39
40#ifdef INET
41#include "../netinet/in.h"
42#include "../netinet/in_systm.h"
43#include "../netinet/in_var.h"
44#include "../netinet/ip.h"
45#include "../netinet/if_ether.h"
46#endif
47
48#ifdef NS
49#include "../netns/ns.h"
50#include "../netns/ns_if.h"
51#endif
52
53#include "if_wdreg.h"
54#include "../isa/isavar.h"
55
56/*
57 * This constant should really be 60 because the wd adds 4 bytes of crc.
58 * However when set to 60 our packets are ignored by deuna's , 3coms are
59 * okay ??????????????????????????????????????????
60 */
61#define ETHER_MIN_LEN 64
62#define ETHER_ADDR_LEN 6
63#define ETHER_HDR_SIZE 14
64
65/*
66 * Ethernet software status per interface.
67 *
68 * Each interface is referenced by a network interface structure,
69 * qe_if, which the routing code uses to locate the interface.
70 * This structure contains the output queue for the interface, its address, ...
71 */
72struct wd_softc {
73 struct arpcom wd_ac; /* Ethernet common part */
74#define wd_if wd_ac.ac_if /* network-visible interface */
75#define wd_addr wd_ac.ac_enaddr /* hardware Ethernet address */
76
77 u_char wd_flags; /* software state */
78#define WDF_RUNNING 0x01
79#define WDF_TXBUSY 0x02
80
81 u_char wd_type; /* interface type code */
82 u_short wd_vector; /* interrupt vector */
83 caddr_t wd_io_ctl_addr; /* i/o bus address, control */
84 caddr_t wd_io_nic_addr; /* i/o bus address, NS32490 */
85
86 caddr_t wd_vmem_addr; /* card RAM virtual memory base */
87 u_long wd_vmem_size; /* card RAM bytes */
88 caddr_t wd_vmem_ring; /* receive ring RAM vaddress */
89} wd_softc[NWD];
90
91int wdprobe(), wdattach(), wdintr();
92int wdinit(), wdoutput(), wdioctl(), wdreset();
93
94/*
95 * Probe the WD8003 to see if it's there
96 */
97wdprobe(reg, is)
98 caddr_t reg;
99 struct isa_device *is;
100{
101 register int i;
102 register struct wd_softc *sc = &wd_softc[is->is_unit];
103 union wd_mem_sel wdm;
104 u_char sum;
105
106 /*
107 * Here we check the card ROM, if the checksum passes, and the
108 * type code and ethernet address check out, then we know we have
109 * a wd8003 card.
110 *
111 * Autoconfiguration: No warning message is printed on error.
112 */
113 for (sum = 0, i = 0; i < 8; ++i)
114 sum += INB(reg + WD_ROM_OFFSET + i);
115 if (sum != WD_CHECKSUM)
116 return (0);
117 sc->wd_type = INB(reg + WD_ROM_OFFSET + 6);
118 if ((sc->wd_type != WD_ETHER) && (sc->wd_type != WD_STARLAN))
119 return (0);
120
121 /*
122 * Setup card RAM area and i/o addresses
123 * Kernel Virtual to segment C0000-DFFFF?????
124 */
125 sc->wd_io_ctl_addr = reg;
126 sc->wd_io_nic_addr = sc->wd_io_ctl_addr + WD_NIC_OFFSET;
127 sc->wd_vector = is->is_vector;
128 sc->wd_vmem_addr = (caddr_t)is->is_mem;
129 sc->wd_vmem_size = is->is_memsize;
130 sc->wd_vmem_ring = sc->wd_vmem_addr + (WD_PAGE_SIZE * WD_TXBUF_SIZE);
131
132 /*
133 * Save board ROM station address
134 */
135 for (i = 0; i < ETHER_ADDR_LEN; ++i)
136 sc->wd_addr[i] = INB(sc->wd_io_ctl_addr + WD_ROM_OFFSET + i);
137
138 /*
139 * Mapin interface memory, setup memory select register
140 */
141 wdm.ms_addr = (u_long)sc->wd_vmem_addr >> 13;
142 wdm.ms_enable = 1;
143 wdm.ms_reset = 0;
144 OUTB(sc->wd_io_ctl_addr, wdm.ms_byte);
145
146 /*
147 * clear interface memory, then sum to make sure its valid
148 */
149 for (i = 0; i < sc->wd_vmem_size; ++i)
150 sc->wd_vmem_addr[i] = 0x0;
151 for (sum = 0, i = 0; i < sc->wd_vmem_size; ++i)
152 sum += sc->wd_vmem_addr[i];
153 if (sum != 0x0) {
154 printf("wd%d: wd8003 dual port RAM address error\n", is->is_unit);
155 return (0);
156 }
157
158 return (WD_IO_PORTS);
159}
160
161/*
162 * Interface exists: make available by filling in network interface
163 * record. System will initialize the interface when it is ready
164 * to accept packets.
165 */
166wdattach(is)
167 struct isa_device *is;
168{
169 register struct wd_softc *sc = &wd_softc[is->is_unit];
170 register struct ifnet *ifp = &sc->wd_if;
171
172 /*
173 * Initialize ifnet structure
174 */
175 ifp->if_unit = is->is_unit;
176 ifp->if_name = "wd";
177 ifp->if_mtu = ETHERMTU;
178 ifp->if_flags = IFF_BROADCAST|IFF_NOTRAILERS;
179 ifp->if_init = wdinit;
180 ifp->if_output = wdoutput;
181 ifp->if_ioctl = wdioctl;
182 ifp->if_reset = wdreset;
183 ifp->if_watchdog = 0;
184 if_attach(ifp);
185
186 /*
187 * Banner...
188 */
189 printf("wd%d: %s, hardware address %s\n", is->is_unit,
190 ((sc->wd_type == WD_ETHER) ? "ethernet" : "starlan"),
191 ether_sprintf(sc->wd_addr));
192}
193
194/*
195 * Reset of interface.
196 */
197wdreset(unit, uban)
198 int unit, uban;
199{
200 if (unit >= NWD)
201 return;
202 printf("wd%d: reset\n", unit);
203 wd_softc[unit].wd_flags &= ~WDF_RUNNING;
204 wdinit(unit);
205}
206
207/*
208 * Take interface offline.
209 */
210wdstop(unit)
211 int unit;
212{
213 register struct wd_softc *sc = &wd_softc[unit];
214 union wd_command wdcmd;
215 int s;
216
217 /*
218 * Shutdown NS32490
219 */
220 s = splimp();
221 wdcmd.cs_byte = INB(sc->wd_io_nic_addr + WD_P0_COMMAND);
222 wdcmd.cs_stp = 1;
223 wdcmd.cs_sta = 0;
224 wdcmd.cs_ps = 0;
225 OUTB(sc->wd_io_nic_addr + WD_P0_COMMAND, wdcmd.cs_byte);
226 (void) splx(s);
227}
228
229/*
230 * Initialization of interface (really just NS32490).
231 */
232wdinit(unit)
233 int unit;
234{
235 register struct wd_softc *sc = &wd_softc[unit];
236 register struct ifnet *ifp = &sc->wd_if;
237 union wd_command wdcmd;
238 int i, s;
239
240 /* address not known */
241 if (ifp->if_addrlist == (struct ifaddr *)0)
242 return;
243
244 /* already running */
245 if (sc->wd_flags & WDF_RUNNING)
246 return;
247
248 /*
249 * Initialize NS32490 in order given in NSC NIC manual.
250 * this is stock code...please see the National manual for details.
251 */
252 s = splhi();
253 wdcmd.cs_byte = INB(sc->wd_io_nic_addr + WD_P0_COMMAND);
254 wdcmd.cs_stp = 1;
255 wdcmd.cs_sta = 0;
256 wdcmd.cs_ps = 0;
257 OUTB(sc->wd_io_nic_addr + WD_P0_COMMAND, wdcmd.cs_byte);
258 OUTB(sc->wd_io_nic_addr + WD_P0_DCR, WD_D_CONFIG);
259 OUTB(sc->wd_io_nic_addr + WD_P0_RBCR0, 0);
260 OUTB(sc->wd_io_nic_addr + WD_P0_RBCR1, 0);
261 OUTB(sc->wd_io_nic_addr + WD_P0_RCR, WD_R_MON);
262 OUTB(sc->wd_io_nic_addr + WD_P0_TCR, WD_T_CONFIG);
263 OUTB(sc->wd_io_nic_addr + WD_P0_TPSR, 0);
264 OUTB(sc->wd_io_nic_addr + WD_P0_PSTART, WD_TXBUF_SIZE);
265 OUTB(sc->wd_io_nic_addr + WD_P0_PSTOP,
266 sc->wd_vmem_size / WD_PAGE_SIZE);
267 OUTB(sc->wd_io_nic_addr + WD_P0_BNRY, WD_TXBUF_SIZE);
268 OUTB(sc->wd_io_nic_addr + WD_P0_ISR, 0xff);
269 OUTB(sc->wd_io_nic_addr + WD_P0_IMR, WD_I_CONFIG);
270 wdcmd.cs_ps = 1;
271 OUTB(sc->wd_io_nic_addr + WD_P0_COMMAND, wdcmd.cs_byte);
272 for (i = 0; i < ETHER_ADDR_LEN; ++i)
273 OUTB(sc->wd_io_nic_addr + WD_P1_PAR0 + i, sc->wd_addr[i]);
274 for (i = 0; i < ETHER_ADDR_LEN; ++i) /* == broadcast addr */
275 OUTB(sc->wd_io_nic_addr + WD_P1_MAR0 + i, 0xff);
276 OUTB(sc->wd_io_nic_addr + WD_P1_CURR, WD_TXBUF_SIZE);
277 wdcmd.cs_ps = 0;
278 wdcmd.cs_stp = 0;
279 wdcmd.cs_sta = 1;
280 wdcmd.cs_rd = 0x4;
281 OUTB(sc->wd_io_nic_addr + WD_P1_COMMAND, wdcmd.cs_byte);
282 OUTB(sc->wd_io_nic_addr + WD_P0_RCR, WD_R_CONFIG);
283
284 /*
285 * Take the interface out of reset, program the vector,
286 * enable interrupts, and tell the world we are up.
287 */
288 ifp->if_flags |= IFF_UP | IFF_RUNNING;
289 sc->wd_flags |= WDF_RUNNING;
290 sc->wd_flags &= ~WDF_TXBUSY;
291 (void) splx(s);
292 wdstart(unit);
293}
294
295/*
296 * Start output on interface.
297 */
298wdstart(unit)
299 int unit;
300{
301 register struct wd_softc *sc = &wd_softc[unit];
302 struct mbuf *m0, *m;
303 register caddr_t buffer;
304 int len = 0, s;
305 union wd_command wdcmd;
306
307 /*
308 * The NS32490 has only one transmit buffer, if it is busy we
309 * must wait until the transmit interrupt completes.
310 */
311 s = splhi();
312 if (sc->wd_flags & WDF_TXBUSY) {
313 (void) splx(s);
314 return;
315 }
316 IF_DEQUEUE(&sc->wd_if.if_snd, m);
317 if (m == 0) {
318 (void) splx(s);
319 return;
320 }
321 sc->wd_flags |= WDF_TXBUSY;
322 (void) splx(s);
323
324 /*
325 * Copy the mbuf chain into the transmit buffer
326 */
327 buffer = sc->wd_vmem_addr;
328 for (m0 = m; m != 0; m = m->m_next) {
329 bcopy(mtod(m, caddr_t), buffer, m->m_len);
330 buffer += m->m_len;
331 len += m->m_len;
332 }
333
334 /*
335 * If this was a broadcast packet loop it
336 * back because the hardware can't hear its own
337 * transmits.
338 */
339 if (bcmp((caddr_t)(mtod(m0, struct ether_header *)->ether_dhost),
340 (caddr_t)etherbroadcastaddr,
341 sizeof(etherbroadcastaddr)) == 0) {
342 wdread(sc, m0);
343 } else {
344 m_freem(m0);
345 }
346
347 /*
348 * Init transmit length registers, and set transmit start flag.
349 */
350 s = splhi();
351 len = MAX(len, ETHER_MIN_LEN);
352 wdcmd.cs_byte = INB(sc->wd_io_nic_addr + WD_P0_COMMAND);
353 wdcmd.cs_ps = 0;
354 OUTB(sc->wd_io_nic_addr + WD_P0_COMMAND, wdcmd.cs_byte);
355 OUTB(sc->wd_io_nic_addr + WD_P0_TBCR0, len & 0xff);
356 OUTB(sc->wd_io_nic_addr + WD_P0_TBCR1, len >> 8);
357 wdcmd.cs_txp = 1;
358 OUTB(sc->wd_io_nic_addr + WD_P0_COMMAND, wdcmd.cs_byte);
359 (void) splx(s);
360}
361
362/*
363 * Ethernet interface interrupt processor
364 */
365wdintr(unit)
366 int unit;
367{
368 register struct wd_softc *sc = &wd_softc[unit];
369 union wd_command wdcmd;
370 union wd_interrupt wdisr;
371 int s;
372
373 /* disable onboard interrupts, then get interrupt status */
374 s = splhi();
375 wdcmd.cs_byte = INB(sc->wd_io_nic_addr + WD_P0_COMMAND);
376 wdcmd.cs_ps = 0;
377 OUTB(sc->wd_io_nic_addr + WD_P0_COMMAND, wdcmd.cs_byte);
378 OUTB(sc->wd_io_nic_addr + WD_P0_IMR, 0);
379 wdisr.is_byte = INB(sc->wd_io_nic_addr + WD_P0_ISR);
380 OUTB(sc->wd_io_nic_addr + WD_P0_ISR, 0xff);
381 (void) splx(s);
382
383 /* transmit error */
384 if (wdisr.is_txe) {
385 /* need to read these registers to clear status */
386 sc->wd_if.if_collisions +=
387 INB(sc->wd_io_nic_addr + WD_P0_TBCR0);
388 ++sc->wd_if.if_oerrors;
389 }
390
391 /* receiver error */
392 if (wdisr.is_rxe) {
393 /* need to read these registers to clear status */
394 (void) INB(sc->wd_io_nic_addr + 0xD);
395 (void) INB(sc->wd_io_nic_addr + 0xE);
396 (void) INB(sc->wd_io_nic_addr + 0xF);
397 ++sc->wd_if.if_ierrors;
398 }
399
400 /* normal transmit complete */
401 if (wdisr.is_ptx)
402 wdtint (unit);
403
404 /* normal receive notification */
405 if (wdisr.is_prx)
406 wdrint (unit);
407
408 /* try to start transmit */
409 wdstart(unit);
410
411 /* re-enable onboard interrupts */
412 wdcmd.cs_byte = INB(sc->wd_io_nic_addr + WD_P0_COMMAND);
413 wdcmd.cs_ps = 0;
414 OUTB(sc->wd_io_nic_addr + WD_P0_COMMAND, wdcmd.cs_byte);
415 OUTB(sc->wd_io_nic_addr + WD_P0_IMR, WD_I_CONFIG);
416}
417
418/*
419 * Ethernet interface transmit interrupt.
420 */
421wdtint(unit)
422 int unit;
423{
424 register struct wd_softc *sc = &wd_softc[unit];
425
426 /*
427 * Do some statistics (assume page zero of NIC mapped in)
428 */
429 sc->wd_flags &= ~WDF_TXBUSY;
430 sc->wd_if.if_timer = 0;
431 ++sc->wd_if.if_opackets;
432 sc->wd_if.if_collisions += INB(sc->wd_io_nic_addr + WD_P0_TBCR0);
433}
434
435/*
436 * Ethernet interface receiver interrupt.
437 */
438wdrint(unit)
439 int unit;
440{
441 register struct wd_softc *sc = &wd_softc[unit];
442 register struct mbuf **m;
443 int mlen, len, count;
444 u_char bnry, curr;
445 union wd_command wdcmd;
446 struct wd_ring *wdr;
447 struct mbuf *m0;
448 caddr_t pkt, endp;
449
450 /*
451 * Traverse the receive ring looking for packets to pass back.
452 * The search is complete when we find a descriptor not in use.
453 */
454 wdcmd.cs_byte = INB(sc->wd_io_nic_addr + WD_P0_COMMAND);
455 wdcmd.cs_ps = 0;
456 OUTB(sc->wd_io_nic_addr + WD_P0_COMMAND, wdcmd.cs_byte);
457 bnry = INB(sc->wd_io_nic_addr + WD_P0_BNRY);
458 wdcmd.cs_ps = 1;
459 OUTB(sc->wd_io_nic_addr + WD_P0_COMMAND, wdcmd.cs_byte);
460 curr = INB(sc->wd_io_nic_addr + WD_P1_CURR);
461 while (bnry != curr)
462 {
463 /* get pointer to this buffer header structure */
464 wdr = (struct wd_ring *)(sc->wd_vmem_addr + (bnry << 8));
465 len = wdr->wd_count - 4; /* count includes CRC */
466 pkt = (caddr_t)(wdr + 1) - 2; /* 2 - word align pkt data */
467 count = len + 2; /* copy two extra bytes */
468 endp = (caddr_t)(sc->wd_vmem_addr + sc->wd_vmem_size);
469 ++sc->wd_if.if_ipackets;
470
471 /* pull packet out of dual ported RAM */
472 m = &m0; m0 = 0;
473 while (count > 0)
474 {
475 /* drop chain if can't get another buffer */
476 MGET(*m, M_DONTWAIT, MT_DATA);
477 if (*m == 0)
478 {
479 m_freem(m0);
480 goto outofbufs;
481 }
482
483 /* fill mbuf and attach to packet list */
484 mlen = MIN(MLEN, count);
485 mlen = MIN(mlen, endp - pkt);
486 bcopy(pkt, mtod(*m, caddr_t), mlen);
487 (*m)->m_len = mlen;
488 m = &((*m)->m_next);
489 pkt += mlen;
490 count -= mlen;
491
492 /* wrap memory pointer around circ buffer */
493 if (pkt == endp)
494 pkt = (caddr_t)sc->wd_vmem_ring;
495 }
496
497 /* skip aligment bytes, send packet up to higher levels */
498 if (m0 != 0)
499 {
500 m0->m_off += 2;
501 wdread(sc, m0);
502 }
503
504outofbufs:
505 /* advance on chip Boundry register */
506 bnry = wdr->wd_next_packet;
507 wdcmd.cs_byte = INB(sc->wd_io_nic_addr + WD_P0_COMMAND);
508 wdcmd.cs_ps = 0;
509 OUTB(sc->wd_io_nic_addr + WD_P0_COMMAND, wdcmd.cs_byte);
510
511 /* watch out for NIC overflow, reset Boundry if invalid */
512 if ((bnry - 1) < WD_TXBUF_SIZE) {
513#ifdef notdef
514 wdreset(unit, 0);
515 break;
516#else
517 OUTB(sc->wd_io_nic_addr + WD_P0_BNRY,
518 (sc->wd_vmem_size / WD_PAGE_SIZE) - 1);
519#endif
520 }
521 OUTB(sc->wd_io_nic_addr + WD_P0_BNRY, bnry - 1);
522
523 /* refresh our copy of CURR */
524 wdcmd.cs_ps = 1;
525 OUTB(sc->wd_io_nic_addr + WD_P0_COMMAND, wdcmd.cs_byte);
526 curr = INB(sc->wd_io_nic_addr + WD_P1_CURR);
527 }
528}
529
530/*
531 * Ethernet output routine.
532 * Encapsulate a packet of type family for the local net.
533 */
534wdoutput(ifp, m0, dst)
535 struct ifnet *ifp;
536 struct mbuf *m0;
537 struct sockaddr *dst;
538{
539 int type, s, error;
540 u_char edst[6];
541 struct in_addr idst;
542 register struct wd_softc *sc = &wd_softc[ifp->if_unit];
543 register struct mbuf *m = m0;
544 register struct ether_header *eh;
545 int usetrailers;
546
547 if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) {
548 error = ENETDOWN;
549 goto bad;
550 }
551
552 switch (dst->sa_family) {
553
554#ifdef INET
555 case AF_INET:
556 /* Note: we ignore usetrailers */
557 idst = ((struct sockaddr_in *)dst)->sin_addr;
558 if (!arpresolve(&sc->wd_ac, m, &idst, edst, &usetrailers))
559 return (0); /* if not yet resolved */
560 type = ETHERTYPE_IP;
561 break;
562#endif
563#ifdef NS
564 case AF_NS:
565 type = ETHERTYPE_NS;
566 bcopy((caddr_t)&(((struct sockaddr_ns *)dst)->sns_addr.x_host),
567 (caddr_t)edst, sizeof (edst));
568 break;
569#endif
570
571
572 case AF_UNSPEC:
573 eh = (struct ether_header *)dst->sa_data;
574 bcopy((caddr_t)eh->ether_dhost, (caddr_t)edst, sizeof (edst));
575 type = eh->ether_type;
576 break;
577
578 default:
579 printf("wd%d: can't handle af%d\n", ifp->if_unit,
580 dst->sa_family);
581 error = EAFNOSUPPORT;
582 goto bad;
583 }
584
585 /*
586 * Add local net header. If no space in first mbuf,
587 * allocate another.
588 */
589 if (m->m_off > MMAXOFF || MMINOFF + ETHER_HDR_SIZE > m->m_off) {
590 m = m_get(M_DONTWAIT, MT_HEADER);
591 if (m == 0) {
592 error = ENOBUFS;
593 goto bad;
594 }
595 m->m_next = m0;
596 m->m_off = MMINOFF;
597 m->m_len = ETHER_HDR_SIZE;
598 } else {
599 m->m_off -= ETHER_HDR_SIZE;
600 m->m_len += ETHER_HDR_SIZE;
601 }
602 eh = mtod(m, struct ether_header *);
603 eh->ether_type = htons((u_short)type);
604 bcopy((caddr_t)edst, (caddr_t)eh->ether_dhost, sizeof (edst));
605 bcopy((caddr_t)sc->wd_addr, (caddr_t)eh->ether_shost,
606 sizeof (sc->wd_addr));
607
608 /*
609 * Queue message on interface, and start output if interface
610 * not yet active.
611 */
612 s = splimp();
613 if (IF_QFULL(&ifp->if_snd)) {
614 IF_DROP(&ifp->if_snd);
615 (void) splx(s);
616 m_freem(m);
617 return (ENOBUFS);
618 }
619 IF_ENQUEUE(&ifp->if_snd, m);
620 (void) splx(s);
621 wdstart(ifp->if_unit);
622 return (0);
623
624bad:
625 m_freem(m0);
626 return (error);
627}
628
629/*
630 * Process an ioctl request.
631 */
632wdioctl(ifp, cmd, data)
633 register struct ifnet *ifp;
634 int cmd;
635 caddr_t data;
636{
637 struct wd_softc *sc = &wd_softc[ifp->if_unit];
638 struct ifaddr *ifa = (struct ifaddr *)data;
639 int s = splimp(), error = 0;
640
641 switch (cmd) {
642
643 case SIOCSIFADDR:
644 ifp->if_flags |= IFF_UP;
645 wdinit(ifp->if_unit);
646 switch(ifa->ifa_addr.sa_family) {
647#ifdef INET
648 case AF_INET:
649 ((struct arpcom *)ifp)->ac_ipaddr =
650 IA_SIN(ifa)->sin_addr;
651 arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr);
652 break;
653#endif
654#ifdef NS
655 case AF_NS:
656 {
657 register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr);
658
659 if (ns_nullhost(*ina))
660 ina->x_host = *(union ns_host *)(sc->wd_addr);
661 else
662 wdsetaddr(ina->x_host.c_host, ifp->if_unit);
663 break;
664 }
665#endif
666 }
667 break;
668
669 case SIOCSIFFLAGS:
670 if (((ifp->if_flags & IFF_UP) == 0) &&
671 (sc->wd_flags & WDF_RUNNING)) {
672 wdstop(ifp->if_unit);
673 } else if (((ifp->if_flags & IFF_UP) == IFF_UP) &&
674 ((sc->wd_flags & WDF_RUNNING) == 0))
675 wdinit(ifp->if_unit);
676 break;
677
678 default:
679 error = EINVAL;
680
681 }
682 (void) splx(s);
683 return (error);
684}
685
686/*
687 * set ethernet address for unit
688 */
689wdsetaddr(physaddr, unit)
690 u_char *physaddr;
691 int unit;
692{
693 register struct wd_softc *sc = &wd_softc[unit];
694 register int i;
695
696 /*
697 * Rewrite ethernet address, and then force restart of NIC
698 */
699 for (i = 0; i < ETHER_ADDR_LEN; i++)
700 sc->wd_addr[i] = physaddr[i];
701 sc->wd_flags &= ~WDF_RUNNING;
702 wdinit(unit);
703}
704
705/*
706 * Pass a packet to the higher levels.
707 * NO TRAILER PROTOCOL!
708 */
709wdread(sc, m)
710 register struct wd_softc *sc;
711 struct mbuf *m;
712{
713 struct ether_header *eh;
714 int scn, type, s;
715 struct ifqueue *inq;
716
717 /*
718 * Get ethernet protocol type out of ether header
719 */
720 eh = mtod(m, struct ether_header *);
721 type = ntohs((u_short)eh->ether_type);
722
723 /*
724 * Drop ethernet header
725 */
726 m->m_off += ETHER_HDR_SIZE;
727 m->m_len -= ETHER_HDR_SIZE;
728
729 /*
730 * Insert ifp pointer at start of packet
731 */
732 m->m_off -= sizeof (struct ifnet *);
733 m->m_len += sizeof (struct ifnet *);
734 *(mtod(m, struct ifnet **)) = &sc->wd_if;
735
736 switch (type) {
737
738#ifdef INET
739 case ETHERTYPE_IP:
740 scn = NETISR_IP;
741 inq = &ipintrq;
742 break;
743
744 case ETHERTYPE_ARP:
745 arpinput(&sc->wd_ac, m);
746 return;
747#endif
748#ifdef NS
749 case ETHERTYPE_NS:
750 scn = NETISR_NS;
751 inq = &nsintrq;
752 break;
753
754#endif
755
756 default:
757 m_freem(m);
758 return;
759 }
760
761 s = splimp();
762 if (IF_QFULL(inq)) {
763 IF_DROP(inq);
764 m_freem(m);
765 } else
766 IF_ENQUEUE(inq, m);
767 schednetisr(scn);
768 (void) splx(s);
769}
770
771#endif