summaryrefslogtreecommitdiff
path: root/i386/i386at/if_de6c.c
diff options
context:
space:
mode:
authorThomas Bushnell <thomas@gnu.org>1997-02-25 21:28:37 +0000
committerThomas Bushnell <thomas@gnu.org>1997-02-25 21:28:37 +0000
commitf07a4c844da9f0ecae5bbee1ab94be56505f26f7 (patch)
tree12b07c7e578fc1a5f53dbfde2632408491ff2a70 /i386/i386at/if_de6c.c
Initial source
Diffstat (limited to 'i386/i386at/if_de6c.c')
-rw-r--r--i386/i386at/if_de6c.c1777
1 files changed, 1777 insertions, 0 deletions
diff --git a/i386/i386at/if_de6c.c b/i386/i386at/if_de6c.c
new file mode 100644
index 0000000..0bad780
--- /dev/null
+++ b/i386/i386at/if_de6c.c
@@ -0,0 +1,1777 @@
+#define DEBUG 1
+/*
+ * Mach Operating System
+ * Copyright (c) 1994,1993,1992 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+
+/*
+ * HISTORY
+ * 17-Feb-94 David Golub (dbg) at Carnegie-Mellon University
+ * Fix from Bob Baron to fix transmitter problems.
+ *
+ * $Log: if_de6c.c,v $
+ * Revision 1.1.1.1 1996/10/30 01:39:26 thomas
+ * Imported from UK22
+ *
+ * Revision 1.1 1994/11/08 20:47:24 baford
+ * merged in CMU's MK83-MK83a diffs
+ *
+ * Revision 2.2 93/11/17 18:29:25 dbg
+ * Moved source into kernel/i386at/DLINK/if_de6c.c, since we
+ * can't release it but don't want to lose it.
+ * [93/11/17 dbg]
+ *
+ * Removed u_long.
+ * [93/03/25 dbg]
+ *
+ * Created.
+ * I have used if_3c501.c as a typical driver template and
+ * spliced in the appropriate particulars for the
+ * d-link 600.
+ * [92/08/13 rvb]
+ *
+ *
+ * File: if_de6c.c
+ * Author: Robert V. Baron
+ */
+
+/*
+ * File: if_3c501.c
+ * Author: Philippe Bernadat
+ * Date: 1989
+ * Copyright (c) 1989 OSF Research Institute
+ *
+ * 3COM Etherlink d-link "600" Mach Ethernet drvier
+ */
+/*
+ Copyright 1990 by Open Software Foundation,
+Cambridge, MA.
+
+ All Rights Reserved
+
+ Permission to use, copy, modify, and distribute this software and
+its documentation for any purpose and without fee is hereby granted,
+provided that the above copyright notice appears in all copies and
+that both the copyright notice and this permission notice appear in
+supporting documentation, and that the name of OSF or Open Software
+Foundation not be used in advertising or publicity pertaining to
+distribution of the software without specific, written prior
+permission.
+
+ OSF DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
+IN NO EVENT SHALL OSF BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
+CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
+NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+*/
+
+/*
+ * I have tried to make it clear what is device specific code
+ * and what code supports the general BSD ethernet interface. d-link
+ * specific code is preceded by a line or two of
+ * "d-link 600 ON; d-link 600 ON; d-link 600 ON; d-link 600 ON"
+ * and followed by a line or two of
+ * "d-link 600 OFF; d-link 600 OFF; d-link 600 OFF; d-link 600 OFF"
+ *
+ * The main routines that do device specific processing are:
+ * de6cintr - interrupt dispatcher
+ * de6crcv - rcv packets and switch to new buffers
+ * de6cxmt - xmt packet and wait for xmtbusy to clear
+ * de6calive - probe for device
+ * de6cinit - device initialization
+ * de6cintoff - turn it off.
+ * There are a couple of interesting macros at the head of this
+ * file and some support subroutines at the end.
+ *
+ * Lastly, to get decent performance on i386SX class machines, it
+ * was necessary to recode the read and write d-link memory routines in
+ * assembler. The deread and dewrite routines that are used are in
+ * if_de6s.s
+ *
+ */
+
+/* Questions:
+
+ Make sure that iopl maps 378, 278 and 3bc.
+
+ If you set command w/o MODE and page bit, what happens?
+
+ Could I get xmt interrupts; currently I spin - this is not an issue?
+
+ enable promiscuous?
+
+ Can you assert TXEN and RXen simulatneously?
+*/
+
+#include <de6c.h>
+#include <par.h>
+
+#ifdef MACH_KERNEL
+#include <kern/time_out.h>
+#include <device/device_types.h>
+#include <device/errno.h>
+#include <device/io_req.h>
+#include <device/if_hdr.h>
+#include <device/if_ether.h>
+#include <device/net_status.h>
+#include <device/net_io.h>
+#include <chips/busses.h>
+#else MACH_KERNEL
+#include <sys/param.h>
+#include <mach/machine/vm_param.h>
+#include <sys/systm.h>
+#include <sys/mbuf.h>
+#include <sys/buf.h>
+#include <sys/protosw.h>
+#include <sys/socket.h>
+#include <sys/vmmac.h>
+#include <sys/ioctl.h>
+#include <sys/errno.h>
+#include <sys/syslog.h>
+
+#include <net/if.h>
+#include <net/netisr.h>
+#include <net/route.h>
+#include <i386at/atbus.h>
+
+#ifdef INET
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/in_var.h>
+#include <netinet/ip.h>
+#include <netinet/if_ether.h>
+#endif
+
+#ifdef NS
+#include <netns/ns.h>
+#include <netns/ns_if.h>
+#endif
+#endif MACH_KERNEL
+
+#include <vm/vm_kern.h>
+#include <i386/ipl.h>
+#include <i386/pio.h>
+#include <i386at/if_de6c.h>
+
+#define SPLNET spl6
+
+/* d-link 600 ON; d-link 600 ON; d-link 600 ON; d-link 600 ON */
+/* d-link 600 ON; d-link 600 ON; d-link 600 ON; d-link 600 ON */
+#define de6cwrite(sp, addr, buf, len) \
+ de6cwriteasm(addr, buf, len, DATA(sp->port), sp->latency)
+
+#define de6cread(sp, addr, buf, len) \
+ de6creadasm(addr, buf, len, DATA(sp->port), sp->latency)
+
+#define DATA_OUT(sp, p, f, z) \
+ de6coutb(sp, DATA(p), ((z)<<4) | f);\
+ de6coutb(sp, DATA(p), ((z)&0xf0)| f | STROBE)
+
+#define STAT_IN(sp, p, in) \
+ de6coutb(sp, DATA(p), STATUS); \
+ in = inb(STAT(port)); \
+ de6coutb(sp, DATA(p), NUL_CMD | STROBE)
+
+#define XMTidx 3
+#define XMT_BSY_WAIT 10000
+/* d-link 600 OFF; d-link 600 OFF; d-link 600 OFF; d-link 600 OFF */
+/* d-link 600 OFF; d-link 600 OFF; d-link 600 OFF; d-link 600 OFF */
+
+int de6cprobe();
+void de6cattach();
+int de6cintr();
+int de6cinit();
+int de6coutput();
+int de6cioctl();
+int de6creset();
+void de6cwatch();
+
+static vm_offset_t de6c_std[NDE6C] = { 0 };
+static struct bus_device *de6c_info[NDE6C];
+
+#ifdef MACH_KERNEL
+struct bus_driver de6cdriver =
+ {de6cprobe, 0, de6cattach, 0, de6c_std, "de", de6c_info, };
+extern struct bus_device *lprinfo[];
+
+#define MM io_req_t
+#define PIC sysdep1
+#define DEV bus_device
+#else MACH_KERNEL
+int (*de6cintrs[])() = { de6cintr, 0};
+struct isa_driver de6cdriver =
+ {de6cprobe, 0, de6cattach, "de", 0, 0, 0};
+extern struct isa_dev *lprinfo[];
+
+#define MM struct mbuf *
+#define PIC dev_pic
+#define DEV isa_dev
+#endif MACH_KERNEL
+
+int watchdog_id;
+
+typedef struct {
+#ifdef MACH_KERNEL
+ struct ifnet ds_if; /* generic interface header */
+ u_char ds_addr[6]; /* Ethernet hardware address */
+#else MACH_KERNEL
+ struct arpcom de6c_ac;
+#define ds_if de6c_ac.ac_if
+#define ds_addr de6c_ac.ac_enaddr
+#endif MACH_KERNEL
+ int flags;
+ int timer;
+ u_char address[6];
+ short mode;
+ int port;
+ int latency;
+ int xmt;
+ int rcv;
+ int rcvoff;
+ int rcvspin;
+/* d-link 600 ON; d-link 600 ON; d-link 600 ON; d-link 600 ON */
+/* d-link 600 ON; d-link 600 ON; d-link 600 ON; d-link 600 ON */
+ int produce;
+ int consume;
+ int rcvlen[XMTidx];
+ int alive;
+/* d-link 600 OFF; d-link 600 OFF; d-link 600 OFF; d-link 600 OFF */
+/* d-link 600 OFF; d-link 600 OFF; d-link 600 OFF; d-link 600 OFF */
+ int (*oldvect)();
+ int oldunit;
+} de6c_softc_t;
+
+de6c_softc_t de6c_softc[NDE6C];
+
+int de6cactive[NDE6C];
+
+/*
+ * Patch to change latency value
+ */
+int de6c_latency = 30; /* works on NEC Versa (pottsylvania.mach) */
+
+#ifdef DEBUG
+int de6crcv0, de6crcv1, de6crcv2, de6crcv3;
+int de6cdo_rcvintr = 0, de6cdo_watch = 0;
+int de6cdo_xmt = 0;
+#define D(X) X
+#else /* DEBUG */
+#define D(X)
+#endif /* DEBUG */
+
+/*
+ * de6cprobe:
+ * We are not directly probed. The lprattach will call de6cattach.
+ * But what we have is plausible for a probe.
+ */
+de6cprobe(port, dev)
+struct DEV *dev;
+{
+#ifdef MACH_KERNEL
+ int unit = dev->unit;
+#else MACH_KERNEL
+ int unit = dev->dev_unit;
+#endif MACH_KERNEL
+
+ if ((unit < 0) || (unit >= NDE6C)) {
+ return(0);
+ }
+ return(1);
+}
+
+/*
+ * de6cattach:
+ *
+ * Called from lprattach
+ *
+ */
+void de6cattach(dev)
+#ifdef MACH_KERNEL
+struct bus_device *dev;
+#else MACH_KERNEL
+struct isa_dev *dev;
+#endif MACH_KERNEL
+{
+ de6c_softc_t *sp;
+ struct ifnet *ifp;
+#ifdef MACH_KERNEL
+ int unit = dev->unit;
+ int port = (int)dev->address;
+#else MACH_KERNEL
+ int unit = dev->dev_unit;
+ int port = (int)dev->dev_addr;
+#endif MACH_KERNEL
+
+ sp = &de6c_softc[unit];
+ sp->port = port;
+ sp->timer = -1;
+ sp->flags = 0;
+ sp->mode = 0;
+
+ ifp = &(sp->ds_if);
+ ifp->if_unit = unit;
+ ifp->if_mtu = ETHERMTU;
+ ifp->if_flags = IFF_BROADCAST;
+
+#ifdef MACH_KERNEL
+ ifp->if_header_size = sizeof(struct ether_header);
+ ifp->if_header_format = HDR_ETHERNET;
+ ifp->if_address_size = 6;
+ ifp->if_address = (char *)&sp->address[0];
+ if_init_queues(ifp);
+#else MACH_KERNEL
+ ifp->if_name = "de";
+ ifp->if_init = de6cinit;
+ ifp->if_output = de6coutput;
+ ifp->if_ioctl = de6cioctl;
+ ifp->if_reset = de6creset;
+ ifp->if_next = NULL;
+ if_attach(ifp);
+#endif MACH_KERNEL
+
+ sp->alive = de6calive(sp);
+}
+
+de6calive(sp)
+de6c_softc_t *sp;
+{
+ int port = sp->port;
+ int unit = sp->ds_if.if_unit;
+ struct DEV *dev = lprinfo[unit];
+ int i;
+
+#ifdef MACH_KERNEL
+#else /* MACH_KERNEL */
+ extern int tcp_recvspace; /* empircal messure */
+#endif /* MACH_KERNEL */
+
+/* d-link 600 ON; d-link 600 ON; d-link 600 ON; d-link 600 ON */
+/* d-link 600 ON; d-link 600 ON; d-link 600 ON; d-link 600 ON */
+ de6coutb(sp, CMD(port), SLT_NIC);
+ DATA_OUT(sp, port, COMMAND, RESET);
+ DATA_OUT(sp, port, COMMAND, STOP_RESET);
+ sp->latency = 101;
+ if (!de6cgetid(sp, sp->ds_addr)) {
+ de6coutb(sp, CMD(port), SLT_PRN);
+ return 0;
+ }
+
+#ifdef MACH_KERNEL
+#else /* MACH_KERNEL */
+ tcp_recvspace = 0x300; /* empircal messure */
+#endif /* MACH_KERNEL */
+
+#ifdef de6cwrite
+ sp->latency = de6c_latency;
+#else /* de6cwrite */
+ sp->latency = 0;
+#endif /* de6cwrite */
+
+ for (i = 0; i++ < 10;) {
+ if (de6cmemcheck(sp))
+ break;
+ sp->latency += 10;
+ }
+
+ de6cgetid(sp, sp->ds_addr);
+ de6cgetid(sp, sp->address);
+ de6csetid(sp, sp->address);
+ de6coutb(sp, CMD(port), SLT_PRN);
+/* d-link 600 OFF; d-link 600 OFF; d-link 600 OFF; d-link 600 OFF */
+/* d-link 600 OFF; d-link 600 OFF; d-link 600 OFF; d-link 600 OFF */
+
+#ifdef MACH_KERNEL
+#if NPAR > 0
+ printf("\n");
+#endif /* NPAR > 0 */
+ printf(" de%d: at lpr%d, port = %x, spl = %d, pic = %d. ",
+ unit, unit, dev->address, dev->sysdep, dev->sysdep1);
+
+ printf("ethernet id [%x:%x:%x:%x:%x:%x]",
+ sp->address[0],sp->address[1],sp->address[2],
+ sp->address[3],sp->address[4],sp->address[5]);
+
+ if (sp->latency > 1) {
+ printf("\n");
+ printf(" LATENCY = %d", sp->latency);
+ printf(" LATENCY = %d", sp->latency);
+ printf(" LATENCY = %d", sp->latency);
+ printf(" LATENCY = %d", sp->latency);
+ }
+#else MACH_KERNEL
+ printf("de%d: port = %x, spl = %d, pic = %d. ",
+ unit, dev->dev_addr, dev->dev_spl, dev->dev_pic);
+
+ printf("ethernet id [%x:%x:%x:%x:%x:%x]\n",
+ sp->address[0],sp->address[1],sp->address[2],
+ sp->address[3],sp->address[4],sp->address[5]);
+
+ if (sp->latency > 1) {
+ printf("de%d:", unit);
+ printf(" LATENCY = %d", sp->latency);
+ printf(" LATENCY = %d", sp->latency);
+ printf(" LATENCY = %d", sp->latency);
+ printf(" LATENCY = %d", sp->latency);
+ printf("\n");
+ }
+#endif MACH_KERNEL
+
+ return 1;
+}
+
+/*
+ * de6cwatch():
+ *
+ */
+void de6cwatch(b_ptr)
+short *b_ptr;
+{
+#ifdef DEBUG_MORE
+ int unit = *b_ptr;
+ de6c_softc_t *sp = &de6c_softc[unit];
+
+ if(!de6cdo_watch) return;
+ de6cintr(unit);
+ if (sp->ds_if.if_flags & IFF_RUNNING)
+ timeout(de6cwatch, b_ptr, de6cdo_watch);
+#endif /* DEBUG_MORE */
+}
+
+#ifdef MACH_KERNEL
+void de6cstart(int); /* forward */
+
+de6coutput(dev, ior)
+ dev_t dev;
+ io_req_t ior;
+{
+ register int unit = minor(dev);
+
+ if (unit < 0 || unit >= NDE6C ||
+ de6c_softc[unit].port == 0)
+ return (ENXIO);
+
+ return (net_write(&de6c_softc[unit].ds_if, de6cstart, ior));
+}
+
+io_return_t
+de6csetinput(
+ dev_t dev,
+ mach_port_t receive_port,
+ int priority,
+ filter_t filter[],
+ natural_t filter_count)
+{
+ register int unit = minor(dev);
+
+ if (unit < 0 || unit >= NDE6C ||
+ de6c_softc[unit].port == 0)
+ return ENXIO;
+
+ return net_set_filter(&de6c_softc[unit].ds_if,
+ receive_port, priority,
+ filter, filter_count);
+}
+
+#else MACH_KERNEL
+/*
+ * de6coutput:
+ *
+ * This routine is called by the "if" layer to output a packet to
+ * the network. This code resolves the local ethernet address, and
+ * puts it into the mbuf if there is room. If not, then a new mbuf
+ * is allocated with the header information and precedes the data
+ * to be transmitted.
+ *
+ * input: ifnet structure pointer, an mbuf with data, and address
+ * to be resolved
+ * output: mbuf is updated to hold enet address, or a new mbuf
+ * with the address is added
+ *
+ */
+de6coutput(ifp, m0, dst)
+struct ifnet *ifp;
+struct mbuf *m0;
+struct sockaddr *dst;
+{
+ register de6c_softc_t *sp = &de6c_softc[ifp->if_unit];
+ int type, opri, error;
+ u_char edst[6];
+ struct in_addr idst;
+ register struct mbuf *m = m0;
+ register struct ether_header *eh;
+ register int off;
+ int usetrailers;
+
+ if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) {
+ de6cintoff(ifp->if_unit);
+ error = ENETDOWN;
+ goto bad;
+ }
+ switch (dst->sa_family) {
+
+#ifdef INET
+ case AF_INET:
+ idst = ((struct sockaddr_in *)dst)->sin_addr;
+ if (!arpresolve(&sp->de6c_ac, m, &idst, edst, &usetrailers)){
+ return (0); /* if not yet resolved */
+ }
+ off = ntohs((u_short)mtod(m, struct ip *)->ip_len) - m->m_len;
+
+ if (usetrailers && off > 0 && (off & 0x1ff) == 0 &&
+ m->m_off >= MMINOFF + 2 * sizeof (u_short)) {
+ type = ETHERTYPE_TRAIL + (off>>9);
+ m->m_off -= 2 * sizeof (u_short);
+ m->m_len += 2 * sizeof (u_short);
+ *mtod(m, u_short *) = htons((u_short)ETHERTYPE_IP);
+ *(mtod(m, u_short *) + 1) = htons((u_short)m->m_len);
+ goto gottrailertype;
+ }
+ type = ETHERTYPE_IP;
+ off = 0;
+ goto gottype;
+#endif
+#ifdef NS
+ case AF_NS:
+ type = ETHERTYPE_NS;
+ bcopy((caddr_t)&(((struct sockaddr_ns *)dst)->sns_addr.x_host),
+ (caddr_t)edst, sizeof (edst));
+ off = 0;
+ goto gottype;
+#endif
+
+ case AF_UNSPEC:
+ eh = (struct ether_header *)dst->sa_data;
+ bcopy((caddr_t)eh->ether_dhost, (caddr_t)edst, sizeof (edst));
+ type = eh->ether_type;
+ goto gottype;
+
+ default:
+ printf("de6c%d: can't handle af%d\n", ifp->if_unit,
+ dst->sa_family);
+ error = EAFNOSUPPORT;
+ goto bad;
+ }
+
+gottrailertype:
+ /*
+ * Packet to be sent as trailer: move first packet
+ * (control information) to end of chain.
+ */
+ while (m->m_next)
+ m = m->m_next;
+ m->m_next = m0;
+ m = m0->m_next;
+ m0->m_next = 0;
+ m0 = m;
+
+gottype:
+ /*
+ * Add local net header. If no space in first mbuf,
+ * allocate another.
+ */
+ if (m->m_off > MMAXOFF ||
+ MMINOFF + sizeof (struct ether_header) > m->m_off) {
+ m = m_get(M_DONTWAIT, MT_HEADER);
+ if (m == 0) {
+ error = ENOBUFS;
+ goto bad;
+ }
+ m->m_next = m0;
+ m->m_off = MMINOFF;
+ m->m_len = sizeof (struct ether_header);
+ } else {
+ m->m_off -= sizeof (struct ether_header);
+ m->m_len += sizeof (struct ether_header);
+ }
+ eh = mtod(m, struct ether_header *);
+ eh->ether_type = htons((u_short)type);
+ bcopy((caddr_t)edst, (caddr_t)eh->ether_dhost, sizeof (edst));
+ bcopy((caddr_t)sp->address,(caddr_t)eh->ether_shost, sizeof(edst));
+ /*
+ * Queue message on interface, and start output if interface
+ * not yet active.
+ */
+ opri = SPLNET();
+ if (IF_QFULL(&ifp->if_snd)) {
+ IF_DROP(&ifp->if_snd);
+ splx(opri);
+ m_freem(m);
+ return (ENOBUFS);
+ }
+ IF_ENQUEUE(&ifp->if_snd, m);
+ de6cstart(ifp->if_unit);
+ splx(opri);
+ return (0);
+
+bad:
+ m_freem(m0);
+ return (error);
+}
+#endif MACH_KERNEL
+
+/*
+ * de6creset:
+ *
+ * This routine is in part an entry point for the "if" code. Since most
+ * of the actual initialization has already (we hope already) been done
+ * by calling de6cattach().
+ *
+ * input : unit number or board number to reset
+ * output : board is reset
+ *
+ */
+de6creset(unit)
+int unit;
+{
+ de6c_softc[unit].ds_if.if_flags &= ~IFF_RUNNING;
+ return(de6cinit(unit));
+}
+
+
+
+/*
+ * de6cinit:
+ *
+ * Another routine that interfaces the "if" layer to this driver.
+ * Simply resets the structures that are used by "upper layers".
+ *
+ * input : board number
+ * output : structures (if structs) and board are reset
+ *
+ */
+de6cinit(unit)
+int unit;
+{
+ de6c_softc_t *sp = &de6c_softc[unit];
+ struct ifnet *ifp = &(sp->ds_if);
+ int port = sp->port;
+ int pic = lprinfo[unit]->PIC;
+ spl_t oldpri;
+
+#ifdef MACH_KERNEL
+#else MACH_KERNEL
+ if (ifp->if_addrlist == (struct ifaddr *)0) {
+ return;
+ }
+#endif MACH_KERNEL
+ oldpri = SPLNET();
+
+ if (ivect[pic] != de6cintr) {
+ sp->oldvect = ivect[pic];
+ ivect[pic] = de6cintr;
+ sp->oldunit = iunit[pic];
+ iunit[pic] = unit;
+ }
+
+/* d-link 600 ON; d-link 600 ON; d-link 600 ON; d-link 600 ON */
+/* d-link 600 ON; d-link 600 ON; d-link 600 ON; d-link 600 ON */
+ sp->consume = 0;
+ sp->produce = 0;
+ de6coutb(sp, CMD(port), SLT_NIC);
+ DATA_OUT(sp, port, COMMAND, RESET);
+ DATA_OUT(sp, port, COMMAND, STOP_RESET);
+ de6coutb(sp, CMD(port), IRQEN);
+ DATA_OUT(sp, port, COMMAND, RX_BP|(sp->produce<<4));
+ DATA_OUT(sp, port, COMMAND, RX_BP|(sp->produce<<4)|RXEN);
+ de6coutb(sp, CMD(port), SLT_PRN);
+#if 0
+ if (sp->mode & IFF_PROMISC) {
+ /* handle promiscuous case */;
+ }
+#endif 0
+/* d-link 600 OFF; d-link 600 OFF; d-link 600 OFF; d-link 600 OFF */
+/* d-link 600 OFF; d-link 600 OFF; d-link 600 OFF; d-link 600 OFF */
+ sp->ds_if.if_flags |= IFF_RUNNING;
+ sp->flags |= DSF_RUNNING;
+ sp->timer = 5;
+ timeout(de6cwatch, &(ifp->if_unit), 3);
+ de6cstart(unit);
+ splx(oldpri);
+}
+
+#ifdef MACH_KERNEL
+/*ARGSUSED*/
+de6copen(dev, flag)
+ dev_t dev;
+ int flag;
+{
+ register int unit = minor(dev);
+
+ if (unit < 0 || unit >= NDE6C ||
+ de6c_softc[unit].port == 0)
+ return (ENXIO);
+
+ de6c_softc[unit].ds_if.if_flags |= IFF_UP;
+ de6cinit(unit);
+ return(0);
+}
+#endif MACH_KERNEL
+
+/*
+ * de6cstart:
+ *
+ * This is yet another interface routine that simply tries to output a
+ * in an mbuf after a reset.
+ *
+ * input : board number
+ * output : stuff sent to board if any there
+ *
+ */
+
+/* NOTE: called at SPLNET */
+void de6cstart(
+ int unit)
+{
+ struct ifnet *ifp = &(de6c_softc[unit].ds_if);
+ MM m;
+
+ for(;;) {
+ IF_DEQUEUE(&ifp->if_snd, m);
+ if (m != (MM) 0)
+ de6cxmt(unit, m);
+ else
+ return;
+ }
+}
+
+#ifdef MACH_KERNEL
+/*ARGSUSED*/
+io_return_t
+de6cgetstat(
+ dev_t dev,
+ int flavor,
+ dev_status_t status, /* pointer to OUT array */
+ natural_t *count) /* out */
+{
+ register int unit = minor(dev);
+ register de6c_softc_t *sp;
+
+ if (unit < 0 || unit >= NDE6C ||
+ de6c_softc[unit].port == 0)
+ return (ENXIO);
+
+ sp = &de6c_softc[unit];
+ if (! sp->alive)
+ if (! (sp->alive = de6calive(sp)))
+ return ENXIO;
+
+ return (net_getstat(&de6c_softc[unit].ds_if,
+ flavor,
+ status,
+ count));
+}
+
+io_return_t
+de6csetstat(
+ dev_t dev,
+ int flavor,
+ dev_status_t status,
+ natural_t count)
+{
+ register int unit = minor(dev);
+ register de6c_softc_t *sp;
+
+ if (unit < 0 || unit >= NDE6C ||
+ de6c_softc[unit].port == 0)
+ return (ENXIO);
+
+ sp = &de6c_softc[unit];
+ if (! sp->alive)
+ if (! (sp->alive = de6calive(sp)))
+ return ENXIO;
+
+
+ switch (flavor) {
+ case NET_STATUS:
+ {
+ /*
+ * All we can change are flags, and not many of those.
+ */
+ register struct net_status *ns = (struct net_status *)status;
+ int mode = 0;
+
+ if (count < NET_STATUS_COUNT)
+ return (D_INVALID_SIZE);
+
+ if (ns->flags & IFF_ALLMULTI)
+ mode |= MOD_ENAL;
+ if (ns->flags & IFF_PROMISC)
+ mode |= MOD_PROM;
+
+ /*
+ * Force a compilete reset if the receive mode changes
+ * so that these take effect immediately.
+ */
+ if (sp->mode != mode) {
+ sp->mode = mode;
+ if (sp->flags & DSF_RUNNING) {
+ sp->flags &= ~(DSF_LOCK | DSF_RUNNING);
+ de6cinit(unit);
+ }
+ }
+ break;
+ }
+ case NET_ADDRESS:
+ {
+ register union ether_cvt {
+ char addr[6];
+ int lwd[2];
+ } *ec = (union ether_cvt *)status;
+
+ if (count < sizeof(*ec)/sizeof(int))
+ return (D_INVALID_SIZE);
+
+ ec->lwd[0] = ntohl(ec->lwd[0]);
+ ec->lwd[1] = ntohl(ec->lwd[1]);
+ de6csetid(sp->port, ec->addr);
+ break;
+ }
+
+ default:
+ return (D_INVALID_OPERATION);
+ }
+ return (D_SUCCESS);
+}
+#else MACH_KERNEL
+
+/*
+ * de6cioctl:
+ *
+ * This routine processes an ioctl request from the "if" layer
+ * above.
+ *
+ * input : pointer the appropriate "if" struct, command, and data
+ * output : based on command appropriate action is taken on the
+ * de6c board(s) or related structures
+ * return : error is returned containing exit conditions
+ *
+ */
+de6cioctl(ifp, cmd, data)
+struct ifnet *ifp;
+int cmd;
+caddr_t data;
+{
+ register struct ifaddr *ifa = (struct ifaddr *)data;
+ register de6c_softc_t *sp = &de6c_softc[ifp->if_unit];
+ int opri, error;
+ short mode = 0;
+
+ if (! sp->alive)
+ if (! (sp->alive = de6calive(sp)))
+ return ENXIO;
+
+ opri = SPLNET();
+ error = 0;
+ switch (cmd) {
+ case SIOCSIFADDR:
+ ifp->if_flags |= IFF_UP;
+ de6cinit(ifp->if_unit);
+ switch (ifa->ifa_addr.sa_family) {
+#ifdef INET
+ case AF_INET:
+ ((struct arpcom *)ifp)->ac_ipaddr =
+ IA_SIN(ifa)->sin_addr;
+ arpwhohas((struct arpcom *)ifp,
+ &IA_SIN(ifa)->sin_addr);
+ break;
+#endif
+#ifdef NS
+ case AF_NS:
+ {
+ register struct ns_addr *ina =
+ &(IA_SNS(ifa)->sns_addr);
+ if (ns_nullhost(*ina))
+ ina->x_host =
+ *(union ns_host *)(ds->ds_addr);
+ else
+ de6cseteh(ina->x_host.c_host,
+ de6c_softc[ifp->if_unit].port);
+ break;
+ }
+#endif
+ }
+ break;
+ case SIOCSIFFLAGS:
+ if (ifp->if_flags & IFF_ALLMULTI)
+ mode |= MOD_ENAL;
+ if (ifp->if_flags & IFF_PROMISC)
+ mode |= MOD_PROM;
+ /*
+ * force a complete reset if the receive multicast/
+ * promiscuous mode changes so that these take
+ * effect immediately.
+ *
+ */
+ if (sp->mode != mode) {
+ sp->mode = mode;
+ if (sp->flags & DSF_RUNNING) {
+ sp->flags &=
+ ~(DSF_LOCK|DSF_RUNNING);
+ de6cinit(ifp->if_unit);
+ }
+ }
+ if ((ifp->if_flags & IFF_UP) == 0 &&
+ sp->flags & DSF_RUNNING) {
+ sp->timer = -1;
+ de6cintoff(ifp->if_unit);
+ } else
+ if (ifp->if_flags & IFF_UP &&
+ (sp->flags & DSF_RUNNING) == 0)
+ de6cinit(ifp->if_unit);
+ break;
+ default:
+ error = EINVAL;
+ }
+ splx(opri);
+ return (error);
+}
+#endif MACH_KERNEL
+
+/*
+ * de6cintr:
+ *
+ * This function is the interrupt handler for the de6c ethernet
+ * board. This routine will be called whenever either a packet
+ * is received, or a packet has successfully been transfered and
+ * the unit is ready to transmit another packet.
+ *
+ * input : board number that interrupted
+ * output : either a packet is received, or a packet is transfered
+ *
+ */
+/* d-link 600 ON; d-link 600 ON; d-link 600 ON; d-link 600 ON */
+/* d-link 600 ON; d-link 600 ON; d-link 600 ON; d-link 600 ON */
+#ifdef DEBUG_MORE
+de6crcvintr(unit)
+int unit;
+{
+ if(!de6cdo_rcvintr)
+ return;
+ de6cintr(unit);
+}
+#endif /* DEBUG_MORE */
+
+de6cintr(unit)
+int unit;
+{
+ register de6c_softc_t *sp = &de6c_softc[unit];
+ int port = sp->port;
+ int in;
+
+ if (de6cactive[unit] || !(sp->flags & DSF_RUNNING))
+ return;
+ de6cactive[unit]++;
+ de6coutb(sp, CMD(port), SLT_NIC);
+ STAT_IN(sp, port, in);
+
+ if ((in & (GOOD|TXBUSY)) == (GOOD|TXBUSY)) {
+ /* on L40's means that we are disconnected */
+ printf("de6intr%d: Card was disconnected; turning off network.\n", unit);
+ de6cintoff(unit);
+ de6cactive[unit]--;
+ return;
+ }
+
+ if (in & GOOD)
+ de6crcv(unit, in);
+ else
+/*rvb:tmp printf("intr: %x\n", in)*/;
+
+
+ de6coutb(sp, CMD(port), SLT_PRN);
+ de6cactive[unit]--;
+}
+/* d-link 600 OFF; d-link 600 OFF; d-link 600 OFF; d-link 600 OFF */
+/* d-link 600 OFF; d-link 600 OFF; d-link 600 OFF; d-link 600 OFF */
+
+/*
+ * de6crcv:
+ *
+ * This routine is called by the interrupt handler to initiate a
+ * packet transfer from the board to the "if" layer above this
+ * driver. This routine checks if a buffer has been successfully
+ * received by the de6c. If so, the routine de6cread is called
+ * to do the actual transfer of the board data (including the
+ * ethernet header) into a packet (consisting of an mbuf chain).
+ *
+ * input : number of the board to check
+ * output : if a packet is available, it is "sent up"
+ *
+ */
+de6crcv(unit, in)
+int unit, in;
+{
+ register de6c_softc_t *sp = &de6c_softc[unit];
+ register struct ifnet *ifp = &sp->ds_if;
+ int port = sp->port;
+ int bo;
+ int collision = 0;
+ int spins = 0;
+ u_short len;
+ struct ether_header header;
+ int tlen;
+ register struct ifqueue *inq;
+ int opri;
+ struct ether_header eh;
+#ifdef MACH_KERNEL
+ ipc_kmsg_t new_kmsg;
+ struct ether_header *ehp;
+ struct packet_header *pkt;
+#else MACH_KERNEL
+ struct mbuf *m, *tm;
+#endif MACH_KERNEL
+
+ sp->rcv++;
+
+/* d-link 600 ON; d-link 600 ON; d-link 600 ON; d-link 600 ON */
+/* d-link 600 ON; d-link 600 ON; d-link 600 ON; d-link 600 ON */
+ D(de6crcv0++);
+#define MT (sp->consume == sp->produce)
+ while (in & GOOD || !MT) {
+ spins++;
+ D(de6crcv1++);
+ if (in & GOOD) {
+ sp->rcvlen[sp->produce] = de6clen(sp);
+ if ( ((sp->produce + 1) % XMTidx) != sp->consume) {
+ if (++sp->produce == XMTidx)
+ sp->produce = 0;
+ DATA_OUT(sp, port, COMMAND, RX_BP|(sp->produce<<4));
+ DATA_OUT(sp, port, COMMAND, RX_BP|(sp->produce<<4)|RXEN);
+ } else collision = 1;
+ }
+ len = sp->rcvlen[sp->consume];
+ bo = sp->consume*BFRSIZ;
+ if (len < 60) {
+ printf("de%d: len(%d) < 60\n", unit, len);
+ goto out;
+ return;
+ }
+ de6cread(sp, bo, &eh, sizeof(struct ether_header));
+ bo += sizeof(struct ether_header);
+ len -= 18;
+/* d-link 600 OFF; d-link 600 OFF; d-link 600 OFF; d-link 600 OFF */
+/* d-link 600 OFF; d-link 600 OFF; d-link 600 OFF; d-link 600 OFF */
+
+#ifdef MACH_KERNEL
+ new_kmsg = net_kmsg_get();
+ if (new_kmsg == IKM_NULL) {
+ /*
+ * Drop the packet.
+ */
+ sp->ds_if.if_rcvdrops++;
+ goto out;
+ return;
+ }
+
+ ehp = (struct ether_header *)
+ (&net_kmsg(new_kmsg)->header[0]);
+ pkt = (struct packet_header *)
+ (&net_kmsg(new_kmsg)->packet[0]);
+
+ /*
+ * Get header.
+ */
+ *ehp = eh;
+
+ /*
+ * Get body
+ */
+/* d-link 600 ON; d-link 600 ON; d-link 600 ON; d-link 600 ON */
+ de6cread(sp, bo, (char *)(pkt + 1), len);
+/* d-link 600 OFF; d-link 600 OFF; d-link 600 OFF; d-link 600 OFF */
+ pkt->type = ehp->ether_type;
+ pkt->length = len + sizeof(struct packet_header);
+
+ /*
+ * Hand the packet to the network module.
+ */
+ net_packet(ifp, new_kmsg, pkt->length,
+ ethernet_priority(new_kmsg));
+
+#else MACH_KERNEL
+ eh.ether_type = htons(eh.ether_type);
+ m =(struct mbuf *)0;
+ while ( len ) {
+ if (m == (struct mbuf *)0) {
+ m = m_get(M_DONTWAIT, MT_DATA);
+ if (m == (struct mbuf *)0) {
+ printf("de6crcv: Lost frame\n");
+ goto out;
+ return;
+ }
+ tm = m;
+ tm->m_off = MMINOFF;
+ /*
+ * first mbuf in the packet must contain a pointer to the
+ * ifnet structure. other mbufs that follow and make up
+ * the packet do not need this pointer in the mbuf.
+ *
+ */
+ *(mtod(tm, struct ifnet **)) = ifp;
+ tm->m_len = sizeof(struct ifnet **);
+ }
+ else {
+ tm->m_next = m_get(M_DONTWAIT, MT_DATA);
+ tm = tm->m_next;
+ tm->m_off = MMINOFF;
+ tm->m_len = 0;
+ if (tm == (struct mbuf *)0) {
+ m_freem(m);
+ printf("de6crcv: No mbufs, lost frame\n");
+ goto out;
+ return;
+ }
+ }
+ tlen = MIN( MLEN - tm->m_len, len );
+ tm->m_next = (struct mbuf *)0;
+/* d-link 600 ON; d-link 600 ON; d-link 600 ON; d-link 600 ON */
+ de6cread(sp, bo, mtod(tm, char *)+tm->m_len, tlen);
+ bo += tlen;
+/* d-link 600 OFF; d-link 600 OFF; d-link 600 OFF; d-link 600 OFF */
+ tm->m_len += tlen;
+ len -= tlen;
+ }
+/* d-link 600 ON; d-link 600 ON; d-link 600 ON; d-link 600 ON */
+/* d-link 600 ON; d-link 600 ON; d-link 600 ON; d-link 600 ON */
+ STAT_IN(sp, port, in);
+ if (in & GOOD) { /* got another */
+ D(de6crcv2++);
+ sp->rcvlen[sp->produce] = de6clen(sp);
+ if ( ((sp->produce + 1) % XMTidx) != sp->consume) {
+ if (++sp->produce == XMTidx)
+ sp->produce = 0;
+ DATA_OUT(sp, port, COMMAND, RX_BP|(sp->produce<<4));
+ DATA_OUT(sp, port, COMMAND, RX_BP|(sp->produce<<4)|RXEN);
+ } else collision = 1;
+ }
+/* d-link 600 OFF; d-link 600 OFF; d-link 600 OFF; d-link 600 OFF */
+/* d-link 600 OFF; d-link 600 OFF; d-link 600 OFF; d-link 600 OFF */
+
+ /*
+ * received packet is now in a chain of mbuf's. next step is
+ * to pass the packet upwards.
+ *
+ */
+ switch (eh.ether_type) {
+
+#ifdef INET
+ case ETHERTYPE_IP:
+ schednetisr(NETISR_IP);
+ inq = &ipintrq;
+ break;
+ case ETHERTYPE_ARP:
+ arpinput(&sp->de6c_ac, m);
+ goto out;
+ return;
+#endif
+#ifdef NS
+ case ETHERTYPE_NS:
+ schednetisr(NETISR_NS);
+ inq = &nsintrq;
+ break;
+#endif
+ default:
+ m_freem(m);
+ goto out;
+ return;
+ }
+ opri = SPLNET();
+ if (IF_QFULL(inq)) {
+ IF_DROP(inq);
+ splx(opri);
+ m_freem(m);
+ goto out;
+ return;
+ }
+ IF_ENQUEUE(inq, m);
+ splx(opri);
+#endif MACH_KERNEL
+out:
+/* d-link 600 ON; d-link 600 ON; d-link 600 ON; d-link 600 ON */
+/* d-link 600 ON; d-link 600 ON; d-link 600 ON; d-link 600 ON */
+ STAT_IN(sp, port, in);
+ if (in & GOOD) { /* got another */
+ D(de6crcv3++);
+ }
+/*2*/ /* implies wrap and pause */
+ if (collision) {
+ collision = 0;
+ D(printf("*C* "));
+ sp->rcvoff++;
+ if (++sp->produce == XMTidx)
+ sp->produce = 0;
+ DATA_OUT(sp, port, COMMAND, RX_BP|(sp->produce<<4));
+ DATA_OUT(sp, port, COMMAND, RX_BP|(sp->produce<<4)|RXEN);
+ }
+/*2*/ /* implies wrap and pause */
+ if (++sp->consume == XMTidx)
+ sp->consume = 0;
+ if (spins > 10) {
+ spins = 0;
+ D(printf("*R* "));
+ sp->rcvspin++;
+ /* how should we recover here ??? */;
+ /* return does not work */;
+ /* de6cinit(unit) gets ugly if we are called from
+ de6cxmt */;
+ }
+/* d-link 600 OFF; d-link 600 OFF; d-link 600 OFF; d-link 600 OFF */
+/* d-link 600 OFF; d-link 600 OFF; d-link 600 OFF; d-link 600 OFF */
+ }
+}
+
+
+/*
+ * de6cxmt:
+ *
+ * This routine fills in the appropriate registers and memory
+ * locations on the d-link "600" board and starts the board off on
+ * the transmit.
+ *
+ * input : board number of interest, and a pointer to the mbuf
+ * output : board memory and registers are set for xfer and attention
+ *
+ */
+/* NOTE: called at SPLNET */
+/*
+ * This implies that rcv interrupts will be blocked.
+ */
+#define max(a,b) (((a) > (b)) ? (a) : (b))
+
+char de6mt[ETHERMIN];
+de6cxmt(unit, m)
+int unit;
+MM m;
+{
+#ifdef MACH_KERNEL
+#else MACH_KERNEL
+ register struct mbuf *tm_p;
+#endif MACH_KERNEL
+ int i;
+ int in;
+ int bo, boo;
+ de6c_softc_t *sp = &de6c_softc[unit];
+ int port = sp->port;
+ u_short count = 0;
+ u_short bytes_in_msg;
+ static int m_length();
+
+/* d-link 600 ON; d-link 600 ON; d-link 600 ON; d-link 600 ON */
+/* d-link 600 ON; d-link 600 ON; d-link 600 ON; d-link 600 ON */
+ if (de6cactive[unit] >= 2) /* a funny loop caused by */
+ return; /* a flood of arps */
+ if (de6cactive[unit]++ == 0)
+ de6coutb(sp, CMD(port), SLT_NIC);
+ STAT_IN(sp, port, in);
+
+ D(if (de6cdo_xmt) printf("xmt: stat[-] = %x\n", in));
+ if (in & GOOD) {
+ de6crcv(unit, in);
+ }
+ sp->xmt++;
+/* d-link 600 OFF; d-link 600 OFF; d-link 600 OFF; d-link 600 OFF */
+/* d-link 600 OFF; d-link 600 OFF; d-link 600 OFF; d-link 600 OFF */
+
+#ifdef MACH_KERNEL
+ count = m->io_count;
+ bytes_in_msg = max(count, ETHERMIN + sizeof(struct ether_header));
+/* d-link 600 ON; d-link 600 ON; d-link 600 ON; d-link 600 ON */
+ boo = bo = XMTidx*BFRSIZ+(BFRSIZ-bytes_in_msg);
+ de6cwrite(sp, bo, m->io_data, count);
+/* d-link 600 OFF; d-link 600 OFF; d-link 600 OFF; d-link 600 OFF */
+ bo += count;
+ iodone(m);
+#else MACH_KERNEL
+ bytes_in_msg = max(m_length(m), ETHERMIN + sizeof(struct ether_header));
+/* d-link 600 ON; d-link 600 ON; d-link 600 ON; d-link 600 ON */
+ boo = bo = XMTidx*BFRSIZ+(BFRSIZ-bytes_in_msg);
+/* d-link 600 OFF; d-link 600 OFF; d-link 600 OFF; d-link 600 OFF */
+
+ for (tm_p = m; tm_p != (struct mbuf *)0; tm_p = tm_p->m_next) {
+ if (count + tm_p->m_len > ETHERMTU + sizeof(struct ether_header))
+ break;
+ if (tm_p->m_len == 0)
+ continue;
+/* d-link 600 ON; d-link 600 ON; d-link 600 ON; d-link 600 ON */
+ de6cwrite(sp, bo, mtod(tm_p, caddr_t), tm_p->m_len);
+ bo += tm_p->m_len;
+/* d-link 600 OFF; d-link 600 OFF; d-link 600 OFF; d-link 600 OFF */
+ count += tm_p->m_len;
+ }
+ m_freem(m);
+#endif MACH_KERNEL
+
+/* d-link 600 ON; d-link 600 ON; d-link 600 ON; d-link 600 ON */
+/* d-link 600 ON; d-link 600 ON; d-link 600 ON; d-link 600 ON */
+ if (bytes_in_msg - count > 0)
+ de6cwrite(sp, bo, de6mt, bytes_in_msg - count);
+
+ DATA_OUT(sp, port, TX_ADR, boo & 0xff);
+ DATA_OUT(sp, port, TX_ADR, (boo >> 8) & 0xff);
+ DATA_OUT(sp, port, COMMAND, RX_BP|(sp->produce<<4));
+ DATA_OUT(sp, port, COMMAND, RX_BP|(sp->produce<<4)|TXEN);
+
+ for (i = 0; i < XMT_BSY_WAIT; i++) {
+ STAT_IN(sp, port, in);
+ D(if (de6cdo_xmt) printf("xmt: stat[%d] = %x\n", i, in));
+ if (in & GOOD) {
+ /*
+ * this does indeed happen
+ * printf("!#");
+ */
+ de6crcv(unit, in);
+ }
+ if (!(in & TXBUSY)) {
+ goto out;
+ return;
+ }
+ }
+ printf("dexmt: stat[??] = %x\n", i, in);
+out:
+ DATA_OUT(sp, port, COMMAND, RX_BP|(sp->produce<<4));
+ DATA_OUT(sp, port, COMMAND, RX_BP|(sp->produce<<4)|RXEN);
+
+ if (--de6cactive[unit] == 0)
+ de6coutb(sp, CMD(port), SLT_PRN);
+/* d-link 600 OFF; d-link 600 OFF; d-link 600 OFF; d-link 600 OFF */
+/* d-link 600 OFF; d-link 600 OFF; d-link 600 OFF; d-link 600 OFF */
+}
+
+/*
+ * de6cintoff:
+ *
+ * This function turns interrupts off for the de6c board indicated.
+ *
+ */
+de6cintoff(unit)
+int unit;
+{
+ de6c_softc_t *sp = &de6c_softc[unit];
+ int port = sp->port;
+ int pic = lprinfo[unit]->PIC;
+
+ printf("de%d: Turning off d-link \"600\"\n", unit);
+ sp->ds_if.if_flags &= ~(IFF_UP|IFF_RUNNING);
+ sp->flags &= ~(DSF_LOCK | DSF_RUNNING);
+
+/* d-link 600 ON; d-link 600 ON; d-link 600 ON; d-link 600 ON */
+/* d-link 600 ON; d-link 600 ON; d-link 600 ON; d-link 600 ON */
+ de6coutb(sp, CMD(port), SLT_NIC);
+ DATA_OUT(sp, port, COMMAND, RESET);
+ DATA_OUT(sp, port, COMMAND, STOP_RESET);
+ de6coutb(sp, CMD(port), SLT_PRN);
+/* d-link 600 OFF; d-link 600 OFF; d-link 600 OFF; d-link 600 OFF */
+/* d-link 600 OFF; d-link 600 OFF; d-link 600 OFF; d-link 600 OFF */
+
+ outb(CMD(sp->port), 0x07);
+ ivect[pic] = sp->oldvect;
+ iunit[pic] = sp->oldunit;
+}
+
+#ifdef MACH_KERNEL
+#else MACH_KERNEL
+/*
+ * The length of an mbuf chain
+ */
+static
+m_length(m)
+ register struct mbuf *m;
+{
+ register int len = 0;
+
+ while (m) {
+ len += m->m_len;
+ m = m->m_next;
+ }
+ return len;
+}
+#endif MACH_KERNEL
+
+
+/* d-link 600 ON; d-link 600 ON; d-link 600 ON; d-link 600 ON */
+/* d-link 600 ON; d-link 600 ON; d-link 600 ON; d-link 600 ON */
+de6cgetid(sp, buf)
+de6c_softc_t *sp;
+u_char *buf;
+{
+ de6cread(sp, EADDR, buf, 6);
+ if ((buf[0] != 0x00) || (buf[1] != 0xde) || (buf[2] != 0x15))
+ return 0;
+ buf[0] = 0x80;
+ buf[1] = 0x00;
+ buf[2] = 0xc8;
+ /* for this model d-link we assert 0x70 as the high mfr's nibble. */
+ buf[3] = 0x70 | (buf[3] & 0xf);
+ return 1;
+}
+
+de6csetid(sp, buf)
+de6c_softc_t *sp;
+char *buf;
+{
+ de6cwrite(sp, EADDR, buf, 6);
+}
+
+/*
+ * get length of packet just rcv'd.
+ * includes ether header and crc
+ */
+de6clen(sp)
+de6c_softc_t *sp;
+{
+ int port = sp->port;
+ int in;
+ int i;
+
+ de6coutb(sp, DATA(port), RX_LEN);
+ in = inb(STAT(port));
+ de6coutb(sp, DATA(port), RX_LEN|STROBE);
+ i = ((in>>4) | (inb(STAT(port)) & 0xf0));
+
+ de6coutb(sp, DATA(port), RX_LEN);
+ in = inb(STAT(port));
+ de6coutb(sp, DATA(port), RX_LEN|STROBE);
+ i |= ((in>>4) | (inb(STAT(port)) & 0xf0)) << 8;
+
+ return i;
+}
+
+#if 0
+de6cread(sp, address, buf, len)
+de6c_softc_t *sp;
+unsigned char *buf;
+{
+ int port = sp->port;
+ u_char in;
+
+ DATA_OUT(sp, port, RW_ADR, address & 0xff);
+ DATA_OUT(sp, port, RW_ADR, (address >> 8) & 0xff);
+
+ while (len--) {
+ de6coutb(sp, DATA(port), READ);
+ in = inb(STAT(port));
+ de6coutb(sp, DATA(port), READ|STROBE);
+ *buf++ = ((in>>4) | (inb(STAT(port)) & 0xf0));
+ }
+}
+
+de6cwrite(sp, address, buf, len)
+de6c_softc_t *sp;
+unsigned char *buf;
+{
+ int port = sp->port;
+ int out;
+
+ DATA_OUT(sp, port, RW_ADR, address & 0xff);
+ DATA_OUT(sp, port, RW_ADR, (address >> 8) & 0xff);
+
+ while (len--) {
+ out = *buf++;
+ DATA_OUT(sp, port, WRITE, out);
+
+ }
+}
+#endif 0
+
+#ifndef de6cread
+de6cread(sp, address, buf, len)
+de6c_softc_t *sp;
+unsigned char *buf;
+{
+ int port = sp->port;
+ register volatile int i;
+ unsigned char in;
+
+ outb(port, ((address)<<4) | RW_ADR);
+ i = sp->latency; while (i-- > 0);
+ outb(port, ((address)&0xf0)| RW_ADR | 0x8);
+ i = sp->latency; while (i-- > 0);
+
+ outb(port, ((address>>8)<<4) | RW_ADR);
+ i = sp->latency; while (i-- > 0);
+ outb(port, ((address>>8)&0xf0)| RW_ADR | 0x8);
+ i = sp->latency; while (i-- > 0);
+
+ while (len--) {
+ outb(port, READ);
+ i = sp->latency; while (i-- > 0);
+ in = inb(STAT(port));
+ outb(port, READ|0x08);
+ i = sp->latency; while (i-- > 0);
+ *buf++ = ((in>>4) | (inb(STAT(port)) & 0xf0));
+ }
+}
+#endif /* de6cread */
+
+#ifndef de6cwrite
+de6cwrite(sp, address, buf, len)
+de6c_softc_t *sp;
+unsigned char *buf;
+{
+ int port = sp->port;
+ register volatile int i;
+ unsigned char out;
+
+ outb(port, ((address)<<4) | RW_ADR);
+ i = sp->latency; while (i-- > 0);
+ outb(port, ((address)&0xf0)| RW_ADR | 0x8);
+ i = sp->latency; while (i-- > 0);
+
+ outb(port, ((address>>8)<<4) | RW_ADR);
+ i = sp->latency; while (i-- > 0);
+ outb(port, ((address>>8)&0xf0)| RW_ADR | 0x8);
+ i = sp->latency; while (i-- > 0);
+
+ while (len--) {
+ out = *buf++;
+ outb(port, ((out)<<4) | WRITE);
+ i = sp->latency; while (i-- > 0);
+ outb(port, ((out)&0xf0)| WRITE | 0x8);
+ i = sp->latency; while (i-- > 0);
+ }
+}
+#endif /* de6cwrite */
+
+de6coutb(sp, p, v)
+de6c_softc_t *sp;
+{
+register volatile int i = sp->latency;
+
+ outb(p, v);
+ while (i-- > 0);
+}
+
+de6cmemcheck(sp)
+de6c_softc_t *sp;
+{
+ int i;
+ int off = 0;
+ int ret = 1;
+#ifdef MACH_KERNEL
+ unsigned short *memchk;
+ unsigned short *chkmem;
+ if (kmem_alloc(kernel_map, (vm_offset_t *)&memchk, BFRS * BFRSIZ) !=
+ KERN_SUCCESS ||
+ kmem_alloc(kernel_map, (vm_offset_t *)&chkmem, BFRS * BFRSIZ) !=
+ KERN_SUCCESS) {
+ printf("de6c: memory allocation failure!!\n");
+ return 0;
+ }
+#else /* MACH_KERNEL */
+ unsigned short *memchk = (unsigned short *) kmem_alloc(kernel_map, BFRS * BFRSIZ);
+ unsigned short *chkmem = (unsigned short *) kmem_alloc(kernel_map, BFRS * BFRSIZ);
+ if ( ! ((int) memchk) || ! ((int) chkmem)) {
+ printf("de6c: memory allocation failure!!\n");
+ return 0;
+ }
+#endif /* MACH_KERNEL */
+
+ for (i = 0; i < BFRS * BFRSIZ/sizeof (short); i++)
+ memchk[i] = i;
+ bzero(chkmem, BFRS * BFRSIZ);
+
+
+ for (off = 0; off < BFRS * BFRSIZ; off += BFRSIZ/2) {
+ de6cwrite(sp, off, memchk+(off/sizeof (short)), BFRSIZ/2);
+ de6cread (sp, off, chkmem+(off/sizeof (short)), BFRSIZ/2);
+ }
+
+ for (i = 0; i < BFRS * (BFRSIZ/sizeof (short)); i++)
+ if (memchk[i] != chkmem[i]) {
+ printf("de: tilt:seq [%x:%d] %x != %x\n",
+ i, i, memchk[i], chkmem[i]);
+ ret = 0;
+ break;
+ }
+
+ kmem_free(kernel_map, (vm_offset_t) memchk, BFRS * BFRSIZ);
+ kmem_free(kernel_map, (vm_offset_t) chkmem, BFRS * BFRSIZ);
+
+ return ret;
+}
+/* d-link 600 OFF; d-link 600 OFF; d-link 600 OFF; d-link 600 OFF */
+/* d-link 600 OFF; d-link 600 OFF; d-link 600 OFF; d-link 600 OFF */
+
+#ifdef DEBUG
+#define STATIC
+STATIC int print_pkt(), print_bdy();
+STATIC int print_e_hdr(), print_ip_hdr(), print_ip();
+STATIC int print_ipa(), print_arp(), print_e(), print_chars();
+
+STATIC
+print_pkt(p, len)
+unsigned char *p;
+{
+ int j, k;
+ int type;
+
+ if (len < 18)
+ printf("print_pkt: too small %d\n", len);
+
+ type = print_e_hdr(p);
+
+ switch (type) {
+ case 0x806:
+ print_arp(p+14);
+ break;
+ case 0x800:
+ print_ip(p+14, len - 18);
+ break;
+ default:
+ for (j = 14; j < len; j +=20) {
+ for (k = 0; k < 20; k++)
+ printf("%2x ", p[j+k]);
+ printf("\n");
+ }
+ }
+}
+
+STATIC
+print_bdy(p, len, type)
+unsigned char *p;
+{
+ int j, k;
+
+ if (len < 18)
+ printf("print_pkt: too small %d|n", len);
+
+ switch (type) {
+ case 0x806:
+ print_arp(p);
+ break;
+ case 0x800:
+ print_ip(p, len);
+ break;
+ default:
+ for (j = 0; j < len; j +=20) {
+ for (k = 0; k < 20; k++)
+ printf("%2x ", p[j+k]);
+ printf("\n");
+ }
+ }
+}
+
+STATIC
+print_e_hdr(p)
+unsigned char *p;
+{
+ int type = ntohs(((unsigned short *)p)[6]);
+
+ printf("S=%x:%x:%x:%x:%x:%x, ", p[6], p[7], p[8], p[9], p[10], p[11]);
+ printf("D=%x:%x:%x:%x:%x:%x, ", p[0], p[1], p[2], p[3], p[4], p[5]);
+ printf("T=%x\n", type);
+
+ return type;
+}
+
+STATIC
+print_ip_hdr(u)
+u_char *u;
+{
+
+ int l = ntohs(*(u_short *)(u+2));
+
+ print_ipa(u+12);
+ printf(" -> ");
+ print_ipa(u+12+4);
+ printf(" L%d(0x%x)\n", l, l);
+}
+
+STATIC
+print_ip(p, len)
+unsigned char *p;
+{
+ int j,k;
+
+ print_ip_hdr(p);
+ for (k =0; k < 12; k++)
+ printf("%2x ", p[k]);
+ print_ipa(p+12);
+ printf(" ");
+ print_ipa(p+12+4);
+ printf("\n");
+ for (j = 20; j < len; j +=16) {
+ for (k = 0; k < 16; k++)
+ printf("%2x ", p[j+k]);
+ print_chars(&p[j], 16);
+ printf("\n");
+ }
+}
+
+STATIC
+print_ipa(u)
+u_char *u;
+{
+ printf("%d.%d.%d.%d", u[0], u[1], u[2], u[3]);
+}
+
+STATIC
+print_arp(p)
+#ifdef MACH_KERNEL
+{}
+#else MACH_KERNEL
+struct arphdr *p;
+{
+ u_char *u = (u_char *)(p+1);
+
+ printf("op = %x, pro = %x, hln = %x, pln = %x\n",
+ ntohs(p->ar_op), ntohs(p->ar_pro), p->ar_hln, p->ar_pln);
+
+ print_e(u);
+ print_ipa(u+p->ar_hln);
+ printf(" seeks\n");
+
+ print_e(u+p->ar_hln+p->ar_pln);
+ print_ipa(u+p->ar_hln+p->ar_pln+p->ar_hln);
+ printf("\n");
+
+}
+#endif MACH_KERNEL
+
+STATIC
+print_e(u)
+u_char *u;
+{
+ printf("%x:%x:%x:%x:%x:%x ", u[0], u[1], u[2], u[3], u[4], u[5]);
+}
+
+STATIC
+print_chars(u, len)
+u_char *u;
+{
+ int c;
+
+ printf("|>");
+ while (len--) {
+ c = *u++;
+ if (c < 0x7f && c > 0x1f)
+ printf("%c", c);
+ else
+ printf(" ");
+ }
+ printf("<|");
+}
+#endif DEBUG