|
|
1.1 root 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: * Redistribution and use in source and binary forms, with or without
9: * modification, are permitted provided that the following conditions
10: * are met:
11: * 1. Redistributions of source code must retain the above copyright
12: * notice, this list of conditions and the following disclaimer.
13: * 2. Redistributions in binary form must reproduce the above copyright
14: * notice, this list of conditions and the following disclaimer in the
15: * documentation and/or other materials provided with the distribution.
16: * 3. All advertising materials mentioning features or use of this software
17: * must display the following acknowledgement:
18: * This product includes software developed by the University of
19: * California, Berkeley and its contributors.
20: * 4. Neither the name of the University nor the names of its contributors
21: * may be used to endorse or promote products derived from this software
22: * without specific prior written permission.
23: *
24: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34: * SUCH DAMAGE.
35: *
36: */
37: /*
38: * A driver for the 3Com 3C503 (Etherlink II) ethernet adaptor.
39: *
40: * Written by Herb Peyerl ([email protected]) on 04/25/92.
41: * (This is my first ever device driver and I couldn't have done
42: * it without the consumption of many "Brock Gummy Bears" so a
43: * big thanx to the "Brock Candy Company" of Chattanooga TN)
44: *
45: * This driver uses the Western Digital 8003 driver for a template
46: * since the two cards use the DP8390 chip by National. Everything
47: * is fairly similar except that the nic on the wd8003 appears to
48: * to see shared memory at 0x0000 and on the 3com, the nic sees it
49: * at 0x2000. Also, the 3c503 has it's own ASIC for controlling
50: * things like the IRQ level in software and whether to use the
51: * onboard xceiver or not. Since the Clarkson drivers do a very
52: * good rendition of a 3c503, I also scavenged a lot of ideas from
53: * there.
54: *
55: * Kludges:
56: * Since I couldn't really think of any non-creative way (other than
57: * using a #define) of configuring the board to use the onboard xceiver,
58: * I kludged the isa_device->unit to contain this information. Simply
59: * put, if bit-7 of isa_device->unit is set (>127) then the driver
60: * configures that unit to onboard-xceiver (BNC) and if <128 it assumes
61: * AUI. ec_attach informs the user of this on bootup. Also, ec_probe
62: * repairs this bit after obtaining it's information since I didn't know
63: * what else within the depths of the kernel would freak out if I left it.
64: */
65: #include "param.h"
66: #include "mbuf.h"
67: #include "socket.h"
68: #include "ioctl.h"
69: #include "errno.h"
70: #include "syslog.h"
71: #include "net/if.h"
72: #include "net/netisr.h"
73: #ifdef INET
74: #include "netinet/in.h"
75: #include "netinet/in_systm.h"
76: #include "netinet/in_var.h"
77: #include "netinet/ip.h"
78: #include "netinet/if_ether.h"
79: #endif
80: #ifdef NS
81: #include "netns/ns.h"
82: #include "netns/ns_if.h"
83: #endif
84: #include "i386/isa/isa_device.h"
85: #include "i386/isa/if_ec.h"
86:
1.1.1.2 ! root 87: #include "ec.h"
! 88:
1.1 root 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: */
96: struct 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 */
1.1.1.2 ! root 100: #define ns_addrp ec_ac.ac_enaddr /* hardware Ethernet address (for ns)*/
1.1 root 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);
119: static Bdry;
120:
121: int 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:
131: struct isa_driver ecdriver = {
132: ecprobe,
133: ecattach,
134: "ec",
135: };
136:
137: ecprobe(is)
138: struct 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:
196: ecattach(is)
197: struct 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:
255: ec_init(unit)
256: int 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;
264: printf("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:
333: ec_start_output(ifp)
334: struct 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: */
391: ecintr(unit)
392: int 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);
406: loop:
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: */
459: ectint(unit)
460: int 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: */
477: ecrint(unit)
478: int 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);
493: if(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);*/
506: outofbufs:
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:
541: ecread(sc, buf, len)
542: register struct ec_softc *sc;
543: char *buf;
544: int 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: }
580: ec_ioctl(ifp, cmd, data)
581: register struct ifnet *ifp;
582: int cmd;
583: caddr_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))
1.1.1.2 ! root 607: ina->x_host = *(union ns_host *)(sc->ns_addrp);
1.1 root 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,
1.1.1.2 ! root 616: (caddr_t)sc->ns_addrp, sizeof(sc->ns_addrp));
1.1 root 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:
652: ec_reset(unit)
653: int unit;
654: {
655: if(unit >= NEC)
656: return;
657: printf("ec%d: reset\n", unit);
658: ec_init(unit);
659: }
660:
661: ec_watchdog(unit)
662: int unit;
663: {
664: log(LOG_WARNING, "ec%d: soft reset\n", unit);
665: ec_stop(unit);
666: ec_init(unit);
667: }
668:
669: ec_stop(unit)
670: int 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: */
695: struct mbuf *
696: ecget(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 = ⊤
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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.