diff options
author | Thomas Bushnell <thomas@gnu.org> | 1997-02-25 21:28:37 +0000 |
---|---|---|
committer | Thomas Bushnell <thomas@gnu.org> | 1997-02-25 21:28:37 +0000 |
commit | f07a4c844da9f0ecae5bbee1ab94be56505f26f7 (patch) | |
tree | 12b07c7e578fc1a5f53dbfde2632408491ff2a70 /i386/i386at/if_de6c.c | |
download | gnumach-f07a4c844da9f0ecae5bbee1ab94be56505f26f7.tar.gz gnumach-f07a4c844da9f0ecae5bbee1ab94be56505f26f7.tar.bz2 gnumach-f07a4c844da9f0ecae5bbee1ab94be56505f26f7.zip |
Initial source
Diffstat (limited to 'i386/i386at/if_de6c.c')
-rw-r--r-- | i386/i386at/if_de6c.c | 1777 |
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 00000000..0bad7803 --- /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 |