diff options
| author | cvs2svn <cvs2svn@FreeBSD.org> | 2001-01-23 12:37:16 +0000 |
|---|---|---|
| committer | cvs2svn <cvs2svn@FreeBSD.org> | 2001-01-23 12:37:16 +0000 |
| commit | 32ad97f92be37079faf2bfb8b296687ba50cb9fa (patch) | |
| tree | d9b2b348ae15ecb198cd80a1df758830babe88cd /sys/dev/cs | |
| parent | a4719ae1eb55973b15af69e211a2cf7233fee13b (diff) | |
Notes
Diffstat (limited to 'sys/dev/cs')
| -rw-r--r-- | sys/dev/cs/if_cs.c | 1268 | ||||
| -rw-r--r-- | sys/dev/cs/if_cs_isa.c | 127 | ||||
| -rw-r--r-- | sys/dev/cs/if_cs_pccard.c | 126 | ||||
| -rw-r--r-- | sys/dev/cs/if_csvar.h | 78 |
4 files changed, 1599 insertions, 0 deletions
diff --git a/sys/dev/cs/if_cs.c b/sys/dev/cs/if_cs.c new file mode 100644 index 000000000000..05b021edc4a3 --- /dev/null +++ b/sys/dev/cs/if_cs.c @@ -0,0 +1,1268 @@ +/* + * 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_csreg.h> +#include <dev/cs/if_csvar.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->nic_addr, PP_EECMD, (off+i)|EEPROM_READ_CMD ); + if (wait_eeprom_ready(sc)<0) + return -1; + buffer[i] = cs_readreg (sc->nic_addr, 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->nic_addr, PP_SelfCTL, self_control ); + + DELAY( 500000 ); +} + + +static int +cs_duplex_auto(struct cs_softc *sc) +{ + int i, error=0, unit=sc->arpcom.ac_if.if_unit; + + cs_writereg(sc->nic_addr, PP_AutoNegCTL, + RE_NEG_NOW | ALLOW_FDX | AUTO_NEG_ENABLE ); + for (i=0; cs_readreg(sc->nic_addr,PP_AutoNegST)&AUTO_NEG_BUSY; i++) { + if (i > 40000) { + printf(CS_NAME"%1d: full/half duplex " + "auto negotiation timeout\n", unit); + error = ETIMEDOUT; + break; + } + DELAY(1000); + } + DELAY( 1000000 ); + return error; +} + +static int +enable_tp(struct cs_softc *sc) +{ + int unit = sc->arpcom.ac_if.if_unit; + + cs_writereg(sc->nic_addr, PP_LineCTL, sc->line_ctl & ~AUI_ONLY); + control_dc_dc(sc, 0); + DELAY( 150000 ); + + if ((cs_readreg(sc->nic_addr, PP_LineST) & LINK_OK)==0) { + printf(CS_NAME"%1d: failed to enable TP\n", unit); + 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->nic_addr, PP_LineCTL, + cs_readreg(sc->nic_addr, 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); + outw(sc->nic_addr + TX_CMD_PORT, sc->send_cmd); + outw(sc->nic_addr + TX_LEN_PORT, sizeof(test_packet)); + + /* Wait for chip to allocate memory */ + DELAY(50000); + if (!(cs_readreg(sc->nic_addr, 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->nic_addr,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) +{ + int unit = sc->arpcom.ac_if.if_unit; + + control_dc_dc(sc, 0); + cs_writereg(sc->nic_addr, PP_LineCTL, + (sc->line_ctl & ~AUTO_AUI_10BASET) | AUI_ONLY); + + if (!send_test_pkt(sc)) { + printf(CS_NAME"%1d failed to enable AUI\n", unit); + return EINVAL; + } + return 0; +} + +/* + * XXX This was rewritten from Linux driver without any tests. + */ +static int +enable_bnc(struct cs_softc *sc) +{ + int unit = sc->arpcom.ac_if.if_unit; + + control_dc_dc(sc, 1); + cs_writereg(sc->nic_addr, PP_LineCTL, + (sc->line_ctl & ~AUTO_AUI_10BASET) | AUI_ONLY); + + if (!send_test_pkt(sc)) { + printf(CS_NAME"%1d failed to enable BNC\n", unit); + return EINVAL; + } + return 0; +} + +int +cs_cs89x0_probe(device_t dev) +{ + int i; + int iobase; + int error; + + u_long irq, junk; + + struct cs_softc *sc = device_get_softc(dev); + + unsigned rev_type = 0; + 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); + + iobase=rman_get_start(sc->port_res); + + if ((inw(iobase+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"); + outw(iobase+ADD_PORT, PP_SelfCTL); + i = inw(iobase+DATA_PORT); + outw(iobase+ADD_PORT, PP_SelfCTL); + outw(iobase+DATA_PORT, i | POWER_ON_RESET); + if ((inw(iobase+ADD_PORT) & ADD_MASK) != ADD_SIG) + return (ENXIO); + } + + outw(iobase+ADD_PORT, PP_ChipID); + if (inw(iobase+DATA_PORT) != CHIP_EISA_ID_SIG) + return (ENXIO); + + rev_type = cs_readreg(iobase, PRODUCT_ID_ADD); + chip_type = rev_type & ~REVISON_BITS; + chip_revision = ((rev_type & REVISON_BITS) >> 8) + 'A'; + + sc->nic_addr = iobase; + 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(iobase, 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(iobase, pp_isaint, irq); + } else { + device_printf(dev, "Unknown or invalid irq\n"); + return (ENXIO); + } + + /* + * Temporary disabled + * + if (drq>0) + cs_writereg(iobase, pp_isadma, drq); + else { + printf( CS_NAME"%1d: incorrect drq\n", unit ); + 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) { + printf(CS_NAME"%d: Couldn't allocate memory for NIC\n", + unit); + 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: printf(CS_NAME"%d: adapter has no media\n", unit); + } + ifmedia_set(&sc->media, media); + cs_mediaset(sc, media); + + ether_ifattach(ifp, ETHER_BPF_SUPPORTED); + } + + if (bootverbose) + printf(CS_NAME"%d: ethernet address %6D\n", + ifp->if_unit, 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->nic_addr, PP_LineCTL, + cs_readreg( sc->nic_addr, 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->nic_addr, PP_RxCFG, rx_cfg); + + cs_writereg(sc->nic_addr, 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->nic_addr, 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->nic_addr, 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->nic_addr, PP_BusCTL, ENABLE_IRQ | RX_DMA_SIZE_64K); + #else + + cs_writereg(sc->nic_addr, PP_BusCTL, ENABLE_IRQ); +#endif +*/ + cs_writereg(sc->nic_addr, 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 + * via ether_input(). + */ +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 = inw(iobase + RX_FRAME_PORT); + length = inw(iobase + RX_FRAME_PORT); + +#ifdef CS_DEBUG + printf(CS_NAME"%1d: rcvd: stat %x, len %d\n", + ifp->if_unit, status, length); +#endif + + if (!(status & RX_OK)) { +#ifdef CS_DEBUG + printf(CS_NAME"%1d: bad pkt stat %x\n", ifp->if_unit, 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)) { + m->m_pkthdr.len -= sizeof(struct ether_header); + m->m_len -= sizeof(struct ether_header); + m->m_data += sizeof(struct ether_header); + + /* Feed the packet to the upper layer */ + ether_input(ifp, eh, 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 + int unit = ifp->if_unit; + printf(CS_NAME"%1d: Interrupt.\n", unit); +#endif + + while ((status=cs_readword(sc->nic_addr, ISQ_PORT))) { + +#ifdef CS_DEBUG + printf( CS_NAME"%1d:from ISQ: %04x\n", unit, 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); + + if (ifp->if_bpf) { + bpf_mtap(ifp, m); + } + + m_freem(m); + } + + /* + * Issue a SEND command + */ + outw(sc->nic_addr+TX_CMD_PORT, sc->send_cmd); + outw(sc->nic_addr+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->nic_addr, 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->nic_addr, PP_RxCFG, 0); + cs_writereg(sc->nic_addr, PP_TxCFG, 0); + cs_writereg(sc->nic_addr, PP_BufCFG, 0); + cs_writereg(sc->nic_addr, 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->nic_addr, PP_LineCTL, + cs_readreg(sc->nic_addr, 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->nic_addr, PP_RxCTL, RX_DEF_ACCEPT | rx_ctl); + + /* Turn on receiver */ + cs_writereg(sc->nic_addr, PP_LineCTL, + cs_readreg(sc->nic_addr, 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 + printf(CS_NAME"%d: ioctl(%lx)\n",sc->arpcom.ac_if.if_unit,command); +#endif + + s=splimp(); + + switch (command) { + case SIOCSIFADDR: + case SIOCGIFADDR: + case SIOCSIFMTU: + ether_ioctl(ifp, command, data); + break; + + 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: + error = EINVAL; + } + + (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->nic_addr, PP_LineST); + if (line_status & TENBASET_ON) { + ifmr->ifm_active |= IFM_10_T; + if (sc->chip_type != CS8900) { + if (cs_readreg(sc->nic_addr, PP_AutoNegST) & FDX_ACTIVE) + ifmr->ifm_active |= IFM_FDX; + if (cs_readreg(sc->nic_addr, 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->nic_addr, PP_SelfCTL, + cs_readreg(sc->nic_addr, PP_SelfCTL) | + HCB1_ENBL); + if (((sc->adapter_cnf & A_CNF_DC_DC_POLARITY)!=0)^ + (cs_readreg(sc->nic_addr, 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->nic_addr, PP_LineCTL, + cs_readreg(sc->nic_addr, PP_LineCTL) & + ~(SERIAL_RX_ON | SERIAL_TX_ON)); + +#ifdef CS_DEBUG + printf(CS_NAME"%d: cs_setmedia(%x)\n",sc->arpcom.ac_if.if_unit,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->nic_addr, PP_LineCTL, + cs_readreg( sc->nic_addr, 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 000000000000..a3364b96d3fd --- /dev/null +++ b/sys/dev/cs/if_cs_isa.c @@ -0,0 +1,127 @@ +/* + * 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> + +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: + 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; + + if (sc->port_used > 0) + cs_alloc_port(dev, sc->port_rid, sc->port_used); + 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 000000000000..6b6a03e339a9 --- /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/pccard/pccardvar.h> +#include <dev/pccard/pccarddevs.h> + +#include "card_if.h" + +static const struct pccard_product cs_pccard_products[] = { + { 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; + + if (sc->port_used > 0) + cs_alloc_port(dev, sc->port_rid, sc->port_used); + if (sc->mem_used) + cs_alloc_memory(dev, sc->mem_rid, sc->mem_used); + 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_csvar.h b/sys/dev/cs/if_csvar.h new file mode 100644 index 000000000000..719a8db46ddc --- /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 */ |
