diff options
Diffstat (limited to 'sys/dev/cs')
-rw-r--r-- | sys/dev/cs/if_cs.c | 1239 | ||||
-rw-r--r-- | sys/dev/cs/if_cs_isa.c | 129 | ||||
-rw-r--r-- | sys/dev/cs/if_cs_pccard.c | 126 | ||||
-rw-r--r-- | sys/dev/cs/if_csreg.h | 578 | ||||
-rw-r--r-- | sys/dev/cs/if_csvar.h | 78 |
5 files changed, 2150 insertions, 0 deletions
diff --git a/sys/dev/cs/if_cs.c b/sys/dev/cs/if_cs.c new file mode 100644 index 0000000..bffccf9 --- /dev/null +++ b/sys/dev/cs/if_cs.c @@ -0,0 +1,1239 @@ +/* + * Copyright (c) 1997,1998 Maxim Bolotin and Oleg Sharoiko. + * 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 unmodified, 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$ + * + * Device driver for Crystal Semiconductor CS8920 based ethernet + * adapters. By Maxim Bolotin and Oleg Sharoiko, 27-April-1997 + */ + +/* +#define CS_DEBUG + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/malloc.h> +#include <sys/mbuf.h> +#include <sys/socket.h> +#include <sys/sockio.h> +#include <sys/kernel.h> +#include <sys/sysctl.h> +#include <sys/syslog.h> + +#include <sys/module.h> +#include <sys/bus.h> +#include <machine/bus.h> +#include <sys/rman.h> +#include <machine/resource.h> + +#include <net/if.h> +#include <net/if_arp.h> +#include <net/if_media.h> +#include <net/ethernet.h> +#include <net/bpf.h> + +#include <dev/cs/if_csvar.h> +#include <dev/cs/if_csreg.h> + +#ifdef CS_USE_64K_DMA +#define CS_DMA_BUFFER_SIZE 65536 +#else +#define CS_DMA_BUFFER_SIZE 16384 +#endif + +static int cs_recv_delay = 570; +SYSCTL_INT(_machdep, OID_AUTO, cs_recv_delay, CTLFLAG_RW, &cs_recv_delay, 0, ""); + +static void cs_init (void *); +static int cs_ioctl (struct ifnet *, u_long, caddr_t); +static void cs_start (struct ifnet *); +static void cs_stop (struct cs_softc *); +static void cs_reset (struct cs_softc *); +static void cs_watchdog (struct ifnet *); + +static int cs_mediachange (struct ifnet *); +static void cs_mediastatus (struct ifnet *, struct ifmediareq *); +static int cs_mediaset (struct cs_softc *, int); + +static void cs_write_mbufs(struct cs_softc*, struct mbuf*); +static void cs_xmit_buf(struct cs_softc*); +static int cs_get_packet(struct cs_softc*); +static void cs_setmode(struct cs_softc*); + +static int get_eeprom_data(struct cs_softc *sc, int, int, int *); +static int get_eeprom_cksum(int, int, int *); +static int wait_eeprom_ready( struct cs_softc *); +static void control_dc_dc( struct cs_softc *, int ); +static int send_test_pkt( struct cs_softc * ); +static int enable_tp(struct cs_softc *); +static int enable_aui(struct cs_softc *); +static int enable_bnc(struct cs_softc *); +static int cs_duplex_auto(struct cs_softc *); + +devclass_t cs_devclass; + +static int +get_eeprom_data( struct cs_softc *sc, int off, int len, int *buffer) +{ + int i; + +#ifdef CS_DEBUG + printf(CS_NAME":EEPROM data from %x for %x:\n", off,len); +#endif + + for (i=0;i<len;i++) { + if (wait_eeprom_ready(sc) < 0) return -1; + /* Send command to EEPROM to read */ + cs_writereg(sc, PP_EECMD, (off + i) | EEPROM_READ_CMD); + if (wait_eeprom_ready(sc)<0) + return (-1); + buffer[i] = cs_readreg(sc, PP_EEData); + +#ifdef CS_DEBUG + printf("%02x %02x ",(unsigned char)buffer[i], + (unsigned char)buffer[i+1]); +#endif + } + +#ifdef CS_DEBUG + printf("\n"); +#endif + return (0); +} + +static int +get_eeprom_cksum(int off, int len, int *buffer) +{ + int i,cksum=0; + + for (i=0;i<len;i++) + cksum+=buffer[i]; + cksum &= 0xffff; + if (cksum==0) + return 0; + return -1; +} + +static int +wait_eeprom_ready(struct cs_softc *sc) +{ + DELAY ( 30000 ); /* XXX should we do some checks here ? */ + return 0; +} + +static void +control_dc_dc(struct cs_softc *sc, int on_not_off) +{ + unsigned int self_control = HCB1_ENBL; + + if (((sc->adapter_cnf & A_CNF_DC_DC_POLARITY)!=0) ^ on_not_off) + self_control |= HCB1; + else + self_control &= ~HCB1; + cs_writereg(sc, PP_SelfCTL, self_control); + + DELAY( 500000 ); +} + + +static int +cs_duplex_auto(struct cs_softc *sc) +{ + int i, error=0; + + cs_writereg(sc, PP_AutoNegCTL, + RE_NEG_NOW | ALLOW_FDX | AUTO_NEG_ENABLE); + for (i=0; cs_readreg(sc, PP_AutoNegST) & AUTO_NEG_BUSY; i++) { + if (i > 40000) { + if_printf(&sc->arpcom.ac_if, + "full/half duplex auto negotiation timeout\n"); + error = ETIMEDOUT; + break; + } + DELAY(1000); + } + DELAY( 1000000 ); + return error; +} + +static int +enable_tp(struct cs_softc *sc) +{ + + cs_writereg(sc, PP_LineCTL, sc->line_ctl & ~AUI_ONLY); + control_dc_dc(sc, 0); + DELAY( 150000 ); + + if ((cs_readreg(sc, PP_LineST) & LINK_OK)==0) { + if_printf(&sc->arpcom.ac_if, "failed to enable TP\n"); + return EINVAL; + } + + return 0; +} + +/* + * XXX This was rewritten from Linux driver without any tests. + */ +static int +send_test_pkt(struct cs_softc *sc) +{ + char test_packet[] = { 0,0,0,0,0,0, 0,0,0,0,0,0, + 0, 46, /* A 46 in network order */ + 0, 0, /* DSAP=0 & SSAP=0 fields */ + 0xf3, 0 /* Control (Test Req + P bit set) */ }; + int i; + u_char ether_address_backup[ETHER_ADDR_LEN]; + + for (i = 0; i < ETHER_ADDR_LEN; i++) { + ether_address_backup[i] = sc->arpcom.ac_enaddr[i]; + } + + cs_writereg(sc, PP_LineCTL, cs_readreg(sc, PP_LineCTL) | SERIAL_TX_ON); + bcopy(test_packet, sc->arpcom.ac_enaddr, ETHER_ADDR_LEN); + bcopy(test_packet+ETHER_ADDR_LEN, + sc->arpcom.ac_enaddr, ETHER_ADDR_LEN); + cs_outw(sc, TX_CMD_PORT, sc->send_cmd); + cs_outw(sc, TX_LEN_PORT, sizeof(test_packet)); + + /* Wait for chip to allocate memory */ + DELAY(50000); + if (!(cs_readreg(sc, PP_BusST) & READY_FOR_TX_NOW)) { + for (i = 0; i < ETHER_ADDR_LEN; i++) { + sc->arpcom.ac_enaddr[i] = ether_address_backup[i]; + } + return 0; + } + + outsw(sc->nic_addr + TX_FRAME_PORT, test_packet, sizeof(test_packet)); + + DELAY(30000); + + if ((cs_readreg(sc, PP_TxEvent) & TX_SEND_OK_BITS) == TX_OK) { + for (i = 0; i < ETHER_ADDR_LEN; i++) { + sc->arpcom.ac_enaddr[i] = ether_address_backup[i]; + } + return 1; + } + for (i = 0; i < ETHER_ADDR_LEN; i++) { + sc->arpcom.ac_enaddr[i] = ether_address_backup[i]; + } + return 0; +} + +/* + * XXX This was rewritten from Linux driver without any tests. + */ +static int +enable_aui(struct cs_softc *sc) +{ + + control_dc_dc(sc, 0); + cs_writereg(sc, PP_LineCTL, + (sc->line_ctl & ~AUTO_AUI_10BASET) | AUI_ONLY); + + if (!send_test_pkt(sc)) { + if_printf(&sc->arpcom.ac_if, "failed to enable AUI\n"); + return EINVAL; + } + return 0; +} + +/* + * XXX This was rewritten from Linux driver without any tests. + */ +static int +enable_bnc(struct cs_softc *sc) +{ + + control_dc_dc(sc, 1); + cs_writereg(sc, PP_LineCTL, + (sc->line_ctl & ~AUTO_AUI_10BASET) | AUI_ONLY); + + if (!send_test_pkt(sc)) { + if_printf(&sc->arpcom.ac_if, "failed to enable BNC\n"); + return EINVAL; + } + return 0; +} + +int +cs_cs89x0_probe(device_t dev) +{ + int i; + int error; + u_long irq, junk; + struct cs_softc *sc = device_get_softc(dev); + unsigned rev_type = 0; + u_int16_t id; + char chip_revision; + int eeprom_buff[CHKSUM_LEN]; + int chip_type, pp_isaint, pp_isadma; + + error = cs_alloc_port(dev, 0, CS_89x0_IO_PORTS); + if (error) + return (error); + + sc->nic_addr = rman_get_start(sc->port_res); + + if ((cs_inw(sc, ADD_PORT) & ADD_MASK) != ADD_SIG) { + /* Chip not detected. Let's try to reset it */ + if (bootverbose) + device_printf(dev, "trying to reset the chip.\n"); + cs_outw(sc, ADD_PORT, PP_SelfCTL); + i = cs_inw(sc, DATA_PORT); + cs_outw(sc, ADD_PORT, PP_SelfCTL); + cs_outw(sc, DATA_PORT, i | POWER_ON_RESET); + if ((cs_inw(sc, ADD_PORT) & ADD_MASK) != ADD_SIG) + return (ENXIO); + } + + for (i = 0; i < 10000; i++) { + id = cs_readreg(sc, PP_ChipID); + if (id == CHIP_EISA_ID_SIG) + break; + } + if (i == 10000) + return (ENXIO); + + rev_type = cs_readreg(sc, PRODUCT_ID_ADD); + chip_type = rev_type & ~REVISON_BITS; + chip_revision = ((rev_type & REVISON_BITS) >> 8) + 'A'; + + sc->chip_type = chip_type; + + if(chip_type==CS8900) { + pp_isaint = PP_CS8900_ISAINT; + pp_isadma = PP_CS8900_ISADMA; + sc->send_cmd = TX_CS8900_AFTER_ALL; + } else { + pp_isaint = PP_CS8920_ISAINT; + pp_isadma = PP_CS8920_ISADMA; + sc->send_cmd = TX_CS8920_AFTER_ALL; + } + + /* + * Clear some fields so that fail of EEPROM will left them clean + */ + sc->auto_neg_cnf = 0; + sc->adapter_cnf = 0; + sc->isa_config = 0; + + /* + * If no interrupt specified (or "?"), use what the board tells us. + */ + error = bus_get_resource(dev, SYS_RES_IRQ, 0, &irq, &junk); + + /* + * Get data from EEPROM + */ + if((cs_readreg(sc, PP_SelfST) & EEPROM_PRESENT) == 0) { + device_printf(dev, "No EEPROM, assuming defaults.\n"); + } else { + if (get_eeprom_data(sc,START_EEPROM_DATA,CHKSUM_LEN, eeprom_buff)<0) { + device_printf(dev, "EEPROM read failed, " + "assuming defaults.\n"); + } else { + if (get_eeprom_cksum(START_EEPROM_DATA,CHKSUM_LEN, eeprom_buff)<0) { + device_printf(dev, "EEPROM cheksum bad, " + "assuming defaults.\n"); + } else { + sc->auto_neg_cnf = + eeprom_buff[AUTO_NEG_CNF_OFFSET/2]; + sc->adapter_cnf = + eeprom_buff[ADAPTER_CNF_OFFSET/2]; + sc->isa_config = + eeprom_buff[ISA_CNF_OFFSET/2]; + + for (i=0; i<ETHER_ADDR_LEN/2; i++) { + sc->arpcom.ac_enaddr[i*2]= + eeprom_buff[i]; + sc->arpcom.ac_enaddr[i*2+1]= + eeprom_buff[i] >> 8; + } + + /* + * If no interrupt specified (or "?"), + * use what the board tells us. + */ + if (error) { + irq = sc->isa_config & INT_NO_MASK; + if (chip_type==CS8900) { + switch(irq) { + case 0: + irq=10; + error=0; + break; + case 1: + irq=11; + error=0; + break; + case 2: + irq=12; + error=0; + break; + case 3: + irq=5; + error=0; + break; + default: + device_printf(dev, "invalid irq in EEPROM.\n"); + error=EINVAL; + } + } else { + if (irq>CS8920_NO_INTS) { + device_printf(dev, "invalid irq in EEPROM.\n"); + error=EINVAL; + } else { + error=0; + } + } + + if (!error) + bus_set_resource(dev, SYS_RES_IRQ, 0, + irq, 1); + } + } + } + } + + if (!error) { + if (chip_type == CS8900) { + switch(irq) { + case 5: + irq = 3; + break; + case 10: + irq = 0; + break; + case 11: + irq = 1; + break; + case 12: + irq = 2; + break; + default: + error=EINVAL; + } + } else { + if (irq > CS8920_NO_INTS) { + error = EINVAL; + } + } + } + + if (!error) { + cs_writereg(sc, pp_isaint, irq); + } else { + device_printf(dev, "Unknown or invalid irq\n"); + return (ENXIO); + } + + /* + * Temporary disabled + * + if (drq>0) + cs_writereg(sc, pp_isadma, drq); + else { + device_printf(dev, "incorrect drq\n",); + return 0; + } + */ + + if (bootverbose) + device_printf(dev, "CS89%c0%s rev %c media%s%s%s\n", + chip_type==CS8900 ? '0' : '2', + chip_type==CS8920M ? "M" : "", + chip_revision, + (sc->adapter_cnf & A_CNF_10B_T) ? " TP" : "", + (sc->adapter_cnf & A_CNF_AUI) ? " AUI" : "", + (sc->adapter_cnf & A_CNF_10B_2) ? " BNC" : ""); + + if ((sc->adapter_cnf & A_CNF_EXTND_10B_2) && + (sc->adapter_cnf & A_CNF_LOW_RX_SQUELCH)) + sc->line_ctl = LOW_RX_SQUELCH; + else + sc->line_ctl = 0; + + + return 0; +} + +/* + * Allocate a port resource with the given resource id. + */ +int cs_alloc_port(device_t dev, int rid, int size) +{ + struct cs_softc *sc = device_get_softc(dev); + struct resource *res; + + res = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, + 0ul, ~0ul, size, RF_ACTIVE); + if (res) { + sc->port_rid = rid; + sc->port_res = res; + sc->port_used = size; + return (0); + } else { + return (ENOENT); + } +} + +/* + * Allocate a memory resource with the given resource id. + */ +int cs_alloc_memory(device_t dev, int rid, int size) +{ + struct cs_softc *sc = device_get_softc(dev); + struct resource *res; + + res = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid, + 0ul, ~0ul, size, RF_ACTIVE); + if (res) { + sc->mem_rid = rid; + sc->mem_res = res; + sc->mem_used = size; + return (0); + } else { + return (ENOENT); + } +} + +/* + * Allocate an irq resource with the given resource id. + */ +int cs_alloc_irq(device_t dev, int rid, int flags) +{ + struct cs_softc *sc = device_get_softc(dev); + struct resource *res; + + res = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, + 0ul, ~0ul, 1, (RF_ACTIVE | flags)); + if (res) { + sc->irq_rid = rid; + sc->irq_res = res; + return (0); + } else { + return (ENOENT); + } +} + +/* + * Release all resources + */ +void cs_release_resources(device_t dev) +{ + struct cs_softc *sc = device_get_softc(dev); + + if (sc->port_res) { + bus_release_resource(dev, SYS_RES_IOPORT, + sc->port_rid, sc->port_res); + sc->port_res = 0; + } + if (sc->mem_res) { + bus_release_resource(dev, SYS_RES_MEMORY, + sc->mem_rid, sc->mem_res); + sc->mem_res = 0; + } + if (sc->irq_res) { + bus_release_resource(dev, SYS_RES_IRQ, + sc->irq_rid, sc->irq_res); + sc->irq_res = 0; + } +} + +/* + * Install the interface into kernel networking data structures + */ +int +cs_attach(struct cs_softc *sc, int unit, int flags) +{ + int media=0; + struct ifnet *ifp = &(sc->arpcom.ac_if); + + cs_stop( sc ); + + if (!ifp->if_name) { + ifp->if_softc=sc; + ifp->if_unit=unit; + ifp->if_name="cs"; + ifp->if_output=ether_output; + ifp->if_start=cs_start; + ifp->if_ioctl=cs_ioctl; + ifp->if_watchdog=cs_watchdog; + ifp->if_init=cs_init; + ifp->if_snd.ifq_maxlen= IFQ_MAXLEN; + /* + * MIB DATA + */ + /* + ifp->if_linkmib=&sc->mibdata; + ifp->if_linkmiblen=sizeof sc->mibdata; + */ + + ifp->if_flags=(IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST ); + + /* + * this code still in progress (DMA support) + * + + sc->recv_ring=malloc(CS_DMA_BUFFER_SIZE<<1, M_DEVBUF, M_NOWAIT); + if (sc->recv_ring == NULL) { + log(LOG_ERR,CS_NAME + "%d: Couldn't allocate memory for NIC\n", unit); + return(0); + } + if ((sc->recv_ring-(sc->recv_ring & 0x1FFFF)) + < (128*1024-CS_DMA_BUFFER_SIZE)) + sc->recv_ring+=16*1024; + + */ + + sc->buffer=malloc(ETHER_MAX_LEN-ETHER_CRC_LEN,M_DEVBUF,M_NOWAIT); + if (sc->buffer == NULL) { + if_printf(ifp, "Couldn't allocate memory for NIC\n"); + return(0); + } + + /* + * Initialize the media structures. + */ + ifmedia_init(&sc->media, 0, cs_mediachange, cs_mediastatus); + + if (sc->adapter_cnf & A_CNF_10B_T) { + ifmedia_add(&sc->media, IFM_ETHER|IFM_10_T, 0, NULL); + if (sc->chip_type != CS8900) { + ifmedia_add(&sc->media, + IFM_ETHER|IFM_10_T|IFM_FDX, 0, NULL); + ifmedia_add(&sc->media, + IFM_ETHER|IFM_10_T|IFM_HDX, 0, NULL); + } + } + + if (sc->adapter_cnf & A_CNF_10B_2) + ifmedia_add(&sc->media, IFM_ETHER|IFM_10_2, 0, NULL); + + if (sc->adapter_cnf & A_CNF_AUI) + ifmedia_add(&sc->media, IFM_ETHER|IFM_10_5, 0, NULL); + + if (sc->adapter_cnf & A_CNF_MEDIA) + ifmedia_add(&sc->media, IFM_ETHER|IFM_AUTO, 0, NULL); + + /* Set default media from EEPROM */ + switch (sc->adapter_cnf & A_CNF_MEDIA_TYPE) { + case A_CNF_MEDIA_AUTO: media = IFM_ETHER|IFM_AUTO; break; + case A_CNF_MEDIA_10B_T: media = IFM_ETHER|IFM_10_T; break; + case A_CNF_MEDIA_10B_2: media = IFM_ETHER|IFM_10_2; break; + case A_CNF_MEDIA_AUI: media = IFM_ETHER|IFM_10_5; break; + default: if_printf(ifp, "adapter has no media\n"); + } + ifmedia_set(&sc->media, media); + cs_mediaset(sc, media); + + ether_ifattach(ifp, sc->arpcom.ac_enaddr); + } + + if (bootverbose) + if_printf(ifp, "ethernet address %6D\n", + sc->arpcom.ac_enaddr, ":"); + + return (0); +} + +/* + * Initialize the board + */ +static void +cs_init(void *xsc) +{ + struct cs_softc *sc=(struct cs_softc *)xsc; + struct ifnet *ifp = &sc->arpcom.ac_if; + int i, s, rx_cfg; + + /* address not known */ + if (TAILQ_EMPTY(&ifp->if_addrhead)) /* unlikely? XXX */ + return; + + /* + * reset whatchdog timer + */ + ifp->if_timer=0; + sc->buf_len = 0; + + s=splimp(); + + /* + * Hardware initialization of cs + */ + + /* Enable receiver and transmitter */ + cs_writereg(sc, PP_LineCTL, + cs_readreg(sc, PP_LineCTL) | SERIAL_RX_ON | SERIAL_TX_ON); + + /* Configure the receiver mode */ + cs_setmode(sc); + + /* + * This defines what type of frames will cause interrupts + * Bad frames should generate interrupts so that the driver + * could track statistics of discarded packets + */ + rx_cfg = RX_OK_ENBL | RX_CRC_ERROR_ENBL | RX_RUNT_ENBL | + RX_EXTRA_DATA_ENBL; + if (sc->isa_config & STREAM_TRANSFER) + rx_cfg |= RX_STREAM_ENBL; + cs_writereg(sc, PP_RxCFG, rx_cfg); + cs_writereg(sc, PP_TxCFG, TX_LOST_CRS_ENBL | + TX_SQE_ERROR_ENBL | TX_OK_ENBL | TX_LATE_COL_ENBL | + TX_JBR_ENBL | TX_ANY_COL_ENBL | TX_16_COL_ENBL); + cs_writereg(sc, PP_BufCFG, READY_FOR_TX_ENBL | + RX_MISS_COUNT_OVRFLOW_ENBL | TX_COL_COUNT_OVRFLOW_ENBL | + TX_UNDERRUN_ENBL /*| RX_DMA_ENBL*/); + + /* Write MAC address into IA filter */ + for (i=0; i<ETHER_ADDR_LEN/2; i++) + cs_writereg(sc, PP_IA + i * 2, + sc->arpcom.ac_enaddr[i * 2] | + (sc->arpcom.ac_enaddr[i * 2 + 1] << 8) ); + + /* + * Now enable everything + */ +/* +#ifdef CS_USE_64K_DMA + cs_writereg(sc, PP_BusCTL, ENABLE_IRQ | RX_DMA_SIZE_64K); +#else + cs_writereg(sc, PP_BusCTL, ENABLE_IRQ); +#endif +*/ + cs_writereg(sc, PP_BusCTL, ENABLE_IRQ); + + /* + * Set running and clear output active flags + */ + sc->arpcom.ac_if.if_flags |= IFF_RUNNING; + sc->arpcom.ac_if.if_flags &= ~IFF_OACTIVE; + + /* + * Start sending process + */ + cs_start(ifp); + + (void) splx(s); +} + +/* + * Get the packet from the board and send it to the upper layer. + */ +static int +cs_get_packet(struct cs_softc *sc) +{ + struct ifnet *ifp = &(sc->arpcom.ac_if); + int iobase = sc->nic_addr, status, length; + struct ether_header *eh; + struct mbuf *m; + +#ifdef CS_DEBUG + int i; +#endif + + status = cs_inw(sc, RX_FRAME_PORT); + length = cs_inw(sc, RX_FRAME_PORT); + +#ifdef CS_DEBUG + if_printf(ifp, "rcvd: stat %x, len %d\n", + status, length); +#endif + + if (!(status & RX_OK)) { +#ifdef CS_DEBUG + if_printf(ifp, "bad pkt stat %x\n", status); +#endif + ifp->if_ierrors++; + return -1; + } + + MGETHDR(m, M_DONTWAIT, MT_DATA); + if (m==NULL) + return -1; + + if (length > MHLEN) { + MCLGET(m, M_DONTWAIT); + if (!(m->m_flags & M_EXT)) { + m_freem(m); + return -1; + } + } + + /* Initialize packet's header info */ + m->m_pkthdr.rcvif = ifp; + m->m_pkthdr.len = length; + m->m_len = length; + + /* Get the data */ + insw(iobase + RX_FRAME_PORT, m->m_data, (length+1)>>1); + + eh = mtod(m, struct ether_header *); + +#ifdef CS_DEBUG + for (i=0;i<length;i++) + printf(" %02x",(unsigned char)*((char *)(m->m_data+i))); + printf( "\n" ); +#endif + + if (status & (RX_IA | RX_BROADCAST) || + (ifp->if_flags & IFF_MULTICAST && status & RX_HASHED)) { + /* Feed the packet to the upper layer */ + (*ifp->if_input)(ifp, m); + + ifp->if_ipackets++; + + if (length==ETHER_MAX_LEN-ETHER_CRC_LEN) + DELAY( cs_recv_delay ); + } else { + m_freem(m); + } + + return 0; +} + +/* + * Handle interrupts + */ +void +csintr(void *arg) +{ + struct cs_softc *sc = (struct cs_softc*) arg; + struct ifnet *ifp = &(sc->arpcom.ac_if); + int status; + +#ifdef CS_DEBUG + if_printf(ifp, "Interrupt.\n"); +#endif + + while ((status=cs_inw(sc, ISQ_PORT))) { + +#ifdef CS_DEBUG + if_printf(ifp, "from ISQ: %04x\n", status); +#endif + + switch (status & ISQ_EVENT_MASK) { + case ISQ_RECEIVER_EVENT: + cs_get_packet(sc); + break; + + case ISQ_TRANSMITTER_EVENT: + if (status & TX_OK) + ifp->if_opackets++; + else + ifp->if_oerrors++; + ifp->if_flags &= ~IFF_OACTIVE; + ifp->if_timer = 0; + break; + + case ISQ_BUFFER_EVENT: + if (status & READY_FOR_TX) { + ifp->if_flags &= ~IFF_OACTIVE; + ifp->if_timer = 0; + } + + if (status & TX_UNDERRUN) { + ifp->if_flags &= ~IFF_OACTIVE; + ifp->if_timer = 0; + ifp->if_oerrors++; + } + break; + + case ISQ_RX_MISS_EVENT: + ifp->if_ierrors+=(status>>6); + break; + + case ISQ_TX_COL_EVENT: + ifp->if_collisions+=(status>>6); + break; + } + } + + if (!(ifp->if_flags & IFF_OACTIVE)) { + cs_start(ifp); + } +} + +/* + * Save the data in buffer + */ + +static void +cs_write_mbufs( struct cs_softc *sc, struct mbuf *m ) +{ + int len; + struct mbuf *mp; + unsigned char *data, *buf; + + for (mp=m, buf=sc->buffer, sc->buf_len=0; mp != NULL; mp=mp->m_next) { + len = mp->m_len; + + /* + * Ignore empty parts + */ + if (!len) + continue; + + /* + * Find actual data address + */ + data = mtod(mp, caddr_t); + + bcopy((caddr_t) data, (caddr_t) buf, len); + buf += len; + sc->buf_len += len; + } +} + + +static void +cs_xmit_buf( struct cs_softc *sc ) +{ + outsw(sc->nic_addr+TX_FRAME_PORT, sc->buffer, (sc->buf_len+1)>>1); + sc->buf_len = 0; +} + +static void +cs_start(struct ifnet *ifp) +{ + int s, length; + struct mbuf *m, *mp; + struct cs_softc *sc = ifp->if_softc; + + s = splimp(); + + for (;;) { + if (sc->buf_len) + length = sc->buf_len; + else { + IF_DEQUEUE( &ifp->if_snd, m ); + + if (m==NULL) { + (void) splx(s); + return; + } + + for (length=0, mp=m; mp != NULL; mp=mp->m_next) + length += mp->m_len; + + /* Skip zero-length packets */ + if (length == 0) { + m_freem(m); + continue; + } + + cs_write_mbufs(sc, m); + + BPF_MTAP(ifp, m); + + m_freem(m); + } + + /* + * Issue a SEND command + */ + cs_outw(sc, TX_CMD_PORT, sc->send_cmd); + cs_outw(sc, TX_LEN_PORT, length ); + + /* + * If there's no free space in the buffer then leave + * this packet for the next time: indicate output active + * and return. + */ + if (!(cs_readreg(sc, PP_BusST) & READY_FOR_TX_NOW)) { + ifp->if_timer = sc->buf_len; + (void) splx(s); + ifp->if_flags |= IFF_OACTIVE; + return; + } + + cs_xmit_buf(sc); + + /* + * Set the watchdog timer in case we never hear + * from board again. (I don't know about correct + * value for this timeout) + */ + ifp->if_timer = length; + + (void) splx(s); + ifp->if_flags |= IFF_OACTIVE; + return; + } +} + +/* + * Stop everything on the interface + */ +static void +cs_stop(struct cs_softc *sc) +{ + int s = splimp(); + + cs_writereg(sc, PP_RxCFG, 0); + cs_writereg(sc, PP_TxCFG, 0); + cs_writereg(sc, PP_BufCFG, 0); + cs_writereg(sc, PP_BusCTL, 0); + + sc->arpcom.ac_if.if_flags &= ~(IFF_RUNNING | IFF_OACTIVE); + sc->arpcom.ac_if.if_timer = 0; + + (void) splx(s); +} + +/* + * Reset the interface + */ +static void +cs_reset(struct cs_softc *sc) +{ + cs_stop(sc); + cs_init(sc); +} + +static void +cs_setmode(struct cs_softc *sc) +{ + struct ifnet *ifp = &(sc->arpcom.ac_if); + int rx_ctl; + + /* Stop the receiver while changing filters */ + cs_writereg(sc, PP_LineCTL, cs_readreg(sc, PP_LineCTL) & ~SERIAL_RX_ON); + + if (ifp->if_flags & IFF_PROMISC) { + /* Turn on promiscuous mode. */ + rx_ctl = RX_OK_ACCEPT | RX_PROM_ACCEPT; + } else { + if (ifp->if_flags & IFF_MULTICAST) { + /* Allow receiving frames with multicast addresses */ + rx_ctl = RX_IA_ACCEPT | RX_BROADCAST_ACCEPT | + RX_OK_ACCEPT | RX_MULTCAST_ACCEPT; + /* + * Here the reconfiguration of chip's multicast + * filters should be done but I've no idea about + * hash transformation in this chip. If you can + * add this code or describe me the transformation + * I'd be very glad. + */ + } else { + /* + * Receive only good frames addressed for us and + * good broadcasts. + */ + rx_ctl = RX_IA_ACCEPT | RX_BROADCAST_ACCEPT | + RX_OK_ACCEPT; + } + } + + /* Set up the filter */ + cs_writereg(sc, PP_RxCTL, RX_DEF_ACCEPT | rx_ctl); + + /* Turn on receiver */ + cs_writereg(sc, PP_LineCTL, cs_readreg(sc, PP_LineCTL) | SERIAL_RX_ON); +} + +static int +cs_ioctl(register struct ifnet *ifp, u_long command, caddr_t data) +{ + struct cs_softc *sc=ifp->if_softc; + struct ifreq *ifr = (struct ifreq *)data; + int s,error=0; + +#ifdef CS_DEBUG + if_printf(ifp, "ioctl(%lx)\n", command); +#endif + + s=splimp(); + + switch (command) { + case SIOCSIFFLAGS: + /* + * Switch interface state between "running" and + * "stopped", reflecting the UP flag. + */ + if (sc->arpcom.ac_if.if_flags & IFF_UP) { + if ((sc->arpcom.ac_if.if_flags & IFF_RUNNING)==0) { + cs_init(sc); + } + } else { + if ((sc->arpcom.ac_if.if_flags & IFF_RUNNING)!=0) { + cs_stop(sc); + } + } + /* + * Promiscuous and/or multicast flags may have changed, + * so reprogram the multicast filter and/or receive mode. + * + * See note about multicasts in cs_setmode + */ + cs_setmode(sc); + break; + + case SIOCADDMULTI: + case SIOCDELMULTI: + /* + * Multicast list has changed; set the hardware filter + * accordingly. + * + * See note about multicasts in cs_setmode + */ + cs_setmode(sc); + error = 0; + break; + + case SIOCSIFMEDIA: + case SIOCGIFMEDIA: + error = ifmedia_ioctl(ifp, ifr, &sc->media, command); + break; + + default: + ether_ioctl(ifp, command, data); + break; + } + + (void) splx(s); + return error; +} + +/* + * Device timeout/watchdog routine. Entered if the device neglects to + * generate an interrupt after a transmit has been started on it. + */ +static void +cs_watchdog(struct ifnet *ifp) +{ + struct cs_softc *sc = ifp->if_softc; + + ifp->if_oerrors++; + log(LOG_ERR, CS_NAME"%d: device timeout\n", ifp->if_unit); + + /* Reset the interface */ + if (ifp->if_flags & IFF_UP) + cs_reset(sc); + else + cs_stop(sc); +} + +static int +cs_mediachange(struct ifnet *ifp) +{ + struct cs_softc *sc = ifp->if_softc; + struct ifmedia *ifm = &sc->media; + + if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER) + return EINVAL; + + return cs_mediaset(sc, ifm->ifm_media); +} + +static void +cs_mediastatus(struct ifnet *ifp, struct ifmediareq *ifmr) +{ + int line_status; + struct cs_softc *sc = ifp->if_softc; + + ifmr->ifm_active = IFM_ETHER; + line_status = cs_readreg(sc, PP_LineST); + if (line_status & TENBASET_ON) { + ifmr->ifm_active |= IFM_10_T; + if (sc->chip_type != CS8900) { + if (cs_readreg(sc, PP_AutoNegST) & FDX_ACTIVE) + ifmr->ifm_active |= IFM_FDX; + if (cs_readreg(sc, PP_AutoNegST) & HDX_ACTIVE) + ifmr->ifm_active |= IFM_HDX; + } + ifmr->ifm_status = IFM_AVALID; + if (line_status & LINK_OK) + ifmr->ifm_status |= IFM_ACTIVE; + } else { + if (line_status & AUI_ON) { + cs_writereg(sc, PP_SelfCTL, cs_readreg(sc, PP_SelfCTL) | + HCB1_ENBL); + if (((sc->adapter_cnf & A_CNF_DC_DC_POLARITY)!=0)^ + (cs_readreg(sc, PP_SelfCTL) & HCB1)) + ifmr->ifm_active |= IFM_10_2; + else + ifmr->ifm_active |= IFM_10_5; + } + } +} + +static int +cs_mediaset(struct cs_softc *sc, int media) +{ + int error; + + /* Stop the receiver & transmitter */ + cs_writereg(sc, PP_LineCTL, cs_readreg(sc, PP_LineCTL) & + ~(SERIAL_RX_ON | SERIAL_TX_ON)); + +#ifdef CS_DEBUG + if_printf(&sc->arpcom.ac_if, "cs_setmedia(%x)\n", media); +#endif + + switch (IFM_SUBTYPE(media)) { + default: + case IFM_AUTO: + if ((error=enable_tp(sc))==0) + error = cs_duplex_auto(sc); + else if ((error=enable_bnc(sc)) != 0) + error = enable_aui(sc); + break; + case IFM_10_T: + if ((error=enable_tp(sc)) != 0) + break; + if (media & IFM_FDX) + cs_duplex_full(sc); + else if (media & IFM_HDX) + cs_duplex_half(sc); + else + error = cs_duplex_auto(sc); + break; + case IFM_10_2: + error = enable_bnc(sc); + break; + case IFM_10_5: + error = enable_aui(sc); + break; + } + + /* + * Turn the transmitter & receiver back on + */ + cs_writereg(sc, PP_LineCTL, cs_readreg(sc, PP_LineCTL) | + SERIAL_RX_ON | SERIAL_TX_ON); + + return error; +} diff --git a/sys/dev/cs/if_cs_isa.c b/sys/dev/cs/if_cs_isa.c new file mode 100644 index 0000000..1f0dfbf --- /dev/null +++ b/sys/dev/cs/if_cs_isa.c @@ -0,0 +1,129 @@ +/* + * Copyright (c) 1997,1998 Maxim Bolotin and Oleg Sharoiko. + * 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 unmodified, 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/param.h> +#include <sys/kernel.h> +#include <sys/socket.h> + +#include <sys/module.h> +#include <sys/bus.h> + +#include <machine/bus.h> +#include <machine/resource.h> + +#include <net/ethernet.h> +#include <net/if.h> +#include <net/if_arp.h> + +#include <isa/isavar.h> + +#include <dev/cs/if_csvar.h> +#include <dev/cs/if_csreg.h> + +static int cs_isa_probe (device_t); +static int cs_isa_attach (device_t); + +static struct isa_pnp_id cs_ids[] = { + { 0x4060630e, NULL }, /* CSC6040 */ + { 0x10104d24, NULL }, /* IBM EtherJet */ + { 0, NULL } +}; + +/* + * Determine if the device is present + */ +static int +cs_isa_probe(device_t dev) +{ + int error = 0; + + /* Check isapnp ids */ + error = ISA_PNP_PROBE(device_get_parent(dev), dev, cs_ids); + + /* If the card had a PnP ID that didn't match any we know about */ + if (error == ENXIO) + goto end; + + /* If we had some other problem. */ + if (!(error == 0 || error == ENOENT)) + goto end; + + error = cs_cs89x0_probe(dev); +end: + /* Make sure IRQ is assigned for probe message and available */ + if (error == 0) + error = cs_alloc_irq(dev, 0, 0); + + cs_release_resources(dev); + return (error); +} + +static int +cs_isa_attach(device_t dev) +{ + struct cs_softc *sc = device_get_softc(dev); + int flags = device_get_flags(dev); + int error; + + cs_alloc_port(dev, 0, CS_89x0_IO_PORTS); + /* XXX mem appears to not be used at all */ + if (sc->mem_used) + cs_alloc_memory(dev, sc->mem_rid, sc->mem_used); + cs_alloc_irq(dev, sc->irq_rid, 0); + + error = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_NET, + csintr, sc, &sc->irq_handle); + if (error) { + cs_release_resources(dev); + return (error); + } + + return (cs_attach(sc, device_get_unit(dev), flags)); +} + +static device_method_t cs_isa_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, cs_isa_probe), + DEVMETHOD(device_attach, cs_isa_attach), +#ifdef CS_HAS_DETACH + DEVMETHOD(device_detach, cs_detach), +#endif + + { 0, 0 } +}; + +static driver_t cs_isa_driver = { + "cs", + cs_isa_methods, + sizeof(struct cs_softc), +}; + +extern devclass_t cs_devclass; + +DRIVER_MODULE(if_cs, isa, cs_isa_driver, cs_devclass, 0, 0); diff --git a/sys/dev/cs/if_cs_pccard.c b/sys/dev/cs/if_cs_pccard.c new file mode 100644 index 0000000..a927f21 --- /dev/null +++ b/sys/dev/cs/if_cs_pccard.c @@ -0,0 +1,126 @@ +/* + * Copyright (c) 1999 M. Warner Losh <imp@village.org> + * 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 ``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/systm.h> +#include <sys/kernel.h> +#include <sys/socket.h> + +#include <sys/module.h> +#include <sys/bus.h> + +#include <machine/bus.h> +#include <machine/resource.h> + +#include <net/ethernet.h> +#include <net/if.h> +#include <net/if_arp.h> + +#include <dev/cs/if_csvar.h> +#include <dev/cs/if_csreg.h> +#include <dev/pccard/pccardvar.h> +#include <dev/pccard/pccarddevs.h> + +#include "card_if.h" + +static const struct pccard_product cs_pccard_products[] = { + PCMCIA_CARD(IBM, ETHERJET, 0), + { NULL } +}; +static int +cs_pccard_match(device_t dev) +{ + const struct pccard_product *pp; + + if ((pp = pccard_product_lookup(dev, cs_pccard_products, + sizeof(cs_pccard_products[0]), NULL)) != NULL) { + device_set_desc(dev, pp->pp_name); + return 0; + } + return EIO; +} + +static int +cs_pccard_probe(device_t dev) +{ + int error; + + error = cs_cs89x0_probe(dev); + cs_release_resources(dev); + return (error); +} + +static int +cs_pccard_attach(device_t dev) +{ + struct cs_softc *sc = device_get_softc(dev); + int flags = device_get_flags(dev); + int error; + + error = cs_alloc_port(dev, sc->port_rid, CS_89x0_IO_PORTS); + if (error != 0) + goto bad; + error = cs_alloc_irq(dev, sc->irq_rid, 0); + if (error != 0) + goto bad; + error = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_NET, + csintr, sc, &sc->irq_handle); + if (error != 0) + goto bad; + + return (cs_attach(sc, device_get_unit(dev), flags)); +bad: + cs_release_resources(dev); + return (error); +} + +static device_method_t cs_pccard_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, pccard_compat_probe), + DEVMETHOD(device_attach, pccard_compat_attach), +#ifdef CS_HAS_DETACH + DEVMETHOD(device_detach, cs_detach), +#endif + + /* Card interface */ + DEVMETHOD(card_compat_match, cs_pccard_match), + DEVMETHOD(card_compat_probe, cs_pccard_probe), + DEVMETHOD(card_compat_attach, cs_pccard_attach), + + { 0, 0 } +}; + +static driver_t cs_pccard_driver = { + "cs", + cs_pccard_methods, + sizeof(struct cs_softc), +}; + +extern devclass_t cs_devclass; + +DRIVER_MODULE(if_cs, pccard, cs_pccard_driver, cs_devclass, 0, 0); +MODULE_DEPEND(if_cs, pccard, 1, 1, 1); diff --git a/sys/dev/cs/if_csreg.h b/sys/dev/cs/if_csreg.h new file mode 100644 index 0000000..6a8fb0ce --- /dev/null +++ b/sys/dev/cs/if_csreg.h @@ -0,0 +1,578 @@ +/* + * Copyright (c) 1997,1998 Maxim Bolotin and Oleg Sharoiko. + * 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 unmodified, 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$ + */ + +#define CS_89x0_IO_PORTS 0x0020 + +#define PP_ChipID 0x0000 /* offset 0h -> Corp -ID */ + /* offset 2h -> Model/Product Number */ + /* offset 3h -> Chip Revision Number */ + +#define PP_ISAIOB 0x0020 /* IO base address */ +#define PP_CS8900_ISAINT 0x0022 /* ISA interrupt select */ +#define PP_CS8900_ISADMA 0x0024 /* ISA Rec DMA channel */ +#define PP_CS8920_ISAINT 0x0370 /* ISA interrupt select */ +#define PP_CS8920_ISADMA 0x0374 /* ISA Rec DMA channel */ +#define PP_ISASOF 0x0026 /* ISA DMA offset */ +#define PP_DmaFrameCnt 0x0028 /* ISA DMA Frame count */ +#define PP_DmaByteCnt 0x002A /* ISA DMA Byte count */ +#define PP_CS8920_ISAMemB 0x0348 /* Memory base */ + +/* EEPROM data and command registers */ +#define PP_EECMD 0x0040 /* NVR Interface Command register */ +#define PP_EEData 0x0042 /* NVR Interface Data Register */ +#define PP_DebugReg 0x0044 /* Debug Register */ + +#define PP_RxCFG 0x0102 /* Rx Bus config */ +#define PP_RxCTL 0x0104 /* Receive Control Register */ +#define PP_TxCFG 0x0106 /* Transmit Config Register */ +#define PP_TxCMD 0x0108 /* Transmit Command Register */ +#define PP_BufCFG 0x010A /* Bus configuration Register */ +#define PP_LineCTL 0x0112 /* Line Config Register */ +#define PP_SelfCTL 0x0114 /* Self Command Register */ +#define PP_BusCTL 0x0116 /* ISA bus control Register */ +#define PP_TestCTL 0x0118 /* Test Register */ +#define PP_AutoNegCTL 0x011C /* Auto Negotiation Ctrl */ + +#define PP_ISQ 0x0120 /* Interrupt Status */ +#define PP_RxEvent 0x0124 /* Rx Event Register */ +#define PP_TxEvent 0x0128 /* Tx Event Register */ +#define PP_BufEvent 0x012C /* Bus Event Register */ +#define PP_RxMiss 0x0130 /* Receive Miss Count */ +#define PP_TxCol 0x0132 /* Transmit Collision Count */ +#define PP_LineST 0x0134 /* Line State Register */ +#define PP_SelfST 0x0136 /* Self State register */ +#define PP_BusST 0x0138 /* Bus Status */ +#define PP_TDR 0x013C /* Time Domain Reflectometry */ +#define PP_AutoNegST 0x013E /* Auto Neg Status */ +#define PP_TxCommand 0x0144 /* Tx Command */ +#define PP_TxLength 0x0146 /* Tx Length */ +#define PP_LAF 0x0150 /* Hash Table */ +#define PP_IA 0x0158 /* Physical Address Register */ + +#define PP_RxStatus 0x0400 /* Receive start of frame */ +#define PP_RxLength 0x0402 /* Receive Length of frame */ +#define PP_RxFrame 0x0404 /* Receive frame pointer */ +#define PP_TxFrame 0x0A00 /* Transmit frame pointer */ + +/* + * Primary I/O Base Address. If no I/O base is supplied by the user, then this + * can be used as the default I/O base to access the PacketPage Area. + */ +#define DEFAULTIOBASE 0x0300 +#define FIRST_IO 0x020C /* First I/O port to check */ +#define LAST_IO 0x037C /* Last I/O port to check (+10h) */ +#define ADD_MASK 0x3000 /* Mask it use of the ADD_PORT register */ +#define ADD_SIG 0x3000 /* Expected ID signature */ + +#define CHIP_EISA_ID_SIG 0x630E /* Product ID Code for Crystal Chip (CS8900 spec 4.3) */ + +#define PRODUCT_ID_ADD 0x0002 /* Address of product ID */ + +/* Mask to find out the types of registers */ +#define REG_TYPE_MASK 0x001F + +/* Eeprom Commands */ +#define ERSE_WR_ENBL 0x00F0 +#define ERSE_WR_DISABLE 0x0000 + +/* Defines Control/Config register quintuplet numbers */ +#define RX_BUF_CFG 0x0003 +#define RX_CONTROL 0x0005 +#define TX_CFG 0x0007 +#define TX_COMMAND 0x0009 +#define BUF_CFG 0x000B +#define LINE_CONTROL 0x0013 +#define SELF_CONTROL 0x0015 +#define BUS_CONTROL 0x0017 +#define TEST_CONTROL 0x0019 + +/* Defines Status/Count registers quintuplet numbers */ +#define RX_EVENT 0x0004 +#define TX_EVENT 0x0008 +#define BUF_EVENT 0x000C +#define RX_MISS_COUNT 0x0010 +#define TX_COL_COUNT 0x0012 +#define LINE_STATUS 0x0014 +#define SELF_STATUS 0x0016 +#define BUS_STATUS 0x0018 +#define TDR 0x001C + +/* + * PP_RxCFG - Receive Configuration and Interrupt Mask + * bit definition - Read/write + */ +#define SKIP_1 0x0040 +#define RX_STREAM_ENBL 0x0080 +#define RX_OK_ENBL 0x0100 +#define RX_DMA_ONLY 0x0200 +#define AUTO_RX_DMA 0x0400 +#define BUFFER_CRC 0x0800 +#define RX_CRC_ERROR_ENBL 0x1000 +#define RX_RUNT_ENBL 0x2000 +#define RX_EXTRA_DATA_ENBL 0x4000 + +/* PP_RxCTL - Receive Control bit definition - Read/write */ +#define RX_IA_HASH_ACCEPT 0x0040 +#define RX_PROM_ACCEPT 0x0080 +#define RX_OK_ACCEPT 0x0100 +#define RX_MULTCAST_ACCEPT 0x0200 +#define RX_IA_ACCEPT 0x0400 +#define RX_BROADCAST_ACCEPT 0x0800 +#define RX_BAD_CRC_ACCEPT 0x1000 +#define RX_RUNT_ACCEPT 0x2000 +#define RX_EXTRA_DATA_ACCEPT 0x4000 +#define RX_ALL_ACCEPT (RX_PROM_ACCEPT | RX_BAD_CRC_ACCEPT | \ + RX_RUNT_ACCEPT | RX_EXTRA_DATA_ACCEPT) +/* + * Default receive mode - individually addressed, broadcast, and error free + */ +#define RX_DEF_ACCEPT (RX_IA_ACCEPT | RX_BROADCAST_ACCEPT | RX_OK_ACCEPT) + +/* + * PP_TxCFG - Transmit Configuration Interrupt Mask + * bit definition - Read/write + */ +#define TX_LOST_CRS_ENBL 0x0040 +#define TX_SQE_ERROR_ENBL 0x0080 +#define TX_OK_ENBL 0x0100 +#define TX_LATE_COL_ENBL 0x0200 +#define TX_JBR_ENBL 0x0400 +#define TX_ANY_COL_ENBL 0x0800 +#define TX_16_COL_ENBL 0x8000 + +/* + * PP_TxCMD - Transmit Command bit definition - Read-only + */ +#define TX_START_4_BYTES 0x0000 +#define TX_START_64_BYTES 0x0040 +#define TX_START_128_BYTES 0x0080 +#define TX_START_ALL_BYTES 0x00C0 +#define TX_FORCE 0x0100 +#define TX_ONE_COL 0x0200 +#define TX_TWO_PART_DEFF_DISABLE 0x0400 +#define TX_NO_CRC 0x1000 +#define TX_RUNT 0x2000 + +/* + * PP_BufCFG - Buffer Configuration Interrupt Mask + * bit definition - Read/write + */ +#define GENERATE_SW_INTERRUPT 0x0040 +#define RX_DMA_ENBL 0x0080 +#define READY_FOR_TX_ENBL 0x0100 +#define TX_UNDERRUN_ENBL 0x0200 +#define RX_MISS_ENBL 0x0400 +#define RX_128_BYTE_ENBL 0x0800 +#define TX_COL_COUNT_OVRFLOW_ENBL 0x1000 +#define RX_MISS_COUNT_OVRFLOW_ENBL 0x2000 +#define RX_DEST_MATCH_ENBL 0x8000 + +/* + * PP_LineCTL - Line Control bit definition - Read/write + */ +#define SERIAL_RX_ON 0x0040 +#define SERIAL_TX_ON 0x0080 +#define AUI_ONLY 0x0100 +#define AUTO_AUI_10BASET 0x0200 +#define MODIFIED_BACKOFF 0x0800 +#define NO_AUTO_POLARITY 0x1000 +#define TWO_PART_DEFDIS 0x2000 +#define LOW_RX_SQUELCH 0x4000 + +/* + * PP_SelfCTL - Software Self Control bit definition - Read/write + */ +#define POWER_ON_RESET 0x0040 +#define SW_STOP 0x0100 +#define SLEEP_ON 0x0200 +#define AUTO_WAKEUP 0x0400 +#define HCB0_ENBL 0x1000 +#define HCB1_ENBL 0x2000 +#define HCB0 0x4000 +#define HCB1 0x8000 + +/* + * PP_BusCTL - ISA Bus Control bit definition - Read/write + */ +#define RESET_RX_DMA 0x0040 +#define MEMORY_ON 0x0400 +#define DMA_BURST_MODE 0x0800 +#define IO_CHANNEL_READY_ON 0x1000 +#define RX_DMA_SIZE_64Ks 0x2000 +#define ENABLE_IRQ 0x8000 + +/* + * PP_TestCTL - Test Control bit definition - Read/write + */ +#define LINK_OFF 0x0080 +#define ENDEC_LOOPBACK 0x0200 +#define AUI_LOOPBACK 0x0400 +#define BACKOFF_OFF 0x0800 +#define FAST_TEST 0x8000 + +/* + * PP_RxEvent - Receive Event Bit definition - Read-only + */ +#define RX_IA_HASHED 0x0040 +#define RX_DRIBBLE 0x0080 +#define RX_OK 0x0100 +#define RX_HASHED 0x0200 +#define RX_IA 0x0400 +#define RX_BROADCAST 0x0800 +#define RX_CRC_ERROR 0x1000 +#define RX_RUNT 0x2000 +#define RX_EXTRA_DATA 0x4000 + +#define HASH_INDEX_MASK 0x0FC00 + +/* + * PP_TxEvent - Transmit Event Bit definition - Read-only + */ +#define TX_LOST_CRS 0x0040 +#define TX_SQE_ERROR 0x0080 +#define TX_OK 0x0100 +#define TX_LATE_COL 0x0200 +#define TX_JBR 0x0400 +#define TX_16_COL 0x8000 +#define TX_SEND_OK_BITS (TX_OK | TX_LOST_CRS) +#define TX_COL_COUNT_MASK 0x7800 + +/* + * PP_BufEvent - Buffer Event Bit definition - Read-only + */ +#define SW_INTERRUPT 0x0040 +#define RX_DMA 0x0080 +#define READY_FOR_TX 0x0100 +#define TX_UNDERRUN 0x0200 +#define RX_MISS 0x0400 +#define RX_128_BYTE 0x0800 +#define TX_COL_OVRFLW 0x1000 +#define RX_MISS_OVRFLW 0x2000 +#define RX_DEST_MATCH 0x8000 + +/* + * PP_LineST - Ethernet Line Status bit definition - Read-only + */ +#define LINK_OK 0x0080 +#define AUI_ON 0x0100 +#define TENBASET_ON 0x0200 +#define POLARITY_OK 0x1000 +#define CRS_OK 0x4000 + +/* + * PP_SelfST - Chip Software Status bit definition + */ +#define ACTIVE_33V 0x0040 +#define INIT_DONE 0x0080 +#define SI_BUSY 0x0100 +#define EEPROM_PRESENT 0x0200 +#define EEPROM_OK 0x0400 +#define EL_PRESENT 0x0800 +#define EE_SIZE_64 0x1000 + +/* + * PP_BusST - ISA Bus Status bit definition + */ +#define TX_BID_ERROR 0x0080 +#define READY_FOR_TX_NOW 0x0100 + +/* + * PP_AutoNegCTL - Auto Negotiation Control bit definition + */ +#define RE_NEG_NOW 0x0040 +#define ALLOW_FDX 0x0080 +#define AUTO_NEG_ENABLE 0x0100 +#define NLP_ENABLE 0x0200 +#define FORCE_FDX 0x8000 +#define AUTO_NEG_BITS (FORCE_FDX | NLP_ENABLE | AUTO_NEG_ENABLE) +#define AUTO_NEG_MASK (FORCE_FDX | NLP_ENABLE | AUTO_NEG_ENABLE | \ + ALLOW_FDX | RE_NEG_NOW) + +/* + * PP_AutoNegST - Auto Negotiation Status bit definition + */ +#define AUTO_NEG_BUSY 0x0080 +#define FLP_LINK 0x0100 +#define FLP_LINK_GOOD 0x0800 +#define LINK_FAULT 0x1000 +#define HDX_ACTIVE 0x4000 +#define FDX_ACTIVE 0x8000 + +/* + * The following block defines the ISQ event types + */ +#define ISQ_RECEIVER_EVENT 0x04 +#define ISQ_TRANSMITTER_EVENT 0x08 +#define ISQ_BUFFER_EVENT 0x0c +#define ISQ_RX_MISS_EVENT 0x10 +#define ISQ_TX_COL_EVENT 0x12 + +#define ISQ_EVENT_MASK 0x003F /* ISQ mask to find out type of event */ +#define ISQ_HIST 16 /* small history buffer */ +#define AUTOINCREMENT 0x8000 /* Bit mask to set bit-15 for autoincrement */ + +#define TXRXBUFSIZE 0x0600 +#define RXDMABUFSIZE 0x8000 +#define RXDMASIZE 0x4000 +#define TXRX_LENGTH_MASK 0x07FF + +/* rx options bits */ +#define RCV_WITH_RXON 1 /* Set SerRx ON */ +#define RCV_COUNTS 2 /* Use Framecnt1 */ +#define RCV_PONG 4 /* Pong respondent */ +#define RCV_DONG 8 /* Dong operation */ +#define RCV_POLLING 0x10 /* Poll RxEvent */ +#define RCV_ISQ 0x20 /* Use ISQ, int */ +#define RCV_AUTO_DMA 0x100 /* Set AutoRxDMAE */ +#define RCV_DMA 0x200 /* Set RxDMA only */ +#define RCV_DMA_ALL 0x400 /* Copy all DMA'ed */ +#define RCV_FIXED_DATA 0x800 /* Every frame same */ +#define RCV_IO 0x1000 /* Use ISA IO only */ +#define RCV_MEMORY 0x2000 /* Use ISA Memory */ + +#define RAM_SIZE 0x1000 /* The card has 4k bytes or RAM */ +#define PKT_START PP_TxFrame /* Start of packet RAM */ + +#define RX_FRAME_PORT 0x0000 +#define TX_FRAME_PORT RX_FRAME_PORT +#define TX_CMD_PORT 0x0004 +#define TX_CS8900_NOW 0x0000 /* Tx packet after 5 bytes copied */ +#define TX_CS8900_AFTER_381 0x0020 /* Tx packet after 381 bytes copied */ +#define TX_CS8900_AFTER_ALL 0x0060 /* Tx packet after all bytes copied */ +#define TX_CS8920_NOW 0x0000 /* Tx packet after 5 bytes copied */ +#define TX_CS8920_AFTER_381 0x0040 /* Tx packet after 381 bytes copied */ +#define TX_CS8920_AFTER_1021 0x0080 /* Tx packet after1021 bytes copied */ +#define TX_CS8920_AFTER_ALL 0x00C0 /* Tx packet after all bytes copied */ +#define TX_LEN_PORT 0x0006 +#define ISQ_PORT 0x0008 +#define ADD_PORT 0x000A +#define DATA_PORT 0x000C + +#define EEPROM_WRITE_EN 0x00F0 +#define EEPROM_WRITE_DIS 0x0000 +#define EEPROM_WRITE_CMD 0x0100 +#define EEPROM_READ_CMD 0x0200 + +/* Receive Header + * Description of header of each packet in receive area of memory + */ +#define RBUF_EVENT_LOW 0 /* Low byte of RxEvent - status of received frame */ +#define RBUF_EVENT_HIGH 1 /* High byte of RxEvent - status of received frame */ +#define RBUF_LEN_LOW 2 /* Length of received data - low byte */ +#define RBUF_LEN_HI 3 /* Length of received data - high byte */ +#define RBUF_HEAD_LEN 4 /* Length of this header */ + +#define CHIP_READ 0x1 /* Used to mark state of the repins code (chip or dma) */ +#define DMA_READ 0x2 /* Used to mark state of the repins code (chip or dma) */ + +/* for bios scan */ +/* */ +#ifdef CSDEBUG +/* use these values for debugging bios scan */ +#define BIOS_START_SEG 0x00000 +#define BIOS_OFFSET_INC 0x0010 +#else +#define BIOS_START_SEG 0x0c000 +#define BIOS_OFFSET_INC 0x0200 +#endif + +#define BIOS_LAST_OFFSET 0x0fc00 + +/* + * Byte offsets into the EEPROM configuration buffer + */ +#define ISA_CNF_OFFSET 0x6 +#define TX_CTL_OFFSET (ISA_CNF_OFFSET + 8) /* 8900 eeprom */ +#define AUTO_NEG_CNF_OFFSET (ISA_CNF_OFFSET + 8) /* 8920 eeprom */ + +/* + * the assumption here is that the bits in the eeprom are generally + * in the same position as those in the autonegctl register. + * Of course the IMM bit is not in that register so it must be + * masked out + */ +#define EE_FORCE_FDX 0x8000 +#define EE_NLP_ENABLE 0x0200 +#define EE_AUTO_NEG_ENABLE 0x0100 +#define EE_ALLOW_FDX 0x0080 +#define EE_AUTO_NEG_CNF_MASK (EE_FORCE_FDX | EE_NLP_ENABLE | \ + EE_AUTO_NEG_ENABLE | EE_ALLOW_FDX) + +#define IMM_BIT 0x0040 /* ignore missing media */ + +#define ADAPTER_CNF_OFFSET (AUTO_NEG_CNF_OFFSET + 2) +#define A_CNF_MEDIA 0x0007 +#define A_CNF_10B_T 0x0001 +#define A_CNF_AUI 0x0002 +#define A_CNF_10B_2 0x0004 +#define A_CNF_MEDIA_TYPE 0x0060 +#define A_CNF_MEDIA_AUTO 0x0000 +#define A_CNF_MEDIA_10B_T 0x0020 +#define A_CNF_MEDIA_AUI 0x0040 +#define A_CNF_MEDIA_10B_2 0x0060 +#define A_CNF_DC_DC_POLARITY 0x0080 +#define A_CNF_NO_AUTO_POLARITY 0x2000 +#define A_CNF_LOW_RX_SQUELCH 0x4000 +#define A_CNF_EXTND_10B_2 0x8000 + +#define PACKET_PAGE_OFFSET 0x8 + +/* + * Bit definitions for the ISA configuration word from the EEPROM + */ +#define INT_NO_MASK 0x000F +#define DMA_NO_MASK 0x0070 +#define ISA_DMA_SIZE 0x0200 +#define ISA_AUTO_RxDMA 0x0400 +#define ISA_RxDMA 0x0800 +#define DMA_BURST 0x1000 +#define STREAM_TRANSFER 0x2000 +#define ANY_ISA_DMA (ISA_AUTO_RxDMA | ISA_RxDMA) + +/* DMA controller registers */ +#define DMA_BASE 0x00 /* DMA controller base */ +#define DMA_BASE_2 0x0C0 /* DMA controller base */ + +#define DMA_STAT 0x0D0 /* DMA controller status register */ +#define DMA_MASK 0x0D4 /* DMA controller mask register */ +#define DMA_MODE 0x0D6 /* DMA controller mode register */ +#define DMA_RESETFF 0x0D8 /* DMA controller first/last flip flop */ + +/* DMA data */ +#define DMA_DISABLE 0x04 /* Disable channel n */ +#define DMA_ENABLE 0x00 /* Enable channel n */ +/* Demand transfers, incr. address, auto init, writes, ch. n */ +#define DMA_RX_MODE 0x14 +/* Demand transfers, incr. address, auto init, reads, ch. n */ +#define DMA_TX_MODE 0x18 + +#define DMA_SIZE (16*1024) /* Size of dma buffer - 16k */ + +#define CS8900 0x0000 +#define CS8920 0x4000 +#define CS8920M 0x6000 +#define REVISON_BITS 0x1F00 +#define EEVER_NUMBER 0x12 +#define CHKSUM_LEN 0x14 +#define CHKSUM_VAL 0x0000 +#define START_EEPROM_DATA 0x001c /* Offset into eeprom for start of data */ +#define IRQ_MAP_EEPROM_DATA 0x0046 /* Offset into eeprom for the IRQ map */ +#define IRQ_MAP_LEN 0x0004 /* No of bytes to read for the IRQ map */ +#define PNP_IRQ_FRMT 0x0022 /* PNP small item IRQ format */ +#define CS8900_IRQ_MAP 0x1c20 /* This IRQ map is fixed */ + +#define CS8920_NO_INTS 0x0F /* Max CS8920 interrupt select # */ + +#define PNP_ADD_PORT 0x0279 +#define PNP_WRITE_PORT 0x0A79 + +#define GET_PNP_ISA_STRUCT 0x40 +#define PNP_ISA_STRUCT_LEN 0x06 +#define PNP_CSN_CNT_OFF 0x01 +#define PNP_RD_PORT_OFF 0x02 +#define PNP_FUNCTION_OK 0x00 +#define PNP_WAKE 0x03 +#define PNP_RSRC_DATA 0x04 +#define PNP_RSRC_READY 0x01 +#define PNP_STATUS 0x05 +#define PNP_ACTIVATE 0x30 +#define PNP_CNF_IO_H 0x60 +#define PNP_CNF_IO_L 0x61 +#define PNP_CNF_INT 0x70 +#define PNP_CNF_DMA 0x74 +#define PNP_CNF_MEM 0x48 + +#define BIT0 1 +#define BIT15 0x8000 + +#define CS_DUPLEX_AUTO 0 +#define CS_DUPLEX_FULL 1 +#define CS_DUPLEX_HALF 2 + +/* Device name */ +#define CS_NAME "cs" + +/* + * It would appear that for pccards (well, the IBM EtherJet PCMCIA card) that + * are connected to card bus bridges there's a problem. For reading the + * value back you have to go into 8 bit mode. The Linux driver also uses + * this trick. This may be a bug in the card and how it handles fast 16-bit + * read after a write. + */ +#define HACK_FOR_CARDBUS_BRIDGE_PROBLEM +#ifdef HACK_FOR_CARDBUS_BRIDGE_PROBLEM +static __inline u_int16_t +cs_inw(struct cs_softc *sc, int off) +{ + return ((inb(sc->nic_addr + off) & 0xff) | + (inb(sc->nic_addr + off + 1) << 8)); +} +#else +static __inline u_int16_t +cs_inw(struct cs_softc *sc, int off) +{ + return (inw(sc->nic_addr + off)); +} +#endif + +static __inline void +cs_outw(struct cs_softc *sc, int off, u_int16_t val) +{ + outw(sc->nic_addr + off, val); +} + +static __inline u_int16_t +cs_readreg(struct cs_softc *sc, u_int16_t port) +{ + cs_outw(sc, ADD_PORT, port); + return (cs_inw(sc, DATA_PORT)); +} +static __inline void +cs_writereg(struct cs_softc *sc, u_int16_t port, u_int16_t val) +{ + cs_outw(sc, ADD_PORT, port); + cs_outw(sc, DATA_PORT, val); +} + +static __inline void +reset_chip(struct cs_softc *sc) +{ + cs_writereg(sc, PP_SelfCTL, + cs_readreg(sc, PP_SelfCTL) | POWER_ON_RESET); +} + +#define cs_duplex_full(sc) \ + (cs_writereg(sc, PP_AutoNegCTL, FORCE_FDX)) + +#define cs_duplex_half(sc) \ + (cs_writereg(sc, PP_AutoNegCTL, NLP_ENABLE)) + diff --git a/sys/dev/cs/if_csvar.h b/sys/dev/cs/if_csvar.h new file mode 100644 index 0000000..719a8db --- /dev/null +++ b/sys/dev/cs/if_csvar.h @@ -0,0 +1,78 @@ +/* + * Copyright (c) 1999 M. Warner Losh <imp@village.org> + * 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 ``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$ + */ + +#ifndef _IF_CSVAR_H +#define _IF_CSVAR_H + +#include <net/if_arp.h> +#include <net/if_media.h> + +/* + * cs_softc: per line info and status + */ +struct cs_softc { + + /* Ethernet common code */ + struct arpcom arpcom; + + /* Configuration words from EEPROM */ + int auto_neg_cnf; /* AutoNegotitation configuration */ + int adapter_cnf; /* Adapter configuration */ + int isa_config; /* ISA configuration */ + int chip_type; /* Type of chip */ + + struct ifmedia media; /* Media information */ + + int port_rid; /* resource id for port range */ + int port_used; /* nonzero if ports used */ + struct resource* port_res; /* resource for port range */ + int mem_rid; /* resource id for memory range */ + int mem_used; /* nonzero if memory used */ + struct resource* mem_res; /* resource for memory range */ + int irq_rid; /* resource id for irq */ + struct resource* irq_res; /* resource for irq */ + void* irq_handle; /* handle for irq handler */ + + int nic_addr; /* Base IO address of card */ + int send_cmd; + int line_ctl; /* */ + int send_underrun; + void *recv_ring; + + unsigned char *buffer; + int buf_len; +}; + +int cs_alloc_port(device_t dev, int rid, int size); +int cs_alloc_memory(device_t dev, int rid, int size); +int cs_alloc_irq(device_t dev, int rid, int flags); +int cs_attach(struct cs_softc *, int, int); +int cs_cs89x0_probe(device_t dev); +void cs_release_resources(device_t dev); +driver_intr_t csintr; + +#endif /* _IF_CSVAR_H */ |