Initial import, 0.1 + pk 0.2.4-B1
[unix-history] / sys / i386 / isa / if_ec.c
CommitLineData
15637ed4
RG
1#include "ec.h"
2#if NEC > 0
3/*-
4 * Copyright (c) 1990 The Regents of the University of California.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to Berkeley by
8 * Tim L. Tucker.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the University of
21 * California, Berkeley and its contributors.
22 * 4. Neither the name of the University nor the names of its contributors
23 * may be used to endorse or promote products derived from this software
24 * without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 * SUCH DAMAGE.
37 *
38 */
39/*
40 * A driver for the 3Com 3C503 (Etherlink II) ethernet adaptor.
41 *
42 * Written by Herb Peyerl (hpeyerl@novatel.cuc.ab.ca) on 04/25/92.
43 * (This is my first ever device driver and I couldn't have done
44 * it without the consumption of many "Brock Gummy Bears" so a
45 * big thanx to the "Brock Candy Company" of Chattanooga TN)
46 *
47 * This driver uses the Western Digital 8003 driver for a template
48 * since the two cards use the DP8390 chip by National. Everything
49 * is fairly similar except that the nic on the wd8003 appears to
50 * to see shared memory at 0x0000 and on the 3com, the nic sees it
51 * at 0x2000. Also, the 3c503 has it's own ASIC for controlling
52 * things like the IRQ level in software and whether to use the
53 * onboard xceiver or not. Since the Clarkson drivers do a very
54 * good rendition of a 3c503, I also scavenged a lot of ideas from
55 * there.
56 *
57 * Kludges:
58 * Since I couldn't really think of any non-creative way (other than
59 * using a #define) of configuring the board to use the onboard xceiver,
60 * I kludged the isa_device->unit to contain this information. Simply
61 * put, if bit-7 of isa_device->unit is set (>127) then the driver
62 * configures that unit to onboard-xceiver (BNC) and if <128 it assumes
63 * AUI. ec_attach informs the user of this on bootup. Also, ec_probe
64 * repairs this bit after obtaining it's information since I didn't know
65 * what else within the depths of the kernel would freak out if I left it.
66 */
67#include "param.h"
68#include "mbuf.h"
69#include "socket.h"
70#include "ioctl.h"
71#include "errno.h"
72#include "syslog.h"
73#include "net/if.h"
74#include "net/netisr.h"
75#ifdef INET
76#include "netinet/in.h"
77#include "netinet/in_systm.h"
78#include "netinet/in_var.h"
79#include "netinet/ip.h"
80#include "netinet/if_ether.h"
81#endif
82#ifdef NS
83#include "netns/ns.h"
84#include "netns/ns_if.h"
85#endif
86#include "i386/isa/isa_device.h"
87#include "i386/isa/if_ec.h"
88
89/*
90 * Ethernet software status per interface.
91 *
92 * Each interface is referenced by a network interface structure,
93 * qe_if, which the routing code uses to locate the interface.
94 * This structure contains the output queue for the interface, its address, ...
95 */
96struct ec_softc {
97 struct arpcom ec_ac; /* Ethernet common part */
98#define ec_if ec_ac.ac_if /* network-visible interface */
99#define ec_addr ec_ac.ac_enaddr /* hardware Ethernet address */
100
101 u_char ec_flags; /* software state */
102#define EC_RUNNING 0x01
103#define EC_TXBUSY 0x02
104
105 u_char ec_type; /* interface type code */
106 u_short ec_vector; /* interrupt vector */
107 short ec_io_ctl_addr; /* i/o bus address, control */
108 short ec_io_nic_addr; /* i/o bus address, DS8390 */
109 short thick_or_thin; /* thick=0;thin=2 */
110
111 caddr_t ec_vmem_addr; /* card RAM virtual memory base */
112 u_long ec_vmem_size; /* card RAM bytes */
113 caddr_t ec_vmem_ring; /* receive ring RAM vaddress */
114 caddr_t ec_vmem_end; /* receive ring RAM end */
115} ec_softc[NEC];
116
117#define PAGE0 outb(sc->ec_io_nic_addr + EN_CCMD, ENC_NODMA|ENC_PAGE0);
118#define PAGE1 outb(sc->ec_io_nic_addr + EN_CCMD, ENC_NODMA|ENC_PAGE1);
119static Bdry;
120
121int ether_output(),
122 ecprobe(),
123 ecattach(),
124 ecintr(),
125 ec_init(),
126 ec_ioctl(),
127 ec_reset(),
128 ec_watchdog(),
129 ec_start_output();
130
131struct isa_driver ecdriver = {
132 ecprobe,
133 ecattach,
134 "ec",
135};
136
137ecprobe(is)
138struct isa_device *is;
139{
140 register struct ec_softc *sc = &ec_softc[is->id_unit&127];
141 int i, sum;
142/*
143 * Set up the softc structure with card specific info.
144 * The 3Com asic is at base+0x400
145 */
146 sc->ec_io_ctl_addr = is->id_iobase + 0x400;
147 sc->ec_io_nic_addr = is->id_iobase;
148 sc->ec_vector = is->id_irq;
149 sc->ec_vmem_addr = (caddr_t)is->id_maddr;
150 sc->ec_vmem_size = is->id_msize;
151 sc->ec_vmem_ring = sc->ec_vmem_addr + (EC_PAGE_SIZE * EC_TXBUF_SIZE);
152 sc->ec_vmem_end = sc->ec_vmem_addr + is->id_msize;
153/*
154 * Now we get the MAC address. Assume thin ethernet unless told otherwise later.
155 */
156 outb(sc->ec_io_ctl_addr + E33G_CNTRL, ECNTRL_RESET|2); /* Toggle reset bit on*/
157 DELAY(100);
158 outb(sc->ec_io_ctl_addr + E33G_CNTRL, 2); /* Toggle reset bit off */
159 DELAY(100);
160 outb(sc->ec_io_ctl_addr + E33G_CNTRL, ECNTRL_SAPROM|2); /* Map SA_PROM */
161 for (i=0;i<ETHER_ADDR_LEN; ++i)
162 sc->ec_addr[i] = inb(sc->ec_io_nic_addr + i);
163 outb(sc->ec_io_ctl_addr + E33G_CNTRL, 2); /* Disable SA_PROM */
164 outb(sc->ec_io_ctl_addr + E33G_GACFR, EGACFR_IRQOFF); /* tcm, rsel, mbs0, nim */
165/*
166 * Stop the chip just in case.
167 */
168 DELAY(1000);
169 PAGE0
170 outb(sc->ec_io_nic_addr + EN_CCMD, ENC_NODMA|ENC_STOP);
171 DELAY(1000);
172
173 /* Check cmd reg and fail if not right */
174 if ((i=inb(sc->ec_io_nic_addr + EN_CCMD)) != (ENC_NODMA|ENC_STOP))
175 return(0);
176
177/*
178 * Test the shared memory.
179 */
180 for(i = 0 ; i < sc->ec_vmem_size ; ++i)
181 sc->ec_vmem_addr[i] = 0x0;
182 for(sum=0, i=0; i<sc->ec_vmem_size; ++i)
183 sum += sc->ec_vmem_addr[i];
184 if(sum)
185 {
186 printf("ec%d: shared memory error (device conflict?)\n",
187 is->id_unit);
188 return(0);
189 }
190/*
191 * All done.
192 */
193 return(1);
194}
195
196ecattach(is)
197struct isa_device *is;
198{
199 register struct ec_softc *sc = &ec_softc[is->id_unit];
200 register struct ifnet *ifp = &sc->ec_if;
201
202/**
203 ** Initialize the ASIC in same order as Clarkson driver.
204 **/
205
206
207/*
208 * Point vector pointer registers off into boonies.
209 */
210 outb(sc->ec_io_ctl_addr + E33G_VP2, 0xff);
211 outb(sc->ec_io_ctl_addr + E33G_VP1, 0xff);
212 outb(sc->ec_io_ctl_addr + E33G_VP0, 0x0);
213/*
214 * Set up control of shared memory, buffer ring, etc.
215 */
216 outb(sc->ec_io_ctl_addr + E33G_STARTPG, EC_RXBUF_OFFSET);
217 outb(sc->ec_io_ctl_addr + E33G_STOPPG, EC_RXBUF_END);
218/*
219 * Set up the IRQ and NBURST on the board.
220 * ( Not sure why we set up NBURST since we don't use DMA.)
221 *
222 * Normally we would is->id_irq<<2 but IRQ2 is defined as 0x200
223 * in icu.h so it's a special case.
224 */
225 if(is->id_irq == 0x200)
226 outb(sc->ec_io_ctl_addr + E33G_IDCFR, 0x10);
227 else
228 outb(sc->ec_io_ctl_addr + E33G_IDCFR, is->id_irq << 2);
229 outb(sc->ec_io_ctl_addr + E33G_NBURST, 0x08); /* Set Burst to 8 */
230 outb(sc->ec_io_ctl_addr + E33G_DMAAH, 0x20);
231 outb(sc->ec_io_ctl_addr + E33G_DMAAL, 0x0);
232/*
233 * Fill in the ifnet structure.
234 */
235 ifp->if_unit = is->id_unit;
236 ifp->if_name = "ec" ;
237 ifp->if_mtu = ETHERMTU;
238 ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS;
239 ifp->if_init = ec_init;
240 ifp->if_output = ether_output;
241 ifp->if_start = ec_start_output;
242 ifp->if_ioctl = ec_ioctl;
243 ifp->if_reset = ec_reset;
244 ifp->if_watchdog = ec_watchdog;
245/*
246 * Attach the interface to something. Have to figure this out later.
247 */
248 if_attach(ifp);
249/*
250 * Weeee.. We get to tell people we exist...
251 */
252 printf(" address %s", ether_sprintf(sc->ec_addr));
253}
254
255ec_init(unit)
256int unit;
257{
258 register struct ec_softc *sc = &ec_softc[unit];
259 register struct ifnet *ifp = &sc->ec_if;
260 int i, s;
261 u_short ax, cx;
262
263 Bdry=0;
264printf("ecinit");
265/*
266 * Address not known.
267 */
268 if(ifp->if_addrlist == (struct ifaddr *) 0)
269 return;
270
271 /*
272 * XXX (untested)
273 * select thick (e.g. AUI connector) if LLC0 bit is set
274 */
275 if (ifp->if_flags & IFF_LLC0)
276 outb(sc->ec_io_ctl_addr + E33G_CNTRL, 0);
277 else
278 outb(sc->ec_io_ctl_addr + E33G_CNTRL, 2);
279
280/*
281 * Set up the 8390 chip.
282 * (Use sequence recommended by 3Com. )
283 */
284 s=splhigh();
285 PAGE0
286 outb(sc->ec_io_nic_addr + EN_CCMD, ENC_NODMA|ENC_PAGE0|ENC_STOP);
287 outb(sc->ec_io_nic_addr + EN0_DCFG, ENDCFG_BM8);
288 outb(sc->ec_io_nic_addr + EN0_RCNTLO, 0x0);
289 outb(sc->ec_io_nic_addr + EN0_RCNTHI, 0x0);
290 outb(sc->ec_io_nic_addr + EN0_RXCR, ENRXCR_MON );
291 outb(sc->ec_io_nic_addr + EN0_TXCR, 0x02);
292 outb(sc->ec_io_nic_addr + EN0_BOUNDARY, EC_RXBUF_OFFSET);
293 outb(sc->ec_io_nic_addr + EN0_TPSR, 0x20);
294 outb(sc->ec_io_nic_addr + EN0_STARTPG, EC_RXBUF_OFFSET);
295 outb(sc->ec_io_nic_addr + EN0_STOPPG, EC_RXBUF_END);
296 outb(sc->ec_io_nic_addr + EN0_ISR, 0xff);
297 outb(sc->ec_io_nic_addr + EN0_IMR, 0x3f);
298/*
299 * Copy Ethernet address from SA_PROM into 8390 chip registers.
300 */
301 PAGE1
302 for(i=0;i<6;i++)
303 outb(sc->ec_io_nic_addr + EN1_PHYS+i, sc->ec_addr[i]);
304/*
305 * Set multicast filter mask bits in case promiscuous rcv wanted (???)
306 * (set to 0xff as in if_we.c)
307 */
308 for(i=0;i<8;i++)
309 outb(sc->ec_io_nic_addr + EN1_MULT+i, 0xff);
310/*
311 * Set current shared page for RX to work on.
312 */
313 outb(sc->ec_io_nic_addr + EN1_CURPAG, EC_RXBUF_OFFSET);
314/*
315 * Start the 8390. Clear Interrupt Status reg, and accept Broadcast
316 * packets.
317 */
318 outb(sc->ec_io_nic_addr + EN_CCMD, ENC_START|ENC_PAGE0|ENC_NODMA);
319 outb(sc->ec_io_nic_addr + EN0_ISR, 0xff);
320 outb(sc->ec_io_nic_addr + EN0_TXCR, 0x0);
321 outb(sc->ec_io_nic_addr + EN0_RXCR, ENRXCR_BCST);
322/*
323 * Take interface out of reset, program the vector,
324 * enable interrupts, and tell the world we are up.
325 */
326 ifp->if_flags |= IFF_RUNNING;
327 outb(sc->ec_io_ctl_addr + E33G_GACFR, EGACFR_NORM); /* tcm, rsel, mbs0 */
328 (void) splx(s);
329 sc->ec_flags &= ~EC_TXBUSY;
330 ec_start_output(ifp);
331}
332
333ec_start_output(ifp)
334struct ifnet *ifp;
335{
336 register struct ec_softc *sc = &ec_softc[ifp->if_unit];
337 struct mbuf *m0, *m;
338 register caddr_t buffer;
339 int len, s;
340 int ec_cmd_reg;
341
342/*
343 * The DS8390 only has one transmit buffer, if it is busy we
344 * must wait until the transmit interrupt completes.
345 */
346 s=splhigh();
347 if(sc->ec_flags & EC_TXBUSY)
348 {
349 (void) splx(s);
350 return;
351 }
352 IF_DEQUEUE(&sc->ec_if.if_snd, m);
353 if(m == 0)
354 {
355 (void) splx(s);
356 return;
357 }
358 sc->ec_flags |= EC_TXBUSY;
359 (void) splx(s);
360
361/*
362 * Copy the mbuf chain into the transmit buffer
363 */
364 buffer = sc->ec_vmem_addr;
365 len = 0;
366 for(m0 = m; m!= 0; m = m->m_next)
367 {
368 bcopy(mtod(m, caddr_t), buffer, m->m_len);
369 buffer += m->m_len;
370 len += m->m_len;
371 }
372 m_freem(m0);
373
374/*
375 * Init transmit length registers and set transmit start flag.
376 */
377 s=splhigh();
378 len = MAX(len, ETHER_MIN_LEN);
379 PAGE0
380 outb(sc->ec_io_nic_addr + EN0_TCNTLO, len & 0xff);
381 outb(sc->ec_io_nic_addr + EN0_TCNTHI, len >> 8);
382 ec_cmd_reg = inb(sc->ec_io_nic_addr + EN_CCMD);
383 outb(sc->ec_io_nic_addr + EN_CCMD, ec_cmd_reg|ENC_TRANS);
384 (void) splx(s);
385}
386
387 int ec_cmd_reg, ec_sts_reg;
388/*
389 * Interrupt handler.
390 */
391ecintr(unit)
392int unit;
393{
394 register struct ec_softc *sc = &ec_softc[unit];
395
396 unit = 0;
397
398/*
399 * Get current command register and interrupt status.
400 * Turn off interrupts while we take care of things.
401 */
402 ec_cmd_reg = inb(sc->ec_io_nic_addr + EN_CCMD);
403 PAGE0
404 ec_sts_reg = inb(sc->ec_io_nic_addr + EN0_ISR);
405 outb(sc->ec_io_nic_addr + EN0_IMR, 0x0);
406loop:
407 outb(sc->ec_io_nic_addr + EN0_ISR, ec_sts_reg);
408 /*
409 * have we lost ourselves somewhere?
410 */
411 if (ec_sts_reg == 0xff)
412 ec_watchdog(unit);
413/*
414 * Transmit error
415 */
416 if(ec_sts_reg & ENISR_TX_ERR)
417 {
418 sc->ec_if.if_collisions += inb(sc->ec_io_nic_addr + EN0_TCNTLO);
419 ++sc->ec_if.if_oerrors;
420 }
421/*
422 * Receive Error
423 */
424 if(ec_sts_reg & ENISR_RX_ERR)
425 {
426 (void) inb(sc->ec_io_nic_addr + 0xD);
427 (void) inb(sc->ec_io_nic_addr + 0xE);
428 (void) inb(sc->ec_io_nic_addr + 0xF);
429 ++sc->ec_if.if_ierrors;
430 }
431/*
432 * Normal transmit complete.
433 */
434 if(ec_sts_reg&ENISR_TX || ec_sts_reg&ENISR_TX_ERR)
435 ectint(unit);
436/*
437 * Normal receive notification
438 */
439 if(ec_sts_reg&(ENISR_RX|ENISR_RX_ERR))
440 ecrint(unit);
441
442/*
443 * Try to start transmit
444 */
445 ec_start_output(&sc->ec_if);
446/*
447 * Reenable onboard interrupts.
448 */
449 /*PAGE0*/
450 outb(sc->ec_io_nic_addr + EN_CCMD, ec_cmd_reg);
451 outb(sc->ec_io_nic_addr + EN0_IMR, 0x3f);
452 if(ec_sts_reg=inb(sc->ec_io_nic_addr + EN0_ISR))
453 goto loop;
454}
455
456/*
457 * Transmit interrupt
458 */
459ectint(unit)
460int unit;
461{
462 register struct ec_softc *sc = &ec_softc[unit];
463/*
464 * Do some statistics.
465 */
466 PAGE0
467 sc->ec_flags &= ~EC_TXBUSY;
468 sc->ec_if.if_timer = 0;
469 ++sc->ec_if.if_opackets;
470 sc->ec_if.if_collisions += inb(sc->ec_io_nic_addr + EN0_TCNTLO);
471}
472
473/*
474 * Receive interrupt.
475 * (This gave me the most trouble so excuse the mess.)
476 */
477ecrint(unit)
478int unit;
479{
480 register struct ec_softc *sc = &ec_softc[unit];
481 u_char bnry, curr;
482 int len;
483 struct ec_ring *ecr;
484
485 /*
486 * Traverse the receive ring looking for packets to pass back.
487 * The search is complete when we find a descriptor not in use.
488 */
489 PAGE0
490 bnry = inb(sc->ec_io_nic_addr + EN0_BOUNDARY);
491 PAGE1
492 curr = inb(sc->ec_io_nic_addr + EN1_CURPAG);
493if(Bdry)
494 bnry =Bdry;
495
496 while (bnry != curr)
497 {
498 /* get pointer to this buffer header structure */
499 ecr = (struct ec_ring *)(sc->ec_vmem_addr + ((bnry-EC_VMEM_OFFSET) << 8));
500
501 /* count includes CRC */
502 len = ecr->ec_count - 4;
503 /*if (len > 30 && len <= ETHERMTU+100) */
504 ecread(sc, (caddr_t)(ecr + 1), len);
505 /*else printf("reject:%x bnry:%x curr:%x", len, bnry, curr);*/
506outofbufs:
507 PAGE0
508 /* advance on chip Boundry register */
509 if((caddr_t) ecr + EC_PAGE_SIZE - 1 > sc->ec_vmem_end) {
510 bnry = EC_RXBUF_OFFSET;
511 outb(sc->ec_io_nic_addr + EN0_BOUNDARY,
512 (sc->ec_vmem_size / EC_PAGE_SIZE) - 1 - EC_VMEM_OFFSET);
513 } else {
514 if (len > 30 && len <= ETHERMTU+100)
515 bnry = ecr->ec_next_packet;
516 else bnry = curr;
517
518 /* watch out for NIC overflow, reset Boundry if invalid */
519 if ((bnry - 1) < EC_RXBUF_OFFSET) {
520 outb(sc->ec_io_nic_addr + EN0_BOUNDARY,
521 (sc->ec_vmem_size / EC_PAGE_SIZE) - 1 - EC_VMEM_OFFSET);
522 bnry = EC_RXBUF_OFFSET;
523 } else
524 outb(sc->ec_io_nic_addr + EN0_BOUNDARY, bnry-1);
525 }
526
527 /* refresh our copy of CURR */
528 PAGE1
529 curr = inb(sc->ec_io_nic_addr + EN1_CURPAG);
530 }
531 Bdry = bnry;
532 PAGE0
533}
534
535#define ecdataaddr(sc, eh, off, type) \
536 ((type) ((caddr_t)((eh)+1)+(off) >= (sc)->ec_vmem_end) ? \
537 (((caddr_t)((eh)+1)+(off))) - (sc)->ec_vmem_end \
538 + (sc)->ec_vmem_ring: \
539 ((caddr_t)((eh)+1)+(off)))
540
541ecread(sc, buf, len)
542register struct ec_softc *sc;
543char *buf;
544int len;
545{
546 register struct ether_header *eh;
547 struct mbuf *m, *ecget();
548 int off, resid;
549
550 /*
551 * Deal with trailer protocol: if type is trailer type
552 * get true type from first 16-bit word past data.
553 * Remember that type was trailer by setting off.
554 */
555 eh = (struct ether_header *)buf;
556 eh->ether_type = ntohs((u_short)eh->ether_type);
557 if (eh->ether_type >= ETHERTYPE_TRAIL &&
558 eh->ether_type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) {
559 off = (eh->ether_type - ETHERTYPE_TRAIL) * 512;
560 if (off >= ETHERMTU) return; /* sanity */
561 eh->ether_type = ntohs(*ecdataaddr(sc, eh, off, u_short *));
562 resid = ntohs(*(ecdataaddr(sc, eh, off+2, u_short *)));
563 if (off + resid > len) return; /* sanity */
564 len = off + resid;
565 } else off = 0;
566
567 len -= sizeof(struct ether_header);
568 if (len <= 0) return;
569
570 /*
571 * Pull packet off interface. Off is nonzero if packet
572 * has trailing header; neget will then force this header
573 * information to be at the front, but we still have to drop
574 * the type and length which are at the front of any trailer data.
575 */
576 m = ecget(buf, len, off, &sc->ec_if, sc);
577 if (m == 0) return;
578 ether_input(&sc->ec_if, eh, m);
579}
580ec_ioctl(ifp, cmd, data)
581register struct ifnet *ifp;
582int cmd;
583caddr_t data;
584{
585 register struct ifaddr *ifa = (struct ifaddr *)data;
586 struct ec_softc *sc = &ec_softc[ifp->if_unit];
587 struct ifreq *ifr = (struct ifreq *)data;
588 int s=splimp(), error=0;
589 switch(cmd){
590 case SIOCSIFADDR:
591 ifp->if_flags |= IFF_UP;
592 switch (ifa->ifa_addr->sa_family) {
593#ifdef INET
594 case AF_INET:
595 ec_init(ifp->if_unit); /* before arpwhohas */
596 ((struct arpcom *)ifp)->ac_ipaddr =
597 IA_SIN(ifa)->sin_addr;
598 arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr);
599 break;
600#endif
601#ifdef NS
602 case AF_NS:
603 {
604 register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr);
605
606 if (ns_nullhost(*ina))
607 ina->x_host = *(union ns_host *)(sc->ns_addr);
608 else {
609 /*
610 * The manual says we can't change the address
611 * while the receiver is armed,
612 * so reset everything
613 */
614 ifp->if_flags &= ~IFF_RUNNING;
615 bcopy((caddr_t)ina->x_host.c_host,
616 (caddr_t)sc->ns_addr, sizeof(sc->ns_addr));
617 }
618 ec_init(ifp->if_unit); /* does ne_setaddr() */
619 break;
620 }
621#endif
622 default:
623 ec_init(ifp->if_unit);
624 break;
625 }
626 break;
627
628 case SIOCSIFFLAGS:
629 if ((ifp->if_flags & IFF_UP) == 0 &&
630 ifp->if_flags & IFF_RUNNING) {
631 ifp->if_flags &= ~IFF_RUNNING;
632 ec_stop(ifp->if_unit);
633 } else if (ifp->if_flags & IFF_UP &&
634 (ifp->if_flags & IFF_RUNNING) == 0)
635 ec_init(ifp->if_unit);
636 break;
637
638#ifdef notdef
639 case SIOCGHWADDR:
640 bcopy((caddr_t)sc->sc_addr, (caddr_t) &ifr->ifr_data,
641 sizeof(sc->sc_addr));
642 break;
643#endif
644
645 default:
646 error = EINVAL;
647 }
648 splx(s);
649 return (error);
650}
651
652ec_reset(unit)
653int unit;
654{
655 if(unit >= NEC)
656 return;
657 printf("ec%d: reset\n", unit);
658 ec_init(unit);
659}
660
661ec_watchdog(unit)
662int unit;
663{
664 log(LOG_WARNING, "ec%d: soft reset\n", unit);
665 ec_stop(unit);
666 ec_init(unit);
667}
668
669ec_stop(unit)
670int unit;
671{
672 register struct ec_softc *sc = &ec_softc[unit];
673 int s;
674
675 s=splimp();
676 PAGE0
677 outb(sc->ec_io_nic_addr + EN_CCMD, ENC_NODMA|ENC_STOP);
678 outb(sc->ec_io_nic_addr + EN0_IMR, 0x0);
679 sc->ec_flags &= ~EC_RUNNING;
680/*
681 * Shutdown the 8390.
682 */
683 (void) splx(s);
684}
685
686/*
687 * Pull read data off a interface.
688 * Len is length of data, with local net header stripped.
689 * Off is non-zero if a trailer protocol was used, and
690 * gives the offset of the trailer information.
691 * We copy the trailer information and then all the normal
692 * data into mbufs. When full cluster sized units are present
693 * we copy into clusters.
694 */
695struct mbuf *
696ecget(buf, totlen, off0, ifp, sc)
697 caddr_t buf;
698 int totlen, off0;
699 struct ifnet *ifp;
700 struct ec_softc *sc;
701{
702 struct mbuf *top, **mp, *m, *p;
703 int off = off0, len;
704 register caddr_t cp = buf;
705 char *epkt;
706 int tc =totlen;
707
708 buf += sizeof(struct ether_header);
709 cp = buf;
710 epkt = cp + totlen;
711
712 if (off) {
713 cp += off + 2 * sizeof(u_short);
714 totlen -= 2 * sizeof(u_short);
715 }
716
717 MGETHDR(m, M_DONTWAIT, MT_DATA);
718 if (m == 0)
719 return (0);
720 m->m_pkthdr.rcvif = ifp;
721 m->m_pkthdr.len = totlen;
722 m->m_len = MHLEN;
723
724 top = 0;
725 mp = &top;
726 while (totlen > 0) {
727 if (top) {
728 MGET(m, M_DONTWAIT, MT_DATA);
729 if (m == 0) {
730 m_freem(top);
731 return (0);
732 }
733 m->m_len = MLEN;
734 }
735 len = min(totlen, epkt - cp);
736 if (len >= MINCLSIZE) {
737 MCLGET(m, M_DONTWAIT);
738 if (m->m_flags & M_EXT)
739 m->m_len = len = min(len, MCLBYTES);
740 else
741 len = m->m_len;
742 } else {
743 /*
744 * Place initial small packet/header at end of mbuf.
745 */
746 if (len < m->m_len) {
747 if (top == 0 && len + max_linkhdr <= m->m_len)
748 m->m_data += max_linkhdr;
749 m->m_len = len;
750 } else
751 len = m->m_len;
752 }
753
754 totlen -= len;
755 /* only do up to end of buffer */
756 if (cp+len > sc->ec_vmem_end) {
757 unsigned toend = sc->ec_vmem_end - cp;
758
759 bcopy(cp, mtod(m, caddr_t), toend);
760 cp = sc->ec_vmem_ring;
761 bcopy(cp, mtod(m, caddr_t)+toend, len - toend);
762 cp += len - toend;
763 epkt = cp + totlen;
764 } else {
765 bcopy(cp, mtod(m, caddr_t), (unsigned)len);
766 cp += len;
767 }
768 *mp = m;
769 mp = &m->m_next;
770 if (cp == epkt) {
771 cp = buf;
772 epkt = cp + tc;
773 }
774 }
775 return (top);
776}
777#endif /* NEC > 0 */