if_ep.c revision 963
1/*
2 * Copyright (c) 1993 Herb Peyerl (hpeyerl@novatel.ca)
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. The name of the author may not be used to endorse or promote products
11 *    derived from this software withough specific prior written permission
12 *
13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
14 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
15 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
16 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
17 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
18 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
19 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
20 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
22 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23 *
24 *	$Id: if_ep.c,v 1.5 1993/12/20 09:05:55 mycroft Exp $
25 */
26/*
27 * TODO:
28 *       Multi-509 configs.
29 *       don't pass unit into epstop.
30 *	 epintr returns an int for magnum. 0=not for me. 1=for me. -1=whoknows?
31 */
32#include "ep.h"
33#if NEP > 0
34#include "bpfilter.h"
35
36#include <sys/param.h>
37#include <sys/mbuf.h>
38#include <sys/socket.h>
39#include <sys/ioctl.h>
40#include <sys/errno.h>
41#include <sys/syslog.h>
42#include <sys/select.h>
43
44#include <net/if.h>
45#include <net/netisr.h>
46#include <net/if_dl.h>
47#include <net/if_types.h>
48#include <net/netisr.h>
49
50#ifdef INET
51#include <netinet/in.h>
52#include <netinet/in_systm.h>
53#include <netinet/in_var.h>
54#include <netinet/ip.h>
55#include <netinet/if_ether.h>
56#endif
57
58#ifdef NS
59#include <netns/ns.h>
60#include <netns/ns_if.h>
61#endif
62
63#if NBPFILTER > 0
64#include <net/bpf.h>
65#include <net/bpfdesc.h>
66#endif
67
68#include <machine/pio.h>
69
70#include <i386/isa/isa.h>
71#include <i386/isa/isa_device.h>
72#include <i386/isa/icu.h>
73#include <i386/isa/if_epreg.h>
74
75#define ETHER_MIN_LEN 64
76#define ETHER_MAX_LEN   1518
77#define ETHER_ADDR_LEN  6
78/*
79 * Ethernet software status per interface.
80 */
81struct  ep_softc {
82	struct  arpcom ep_ac;		/* Ethernet common part	        */
83#define ep_if   ep_ac.ac_if		/* network-visible interface    */
84#define ep_addr ep_ac.ac_enaddr		/* hardware Ethernet address    */
85	short	ep_io_addr;		/* i/o bus address		*/
86	char	ep_connectors;		/* Connectors on this card.	*/
87#define MAX_MBS  8			/* # of mbufs we keep around	*/
88	struct	mbuf *mb[MAX_MBS];	/* spare mbuf storage.		*/
89	int	next_mb;		/* Which mbuf to use next. 	*/
90	int 	last_mb;		/* Last mbuf.			*/
91	int	tx_start_thresh;	/* Current TX_start_thresh.	*/
92	caddr_t bpf;			/* BPF  "magic cookie"		*/
93} ep_softc[NEP];
94
95
96int ether_output(),
97    epprobe(),
98    epattach(),
99    epintr(),
100    epinit(),
101    epioctl(),
102    epreset(),
103    epwatchdog(),
104    epstart(),
105    fill_mbuf_queue();
106
107struct isa_driver epdriver = {
108	epprobe,
109	epattach,
110	"ep"
111};
112
113extern u_short get_eeprom_data(int id_port, int offset);
114extern int is_eeprom_busy(struct isa_device *is);
115
116/*
117 * Rudimentary support for multiple cards is here but is not
118 * currently handled.  In the future we will have to add code
119 * for tagging the cards for later activation.  We wanna do something
120 * about the id_port.  We're limited due to current config procedure.
121 * Magnum config holds promise of a fix but we'll have to wait a bit.
122 */
123epprobe(is)
124	struct isa_device *is;
125{
126	struct ep_softc *sc = &ep_softc[is->id_unit];
127	u_short k;
128	char buf[8];
129	int id_port = 0x100;   /* XXX */
130
131	outw(BASE+EP_COMMAND, GLOBAL_RESET);
132	DELAY(1000);
133	outb(id_port, 0xc0);   /* Global reset to id_port. */
134	DELAY(1000);
135	send_ID_sequence(id_port);
136	DELAY(1000);
137/*
138 * MFG_ID should have 0x6d50.
139 * PROD_ID should be 0x9[0-f]50
140 */
141	k = get_eeprom_data(id_port, EEPROM_MFG_ID);
142	if (k != MFG_ID)
143		return(0);
144	k = get_eeprom_data(id_port, EEPROM_PROD_ID);
145	if ((k & 0xf0ff) != (PROD_ID & 0xf0ff))
146		return(0);
147
148	k = get_eeprom_data(id_port, EEPROM_ADDR_CFG); /* get addr cfg */
149	k = (k & 0x1f)*0x10+0x200;	/* decode base addr. */
150	if (k != is->id_iobase)
151		return(0);
152
153	k = get_eeprom_data(id_port, EEPROM_RESOURCE_CFG);
154	k >>= 12;
155	if (is->id_irq != (1<<((k==2) ? 9 : k)))
156		return(0);
157
158	outb(id_port, ACTIVATE_ADAPTER_TO_CONFIG);
159
160	return(0x10); /* 16 bytes of I/O space used. */
161}
162
163epattach(is)
164	struct isa_device *is;
165{
166	struct ep_softc *sc = &ep_softc[is->id_unit];
167	struct ifnet *ifp = &sc->ep_if;
168	u_short i;
169	struct ifaddr *ifa;
170	struct sockaddr_dl *sdl;
171
172	sc->ep_io_addr = is->id_iobase;
173
174	sc->ep_connectors =  0;
175	i=inw(is->id_iobase+EP_W0_CONFIG_CTRL);
176
177	printf("ep%d: ", is->id_unit);
178
179	if (i & IS_AUI) {
180		if (sc->ep_connectors)
181			printf("/");
182		printf("aui");
183		sc->ep_connectors |= AUI;
184	}
185	if (i & IS_BNC) {
186		if (sc->ep_connectors)
187			printf("/");
188		printf("bnc");
189		sc->ep_connectors |= BNC;
190	}
191	if (i & IS_UTP) {
192		if (sc->ep_connectors)
193			printf("/");
194		printf("utp");
195		sc->ep_connectors |= UTP;
196	}
197	if (!sc->ep_connectors)
198		printf("!no connectors!");
199
200/*
201 * Read the station address from the eeprom
202 */
203	for (i=0; i<3; i++) {
204		u_short *p;
205		GO_WINDOW(0);
206		if (is_eeprom_busy(is))
207			return;
208		outw(BASE+EP_W0_EEPROM_COMMAND, READ_EEPROM | i);
209		if (is_eeprom_busy(is))
210			return;
211		p =(u_short *)&sc->ep_addr[i*2];
212		*p=htons(inw(BASE+EP_W0_EEPROM_DATA));
213		GO_WINDOW(2);
214		outw(BASE+EP_W2_ADDR_0+(i*2), ntohs(*p));
215	}
216	printf(" address %s\n", ether_sprintf(sc->ep_addr));
217
218	ifp->if_unit = is->id_unit;
219	ifp->if_name = "ep" ;
220	ifp->if_mtu = ETHERMTU;
221	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS;
222	ifp->if_init = epinit;
223	ifp->if_output = ether_output;
224	ifp->if_start = epstart;
225	ifp->if_ioctl = epioctl;
226	ifp->if_watchdog = epwatchdog;
227
228	if_attach(ifp);
229
230/*
231 * Fill the hardware address into ifa_addr if we find an AF_LINK entry.
232 * We need to do this so bpf's can get the hardware addr of this card.
233 * netstat likes this too!
234 */
235	ifa = ifp->if_addrlist;
236	while ((ifa != 0) && (ifa->ifa_addr != 0) &&
237		(ifa->ifa_addr->sa_family != AF_LINK))
238			ifa = ifa->ifa_next;
239
240	if ((ifa != 0) && (ifa->ifa_addr != 0)) {
241		sdl = (struct sockaddr_dl *)ifa->ifa_addr;
242		sdl->sdl_type = IFT_ETHER;
243		sdl->sdl_alen = ETHER_ADDR_LEN;
244		sdl->sdl_slen = 0;
245		bcopy(sc->ep_addr, LLADDR(sdl), ETHER_ADDR_LEN);
246	}
247#if NBPFILTER > 0
248	bpfattach(&sc->bpf, ifp, DLT_EN10MB, sizeof(struct ether_header));
249#endif
250}
251
252/* The order in here seems important. Otherwise we may not receive interrupts. ?! */
253epinit(unit)
254	int unit;
255{
256	register struct ep_softc *sc = &ep_softc[unit];
257	register struct ifnet *ifp = &sc->ep_if;
258	int s,i;
259
260	s=splnet();
261
262	if (ifp->if_addrlist == (struct ifaddr *) 0) {
263		printf("ep: address not known...\n");
264		splx(s);
265		return;
266	}
267
268	while (inb(BASE+EP_STATUS) & S_COMMAND_IN_PROGRESS)
269		;
270
271	GO_WINDOW(0);
272	outw(BASE+EP_W0_CONFIG_CTRL, 0);   /* Disable the card */
273
274	outw(BASE+EP_W0_CONFIG_CTRL, ENABLE_DRQ_IRQ);   /* Enable the card */
275
276	GO_WINDOW(2);
277	for(i=0;i<6;i++)	/* Reload the ether_addr. */
278		outb(BASE+EP_W2_ADDR_0+i, sc->ep_addr[i]);
279
280	outw(BASE+EP_COMMAND, RX_RESET);
281	outw(BASE+EP_COMMAND, TX_RESET);
282
283	GO_WINDOW(1);			/* Window 1 is operating window */
284	for(i=0;i<31;i++)
285		inb(BASE+EP_W1_TX_STATUS);
286
287	outw(BASE+EP_COMMAND, ACK_INTR | 0xff);	/* get rid of stray intr's */
288
289	outw(BASE+EP_COMMAND, SET_RD_0_MASK | S_CARD_FAILURE | S_RX_COMPLETE |
290		S_TX_COMPLETE | S_TX_AVAIL);
291	outw(BASE+EP_COMMAND, SET_INTR_MASK | S_CARD_FAILURE | S_RX_COMPLETE |
292		S_TX_COMPLETE | S_TX_AVAIL);
293
294	outw(BASE+EP_COMMAND, SET_RX_FILTER | FIL_INDIVIDUAL |
295		FIL_GROUP | FIL_BRDCST);
296
297	if (!(ifp->if_flags & IFF_LINK0) && (sc->ep_connectors & BNC)) {	/* Want BNC? */
298		outw(BASE+EP_COMMAND, START_TRANSCEIVER);
299		DELAY(1000);
300	}
301	if ((sc->ep_connectors & UTP) & !(ifp->if_flags & IFF_LINK0)) {    /* Want UTP? */
302		GO_WINDOW(4);
303		outw(BASE+EP_W4_MEDIA_TYPE, ENABLE_UTP);
304		GO_WINDOW(1);
305	}
306
307	outw(BASE+EP_COMMAND, RX_ENABLE);
308	outw(BASE+EP_COMMAND, TX_ENABLE);
309
310	ifp->if_flags |= IFF_RUNNING;
311	ifp->if_flags &= ~IFF_OACTIVE;   /* just in case */
312	sc->tx_start_thresh = 20;	/* probably a good starting point. */
313	/*
314	 * Store up a bunch of mbuf's for use later. (MAX_MBS). First we
315	 * free up any that we had in case we're being called from intr or
316	 * somewhere else.
317	 */
318	sc->last_mb = 0;
319	sc->next_mb = 0;
320	fill_mbuf_queue(sc);
321
322	epstart(ifp);
323
324	splx(s);
325}
326
327epstart(ifp)
328	struct ifnet *ifp;
329{
330	register struct ep_softc *sc = &ep_softc[ifp->if_unit];
331	struct mbuf *m, *top;
332	int s, len, pad;
333
334	s=splnet();
335	if (sc->ep_if.if_flags & IFF_OACTIVE) {
336		splx(s);
337		return;
338	}
339
340startagain:
341	m = sc->ep_if.if_snd.ifq_head;    /* Sneak a peek at the next packet */
342	if (m == 0) {
343		splx(s);
344		return;
345	}
346	pad = (4-(m->m_pkthdr.len%4)+4)%4; /* icky pooh!! */
347
348	if ((inw(BASE+EP_W1_FREE_TX)) < (m->m_pkthdr.len)+pad+4) {   /* no room in FIFO */
349		outw(BASE+EP_COMMAND, SET_TX_AVAIL_THRESH | (m->m_pkthdr.len)+pad+4);
350		sc->ep_if.if_flags |= IFF_OACTIVE;
351		splx(s);
352		return;
353	}
354
355	IF_DEQUEUE(&sc->ep_if.if_snd, m);
356	if (m == 0)  {   /* Could make this go away. */
357		splx(s);
358		return;
359	}
360
361	outw(BASE+EP_COMMAND, SET_TX_START_THRESH |
362		(m->m_pkthdr.len/4 + sc->tx_start_thresh));
363
364	outw(BASE+EP_W1_TX_PIO_WR_1, m->m_pkthdr.len);
365	outw(BASE+EP_W1_TX_PIO_WR_1, 0xffff); /* Second dword meaningless */
366
367	for(top = m; m != 0; m = m->m_next) {
368		outsw(BASE+EP_W1_TX_PIO_WR_1, mtod(m, caddr_t), m->m_len/2);
369		if(m->m_len & 1)
370			outb(BASE+EP_W1_TX_PIO_WR_1,
371				*(mtod(m, caddr_t)+m->m_len-1));
372	}
373
374	while (pad--)
375		outb(BASE+EP_W1_TX_PIO_WR_1, 0); /* Padding */
376#if NBPFILTER > 0
377	if (sc->bpf) {
378	u_short etype;
379		int off, datasize, resid;
380		struct ether_header *eh;
381		struct trailer_header {
382			u_short ether_type;
383			u_short ether_residual;
384		} trailer_header;
385		char ether_packet[ETHER_MAX_LEN];
386		char *ep;
387
388		ep = ether_packet;
389
390		/*
391		 * We handle trailers below:
392		 * Copy ether header first, then residual data,
393		 * then data. Put all this in a temporary buffer
394		 * 'ether_packet' and send off to bpf. Since the
395		 * system has generated this packet, we assume
396		 * that all of the offsets in the packet are
397		 * correct; if they're not, the system will almost
398		 * certainly crash in m_copydata.
399		 * We make no assumptions about how the data is
400		 * arranged in the mbuf chain (i.e. how much
401		 * data is in each mbuf, if mbuf clusters are
402		 * used, etc.), which is why we use m_copydata
403		 * to get the ether header rather than assume
404		 * that this is located in the first mbuf.
405		 */
406		/* copy ether header */
407                m_copydata(top, 0, sizeof(struct ether_header), ep);
408                eh = (struct ether_header *) ep;
409                ep += sizeof(struct ether_header);
410                etype = ntohs(eh->ether_type);
411                if (etype >= ETHERTYPE_TRAIL &&
412                    etype < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) {
413                        datasize = ((etype - ETHERTYPE_TRAIL) << 9);
414                        off = datasize + sizeof(struct ether_header);
415
416                        /* copy trailer_header into a data structure */
417                        m_copydata(top, off, sizeof(struct trailer_header),
418                                &trailer_header.ether_type);
419
420                        /* copy residual data */
421			resid = trailer_header.ether_residual -
422				sizeof(struct trailer_header);
423			resid = ntohs(resid);
424                        m_copydata(top, off+sizeof(struct trailer_header),
425                                resid, ep);
426                        ep += resid;
427
428                        /* copy data */
429                        m_copydata(top, sizeof(struct ether_header),
430                                datasize, ep);
431                        ep += datasize;
432
433                        /* restore original ether packet type */
434                        eh->ether_type = trailer_header.ether_type;
435
436                        bpf_tap(sc->bpf, ether_packet, ep - ether_packet);
437                } else
438                        bpf_mtap(sc->bpf, top);
439        }
440#endif
441
442	m_freem(top);
443	++sc->ep_if.if_opackets;
444	/*
445	 * Is another packet coming in? We don't want to overflow the
446	 * tiny RX fifo.
447	 */
448	if (inw(BASE+EP_W1_RX_STATUS) & RX_BYTES_MASK) {
449		splx(s);
450		return;
451	}
452	goto startagain;
453}
454
455epintr(unit)
456	int unit;
457{
458	int status, i;
459	register struct ep_softc *sc = &ep_softc[unit];
460	struct ifnet *ifp = &sc->ep_if;
461	struct mbuf *m;
462
463	status=0;
464checkintr:
465	status = inw(BASE + EP_STATUS) & (S_TX_COMPLETE|S_TX_AVAIL|S_RX_COMPLETE|S_CARD_FAILURE);
466	if (status == 0) {                     /* No interrupts. */
467		outw(BASE+EP_COMMAND, C_INTR_LATCH);
468		return;
469	}
470	outw(BASE+EP_COMMAND, ACK_INTR | status);  /* important that we do this first. */
471
472	if (status & S_TX_AVAIL) {
473		status &= ~S_TX_AVAIL;
474		inw(BASE+EP_W1_FREE_TX);
475		sc->ep_if.if_flags &= ~IFF_OACTIVE;
476		epstart(&sc->ep_if);
477	}
478	if (status & S_RX_COMPLETE) {
479		status &= ~S_RX_COMPLETE;
480		epread(sc);
481	}
482	if (status & S_CARD_FAILURE) {
483		printf("ep%d: reset (status: %x)\n", unit, status);
484		outw(BASE+EP_COMMAND, C_INTR_LATCH);
485		epinit(unit);
486		return;
487	}
488	if (status & S_TX_COMPLETE) {
489		status &= ~S_TX_COMPLETE;
490		/*
491		 * We need to read TX_STATUS until we get a 0 status in
492		 * order to turn off the interrupt flag.
493		 */
494		while ((i=inb(BASE+EP_W1_TX_STATUS)) & TXS_COMPLETE) {
495			outw(BASE+EP_W1_TX_STATUS, 0x0);
496			if (i & (TXS_MAX_COLLISION|TXS_JABBER|TXS_UNDERRUN)) {
497				if (i & TXS_MAX_COLLISION)
498					++sc->ep_if.if_collisions;
499				if (i & (TXS_JABBER|TXS_UNDERRUN)) {
500					outw(BASE+EP_COMMAND, TX_RESET);
501					if(i & TXS_UNDERRUN) {
502						if (sc->tx_start_thresh < ETHER_MAX_LEN) {
503							sc->tx_start_thresh += 20;
504							outw(BASE+EP_COMMAND,
505								SET_TX_START_THRESH |
506								sc->tx_start_thresh);
507						}
508					}
509				}
510				outw(BASE+EP_COMMAND, TX_ENABLE);
511				++sc->ep_if.if_oerrors;
512			}
513		}
514		epstart(ifp);
515	}
516	goto checkintr;
517}
518
519epread(sc)
520	register struct ep_softc *sc;
521{
522	struct ether_header *eh;
523	struct mbuf *mcur, *m, *m0, *top;
524	int totlen, lenthisone;
525	int save_totlen;
526	u_short etype;
527	int off, resid;
528	int count, spinwait;
529	int i;
530
531	totlen = inw(BASE + EP_W1_RX_STATUS);
532	off = 0;
533	top = 0;
534
535	if (totlen & ERR_RX) {
536		++sc->ep_if.if_ierrors;
537		goto out;
538	}
539	save_totlen = totlen &= RX_BYTES_MASK;	/* Lower 10 bits = RX bytes. */
540
541	m = sc->mb[sc->next_mb];
542	sc->mb[sc->next_mb] = 0;
543
544	if (m == 0) {
545		MGETHDR(m, M_DONTWAIT, MT_DATA);
546		if (m == 0)
547			goto out;
548	} else {	/* Convert one of our saved mbuf's */
549		sc->next_mb = (sc->next_mb + 1) % MAX_MBS;
550		m->m_data = m->m_pktdat;
551		m->m_flags = M_PKTHDR;
552	}
553
554	top = m0 = m;    /* We assign top so we can "goto out" */
555#	define EROUND  ((sizeof(struct ether_header) + 3) & ~3)
556#	define EOFF    (EROUND - sizeof(struct ether_header))
557	m0->m_data += EOFF;
558	/* Read what should be the header. */
559	insw(BASE+EP_W1_RX_PIO_RD_1, mtod(m0, caddr_t), sizeof(struct ether_header)/2);
560	m->m_len = sizeof(struct ether_header);
561	totlen -= sizeof(struct ether_header);
562	/*
563 	 * mostly deal with trailer here.  (untested)
564	 * We do this in a couple of parts.  First we check for a trailer, if
565	 * we have one we convert the mbuf back to a regular mbuf and set the offset and
566	 * subtract sizeof(struct ether_header) from the pktlen.
567	 * After we've read the packet off the interface (all except for the trailer
568	 * header, we then get a header mbuf, read the trailer into it, and fix up
569	 * the mbuf pointer chain.
570	 */
571	eh=mtod(m, struct ether_header *);
572	eh->ether_type = ntohs((u_short)eh->ether_type);
573	if (eh->ether_type >=  ETHERTYPE_TRAIL &&
574	    eh->ether_type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) {
575		m->m_data = m->m_dat;   /* Convert back to regular mbuf.  */
576		m->m_flags = 0;		/* This sucks but non-trailers are the norm */
577		off = (eh->ether_type - ETHERTYPE_TRAIL) * 512;
578		if (off >= ETHERMTU) {
579			m_freem(m);
580			return;		/* sanity */
581		}
582		totlen -= sizeof(struct ether_header); /* We don't read the trailer */
583		m->m_data += 2 * sizeof(u_short);      /* Get rid of type & len*/
584	}
585	while (totlen>0) {
586		lenthisone=min(totlen, M_TRAILINGSPACE(m));
587		if (lenthisone == 0) {	/* no room in this one */
588			mcur = m;
589			m = sc->mb[sc->next_mb];
590			sc->mb[sc->next_mb] = 0;
591			if (!m) {
592				MGET(m, M_DONTWAIT, MT_DATA);
593				if (m==0)
594					goto out;
595			} else {
596				timeout(fill_mbuf_queue, sc, 1);
597				sc->next_mb = (sc->next_mb + 1) % MAX_MBS;
598			}
599			if (totlen >= MINCLSIZE)
600				MCLGET(m, M_DONTWAIT);
601			m->m_len = 0;
602			mcur->m_next = m;
603			lenthisone = min(totlen, M_TRAILINGSPACE(m));
604		}
605		insw(BASE+EP_W1_RX_PIO_RD_1, mtod(m, caddr_t)+m->m_len, lenthisone/2);
606		m->m_len += lenthisone;
607		if (lenthisone & 1)
608			*(mtod(m, caddr_t)+m->m_len-1) = inb(BASE+EP_W1_RX_PIO_RD_1);
609		totlen -= lenthisone;
610	}
611	if (off) {
612		top = sc->mb[sc->next_mb];
613		sc->mb[sc->next_mb] = 0;
614		if (top == 0) {
615			MGETHDR(m, M_DONTWAIT, MT_DATA);
616			if (top == 0)
617				goto out;
618		} else {	/* Convert one of our saved mbuf's */
619			sc->next_mb = (sc->next_mb + 1) % MAX_MBS;
620			top->m_data = top->m_pktdat;
621			top->m_flags = M_PKTHDR;
622		}
623		insw(BASE+EP_W1_RX_PIO_RD_1, mtod(m, caddr_t)+m->m_len,
624			sizeof(struct ether_header));
625		eh->ether_type = ntohs(eh->ether_type);
626		top->m_next = m0;
627		top->m_len = sizeof(struct ether_header);
628		/*  XXX Accomodate for type and len from beginning of trailer data */
629		top->m_pkthdr.len = save_totlen - (2 * sizeof(u_short));
630	} else {
631		top = m0;
632		top->m_pkthdr.len = save_totlen;
633	}
634
635        top->m_pkthdr.rcvif = &sc->ep_if;
636	outw(BASE+EP_COMMAND, RX_DISCARD_TOP_PACK);
637	while (inb(BASE+EP_STATUS) & S_COMMAND_IN_PROGRESS)
638		;
639        ++sc->ep_if.if_ipackets;
640	m_adj(top, sizeof(struct ether_header));
641        ether_input(&sc->ep_if, eh, top);
642	return;
643
644out:	outw(BASE+EP_COMMAND, RX_DISCARD_TOP_PACK);
645	while (inb(BASE+EP_STATUS) & S_COMMAND_IN_PROGRESS)
646		;
647	if (top)
648		m_freem(top);
649}
650
651/*
652 * Look familiar?
653 */
654epioctl(ifp, cmd, data)
655	register struct ifnet *ifp;
656	int cmd;
657	caddr_t data;
658{
659	register struct ifaddr *ifa = (struct ifaddr *)data;
660	struct ep_softc *sc = &ep_softc[ifp->if_unit];
661	struct ifreq *ifr = (struct ifreq *)data;
662	int s, error=0;
663
664	switch(cmd){
665	case SIOCSIFADDR:
666		ifp->if_flags |= IFF_UP;
667		switch (ifa->ifa_addr->sa_family) {
668#ifdef INET
669		case AF_INET:
670			epinit(ifp->if_unit);  /* before arpwhohas */
671			((struct arpcom *)ifp)->ac_ipaddr = IA_SIN(ifa)->sin_addr;
672			arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr);
673			break;
674#endif
675#ifdef NS
676		case AF_NS:
677		{
678			register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr);
679
680			if (ns_nullhost(*ina))
681				ina->x_host = *(union ns_host *)(sc->ep_ac.ac_enaddr);
682			else {
683				ifp->if_flags &= ~IFF_RUNNING;
684				bcopy((caddr_t)ina->x_host.c_host,
685					(caddr_t)sc->ns_addr,
686					sizeof(sc->ep_ac.ac_enaddr));
687			}
688			epinit(ifp->if_unit);
689			break;
690		}
691#endif
692		default:
693			epinit(ifp->if_unit);
694			break;
695		}
696		break;
697	case SIOCSIFFLAGS:
698		if ((ifp->if_flags & IFF_UP) == 0 && ifp->if_flags & IFF_RUNNING) {
699			ifp->if_flags &= ~IFF_RUNNING;
700			epstop(ifp->if_unit);
701		} else if (ifp->if_flags & IFF_UP && (ifp->if_flags & IFF_RUNNING) == 0)
702			 epinit(ifp->if_unit);
703		break;
704
705#ifdef notdef
706	case SIOCGHWADDR:
707		bcopy((caddr_t)sc->sc_addr, (caddr_t) &ifr->ifr_data, sizeof(sc->sc_addr));
708		break;
709#endif
710
711	default:
712		error = EINVAL;
713	}
714	return (error);
715}
716
717epreset(unit)
718	int unit;
719{
720	int s;
721
722	epstop(unit);
723	epinit(unit);
724	return;
725}
726
727epwatchdog(unit)
728	int unit;
729{
730	return;
731}
732
733epstop(unit)
734	int unit;
735{
736        register struct ep_softc *sc = &ep_softc[unit];
737
738	outw(BASE+EP_COMMAND, RX_DISABLE);
739	outw(BASE+EP_COMMAND, RX_DISCARD_TOP_PACK);
740	while (inb(BASE+EP_STATUS) & S_COMMAND_IN_PROGRESS)
741		;
742	outw(BASE+EP_COMMAND, TX_DISABLE);
743	outw(BASE+EP_COMMAND, STOP_TRANSCEIVER);
744	outw(BASE+EP_COMMAND, RX_RESET);
745	outw(BASE+EP_COMMAND, TX_RESET);
746	outw(BASE+EP_COMMAND, C_INTR_LATCH);
747	outw(BASE+EP_COMMAND, SET_RD_0_MASK);
748	outw(BASE+EP_COMMAND, SET_INTR_MASK);
749	outw(BASE+EP_COMMAND, SET_RX_FILTER);
750	return;
751}
752
753/*
754 * This is adapted straight from the book. There's probably a better way.
755 */
756send_ID_sequence(port)
757	u_short port;
758{
759	char cx, al;
760
761	cx=0x0ff;
762	al=0x0ff;
763
764	outb(port, 0x0);
765	DELAY(1000);
766	outb(port, 0x0);
767	DELAY(1000);
768
769loop1:  cx--;
770	outb(port, al);
771	if (!(al & 0x80)) {
772		al=al<<1;
773		goto loop1;
774	}
775	al=al<<1;
776	al^=0xcf;
777	if (cx)
778		goto loop1;
779
780}
781
782/*
783 * We get eeprom data from the id_port given an offset into the
784 * eeprom.  Basically; after the ID_sequence is sent to all of
785 * the cards; they enter the ID_CMD state where they will accept
786 * command requests. 0x80-0xbf loads the eeprom data.  We then
787 * read the port 16 times and with every read; the cards check
788 * for contention (ie: if one card writes a 0 bit and another
789 * writes a 1 bit then the host sees a 0. At the end of the cycle;
790 * each card compares the data on the bus; if there is a difference
791 * then that card goes into ID_WAIT state again). In the meantime;
792 * one bit of data is returned in the AX register which is conveniently
793 * returned to us by inb().  Hence; we read 16 times getting one
794 * bit of data with each read.
795 */
796u_short get_eeprom_data(id_port, offset)
797	int id_port;
798	int offset;
799{
800	int i, data=0;
801	outb(id_port, 0x80+offset);
802	DELAY(1000);
803	for (i=0; i<16; i++)
804		data = (data<<1) | (inw(id_port) & 1);
805	return(data);
806}
807
808int
809is_eeprom_busy(is)
810	struct isa_device *is;
811{
812	int i=0, j;
813	register struct ep_softc *sc = &ep_softc[is->id_unit];
814
815	while (i++<100) {
816		j=inw(BASE+EP_W0_EEPROM_COMMAND);
817		if (j & EEPROM_BUSY)
818			DELAY(100);
819		else
820			break;
821	}
822	if (i>=100) {
823		printf("\nep%d: eeprom failed to come ready.\n", is->id_unit);
824		return(1);
825	}
826	if (j & EEPROM_TST_MODE) {
827		printf("\nep%d: 3c509 in test mode. Erase pencil mark!\n", is->id_unit);
828		return(1);
829	}
830	return(0);
831}
832
833int
834fill_mbuf_queue(sc)
835	struct ep_softc *sc;
836{
837	int i=0;
838	if (sc->mb[sc->last_mb])
839		return;
840	i=sc->last_mb;
841	do {
842		MGET(sc->mb[i], M_DONTWAIT, MT_DATA);
843		if (!sc->mb[i])
844			break;
845		i = (i+1) % MAX_MBS;
846	} while(i != sc->next_mb);
847	sc->last_mb = i;
848}
849#endif /* NEP > 0 */
850