summaryrefslogtreecommitdiffstats
path: root/sys/i386/isa/if_zp.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/i386/isa/if_zp.c')
-rw-r--r--sys/i386/isa/if_zp.c1118
1 files changed, 0 insertions, 1118 deletions
diff --git a/sys/i386/isa/if_zp.c b/sys/i386/isa/if_zp.c
deleted file mode 100644
index 4de0ea1..0000000
--- a/sys/i386/isa/if_zp.c
+++ /dev/null
@@ -1,1118 +0,0 @@
-/*
- * This code is based on
- * (1) FreeBSD implementation on ISA/EISA Ethelink III by Herb Peyerl
- * (2) Linux implementation on PCMCIA Etherlink III by David Hinds
- * (3) FreeBSD implementation on PCMCIA IBM Ethernet Card I/II
- * by David Greenman
- * (4) RT-Mach implementation on PCMCIA/ISA/EISA Etherlink III
- * by Seiji Murata
- *
- * Copyright (c) by HOSOKAWA, Tatsumi <hosokawa@mt.cs.keio.ac.jp>
- * Copyright (c) by Seiji Murata <seiji@mt.cs.keio.ac.jp>
- */
-/*
- * Copyright (c) 1993 Herb Peyerl <hpeyerl@novatel.ca>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * From: if_ep.c,v 1.9 1994/01/25 10:46:29 deraadt Exp $
- * $FreeBSD$
- */
-/*-
- * TODO:
- * [1] integrate into current if_ed.c
- * [2] parse tuples to find out where to map the shared memory buffer,
- * and what to write into the configuration register
- * [3] move pcic-specific code into a separate module.
- *
- * Device driver for IBM PCMCIA Credit Card Adapter for Ethernet,
- * if_ze.c
- *
- * Based on the Device driver for National Semiconductor DS8390 ethernet
- * adapters by David Greenman. Modifications for PCMCIA by Keith Moore.
- * Adapted for FreeBSD 1.1.5 by Jordan Hubbard.
- *
- * Currently supports only the IBM Credit Card Adapter for Ethernet, but
- * could probably work with other PCMCIA cards also, if it were modified
- * to get the locations of the PCMCIA configuration option register (COR)
- * by parsing the configuration tuples, rather than by hard-coding in
- * the value expected by IBM's card.
- *
- * Sources for data on the PCMCIA/IBM CCAE specific portions of the driver:
- *
- * [1] _Local Area Network Credit Card Adapters Technical Reference_,
- * IBM Corp., SC30-3585-00, part # 33G9243.
- * [2] "pre-alpha" PCMCIA support code for Linux by Barry Jaspan.
- * [3] Intel 82536SL PC Card Interface Controller Data Sheet, Intel
- * Order Number 290423-002
- * [4] National Semiconductor DP83902A ST-NIC (tm) Serial Network
- * Interface Controller for Twisted Pair data sheet.
- *
- *
- * Copyright (C) 1993, David Greenman. This software may be used, modified,
- * copied, distributed, and sold, in both source and binary form provided
- * that the above copyright and these terms are retained. Under no
- * circumstances is the author responsible for the proper functioning
- * of this software, nor does the author assume any responsibility
- * for damages incurred with its use.
- */
-/*======================================================================
-
- A PCMCIA ethernet driver for the 3com 3c589 card.
-
- Written by David Hinds, dhinds@allegro.stanford.edu
-
- The network driver code is based on Donald Becker's 3c589 code:
-
- Written 1994 by Donald Becker.
- Copyright 1993 United States Government as represented by the
- Director, National Security Agency. This software may be used and
- distributed according to the terms of the GNU Public License,
- incorporated herein by reference.
- Donald Becker may be reached at becker@cesdis1.gsfc.nasa.gov
-
-======================================================================*/
-/*
- * I doubled delay loops in this file because it is not enough for some
- * laptop machines' PCIC (especially, on my Chaplet ILFA 350 ^^;).
- * HOSOKAWA, Tatsumi <hosokawa@mt.cs.keio.ac.jp>
- */
-/*
- * Very small patch for IBM Ethernet PCMCIA Card II and IBM ThinkPad230Cs.
- * ETO, Toshihisa <eto@osl.fujitsu.co.jp>
- */
-
-/* XXX don't mix different PCCARD support code. */
-#include "card.h"
-#include "pcic.h"
-#if NCARD > 0 || NPCIC > 0
-#include "opt_lint.h"
-#ifdef COMPILING_LINT
-static char const zpdummy[] = "code to use the includes of card.h and pcic.h";
-#else
-#error "Dedicated PCMCIA drivers and generic PCMCIA support can't be mixed"
-#endif
-#endif
-
-#include "zp.h"
-
-#include "opt_inet.h"
-#include "opt_ipx.h"
-
-#include <sys/param.h>
-#if defined(__FreeBSD__)
-#include <sys/systm.h>
-#include <sys/conf.h>
-#endif
-#include <sys/mbuf.h>
-#include <sys/socket.h>
-#include <sys/sockio.h>
-#include <sys/syslog.h>
-
-#include <net/ethernet.h>
-#include <net/if.h>
-
-#include <netinet/in.h>
-#include <netinet/if_ether.h>
-
-#include <net/bpf.h>
-
-#include <machine/clock.h>
-#include <machine/md_var.h>
-
-#include <i386/isa/isa_device.h>
-#include <i386/isa/if_zpreg.h>
-#include <i386/isa/pcic.h>
-
-#include "apm.h"
-#if NAPM > 0
-#include <machine/apm_bios.h>
-#endif /* NAPM > 0 */
-
-
-/*****************************************************************************
- * Driver for Ethernet Adapter *
- *****************************************************************************/
-/*
- * zp_softc: per line info and status
- */
-static struct zp_softc {
- struct arpcom arpcom; /* Ethernet common part */
-#define MAX_MBS 8 /* # of mbufs we keep around */
- struct mbuf *mb[MAX_MBS]; /* spare mbuf storage. */
- int next_mb; /* Which mbuf to use next. */
- int last_mb; /* Last mbuf. */
- int ep_io_addr; /* i/o bus address */
- char ep_connectors; /* Connectors on this card. */
- int tx_start_thresh;/* Current TX_start_thresh. */
- char bus32bit; /* 32bit access possible */
- u_short if_port;
- u_char last_alive; /* information for reconfiguration */
- u_char last_up; /* information for reconfiguration */
- int slot; /* PCMCIA slot */
- struct callout_handle ch; /* Callout handle for timeouts */
- int buffill_pending;
-#if NAPM > 0
- struct apmhook s_hook; /* reconfiguration support */
- struct apmhook r_hook; /* reconfiguration support */
-#endif /* NAPM > 0 */
-} zp_softc[NZP];
-
-static int zpprobe __P((struct isa_device *));
-static int zpattach __P((struct isa_device *));
-static int zp_suspend __P((void *visa_dev));
-static int zp_resume __P((void *visa_dev));
-static int zpioctl __P((struct ifnet * ifp, u_long, caddr_t));
-static u_short read_eeprom_data __P((int, int));
-
-static void zpinit __P((int));
-static ointhand2_t zpintr;
-static void zpmbuffill __P((void *));
-static void zpmbufempty __P((struct zp_softc *));
-static void zpread __P((struct zp_softc *));
-static void zpreset __P((int));
-static void zpstart __P((struct ifnet *));
-static void zpstop __P((int));
-static void zpwatchdog __P((struct ifnet *));
-
-struct isa_driver zpdriver = {
- zpprobe,
- zpattach,
- "zp"
-};
-#define CARD_INFO "3Com Corporation~3C589"
-
-static unsigned char card_info[256];
-
-/*
- * scan the card information structure looking for the version/product info
- * tuple. when we find it, compare it to the string we are looking for.
- * return 1 if we find it, 0 otherwise.
- */
-
-static int
-zp_check_cis(unsigned char *scratch)
-{
- int i, j, k;
-
- card_info[0] = '\0';
- i = 0;
- while (scratch[i] != 0xff && i < 1024) {
- unsigned char link = scratch[i + 2];
-
- if (scratch[i] == 0x15) {
- /* level 1 version/product info copy to card_info,
- * translating '\0' to '~' */
- k = 0;
- for (j = i + 8; scratch[j] != 0xff; j += 2)
- card_info[k++] = scratch[j] == '\0' ? '~' : scratch[j];
- card_info[k++] = '\0';
- return (bcmp(card_info, CARD_INFO, sizeof(CARD_INFO) - 1) == 0);
- }
- i += 4 + 2 * link;
- }
- return 0;
-}
-/*
- * Probe each slot looking for an IBM Credit Card Adapter for Ethernet
- * For each card that we find, map its card information structure
- * into system memory at 'scratch' and see whether it's one of ours.
- * Return the slot number if we find a card, or -1 otherwise.
- *
- * Side effects:
- * + On success, leaves CIS mapped into memory at 'scratch';
- * caller must free it.
- * + On success, leaves ethernet address in enet_addr.
- * + Leaves product/vendor id of last card probed in 'card_info'
- */
-
-static int prev_slot = 0;
-
-static int
-zp_find_adapter(unsigned char *scratch, int reconfig)
-{
- int slot;
-
- for (slot = prev_slot; slot < MAXSLOT; ++slot) {
- /* see if there's a PCMCIA controller here Intel PCMCIA
- * controllers use 0x82 and 0x83 IBM clone chips use 0x88 and
- * 0x89, apparently */
- /* IBM ThinkPad230Cs use 0x84. */
- unsigned char idbyte = pcic_getb(slot, PCIC_ID_REV);
-
- if (idbyte != 0x82 && idbyte != 0x83 &&
- idbyte != 0x84 && /* for IBM ThinkPad 230Cs */
- idbyte != 0x88 && idbyte != 0x89) {
- continue;
- }
- if ((pcic_getb(slot, PCIC_STATUS) & PCIC_CD) != PCIC_CD) {
- if (!reconfig) {
- printf("zp: slot %d: no card in slot\n", slot);
- } else {
- log(LOG_NOTICE, "zp: slot %d: no card in slot\n", slot);
- }
- /* no card in slot */
- continue;
- }
- pcic_power_on(slot);
- pcic_reset(slot);
- DELAY(50000);
- /* map the card's attribute memory and examine its card
- * information structure tuples for something we recognize. */
- pcic_map_memory(slot, 0, kvtop(scratch), 0L,
- 0xFFFL, ATTRIBUTE, 1);
-
- if ((zp_check_cis(scratch)) > 0) {
- /* found it */
- if (!reconfig) {
- printf("zp: found card in slot %d\n", slot);
- } else {
- log(LOG_NOTICE, "zp: found card in slot %d\n", slot);
- }
- prev_slot = (prev_slot == MAXSLOT - 1) ? 0 : prev_slot + 1;
-
- return slot;
- } else {
- if (!reconfig) {
- printf("zp: pcmcia slot %d: %s\n", slot, card_info);
- } else {
- log(LOG_NOTICE, "zp: pcmcia slot %d: %s\n", slot, card_info);
- }
- }
- pcic_unmap_memory(slot, 0);
- }
- prev_slot = 0;
- return -1;
-}
-
-
-/*
- * macros to handle casting unsigned long to (char *) so we can
- * read/write into physical memory space.
- */
-
-#define PEEK(addr) (*((unsigned char *)(addr)))
-#define POKE(addr,val) do { PEEK(addr) = (val); } while (0)
-
-/*
- * Determine if the device is present
- *
- * on entry:
- * a pointer to an isa_device struct
- * on exit:
- * NULL if device not found
- * or # of i/o addresses used (if found)
- */
-static int
-zpprobe(struct isa_device * isa_dev)
-{
- struct zp_softc *sc = &zp_softc[isa_dev->id_unit];
- int slot;
- u_short k;
- int re_init_flag;
-
- if ((slot = zp_find_adapter(isa_dev->id_maddr, isa_dev->id_reconfig)) < 0)
- return 0;
-
- /* okay, we found a card, so set it up */
- /* Inhibit 16 bit memory delay. POINTETH.SYS apparently does this, for
- * what reason I don't know. */
- pcic_putb(slot, PCIC_CDGC,
- pcic_getb(slot, PCIC_CDGC) | PCIC_16_DL_INH);
- /* things to map (1) card's EEPROM is already mapped by the
- * find_adapter routine but we still need to get the card's ethernet
- * address. after that we unmap that part of attribute memory. (2)
- * card configuration registers need to be mapped in so we can set the
- * configuration and socket # registers. (3) shared memory packet
- * buffer (4) i/o ports (5) IRQ */
-#ifdef notdef
- /* Sigh. Location of the ethernet address isn't documented in [1]. It
- * was derived by doing a hex dump of all of attribute memory and
- * looking for the IBM vendor prefix. */
- enet_addr[0] = PEEK(isa_dev->id_maddr + 0xff0);
- enet_addr[1] = PEEK(isa_dev->id_maddr + 0xff2);
- enet_addr[2] = PEEK(isa_dev->id_maddr + 0xff4);
- enet_addr[3] = PEEK(isa_dev->id_maddr + 0xff6);
- enet_addr[4] = PEEK(isa_dev->id_maddr + 0xff8);
- enet_addr[5] = PEEK(isa_dev->id_maddr + 0xffa);
-#endif
- re_init_flag = 0;
-re_init:
- /* (2) map card configuration registers. these are offset in card
- * memory space by 0x20000. normally we could get this offset from
- * the card information structure, but I'm too lazy and am not quite
- * sure if I understand the CIS anyway.
- *
- * XXX IF YOU'RE TRYING TO PORT THIS DRIVER FOR A DIFFERENT PCMCIA CARD,
- * the most likely thing to change is the constant 0x20000 in the next
- * statement. Oh yes, also change the card id string that we probe
- * for. */
- pcic_map_memory(slot, 0, kvtop(isa_dev->id_maddr), 0x10000, 8L,
- ATTRIBUTE, 1);
-#if OLD_3C589B_CARDS
- POKE(isa_dev->id_maddr, 0x80); /* reset the card (how long?) */
- DELAY(40000);
-#endif
- /* Set the configuration index. According to [1], the adapter won't
- * respond to any i/o signals until we do this; it uses the Memory
- * Only interface (whatever that is; it's not documented). Also turn
- * on "level" (not pulse) interrupts.
- *
- * XXX probably should init the socket and copy register also, so that we
- * can deal with multiple instances of the same card. */
- POKE(isa_dev->id_maddr, 0x41);
- pcic_unmap_memory(slot, 0);
-
- /* (4) map i/o ports.
- *
- * XXX is it possible that the config file leaves this unspecified, in
- * which case we have to pick one?
- *
- * At least one PCMCIA device driver I'v seen maps a block of 32
- * consecutive i/o ports as two windows of 16 ports each. Maybe some
- * other pcic chips are restricted to 16-port windows; the 82365SL
- * doesn't seem to have that problem. But since we have an extra
- * window anyway... */
- pcic_map_io(slot, 0, isa_dev->id_iobase, 16, 2);
-
- /* (5) configure the card for the desired interrupt
- *
- * XXX is it possible that the config file leaves this unspecified? */
- pcic_map_irq(slot, ffs(isa_dev->id_irq) - 1);
-
- /* tell the PCIC that this is an I/O card (not memory) */
- pcic_putb(slot, PCIC_INT_GEN,
- pcic_getb(slot, PCIC_INT_GEN) | PCIC_CARDTYPE);
-
- sc->ep_io_addr = isa_dev->id_iobase;
- GO_WINDOW(0);
- k = read_eeprom_data(BASE, EEPROM_ADDR_CFG); /* get addr cfg */
- sc->if_port = k >> 14;
- k = (k & 0x1f) * 0x10 + 0x200; /* decode base addr. */
- if (k != (u_short) isa_dev->id_iobase) {
- if (!re_init_flag) {
- re_init_flag++;
- goto re_init;
- }
- return (0);
- }
- k = read_eeprom_data(BASE, EEPROM_RESOURCE_CFG);
-
- k >>= 12;
-
- if (isa_dev->id_irq != (1 << ((k == 2) ? 9 : k)))
- return (0);
-
- outb(BASE, ACTIVATE_ADAPTER_TO_CONFIG);
-
-
- /* information for reconfiguration */
- sc->last_alive = 0;
- sc->last_up = 0;
- sc->slot = slot;
-
- return (0x10); /* 16 bytes of I/O space used. */
-}
-#if NAPM > 0
-static int
-zp_suspend(visa_dev)
- void *visa_dev;
-{
-#if 0
- struct isa_device *isa_dev = visa_dev;
- struct zp_softc *sc = &zp_softc[isa_dev->id_unit];
-
- pcic_power_off(sc->slot);
-#endif
- return 0;
-}
-
-static int
-zp_resume(visa_dev)
- void *visa_dev;
-{
- struct isa_device *isa_dev = visa_dev;
-
- prev_slot = 0;
- reconfig_isadev(isa_dev, &net_imask);
- return 0;
-}
-#endif /* NAPM > 0 */
-
-
-/*
- * Install interface into kernel networking data structures
- */
-
-static int
-zpattach(isa_dev)
- struct isa_device *isa_dev;
-{
- struct zp_softc *sc = &zp_softc[isa_dev->id_unit];
- struct ifnet *ifp = &sc->arpcom.ac_if;
- u_short i;
- int pl;
-
- isa_dev->id_ointr = zpintr;
-
- /* PCMCIA card can be offlined. Reconfiguration is required */
- if (isa_dev->id_reconfig) {
- if (!isa_dev->id_alive && sc->last_alive) {
- pl = splimp();
- sc->last_up = (ifp->if_flags & IFF_UP);
- if_down(ifp);
- splx(pl);
- sc->last_alive = 0;
- }
- if (isa_dev->id_alive && !sc->last_alive) {
- zpreset(isa_dev->id_unit);
- if (sc->last_up) {
- pl = splimp();
- if_up(ifp);
- splx(pl);
- }
- sc->last_alive = 1;
- }
- return 1;
- } else {
- sc->last_alive = 1;
- }
-
-
- sc->ep_io_addr = isa_dev->id_iobase;
- printf("zp%d: ", isa_dev->id_unit);
-
- sc->buffill_pending = 0;
- callout_handle_init(&sc->ch);
-
- sc->ep_connectors = 0;
-
- i = inw(isa_dev->id_iobase + EP_W0_CONFIG_CTRL);
-
- if (i & IS_AUI) {
- printf("aui");
- sc->ep_connectors |= AUI;
- }
- if (i & IS_BNC) {
- if (sc->ep_connectors)
- printf("/");
- printf("bnc");
- sc->ep_connectors |= BNC;
- }
- if (i & IS_UTP) {
- if (sc->ep_connectors)
- printf("/");
- printf("utp");
- sc->ep_connectors |= UTP;
- }
- if (!sc->ep_connectors)
- printf("no connectors!");
-
- GO_WINDOW(0);
- {
- short tmp_addr[3];
- int j;
- for (j = 0; j < 3; j++) {
- tmp_addr[j] = htons(read_eeprom_data(BASE, j));
- }
- bcopy(tmp_addr, sc->arpcom.ac_enaddr, 6);
- }
-
- printf(" address %6D\n", sc->arpcom.ac_enaddr, ":");
-
- sc->arpcom.ac_if.if_snd.ifq_maxlen = ifqmaxlen;
- ifp->if_softc = sc;
- ifp->if_mtu = ETHERMTU;
- ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX;
- ifp->if_unit = isa_dev->id_unit;
- ifp->if_name = "zp";
- ifp->if_output = ether_output;
- ifp->if_start = zpstart;
- ifp->if_ioctl = zpioctl;
- ifp->if_watchdog = zpwatchdog;
- /* Select connector according to board setting. */
- ifp->if_flags |= IFF_LINK0;
-
- if_attach(ifp);
- ether_ifattach(ifp);
-
- bpfattach(ifp, DLT_EN10MB, sizeof(struct ether_header));
-#if NAPM > 0
- sc->s_hook.ah_fun = zp_suspend;
- sc->s_hook.ah_arg = (void *) isa_dev;
- sc->s_hook.ah_name = "3Com PCMCIA Etherlink III 3C589";
- sc->s_hook.ah_order = APM_MID_ORDER;
- apm_hook_establish(APM_HOOK_SUSPEND, &sc->s_hook);
- sc->r_hook.ah_fun = zp_resume;
- sc->r_hook.ah_arg = (void *) isa_dev;
- sc->r_hook.ah_name = "3Com PCMCIA Etherlink III 3C589";
- sc->r_hook.ah_order = APM_MID_ORDER;
- apm_hook_establish(APM_HOOK_RESUME, &sc->r_hook);
-#endif /* NAPM > 0 */
- return 1;
-}
-/*
- * The order in here seems important. Otherwise we may not receive
- * interrupts. ?!
- */
-static void
-zpinit(unit)
- int unit;
-{
- register struct zp_softc *sc = &zp_softc[unit];
- register struct ifnet *ifp = &sc->arpcom.ac_if;
- int s, i;
-
- if (TAILQ_EMPTY(&ifp->if_addrhead)) /* XXX unlikely */
- return;
-
- s = splimp();
- while (inw(BASE + EP_STATUS) & S_COMMAND_IN_PROGRESS);
-
- GO_WINDOW(0);
-
- /* Disable the card */
- outw(BASE + EP_W0_CONFIG_CTRL, 0);
-
- /* Enable the card */
- outw(BASE + EP_W0_CONFIG_CTRL, ENABLE_DRQ_IRQ);
-
- GO_WINDOW(2);
-
- /* Reload the ether_addr. */
- for (i = 0; i < 6; i++)
- outb(BASE + EP_W2_ADDR_0 + i, sc->arpcom.ac_enaddr[i]);
-
- outw(BASE + EP_COMMAND, RX_RESET);
- outw(BASE + EP_COMMAND, TX_RESET);
-
- /* Window 1 is operating window */
- GO_WINDOW(1);
- for (i = 0; i < 31; i++)
- inb(BASE + EP_W1_TX_STATUS);
-
- /* get rid of stray intr's */
- outw(BASE + EP_COMMAND, ACK_INTR | 0xff);
-
- outw(BASE + EP_COMMAND, SET_RD_0_MASK | S_CARD_FAILURE | S_RX_COMPLETE |
- S_TX_COMPLETE | S_TX_AVAIL);
- outw(BASE + EP_COMMAND, SET_INTR_MASK | S_CARD_FAILURE | S_RX_COMPLETE |
- S_TX_COMPLETE | S_TX_AVAIL);
-
-#ifndef IFF_MULTICAST
-#define IFF_MULTICAST 0x10000
-#endif
-
- outw(BASE + EP_COMMAND, SET_RX_FILTER | FIL_INDIVIDUAL |
- ((sc->arpcom.ac_if.if_flags & IFF_MULTICAST) ? FIL_GROUP : 0) |
- FIL_BRDCST |
- ((sc->arpcom.ac_if.if_flags & IFF_PROMISC) ? FIL_ALL : 0));
- /* you can `ifconfig (link0|-link0) ep0' to get the following
- * behaviour: -link0 disable AUI/UTP. enable BNC. link0 disable
- * BNC. enable AUI. if the card has a UTP connector, that is enabled
- * too. not sure, but it seems you have to be careful to not plug
- * things into both AUI & UTP. */
-
- if (!(ifp->if_flags & IFF_LINK0) && (sc->ep_connectors & BNC)) {
- GO_WINDOW(0);
- /* set the xcvr */
- outw(BASE + EP_W0_ADDRESS_CFG, 3 << 14);
- GO_WINDOW(2);
- outw(BASE + EP_COMMAND, START_TRANSCEIVER);
- GO_WINDOW(1);
- }
-#if defined(__NetBSD__) || defined(__FreeBSD__)
- if ((ifp->if_flags & IFF_LINK0) && (sc->ep_connectors & UTP)) {
-#else
- if ((ifp->if_flags & IFF_ALTPHYS) && (sc->ep_connectors & UTP)) {
-#endif
- GO_WINDOW(4);
- outw(BASE + EP_W4_MEDIA_TYPE, ENABLE_UTP);
- GO_WINDOW(1);
- }
- outw(BASE + EP_COMMAND, RX_ENABLE);
- outw(BASE + EP_COMMAND, TX_ENABLE);
-
- ifp->if_flags |= IFF_RUNNING;
- ifp->if_flags &= ~IFF_OACTIVE; /* just in case */
- sc->tx_start_thresh = 20; /* probably a good starting point. */
- /* Store up a bunch of mbuf's for use later. (MAX_MBS). First we free
- * up any that we had in case we're being called from intr or
- * somewhere else. */
- sc->last_mb = 0;
- sc->next_mb = 0;
- if (sc->buffill_pending != 0) {
- untimeout(zpmbuffill, sc, sc->ch);
- sc->buffill_pending = 0;
- }
- zpmbuffill(sc);
- zpstart(ifp);
- splx(s);
-}
-
-static const char padmap[] = {0, 3, 2, 1};
-static void
-zpstart(ifp)
- struct ifnet *ifp;
-{
- register struct zp_softc *sc = ifp->if_softc;
- struct mbuf *m, *top;
-
- int s, len, pad;
-
- s = splimp();
-
- if (sc->arpcom.ac_if.if_flags & IFF_OACTIVE) {
- splx(s);
- return;
- }
-startagain:
-
- /* Sneak a peek at the next packet */
- m = sc->arpcom.ac_if.if_snd.ifq_head;
- if (m == 0) {
- splx(s);
- return;
- }
- for (len = 0, top = m; m; m = m->m_next)
- len += m->m_len;
-
- pad = padmap[len & 3];
-
- /* The 3c509 automatically pads short packets to minimum ethernet
- * length, but we drop packets that are too large. Perhaps we should
- * truncate them instead? */
- if (len + pad > ETHER_MAX_LEN) {
- /* packet is obviously too large: toss it */
- ++sc->arpcom.ac_if.if_oerrors;
- IF_DEQUEUE(&sc->arpcom.ac_if.if_snd, m);
- m_freem(m);
- goto readcheck;
- }
- if (inw(BASE + EP_W1_FREE_TX) < len + pad + 4) {
- /* no room in FIFO */
- outw(BASE + EP_COMMAND, SET_TX_AVAIL_THRESH | (len + pad + 4));
- sc->arpcom.ac_if.if_flags |= IFF_OACTIVE;
- splx(s);
-
- return;
- }
- IF_DEQUEUE(&sc->arpcom.ac_if.if_snd, m);
-
- if (m == 0) { /* not really needed */
- splx(s);
- return;
- }
- outw(BASE + EP_COMMAND, SET_TX_START_THRESH |
- (len / 4 + sc->tx_start_thresh));
-
- outw(BASE + EP_W1_TX_PIO_WR_1, len);
- outw(BASE + EP_W1_TX_PIO_WR_1, 0xffff); /* Second dword meaningless */
-
- for (top = m; m != 0; m = m->m_next) {
- if (sc->bus32bit) {
- outsl(BASE + EP_W1_TX_PIO_WR_1, mtod(m, caddr_t),
- m->m_len / 4);
- if (m->m_len & 3)
- outsb(BASE + EP_W1_TX_PIO_WR_1,
- mtod(m, caddr_t) + (m->m_len & (~3)),
- m->m_len & 3);
- } else {
- outsw(BASE + EP_W1_TX_PIO_WR_1, mtod(m, caddr_t), m->m_len / 2);
- if (m->m_len & 1)
- outb(BASE + EP_W1_TX_PIO_WR_1,
- *(mtod(m, caddr_t) + m->m_len - 1));
- }
- }
- while (pad--)
- outb(BASE + EP_W1_TX_PIO_WR_1, 0); /* Padding */
-
- if (sc->arpcom.ac_if.if_bpf) {
- bpf_mtap(&sc->arpcom.ac_if, top);
- }
-
- m_freem(top);
- ++sc->arpcom.ac_if.if_opackets;
- /* Is another packet coming in? We don't want to overflow the tiny RX
- * fifo. */
-readcheck:
- if (inw(BASE + EP_W1_RX_STATUS) & RX_BYTES_MASK) {
- splx(s);
- return;
- }
- goto startagain;
-}
-static void
-zpintr(unit)
- int unit;
-{
- int status, i;
- register struct zp_softc *sc = &zp_softc[unit];
-
- struct ifnet *ifp = &sc->arpcom.ac_if;
-
-
- status = 0;
-checkintr:
- status = inw(BASE + EP_STATUS) &
- (S_TX_COMPLETE | S_TX_AVAIL | S_RX_COMPLETE | S_CARD_FAILURE);
-checkintr2:
- if (status == 0) {
- /* No interrupts. */
- outw(BASE + EP_COMMAND, C_INTR_LATCH);
-
- status = inw(BASE + EP_STATUS) &
- (S_TX_COMPLETE | S_TX_AVAIL | S_RX_COMPLETE |
- S_CARD_FAILURE);
- if (status)
- goto checkintr2;
-
- return;
- }
- /* important that we do this first. */
- outw(BASE + EP_COMMAND, ACK_INTR | status);
-
- if (status & S_TX_AVAIL) {
- status &= ~S_TX_AVAIL;
- inw(BASE + EP_W1_FREE_TX);
- sc->arpcom.ac_if.if_flags &= ~IFF_OACTIVE;
- zpstart(&sc->arpcom.ac_if);
-
- }
- if (status & S_RX_COMPLETE) {
- status &= ~S_RX_COMPLETE;
- zpread(sc);
- }
- if (status & S_CARD_FAILURE) {
- printf("zp%d: reset (status: %x)\n", unit, status);
- outw(BASE + EP_COMMAND, C_INTR_LATCH);
- zpinit(unit);
- return;
- }
- if (status & S_TX_COMPLETE) {
- status &= ~S_TX_COMPLETE;
- /* We need to read TX_STATUS until we get a 0 status in order
- * to turn off the interrupt flag. */
- while ((i = inb(BASE + EP_W1_TX_STATUS)) & TXS_COMPLETE) {
- outw(BASE + EP_W1_TX_STATUS, 0x0);
- if (i & (TXS_MAX_COLLISION | TXS_JABBER | TXS_UNDERRUN)) {
- if (i & TXS_MAX_COLLISION)
- ++sc->arpcom.ac_if.if_collisions;
- if (i & (TXS_JABBER | TXS_UNDERRUN)) {
- outw(BASE + EP_COMMAND, TX_RESET);
- if (i & TXS_UNDERRUN) {
- if (sc->tx_start_thresh < ETHER_MAX_LEN) {
- sc->tx_start_thresh += 20;
- outw(BASE + EP_COMMAND,
- SET_TX_START_THRESH |
- sc->tx_start_thresh);
- }
- }
- }
- outw(BASE + EP_COMMAND, TX_ENABLE);
- ++sc->arpcom.ac_if.if_oerrors;
- }
- }
- zpstart(ifp);
- }
- goto checkintr;
-}
-
-static void
-zpread(sc)
- register struct zp_softc *sc;
-{
- struct ether_header *eh;
- struct mbuf *mcur, *m, *m0, *top;
- int totlen, lenthisone;
- int save_totlen;
- int off;
-
-
- totlen = inw(BASE + EP_W1_RX_STATUS);
- off = 0;
- top = 0;
-
- if (totlen & ERR_RX) {
- ++sc->arpcom.ac_if.if_ierrors;
- goto out;
- }
- save_totlen = totlen &= RX_BYTES_MASK; /* Lower 11 bits = RX bytes. */
-
- m = sc->mb[sc->next_mb];
- sc->mb[sc->next_mb] = 0;
-
- if (m == 0) {
- MGETHDR(m, M_DONTWAIT, MT_DATA);
- if (m == 0)
- goto out;
- } else {
- /* Convert one of our saved mbuf's */
- sc->next_mb = (sc->next_mb + 1) % MAX_MBS;
- m->m_data = m->m_pktdat;
- m->m_flags = M_PKTHDR;
- }
-
- top = m0 = m; /* We assign top so we can "goto out" */
-#define EROUND ((sizeof(struct ether_header) + 3) & ~3)
-#define EOFF (EROUND - sizeof(struct ether_header))
- m0->m_data += EOFF;
- /* Read what should be the header. */
- insw(BASE + EP_W1_RX_PIO_RD_1,
- mtod(m0, caddr_t), sizeof(struct ether_header) / 2);
- m->m_len = sizeof(struct ether_header);
- totlen -= sizeof(struct ether_header);
- /* mostly deal with trailer here. (untested) We do this in a couple
- * of parts. First we check for a trailer, if we have one we convert
- * the mbuf back to a regular mbuf and set the offset and subtract
- * sizeof(struct ether_header) from the pktlen. After we've read the
- * packet off the interface (all except for the trailer header, we
- * then get a header mbuf, read the trailer into it, and fix up the
- * mbuf pointer chain. */
- eh = mtod(m, struct ether_header *);
- while (totlen > 0) {
- lenthisone = min(totlen, M_TRAILINGSPACE(m));
- if (lenthisone == 0) { /* no room in this one */
- mcur = m;
- m = sc->mb[sc->next_mb];
- sc->mb[sc->next_mb] = 0;
- if (!m) {
- MGET(m, M_DONTWAIT, MT_DATA);
- if (m == 0)
- goto out;
- } else if (sc->buffill_pending == 0) {
- sc->ch = timeout(zpmbuffill, sc, 0);
- sc->buffill_pending = 1;
- sc->next_mb = (sc->next_mb + 1) % MAX_MBS;
- }
- if (totlen >= MINCLSIZE)
- MCLGET(m, M_DONTWAIT);
- m->m_len = 0;
- mcur->m_next = m;
- lenthisone = min(totlen, M_TRAILINGSPACE(m));
- }
- if (sc->bus32bit) {
- insl(BASE + EP_W1_RX_PIO_RD_1, mtod(m, caddr_t) + m->m_len,
- lenthisone / 4);
- m->m_len += (lenthisone & ~3);
- if (lenthisone & 3)
- insb(BASE + EP_W1_RX_PIO_RD_1,
- mtod(m, caddr_t) + m->m_len,
- lenthisone & 3);
- m->m_len += (lenthisone & 3);
- } else {
- insw(BASE + EP_W1_RX_PIO_RD_1, mtod(m, caddr_t) + m->m_len,
- lenthisone / 2);
- m->m_len += lenthisone;
- if (lenthisone & 1)
- *(mtod(m, caddr_t) + m->m_len - 1) = inb(BASE + EP_W1_RX_PIO_RD_1);
- }
- totlen -= lenthisone;
- }
- if (off) {
- top = sc->mb[sc->next_mb];
- sc->mb[sc->next_mb] = 0;
- if (top == 0) {
- MGETHDR(m, M_DONTWAIT, MT_DATA);
- if (top == 0) {
- top = m0;
- goto out;
- }
- } else {
- /* Convert one of our saved mbuf's */
- sc->next_mb = (sc->next_mb + 1) % MAX_MBS;
- top->m_data = top->m_pktdat;
- top->m_flags = M_PKTHDR;
- }
- insw(BASE + EP_W1_RX_PIO_RD_1, mtod(top, caddr_t),
- sizeof(struct ether_header));
- top->m_next = m0;
- top->m_len = sizeof(struct ether_header);
- /* XXX Accomodate for type and len from beginning of trailer */
- top->m_pkthdr.len = save_totlen - (2 * sizeof(u_short));
- } else {
- top = m0;
- top->m_pkthdr.len = save_totlen;
- }
-
- top->m_pkthdr.rcvif = &sc->arpcom.ac_if;
- outw(BASE + EP_COMMAND, RX_DISCARD_TOP_PACK);
- while (inw(BASE + EP_STATUS) & S_COMMAND_IN_PROGRESS);
- ++sc->arpcom.ac_if.if_ipackets;
- if (sc->arpcom.ac_if.if_bpf) {
- bpf_mtap(&sc->arpcom.ac_if, top);
-
- /* Note that the interface cannot be in promiscuous mode if
- * there are no BPF listeners. And if we are in promiscuous
- * mode, we have to check if this packet is really ours. */
- if ((sc->arpcom.ac_if.if_flags & IFF_PROMISC) &&
- (eh->ether_dhost[0] & 1) == 0 &&
- bcmp(eh->ether_dhost, sc->arpcom.ac_enaddr,
- sizeof(eh->ether_dhost)) != 0 &&
- bcmp(eh->ether_dhost, etherbroadcastaddr,
- sizeof(eh->ether_dhost)) != 0) {
- m_freem(top);
- return;
- }
- }
- m_adj(top, sizeof(struct ether_header));
- ether_input(&sc->arpcom.ac_if, eh, top);
- return;
-
-out: outw(BASE + EP_COMMAND, RX_DISCARD_TOP_PACK);
- while (inw(BASE + EP_STATUS) & S_COMMAND_IN_PROGRESS);
- if (top)
- m_freem(top);
-
-}
-
-
-/*
- * Look familiar?
- */
-static int
-zpioctl(ifp, cmd, data)
- register struct ifnet *ifp;
- u_long cmd;
- caddr_t data;
-{
- struct zp_softc *sc = ifp->if_softc;
- int error = 0;
-
-
- switch (cmd) {
- case SIOCSIFADDR:
- case SIOCGIFADDR:
- case SIOCSIFMTU:
- error = ether_ioctl(ifp, cmd, data);
- break;
-
- case SIOCSIFFLAGS:
- if ((ifp->if_flags & IFF_UP) == 0 && ifp->if_flags & IFF_RUNNING) {
- ifp->if_flags &= ~IFF_RUNNING;
- zpstop(ifp->if_unit);
- zpmbufempty(sc);
- break;
- }
- zpinit(ifp->if_unit);
- break;
- default:
- error = EINVAL;
- }
- return (error);
-}
-
-static void
-zpreset(unit)
- int unit;
-{
- int s = splimp();
-
- zpstop(unit);
- zpinit(unit);
- splx(s);
-}
-
-static void
-zpwatchdog(ifp)
- struct ifnet *ifp;
-{
- log(LOG_ERR, "zp%d: watchdog\n", ifp->if_unit);
- ifp->if_oerrors++;
- zpreset(ifp->if_unit);
-}
-
-static void
-zpstop(unit)
- int unit;
-{
- struct zp_softc *sc = &zp_softc[unit];
-
- outw(BASE + EP_COMMAND, RX_DISABLE);
- outw(BASE + EP_COMMAND, RX_DISCARD_TOP_PACK);
- while (inw(BASE + EP_STATUS) & S_COMMAND_IN_PROGRESS);
- outw(BASE + EP_COMMAND, TX_DISABLE);
- outw(BASE + EP_COMMAND, STOP_TRANSCEIVER);
- outw(BASE + EP_COMMAND, RX_RESET);
- outw(BASE + EP_COMMAND, TX_RESET);
- outw(BASE + EP_COMMAND, C_INTR_LATCH);
- outw(BASE + EP_COMMAND, SET_RD_0_MASK);
- outw(BASE + EP_COMMAND, SET_INTR_MASK);
- outw(BASE + EP_COMMAND, SET_RX_FILTER);
-}
-
-
-
-static u_short
-read_eeprom_data(id_port, offset)
- int id_port;
- int offset;
-{
-
- outb(id_port + 10, 0x80 + offset);
- DELAY(1000);
- return inw(id_port + 12);
-}
-
-
-
-
-static void
-zpmbuffill(sp)
- void *sp;
-{
- struct zp_softc *sc = (struct zp_softc *) sp;
- int s, i;
-
- s = splimp();
- i = sc->last_mb;
- do {
- if (sc->mb[i] == NULL)
- MGET(sc->mb[i], M_DONTWAIT, MT_DATA);
- if (sc->mb[i] == NULL)
- break;
- i = (i + 1) % MAX_MBS;
- } while (i != sc->next_mb);
- sc->buffill_pending = 0;
- sc->last_mb = i;
- splx(s);
-}
-
-static void
-zpmbufempty(sc)
- struct zp_softc *sc;
-{
- int s, i;
-
- s = splimp();
- for (i = 0; i < MAX_MBS; i++) {
- if (sc->mb[i]) {
- m_freem(sc->mb[i]);
- sc->mb[i] = NULL;
- }
- }
- sc->last_mb = sc->next_mb = 0;
- if (sc->buffill_pending != 0) {
- untimeout(zpmbuffill, sc, sc->ch);
- sc->buffill_pending = 0;
- }
- splx(s);
-}
OpenPOWER on IntegriCloud