Hi,

We found that our driver doesn't work with PNP in 4.0 and
use old, shared memory softc scheme. We rewrite it for the
new scheme, now We can install it in dev/cs and remove
isa_compat.c lines. I belive we have to commit it before
4.0 release.

Regards,
        Max. 

-
Rostov State University   Computer Center
Rostov-on-Don, +7 (8632) 285794 or 357476
Russia, RUNNet, MAB1-RIPE      [EMAIL PROTECTED]
/*
 * 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: src/sys/i386/isa/if_cs.c,v 1.14 1999/09/25 12:05:52 phk Exp $
 *
 * 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 <isa/isavar.h>

#ifdef BRIDGE
#include <net/bridge.h>
#endif

#include <machine/clock.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

/*
 * 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;
};

static int      cs_recv_delay = 570;
SYSCTL_INT(_machdep, OID_AUTO, cs_recv_delay, CTLFLAG_RW, &cs_recv_delay, 0, "");

static int      cs_isa_probe            __P((device_t dev));
static int      cs_isa_attach           __P((device_t dev));

static int      cs_cs89x0_probe         __P((device_t dev));

driver_intr_t   csintr;

static int      cs_attach               __P((struct cs_softc *, int, int));

static void     cs_init                 __P((void *));
static int      cs_ioctl                __P((struct ifnet *, u_long, caddr_t));
static void     cs_start                __P((struct ifnet *));
static void     cs_stop                 __P((struct cs_softc *));
static void     cs_reset                __P((struct cs_softc *));
static void     cs_watchdog             __P((struct ifnet *));

static int      cs_alloc_port(device_t dev, int rid, int size);
static int      cs_alloc_memory(device_t dev, int rid, int size);
static int      cs_alloc_irq(device_t dev, int rid, int flags);
static void     cs_release_resources(device_t dev);

static int      cs_mediachange  __P((struct ifnet *));
static void     cs_mediastatus  __P((struct ifnet *, struct ifmediareq *));
static int      cs_mediaset     __P((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 *);

static device_method_t cs_methods[] = {
        /* Device interface */
        DEVMETHOD(device_probe,         cs_isa_probe),
        DEVMETHOD(device_attach,        cs_isa_attach),
        { 0, 0 }
};

static driver_t cs_driver = {
        "cs",
        cs_methods,
        sizeof(struct cs_softc)
};

static devclass_t cs_devclass;

DRIVER_MODULE(cs, isa, cs_driver, cs_devclass, 0, 0);

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;
}

static 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;
        }
}

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;

        struct cs_softc *sc = device_get_softc(dev);

        bzero(sc, sizeof(struct cs_softc));

        /* 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);
}

/*
 * Install the interface into kernel networking data structures
 */
static 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);

                if_attach(ifp);
                ether_ifattach(ifp);
        }

        if (bootverbose)
                printf(CS_NAME"%d: ethernet address %6D\n",
                       ifp->if_unit, sc->arpcom.ac_enaddr, ":");

        bpfattach(ifp, DLT_EN10MB, sizeof (struct ether_header));
        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 *);

        if (ifp->if_bpf)
                bpf_mtap(ifp, m);

#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;
}
/*
 * 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: src/sys/i386/isa/if_csreg.h,v 1.2 1999/08/28 00:44:43 peter Exp $
 */

#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"

#define cs_readreg(iobase, portno) \
        (outw((iobase) + ADD_PORT, (portno)), \
        inw((iobase) + DATA_PORT))
#define cs_writereg(iobase, portno, value) \
        (outw((iobase) + ADD_PORT, (portno)), \
        outw((iobase) + DATA_PORT, (value)))
#define cs_readword(iobase, portno) \
        (inw((iobase) + (portno)))
#define cs_writeword(iobase, portno, value) \
        (outw((iobase) + (portno), (value)))

#define reset_chip(nic_addr) \
        cs_writereg(nic_addr, PP_SelfCTL, cs_readreg(ioaddr, PP_SelfCTL) | 
POWER_ON_RESET), \
        DELAY(30000)

#define cs_duplex_full(sc) \
        (cs_writereg(sc->nic_addr, PP_AutoNegCTL, FORCE_FDX))

#define cs_duplex_half(sc) \
        (cs_writereg(sc->nic_addr, PP_AutoNegCTL, NLP_ENABLE))

Reply via email to