diff options
author | mdodd <mdodd@FreeBSD.org> | 1999-09-26 06:42:36 +0000 |
---|---|---|
committer | mdodd <mdodd@FreeBSD.org> | 1999-09-26 06:42:36 +0000 |
commit | 5272c65210119098f91f9749539447f2945f26a9 (patch) | |
tree | 1686bbf05ff020787377386cdef3689839bbc67f | |
parent | 07038f1e994b4a14bbf31e08277be3a83b8b95d1 (diff) | |
download | FreeBSD-src-5272c65210119098f91f9749539447f2945f26a9.zip FreeBSD-src-5272c65210119098f91f9749539447f2945f26a9.tar.gz |
- Split out the ISA and PCCARD specific code.
- Split out the prototypes, externs and struct decls from if_epreg.h into
if_epvar.h.
- Add support for MCA based Etherlink III (3c529) devices.
None of this code is used right now; the old if_ep driver is still
in place and used.
I will eventually get around to converting if_ep_isa.c to newbus once I've
had a talk with Peter and DFR about the DEVICE_IDENTIFY() method.
I have tested this code on my PS/2. It works. I would like EISA and ISA
testers since my example hardware hasn't arrived yet.
Add:
dev/ep/if_ep.c optional ep
dev/ep/if_ep_isa.c optional ep isa
dev/ep/if_ep_eisa.c optional ep eisa
dev/ep/if_ep_mca.c optional ep mca
dev/ep/if_ep_pccard.c optional ep card
to sys/conf/files
Remove:
i386/eisa/3c5x9.c optional ep
i386/isa/if_ep.c optional ep
from sys/i386/conf/files.i386
PCCARD testers wanted!
I will switch off and cvs rm the old driver in favor of this copy once
I've had positive feedback or have the hardware to verify that it works.
-rw-r--r-- | sys/dev/ep/if_ep.c | 556 | ||||
-rw-r--r-- | sys/dev/ep/if_ep_isa.c | 344 | ||||
-rw-r--r-- | sys/dev/ep/if_ep_mca.c | 219 | ||||
-rw-r--r-- | sys/dev/ep/if_ep_pccard.c | 245 | ||||
-rw-r--r-- | sys/dev/ep/if_epreg.h | 81 | ||||
-rw-r--r-- | sys/dev/ep/if_epvar.h | 78 |
6 files changed, 918 insertions, 605 deletions
diff --git a/sys/dev/ep/if_ep.c b/sys/dev/ep/if_ep.c index 4ee050d..7202bf9 100644 --- a/sys/dev/ep/if_ep.c +++ b/sys/dev/ep/if_ep.c @@ -59,270 +59,45 @@ #include "ep.h" #if NEP > 0 -#include "opt_inet.h" -#include "opt_ipx.h" - #include <sys/param.h> -#if defined(__FreeBSD__) #include <sys/kernel.h> #include <sys/systm.h> -#endif #include <sys/malloc.h> #include <sys/mbuf.h> #include <sys/socket.h> #include <sys/sockio.h> -#if defined(__NetBSD__) -#include <sys/select.h> -#endif #include <net/ethernet.h> #include <net/if.h> - #include <netinet/in.h> #include <netinet/if_ether.h> - #include <net/bpf.h> -#if defined(__FreeBSD__) #include <machine/clock.h> -#endif -#include <i386/isa/isa_device.h> -#include <i386/isa/if_epreg.h> #include <i386/isa/elink.h> - -/* DELAY_MULTIPLE: How much to boost "base" delays, except - * for the inter-bit delays in get_eeprom_data. A cyrix Media GX needed this. - */ -#define DELAY_MULTIPLE 10 -#define BIT_DELAY_MULTIPLE 10 +#include <dev/ep/if_epreg.h> +#include <dev/ep/if_epvar.h> /* Exported variables */ -u_long ep_unit; +struct ep_softc * ep_softc[NEP]; +struct ep_board ep_board[EP_MAX_BOARDS + 1]; int ep_boards; -struct ep_board ep_board[EP_MAX_BOARDS + 1]; - -static int eeprom_rdy __P((struct ep_softc *sc)); - -static int ep_isa_probe __P((struct isa_device *)); -static struct ep_board * ep_look_for_board_at __P((struct isa_device *is)); -static int ep_isa_attach __P((struct isa_device *)); -static int epioctl __P((struct ifnet * ifp, u_long, caddr_t)); - -static void epinit __P((void *)); -static ointhand2_t epintr; -static void epread __P((struct ep_softc *)); -void epreset __P((int)); -static void epstart __P((struct ifnet *)); -static void epstop __P((struct ep_softc *)); -static void epwatchdog __P((struct ifnet *)); - -#if 0 -static int send_ID_sequence __P((int)); -#endif -static int get_eeprom_data __P((int, int)); - -static struct ep_softc* ep_softc[NEP]; -static int ep_current_tag = EP_LAST_TAG + 1; -static char *ep_conn_type[] = {"UTP", "AUI", "???", "BNC"}; - -#define ep_ftst(f) (sc->stat&(f)) -#define ep_fset(f) (sc->stat|=(f)) -#define ep_frst(f) (sc->stat&=~(f)) - -struct isa_driver epdriver = { - ep_isa_probe, - ep_isa_attach, - "ep", - 0 -}; - -#include "card.h" - -#if NCARD > 0 -#include <sys/select.h> -#include <sys/module.h> -#include <pccard/cardinfo.h> -#include <pccard/slot.h> - -/* - * PC-Card (PCMCIA) specific code. - */ -static int ep_pccard_init __P((struct pccard_devinfo *)); -static int ep_pccard_attach __P((struct pccard_devinfo *)); -static void ep_unload __P((struct pccard_devinfo *)); -static int card_intr __P((struct pccard_devinfo *)); -static int ep_pccard_identify (struct ep_board *epb, int unit); - -PCCARD_MODULE(ep, ep_pccard_init, ep_unload, card_intr, 0, net_imask); - -/* - * Initialize the device - called from Slot manager. - */ -static int -ep_pccard_init(devi) - struct pccard_devinfo *devi; -{ - struct isa_device *is = &devi->isahd; - struct ep_softc *sc = ep_softc[is->id_unit]; - struct ep_board *epb; - int i; - - epb = &ep_board[is->id_unit]; - - if (sc == 0) { - if ((sc = ep_alloc(is->id_unit, epb)) == 0) { - return (ENXIO); - } - ep_unit++; - } - - /* get_e() requires these. */ - sc->ep_io_addr = is->id_iobase; - sc->unit = is->id_unit; - epb->epb_addr = is->id_iobase; - epb->epb_used = 1; - - /* - * XXX - Certain (newer?) 3Com cards need epb->cmd_off == 2. Sadly, - * you need to have a correct cmd_off in order to identify the card. - * So we have to hit it with both and cross our virtual fingers. There's - * got to be a better way to do this. jyoung@accessus.net 09/11/1999 - */ - - epb->cmd_off = 0; - epb->prod_id = get_e(sc, EEPROM_PROD_ID); - if (!ep_pccard_identify(epb, is->id_unit)) { - if (bootverbose) printf("ep%d: Pass 1 of 2 detection failed (nonfatal)\n", is->id_unit); - epb->cmd_off = 2; - epb->prod_id = get_e(sc, EEPROM_PROD_ID); - if (!ep_pccard_identify(epb, is->id_unit)) { - if (bootverbose) printf("ep%d: Pass 2 of 2 detection failed (fatal!)\n", is->id_unit); - printf("ep%d: Unit failed to come ready or product ID unknown! (id 0x%x)\n", is->id_unit, epb->prod_id); - return (ENXIO); - } - } - - epb->res_cfg = get_e(sc, EEPROM_RESOURCE_CFG); - for (i = 0; i < 3; i++) - sc->epb->eth_addr[i] = get_e(sc, EEPROM_NODE_ADDR_0 + i); - - if (ep_pccard_attach(devi) == 0) - return (ENXIO); - - sc->arpcom.ac_if.if_snd.ifq_maxlen = ifqmaxlen; - return (0); -} - -static int -ep_pccard_identify(epb, unit) - struct ep_board *epb; - int unit; -{ - /* Determine device type and associated MII capabilities */ - switch (epb->prod_id) { - case 0x6055: /* 3C556 */ - if (bootverbose) printf("ep%d: 3Com 3C556\n", unit); - epb->mii_trans = 1; - return (1); - break; /* NOTREACHED */ - case 0x4057: /* 3C574 */ - if (bootverbose) printf("ep%d: 3Com 3C574\n", unit); - epb->mii_trans = 1; - return (1); - break; /* NOTREACHED */ - case 0x4b57: /* 3C574B */ - if (bootverbose) printf("ep%d: 3Com 3C574B, Megahertz 3CCFE574BT or Fast Etherlink 3C574-TX\n", unit); - epb->mii_trans = 1; - return (1); - break; /* NOTREACHED */ - case 0x9058: /* 3C589 */ - if (bootverbose) printf("ep%d: 3Com Etherlink III 3C589[B/C/D]\n", unit); - epb->mii_trans = 0; - return (1); - break; /* NOTREACHED */ - } - return (0); -} - -static int -ep_pccard_attach(devi) - struct pccard_devinfo *devi; -{ - struct isa_device *is = &devi->isahd; - struct ep_softc *sc = ep_softc[is->id_unit]; - u_short config; - - sc->ep_connectors = 0; - config = inw(IS_BASE + EP_W0_CONFIG_CTRL); - if (config & IS_BNC) { - sc->ep_connectors |= BNC; - } - if (config & IS_UTP) { - sc->ep_connectors |= UTP; - } - if (!(sc->ep_connectors & 7)) - /* (Apparently) non-fatal */ - if(bootverbose) printf("ep%d: No connectors or MII.\n", is->id_unit); - - sc->ep_connector = inw(BASE + EP_W0_ADDRESS_CFG) >> ACF_CONNECTOR_BITS; - - /* ROM size = 0, ROM base = 0 */ - /* For now, ignore AUTO SELECT feature of 3C589B and later. */ - outw(BASE + EP_W0_ADDRESS_CFG, get_e(sc, EEPROM_ADDR_CFG) & 0xc000); - - /* Fake IRQ must be 3 */ - outw(BASE + EP_W0_RESOURCE_CFG, (sc->epb->res_cfg & 0x0fff) | 0x3000); - - outw(BASE + EP_W0_PRODUCT_ID, sc->epb->prod_id); - - if (sc->epb->mii_trans) { - /* - * turn on the MII transciever - */ - GO_WINDOW(3); - outw(BASE + EP_W3_OPTIONS, 0x8040); - DELAY(1000); - outw(BASE + EP_W3_OPTIONS, 0xc040); - outw(BASE + EP_COMMAND, RX_RESET); - outw(BASE + EP_COMMAND, TX_RESET); - while (inw(BASE + EP_STATUS) & S_COMMAND_IN_PROGRESS); - DELAY(1000); - outw(BASE + EP_W3_OPTIONS, 0x8040); - } +u_long ep_unit; - ep_attach(sc); +static char * ep_conn_type[] = {"UTP", "AUI", "???", "BNC"}; - return 1; -} +static int eeprom_rdy __P((struct ep_softc *sc)); +static int epioctl __P((struct ifnet * ifp, u_long, caddr_t)); +static void epinit __P((void *)); +static void epread __P((struct ep_softc *)); +static void epstart __P((struct ifnet *)); +static void epstop __P((struct ep_softc *)); +static void epwatchdog __P((struct ifnet *)); -static void -ep_unload(devi) - struct pccard_devinfo *devi; -{ - struct ep_softc *sc = ep_softc[devi->isahd.id_unit]; - - if (sc->gone) { - printf("ep%d: already unloaded\n", devi->isahd.id_unit); - return; - } - sc->arpcom.ac_if.if_flags &= ~IFF_RUNNING; - sc->gone = 1; - printf("ep%d: unload\n", devi->isahd.id_unit); -} - -/* - * card_intr - Shared interrupt called from - * front end of PC-Card handler. - */ -static int -card_intr(devi) - struct pccard_devinfo *devi; -{ - epintr(devi->isahd.id_unit); - return(1); -} -#endif /* NCARD > 0 */ +#define EP_FTST(sc, f) (sc->stat&(f)) +#define EP_FSET(sc, f) (sc->stat|=(f)) +#define EP_FRST(sc, f) (sc->stat&=~(f)) static int eeprom_rdy(sc) @@ -339,120 +114,6 @@ eeprom_rdy(sc) return (1); } -static struct ep_board * -ep_look_for_board_at(is) - struct isa_device *is; -{ - int data, i, j, id_port = ELINK_ID_PORT; - int count = 0; - - if (ep_current_tag == (EP_LAST_TAG + 1)) { - /* Come here just one time */ - - ep_current_tag--; - - /* Look for the ISA boards. Init and leave them actived */ - outb(id_port, 0); - outb(id_port, 0); - - elink_idseq(0xCF); - - elink_reset(); - DELAY(DELAY_MULTIPLE * 10000); - for (i = 0; i < EP_MAX_BOARDS; i++) { - outb(id_port, 0); - outb(id_port, 0); - elink_idseq(0xCF); - - data = get_eeprom_data(id_port, EEPROM_MFG_ID); - if (data != MFG_ID) - break; - - /* resolve contention using the Ethernet address */ - - for (j = 0; j < 3; j++) - get_eeprom_data(id_port, j); - - /* and save this address for later use */ - - for (j = 0; j < 3; j++) - ep_board[ep_boards].eth_addr[j] = get_eeprom_data(id_port, j); - - ep_board[ep_boards].res_cfg = - get_eeprom_data(id_port, EEPROM_RESOURCE_CFG); - - ep_board[ep_boards].prod_id = - get_eeprom_data(id_port, EEPROM_PROD_ID); - - ep_board[ep_boards].epb_used = 0; -#ifdef PC98 - ep_board[ep_boards].epb_addr = - (get_eeprom_data(id_port, EEPROM_ADDR_CFG) & 0x1f) * 0x100 + 0x40d0; -#else - ep_board[ep_boards].epb_addr = - (get_eeprom_data(id_port, EEPROM_ADDR_CFG) & 0x1f) * 0x10 + 0x200; - - if (ep_board[ep_boards].epb_addr > 0x3E0) - /* Board in EISA configuration mode */ - continue; -#endif /* PC98 */ - - outb(id_port, ep_current_tag); /* tags board */ - outb(id_port, ACTIVATE_ADAPTER_TO_CONFIG); - ep_boards++; - count++; - ep_current_tag--; - } - - ep_board[ep_boards].epb_addr = 0; - if (count) { - printf("%d 3C5x9 board(s) on ISA found at", count); - for (j = 0; ep_board[j].epb_addr; j++) - if (ep_board[j].epb_addr <= 0x3E0) - printf(" 0x%x", ep_board[j].epb_addr); - printf("\n"); - } - } - - /* we have two cases: - * - * 1. Device was configured with 'port ?' - * In this case we search for the first unused card in list - * - * 2. Device was configured with 'port xxx' - * In this case we search for the unused card with that address - * - */ - - if (IS_BASE == -1) { /* port? */ - for (i = 0; ep_board[i].epb_addr && ep_board[i].epb_used; i++) - ; - if (ep_board[i].epb_addr == 0) - return 0; - - IS_BASE = ep_board[i].epb_addr; - ep_board[i].epb_used = 1; - - return &ep_board[i]; - } else { - for (i = 0; - ep_board[i].epb_addr && ep_board[i].epb_addr != IS_BASE; - i++) - ; - - if (ep_board[i].epb_used || ep_board[i].epb_addr != IS_BASE) - return 0; - - if (inw(IS_BASE + EP_W0_EEPROM_COMMAND) & EEPROM_TST_MODE) { - printf("ep%d: 3c5x9 at 0x%x in PnP mode. Disable PnP mode!\n", - is->id_unit, IS_BASE); - } - ep_board[i].epb_used = 1; - - return &ep_board[i]; - } -} - /* * get_e: gets a 16 bits word from the EEPROM. we must have set the window * before @@ -472,8 +133,8 @@ get_e(sc, offset) struct ep_softc * ep_alloc(unit, epb) - int unit; - struct ep_board *epb; + int unit; + struct ep_board *epb; { struct ep_softc *sc; @@ -515,108 +176,6 @@ ep_free(sc) } int -ep_isa_probe(is) - struct isa_device *is; -{ - struct ep_softc *sc; - struct ep_board *epb; - u_short k; - - if ((epb = ep_look_for_board_at(is)) == 0) - return (0); - - /* - * Allocate a storage area for us - */ - sc = ep_alloc(ep_unit, epb); - if (!sc) - return (0); - - is->id_unit = ep_unit++; - - /* - * The iobase was found and MFG_ID was 0x6d50. PROD_ID should be - * 0x9[0-f]50 (IBM-PC) - * 0x9[0-f]5[0-f] (PC-98) - */ - GO_WINDOW(0); - k = sc->epb->prod_id; -#ifdef PC98 - if ((k & 0xf0f0) != (PROD_ID & 0xf0f0)) { -#else - if ((k & 0xf0ff) != (PROD_ID & 0xf0ff)) { -#endif - printf("ep_isa_probe: ignoring model %04x\n", k); - ep_free(sc); - return (0); - } - - k = sc->epb->res_cfg; - - k >>= 12; - - /* Now we have two cases again: - * - * 1. Device was configured with 'irq?' - * In this case we use irq read from the board - * - * 2. Device was configured with 'irq xxx' - * In this case we set up the board to use specified interrupt - * - */ - - if (is->id_irq == 0) { /* irq? */ - is->id_irq = 1 << ((k == 2) ? 9 : k); - } - - sc->stat = 0; /* 16 bit access */ - - /* By now, the adapter is already activated */ - - return (EP_IOSIZE); /* 16 bytes of I/O space used. */ -} - -static int -ep_isa_attach(is) - struct isa_device *is; -{ - struct ep_softc *sc = ep_softc[is->id_unit]; - u_short config; - int irq; - - is->id_ointr = epintr; - sc->ep_connectors = 0; - config = inw(IS_BASE + EP_W0_CONFIG_CTRL); - if (config & IS_AUI) { - sc->ep_connectors |= AUI; - } - if (config & IS_BNC) { - sc->ep_connectors |= BNC; - } - if (config & IS_UTP) { - sc->ep_connectors |= UTP; - } - if (!(sc->ep_connectors & 7)) - printf("no connectors!"); - sc->ep_connector = inw(BASE + EP_W0_ADDRESS_CFG) >> ACF_CONNECTOR_BITS; - /* - * Write IRQ value to board - */ - - irq = ffs(is->id_irq) - 1; - if (irq == -1) { - printf(" invalid irq... cannot attach\n"); - return 0; - } - - GO_WINDOW(0); - SET_IRQ(BASE, irq); - - ep_attach(sc); - return 1; -} - -int ep_attach(sc) struct ep_softc *sc; { @@ -680,7 +239,7 @@ ep_attach(sc) sc->rx_bpf_disc = sc->rx_overrunf = sc->rx_overrunl = sc->tx_underrun = 0; #endif - ep_fset(F_RX_FIRST); + EP_FSET(sc, F_RX_FIRST); sc->top = sc->mcur = 0; if (!attached) { @@ -819,7 +378,7 @@ epinit(xsc) sc->rx_bpf_disc = sc->rx_overrunf = sc->rx_overrunl = sc->tx_underrun = 0; #endif - ep_fset(F_RX_FIRST); + EP_FSET(sc, F_RX_FIRST); if (sc->top) { m_freem(sc->top); sc->top = sc->mcur = 0; @@ -901,7 +460,7 @@ startagain: outw(BASE + EP_W1_TX_PIO_WR_1, 0x0); /* Second dword meaningless */ for (top = m; m != 0; m = m->m_next) - if (ep_ftst(F_ACCESS_32_BITS)) { + if (EP_FTST(sc, F_ACCESS_32_BITS)) { outsl(BASE + EP_W1_TX_PIO_WR_1, mtod(m, caddr_t), m->m_len / 4); if (m->m_len & 3) @@ -945,19 +504,6 @@ readcheck: goto startagain; } -static void -epintr(unit) - int unit; -{ - register struct ep_softc *sc = ep_softc[unit]; - - if (sc->gone) { - return; - } - - ep_intr(sc); -} - void ep_intr(arg) void *arg; @@ -1095,7 +641,7 @@ read_again: * expect */ #ifdef EP_LOCAL_STATS - if (ep_ftst(F_RX_FIRST)) + if (EP_FTST(sc, F_RX_FIRST)) sc->rx_overrunf++; else sc->rx_overrunl++; @@ -1105,7 +651,7 @@ read_again: } rx_fifo = rx_fifo2 = status & RX_BYTES_MASK; - if (ep_ftst(F_RX_FIRST)) { + if (EP_FTST(sc, F_RX_FIRST)) { MGETHDR(m, M_DONTWAIT, MT_DATA); if (!m) goto out; @@ -1143,7 +689,7 @@ read_again: mcur->m_next = m; lenthisone = min(rx_fifo, M_TRAILINGSPACE(m)); } - if (ep_ftst(F_ACCESS_32_BITS)) { /* default for EISA configured cards*/ + if (EP_FTST(sc, F_ACCESS_32_BITS)) { /* default for EISA configured cards*/ insl(BASE + EP_W1_RX_PIO_RD_1, mtod(m, caddr_t) + m->m_len, lenthisone / 4); m->m_len += (lenthisone & ~3); @@ -1168,7 +714,7 @@ read_again: #ifdef EP_LOCAL_STATS sc->rx_no_first++; /* to know how often we come here */ #endif - ep_frst(F_RX_FIRST); + EP_FRST(sc, F_RX_FIRST); if (!((status = inw(BASE + EP_W1_RX_STATUS)) & ERR_RX_INCOMPLETE)) { /* we see if by now, the packet has completly arrived */ goto read_again; @@ -1178,7 +724,7 @@ read_again: } outw(BASE + EP_COMMAND, RX_DISCARD_TOP_PACK); ++ifp->if_ipackets; - ep_fset(F_RX_FIRST); + EP_FSET(sc, F_RX_FIRST); top->m_pkthdr.rcvif = &sc->arpcom.ac_if; top->m_pkthdr.len = sc->cur_len; @@ -1201,7 +747,7 @@ read_again: m_freem(sc->top); sc->top = 0; } - ep_fset(F_RX_FIRST); + EP_FSET(sc, F_RX_FIRST); #ifdef EP_LOCAL_STATS sc->rx_bpf_disc++; #endif @@ -1228,7 +774,7 @@ out: sc->rx_no_mbuf++; #endif } - ep_fset(F_RX_FIRST); + EP_FSET(sc, F_RX_FIRST); while (inw(BASE + EP_STATUS) & S_COMMAND_IN_PROGRESS); outw(BASE + EP_COMMAND, SET_RX_EARLY_THRESH | RX_INIT_EARLY_THRESH); } @@ -1338,50 +884,4 @@ epstop(sc) outw(BASE + EP_COMMAND, SET_RX_FILTER); } - -#if 0 -static int -send_ID_sequence(port) - int port; -{ - int cx, al; - - for (al = 0xff, cx = 0; cx < 255; cx++) { - outb(port, al); - al <<= 1; - if (al & 0x100) - al ^= 0xcf; - } - return (1); -} -#endif - - -/* - * We get eeprom data from the id_port given an offset into the eeprom. - * Basically; after the ID_sequence is sent to all of the cards; they enter - * the ID_CMD state where they will accept command requests. 0x80-0xbf loads - * the eeprom data. We then read the port 16 times and with every read; the - * cards check for contention (ie: if one card writes a 0 bit and another - * writes a 1 bit then the host sees a 0. At the end of the cycle; each card - * compares the data on the bus; if there is a difference then that card goes - * into ID_WAIT state again). In the meantime; one bit of data is returned in - * the AX register which is conveniently returned to us by inb(). Hence; we - * read 16 times getting one bit of data with each read. - */ - -static int -get_eeprom_data(id_port, offset) - int id_port; - int offset; -{ - int i, data = 0; - outb(id_port, 0x80 + offset); - for (i = 0; i < 16; i++) { - DELAY(BIT_DELAY_MULTIPLE * 1000); - data = (data << 1) | (inw(id_port) & 1); - } - return (data); -} - #endif /* NEP > 0 */ diff --git a/sys/dev/ep/if_ep_isa.c b/sys/dev/ep/if_ep_isa.c new file mode 100644 index 0000000..b36ff57 --- /dev/null +++ b/sys/dev/ep/if_ep_isa.c @@ -0,0 +1,344 @@ +/* + * Copyright (c) 1994 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. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Herb Peyerl. + * 4. The name of Herb Peyerl 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. + * + * $FreeBSD$ + */ + +#include <sys/param.h> +#include <sys/kernel.h> +#include <sys/systm.h> +#include <sys/malloc.h> +#include <sys/mbuf.h> +#include <sys/socket.h> +#include <sys/sockio.h> + +#include <net/ethernet.h> +#include <net/if.h> +#include <netinet/in.h> +#include <netinet/if_ether.h> + +#include <machine/clock.h> + +#include <i386/isa/isa_device.h> + +#include <dev/ep/if_epreg.h> +#include <dev/ep/if_epvar.h> +#include <i386/isa/elink.h> + +static int ep_isa_probe (struct isa_device *); +static int ep_isa_attach (struct isa_device *); +static struct ep_board *ep_look_for_board_at (struct isa_device *is); +static int get_eeprom_data (int, int); +static void epintr (int); + +#if 0 +static int send_ID_sequence (int); +#endif + +static int ep_current_tag = EP_LAST_TAG + 1; + +struct isa_driver epdriver = { + ep_isa_probe, + ep_isa_attach, + "ep", + 0 +}; + +int +ep_isa_probe(is) + struct isa_device *is; +{ + struct ep_softc *sc; + struct ep_board *epb; + u_short k; + + if ((epb = ep_look_for_board_at(is)) == 0) + return (0); + + /* + * Allocate a storage area for us + */ + sc = ep_alloc(ep_unit, epb); + if (!sc) + return (0); + + is->id_unit = ep_unit++; + + /* + * The iobase was found and MFG_ID was 0x6d50. PROD_ID should be + * 0x9[0-f]50 (IBM-PC) + * 0x9[0-f]5[0-f] (PC-98) + */ + GO_WINDOW(0); + k = sc->epb->prod_id; +#ifdef PC98 + if ((k & 0xf0f0) != (PROD_ID & 0xf0f0)) { +#else + if ((k & 0xf0ff) != (PROD_ID & 0xf0ff)) { +#endif + printf("ep_isa_probe: ignoring model %04x\n", k); + ep_free(sc); + return (0); + } + + k = sc->epb->res_cfg; + + k >>= 12; + + /* Now we have two cases again: + * + * 1. Device was configured with 'irq?' + * In this case we use irq read from the board + * + * 2. Device was configured with 'irq xxx' + * In this case we set up the board to use specified interrupt + * + */ + + if (is->id_irq == 0) { /* irq? */ + is->id_irq = 1 << ((k == 2) ? 9 : k); + } + + sc->stat = 0; /* 16 bit access */ + + /* By now, the adapter is already activated */ + + return (EP_IOSIZE); /* 16 bytes of I/O space used. */ +} + +static int +ep_isa_attach(is) + struct isa_device *is; +{ + struct ep_softc *sc = ep_softc[is->id_unit]; + u_short config; + int irq; + + is->id_ointr = epintr; + sc->ep_connectors = 0; + config = inw(IS_BASE + EP_W0_CONFIG_CTRL); + if (config & IS_AUI) { + sc->ep_connectors |= AUI; + } + if (config & IS_BNC) { + sc->ep_connectors |= BNC; + } + if (config & IS_UTP) { + sc->ep_connectors |= UTP; + } + if (!(sc->ep_connectors & 7)) + printf("no connectors!"); + sc->ep_connector = inw(BASE + EP_W0_ADDRESS_CFG) >> ACF_CONNECTOR_BITS; + /* + * Write IRQ value to board + */ + + irq = ffs(is->id_irq) - 1; + if (irq == -1) { + printf(" invalid irq... cannot attach\n"); + return 0; + } + + GO_WINDOW(0); + SET_IRQ(BASE, irq); + + ep_attach(sc); + return 1; +} + +static struct ep_board * +ep_look_for_board_at(is) + struct isa_device *is; +{ + int data, i, j, id_port = ELINK_ID_PORT; + int count = 0; + + if (ep_current_tag == (EP_LAST_TAG + 1)) { + /* Come here just one time */ + + ep_current_tag--; + + /* Look for the ISA boards. Init and leave them actived */ + outb(id_port, 0); + outb(id_port, 0); + + elink_idseq(0xCF); + + elink_reset(); + DELAY(DELAY_MULTIPLE * 10000); + for (i = 0; i < EP_MAX_BOARDS; i++) { + outb(id_port, 0); + outb(id_port, 0); + elink_idseq(0xCF); + + data = get_eeprom_data(id_port, EEPROM_MFG_ID); + if (data != MFG_ID) + break; + + /* resolve contention using the Ethernet address */ + + for (j = 0; j < 3; j++) + get_eeprom_data(id_port, j); + + /* and save this address for later use */ + + for (j = 0; j < 3; j++) + ep_board[ep_boards].eth_addr[j] = get_eeprom_data(id_port, j); + + ep_board[ep_boards].res_cfg = + get_eeprom_data(id_port, EEPROM_RESOURCE_CFG); + + ep_board[ep_boards].prod_id = + get_eeprom_data(id_port, EEPROM_PROD_ID); + + ep_board[ep_boards].epb_used = 0; +#ifdef PC98 + ep_board[ep_boards].epb_addr = + (get_eeprom_data(id_port, EEPROM_ADDR_CFG) & 0x1f) * + 0x100 + 0x40d0; +#else + ep_board[ep_boards].epb_addr = + (get_eeprom_data(id_port, EEPROM_ADDR_CFG) & 0x1f) * + 0x10 + 0x200; + + if (ep_board[ep_boards].epb_addr > 0x3E0) + /* Board in EISA configuration mode */ + continue; +#endif /* PC98 */ + + outb(id_port, ep_current_tag); /* tags board */ + outb(id_port, ACTIVATE_ADAPTER_TO_CONFIG); + ep_boards++; + count++; + ep_current_tag--; + } + + ep_board[ep_boards].epb_addr = 0; + if (count) { + printf("%d 3C5x9 board(s) on ISA found at", count); + for (j = 0; ep_board[j].epb_addr; j++) + if (ep_board[j].epb_addr <= 0x3E0) + printf(" 0x%x", ep_board[j].epb_addr); + printf("\n"); + } + } + + /* we have two cases: + * + * 1. Device was configured with 'port ?' + * In this case we search for the first unused card in list + * + * 2. Device was configured with 'port xxx' + * In this case we search for the unused card with that address + * + */ + + if (IS_BASE == -1) { /* port? */ + for (i = 0; ep_board[i].epb_addr && ep_board[i].epb_used; i++) + ; + if (ep_board[i].epb_addr == 0) + return 0; + + IS_BASE = ep_board[i].epb_addr; + ep_board[i].epb_used = 1; + + return &ep_board[i]; + } else { + for (i = 0; + ep_board[i].epb_addr && ep_board[i].epb_addr != IS_BASE; + i++) + ; + + if (ep_board[i].epb_used || ep_board[i].epb_addr != IS_BASE) + return 0; + + if (inw(IS_BASE + EP_W0_EEPROM_COMMAND) & EEPROM_TST_MODE) { + printf("ep%d: 3c5x9 at 0x%x in PnP mode. Disable PnP mode!\n", + is->id_unit, IS_BASE); + } + ep_board[i].epb_used = 1; + + return &ep_board[i]; + } +} + +/* + * We get eeprom data from the id_port given an offset into the eeprom. + * Basically; after the ID_sequence is sent to all of the cards; they enter + * the ID_CMD state where they will accept command requests. 0x80-0xbf loads + * the eeprom data. We then read the port 16 times and with every read; the + * cards check for contention (ie: if one card writes a 0 bit and another + * writes a 1 bit then the host sees a 0. At the end of the cycle; each card + * compares the data on the bus; if there is a difference then that card goes + * into ID_WAIT state again). In the meantime; one bit of data is returned in + * the AX register which is conveniently returned to us by inb(). Hence; we + * read 16 times getting one bit of data with each read. + */ + +static int +get_eeprom_data(id_port, offset) + int id_port; + int offset; +{ + int i, data = 0; + outb(id_port, 0x80 + offset); + for (i = 0; i < 16; i++) { + DELAY(BIT_DELAY_MULTIPLE * 1000); + data = (data << 1) | (inw(id_port) & 1); + } + return (data); +} + +void +epintr(unit) + int unit; +{ + register struct ep_softc *sc = ep_softc[unit]; + + ep_intr(sc); + + return; +} + +#if 0 +static int +send_ID_sequence(port) + int port; +{ + int cx, al; + + for (al = 0xff, cx = 0; cx < 255; cx++) { + outb(port, al); + al <<= 1; + if (al & 0x100) + al ^= 0xcf; + } + return (1); +} +#endif diff --git a/sys/dev/ep/if_ep_mca.c b/sys/dev/ep/if_ep_mca.c new file mode 100644 index 0000000..6e0b9e3 --- /dev/null +++ b/sys/dev/ep/if_ep_mca.c @@ -0,0 +1,219 @@ +/*- + * Copyright (c) 1999 Matthew N. Dodd <winter@jurai.net> + * 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. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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. + * + * $FreeBSD$ + */ + +#include <sys/types.h> +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/socket.h> + +#include <vm/vm.h> +#include <vm/vm_param.h> +#include <vm/pmap.h> + +#include <machine/clock.h> +#include <machine/cpufunc.h> +#include <machine/md_var.h> + +#include <sys/module.h> +#include <sys/bus.h> +#include <machine/bus.h> +#include <machine/resource.h> +#include <sys/rman.h> + +#include <net/if.h> +#include <net/if_mib.h> + +#include <netinet/in.h> +#include <netinet/if_ether.h> + +#include <dev/mca/mca_busreg.h> +#include <dev/mca/mca_busvar.h> + +#include <dev/ep/if_epreg.h> +#include <dev/ep/if_epvar.h> + +#define EP_MCA_627C 0x627C +#define EP_MCA_627D 0x627D +#define EP_MCA_62DB 0x62db +#define EP_MCA_62F6 0x62f6 +#define EP_MCA_62F7 0x62f7 + +static struct mca_ident ep_mca_devs[] = { + { EP_MCA_627C, "3Com 3C529 Network Adapter" }, + { EP_MCA_627D, "3Com 3C529-TP Network Adapter" }, + + /* + * These are from the linux 3c509 driver. + * I have not seen the ADFs for them and have + * not tested or even seen the hardware. + * Someone with the ADFs should replace the names with + * whatever is in the AdapterName field of the ADF. + * (and fix the media setup for the cards as well.) + */ + { EP_MCA_62DB, "3Com 3c529 EtherLink III (test mode)" }, + { EP_MCA_62F6, "3Com 3c529 EtherLink III (TP or coax)" }, + { EP_MCA_62F7, "3Com 3c529 EtherLink III (TP)" }, + + { 0, NULL }, +}; + +#define EP_MCA_IOPORT_POS MCA_ADP_POS(MCA_POS2) +#define EP_MCA_IOPORT_MASK 0xfc +#define EP_MCA_IOPORT_SIZE 0x0f +#define EP_MCA_IOPORT(pos) ((((u_int32_t)pos & EP_MCA_IOPORT_MASK) \ + | 0x02) << 8) + +#define EP_MCA_IRQ_POS MCA_ADP_POS(MCA_POS3) +#define EP_MCA_IRQ_MASK 0x0f +#define EP_MCA_IRQ(pos) (pos & EP_MCA_IRQ_MASK) + +#define EP_MCA_MEDIA_POS MCA_ADP_POS(MCA_POS2) +#define EP_MCA_MEDIA_MASK 0x03 +#define EP_MCA_MEDIA(pos) (pos & EP_MCA_MEDIA_MASK) + +static int +ep_mca_probe (device_t dev) +{ + const char * desc; + u_int32_t iobase = 0; + u_int8_t irq = 0; + u_int8_t pos; + + desc = mca_match_id(mca_get_id(dev), ep_mca_devs); + if (!desc) + return (ENXIO); + device_set_desc(dev, desc); + + pos = mca_pos_read(dev, EP_MCA_IOPORT_POS); + iobase = EP_MCA_IOPORT(pos); + + pos = mca_pos_read(dev, EP_MCA_IRQ_POS); + irq = EP_MCA_IRQ(pos); + + mca_add_iospace(dev, iobase, EP_MCA_IOPORT_SIZE); + mca_add_irq(dev, irq); + + return (0); +} + +static int +ep_mca_attach (device_t dev) +{ + struct ep_softc * sc; + struct ep_board * epb; + struct resource * io = 0; + struct resource * irq = 0; + u_int8_t pos; + int unit = device_get_unit(dev); + int i, rid; + void * ih; + + rid = 0; + io = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, + 0, ~0, 1, RF_ACTIVE); + if (!io) { + device_printf(dev, "No I/O space?!\n"); + goto bad; + } + + rid = 0; + irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, + 0, ~0, 1, RF_ACTIVE); + if (!irq) { + device_printf(dev, "No irq?!\n"); + goto bad; + } + + epb = &ep_board[ep_boards]; + + epb->epb_addr = rman_get_start(io); + epb->epb_used = 1; + + if(!(sc = ep_alloc(unit, epb))) + goto bad; + + ep_boards++; + + sc->stat = F_ACCESS_32_BITS; + + switch(mca_get_id(dev)) { + case EP_MCA_627C: + sc->ep_connectors = BNC|AUI; + break; + case EP_MCA_627D: + sc->ep_connectors = UTP|AUI; + break; + default: + break; + } + pos = mca_pos_read(dev, EP_MCA_MEDIA_POS); + sc->ep_connector = EP_MCA_MEDIA(pos); + + /* + * Retrieve our ethernet address + */ + GO_WINDOW(0); + for(i = 0; i < 3; i++) + sc->epb->eth_addr[i] = get_e(sc, i); + + GO_WINDOW(0); + SET_IRQ(BASE, rman_get_start(irq)); + + ep_attach(sc); + + bus_setup_intr(dev, irq, INTR_TYPE_NET, ep_intr, sc, &ih); + + return (0); + +bad: + if (io) + bus_release_resource(dev, SYS_RES_IOPORT, 0, io); + if (irq) + bus_release_resource(dev, SYS_RES_IRQ, 0, irq); + + return (-1); +} + +static device_method_t ep_mca_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, ep_mca_probe), + DEVMETHOD(device_attach, ep_mca_attach), + + { 0, 0 } +}; + +static driver_t ep_mca_driver = { + "ep", + ep_mca_methods, + 1, /* unusep */ +}; + +static devclass_t ep_devclass; + +DRIVER_MODULE(ep, mca, ep_mca_driver, ep_devclass, 0, 0); diff --git a/sys/dev/ep/if_ep_pccard.c b/sys/dev/ep/if_ep_pccard.c new file mode 100644 index 0000000..4b18497 --- /dev/null +++ b/sys/dev/ep/if_ep_pccard.c @@ -0,0 +1,245 @@ +/* + * Copyright (c) 1994 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. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Herb Peyerl. + * 4. The name of Herb Peyerl 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. + * + * $FreeBSD$ + */ + +/* + * Pccard support for 3C589 by: + * HAMADA Naoki + * nao@tom-yam.or.jp + */ + +#include <sys/param.h> +#include <sys/kernel.h> +#include <sys/systm.h> +#include <sys/malloc.h> +#include <sys/mbuf.h> +#include <sys/socket.h> +#include <sys/sockio.h> + +#include <net/ethernet.h> +#include <net/if.h> +#include <netinet/in.h> +#include <netinet/if_ether.h> + +#include <machine/clock.h> + +#include <sys/select.h> +#include <sys/module.h> +#include <pccard/cardinfo.h> +#include <pccard/slot.h> + +#include <dev/ep/if_epreg.h> +#include <dev/ep/if_epvar.h> + +/* + * PC-Card (PCMCIA) specific code. + */ +static int ep_pccard_init (struct pccard_devinfo *); +static int ep_pccard_attach ((struct pccard_devinfo *); +static void ep_pccard_unload (struct pccard_devinfo *); +static int ep_pccard_intr (struct pccard_devinfo *); +static int ep_pccard_identify (struct ep_board *epb, int unit); + +PCCARD_MODULE(ep, ep_pccard_init, ep_pccard_unload, ep_pccard_intr, 0, net_imask); + +/* + * Initialize the device - called from Slot manager. + */ +static int +ep_pccard_init(devi) + struct pccard_devinfo *devi; +{ + struct isa_device *is = &devi->isahd; + struct ep_softc *sc = ep_softc[is->id_unit]; + struct ep_board *epb; + int i; + + epb = &ep_board[is->id_unit]; + + if (sc == 0) { + if ((sc = ep_alloc(is->id_unit, epb)) == 0) { + return (ENXIO); + } + ep_unit++; + } + + /* get_e() requires these. */ + sc->ep_io_addr = is->id_iobase; + sc->unit = is->id_unit; + epb->epb_addr = is->id_iobase; + epb->epb_used = 1; + + /* + * XXX - Certain (newer?) 3Com cards need epb->cmd_off == 2. Sadly, + * you need to have a correct cmd_off in order to identify the card. + * So we have to hit it with both and cross our virtual fingers. There's + * got to be a better way to do this. jyoung@accessus.net 09/11/1999 + */ + + epb->cmd_off = 0; + epb->prod_id = get_e(sc, EEPROM_PROD_ID); + if (!ep_pccard_identify(epb, is->id_unit)) { + if (bootverbose) printf("ep%d: Pass 1 of 2 detection failed (nonfatal)\n", is->id_unit); + epb->cmd_off = 2; + epb->prod_id = get_e(sc, EEPROM_PROD_ID); + if (!ep_pccard_identify(epb, is->id_unit)) { + if (bootverbose) printf("ep%d: Pass 2 of 2 detection failed (fatal!)\n", is->id_unit); + printf("ep%d: Unit failed to come ready or product ID unknown! (id 0x%x)\n", is->id_unit, epb->prod_id); + return (ENXIO); + } + } + + epb->res_cfg = get_e(sc, EEPROM_RESOURCE_CFG); + for (i = 0; i < 3; i++) + sc->epb->eth_addr[i] = get_e(sc, EEPROM_NODE_ADDR_0 + i); + + if (ep_pccard_attach(devi) == 0) + return (ENXIO); + + sc->arpcom.ac_if.if_snd.ifq_maxlen = ifqmaxlen; + return (0); +} + +static int +ep_pccard_identify(epb, unit) + struct ep_board *epb; + int unit; +{ + /* Determine device type and associated MII capabilities */ + switch (epb->prod_id) { + case 0x6055: /* 3C556 */ + if (bootverbose) printf("ep%d: 3Com 3C556\n", unit); + epb->mii_trans = 1; + return (1); + break; /* NOTREACHED */ + case 0x4057: /* 3C574 */ + if (bootverbose) printf("ep%d: 3Com 3C574\n", unit); + epb->mii_trans = 1; + return (1); + break; /* NOTREACHED */ + case 0x4b57: /* 3C574B */ + if (bootverbose) printf("ep%d: 3Com 3C574B, Megahertz 3CCFE574BT or Fast Etherlink 3C574-TX\n", unit); + epb->mii_trans = 1; + return (1); + break; /* NOTREACHED */ + case 0x9058: /* 3C589 */ + if (bootverbose) printf("ep%d: 3Com Etherlink III 3C589[B/C/D]\n", unit); + epb->mii_trans = 0; + return (1); + break; /* NOTREACHED */ + } + return (0); +} + +static int +ep_pccard_attach(devi) + struct pccard_devinfo *devi; +{ + struct isa_device *is = &devi->isahd; + struct ep_softc *sc = ep_softc[is->id_unit]; + u_short config; + + sc->ep_connectors = 0; + config = inw(IS_BASE + EP_W0_CONFIG_CTRL); + if (config & IS_BNC) { + sc->ep_connectors |= BNC; + } + if (config & IS_UTP) { + sc->ep_connectors |= UTP; + } + if (!(sc->ep_connectors & 7)) + /* (Apparently) non-fatal */ + if(bootverbose) printf("ep%d: No connectors or MII.\n", is->id_unit); + + sc->ep_connector = inw(BASE + EP_W0_ADDRESS_CFG) >> ACF_CONNECTOR_BITS; + + /* ROM size = 0, ROM base = 0 */ + /* For now, ignore AUTO SELECT feature of 3C589B and later. */ + outw(BASE + EP_W0_ADDRESS_CFG, get_e(sc, EEPROM_ADDR_CFG) & 0xc000); + + /* Fake IRQ must be 3 */ + outw(BASE + EP_W0_RESOURCE_CFG, (sc->epb->res_cfg & 0x0fff) | 0x3000); + + outw(BASE + EP_W0_PRODUCT_ID, sc->epb->prod_id); + + if (sc->epb->mii_trans) { + /* + * turn on the MII transciever + */ + GO_WINDOW(3); + outw(BASE + EP_W3_OPTIONS, 0x8040); + DELAY(1000); + outw(BASE + EP_W3_OPTIONS, 0xc040); + outw(BASE + EP_COMMAND, RX_RESET); + outw(BASE + EP_COMMAND, TX_RESET); + while (inw(BASE + EP_STATUS) & S_COMMAND_IN_PROGRESS); + DELAY(1000); + outw(BASE + EP_W3_OPTIONS, 0x8040); + } + + ep_attach(sc); + + return 1; +} + +static void +ep_pccard_unload(devi) + struct pccard_devinfo *devi; +{ + struct ep_softc *sc = ep_softc[devi->isahd.id_unit]; + + if (sc->gone) { + printf("ep%d: already unloaded\n", devi->isahd.id_unit); + return; + } + sc->arpcom.ac_if.if_flags &= ~IFF_RUNNING; + sc->gone = 1; + printf("ep%d: unload\n", devi->isahd.id_unit); +} + +/* + * card_intr - Shared interrupt called from + * front end of PC-Card handler. + */ +static int +ep_pccard_intr(devi) + struct pccard_devinfo *devi; +{ + struct ep_softc *sc = ep_softc[devi->isahd.id_unit]; + + if (sc->gone) { + return; + } + + ep_intr((void *)sc); + + return(1); +} diff --git a/sys/dev/ep/if_epreg.h b/sys/dev/ep/if_epreg.h index 08ff37b..fb729cb 100644 --- a/sys/dev/ep/if_epreg.h +++ b/sys/dev/ep/if_epreg.h @@ -19,78 +19,15 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * if_epreg.h,v 1.4 1994/11/13 10:12:37 gibbs Exp Modified by: - * - October 2, 1994 - - Modified by: Andres Vega Garcia - - INRIA - Sophia Antipolis, France - e-mail: avega@sophia.inria.fr - finger: avega@pax.inria.fr - - */ -/* * $FreeBSD$ - * - * Promiscuous mode added and interrupt logic slightly changed - * to reduce the number of adapter failures. Transceiver select - * logic changed to use value from EEPROM. Autoconfiguration - * features added. - * Done by: - * Serge Babkin - * Chelindbank (Chelyabinsk, Russia) - * babkin@hq.icb.chel.su - */ - -/* - * Pccard support for 3C589 by: - * HAMADA Naoki - * nao@tom-yam.or.jp */ /* - * Ethernet software status per interface. + * DELAY_MULTIPLE: How much to boost "base" delays, except + * for the inter-bit delays in get_eeprom_data. A cyrix Media GX needed this. */ -struct ep_softc { - struct arpcom arpcom; /* Ethernet common part */ - int ep_io_addr; /* i/o bus address */ - struct mbuf *top, *mcur; - short cur_len; - u_short ep_connectors; /* Connectors on this card. */ - u_char ep_connector; /* Configured connector. */ - int stat; /* some flags */ - int gone; /* adapter is not present (for PCCARD) */ -#define F_RX_FIRST 0x1 -#define F_PROMISC 0x8 - -#define F_ACCESS_32_BITS 0x100 - - struct ep_board *epb; - - int unit; - -#ifdef EP_LOCAL_STATS - short tx_underrun; - short rx_no_first; - short rx_no_mbuf; - short rx_bpf_disc; - short rx_overrunf; - short rx_overrunl; -#endif -}; - -struct ep_board { - int epb_addr; /* address of this board */ - char epb_used; /* was this entry already used for configuring ? */ - /* data from EEPROM for later use */ - u_short eth_addr[3]; /* Ethernet address */ - u_short prod_id; /* product ID */ - int cmd_off; /* command offset (bit shift) */ - int mii_trans; /* activate MII transiever */ - u_short res_cfg; /* resource configuration */ -}; - +#define DELAY_MULTIPLE 10 +#define BIT_DELAY_MULTIPLE 10 /* * Some global constants @@ -455,16 +392,6 @@ struct ep_board { #define RX_BYTES_MASK (u_short) (0x07ff) -extern struct ep_board ep_board[]; -extern int ep_boards; -extern u_long ep_unit; -extern struct ep_softc *ep_alloc __P((int unit, struct ep_board *epb)); -extern void ep_free __P((struct ep_softc *sc)); -extern void ep_intr __P((void *sc)); -extern int ep_attach __P((struct ep_softc *sc)); - -extern u_int16_t get_e __P((struct ep_softc *sc, int offset)); - /* * Config flags */ diff --git a/sys/dev/ep/if_epvar.h b/sys/dev/ep/if_epvar.h new file mode 100644 index 0000000..4ad224f --- /dev/null +++ b/sys/dev/ep/if_epvar.h @@ -0,0 +1,78 @@ +/* + * 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. + * + * $FreeBSD$ + */ + +/* + * Ethernet software status per interface. + */ +struct ep_softc { + struct arpcom arpcom; /* Ethernet common part */ + int ep_io_addr; /* i/o bus address */ + struct mbuf * top; + struct mbuf * mcur; + short cur_len; + u_short ep_connectors; /* Connectors on this card. */ + u_char ep_connector; /* Configured connector. */ + int stat; /* some flags */ + int gone; /* adapter is not present (for PCCARD) */ +#define F_RX_FIRST 0x1 +#define F_PROMISC 0x8 + +#define F_ACCESS_32_BITS 0x100 + + struct ep_board *epb; + + int unit; + +#ifdef EP_LOCAL_STATS + short tx_underrun; + short rx_no_first; + short rx_no_mbuf; + short rx_bpf_disc; + short rx_overrunf; + short rx_overrunl; +#endif +}; + +struct ep_board { + int epb_addr; /* address of this board */ + char epb_used; /* was this entry already used for configuring ? */ + /* data from EEPROM for later use */ + u_short eth_addr[3]; /* Ethernet address */ + u_short prod_id; /* product ID */ + int cmd_off; /* command offset (bit shift) */ + int mii_trans; /* activate MII transiever */ + u_short res_cfg; /* resource configuration */ +}; + +extern struct ep_softc* ep_softc[]; +extern struct ep_board ep_board[]; +extern int ep_boards; +extern u_long ep_unit; + +extern struct ep_softc* ep_alloc (int, struct ep_board *); +extern int ep_attach (struct ep_softc *); +extern void ep_free (struct ep_softc *); +extern void ep_intr (void *); + +extern u_int16_t get_e (struct ep_softc *, int); |