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