Minor reorg of pccard attach code to fix ax88x90 case broken after fixing

dl100xx case.
o We no longer acquire and release resources during attach many times.  We now
  do it once at the beginning.
o Move setting the resource offsets to just after acquiring the ports in
  attach.
o Move ax88x90 code to the end of the file, just after the dl100xx specific
  code.
o Rename ed_pccard_Linksys to ed_pccard_dl100xx to reflect the underlying
  chipset.
o Pass the ed_product structure into ed_pccard_{dl100xx,ax88x90} and have
  those routines test the flags to see if this card should be probed in that
  way.
o transition from ed_probe_Novell to ed_probe_Novell_generic since we already
  have the resources setup.
o Move use of ed_probe_Novell_generic into ed_pccard_dl100xx to be more
  consistant with ax88x90 case.
o simplify the code where we probe for the chipsets
This commit is contained in:
imp 2005-09-07 03:30:58 +00:00
parent aa9d523c41
commit 1c4b0b9c5f

View File

@ -79,25 +79,6 @@ MODULE_DEPEND(ed, ether, 1, 1, 1);
*/
#define ED_DEFAULT_MAC_OFFSET 0xff0
/*
* PC Card (PCMCIA) specific code.
*/
static int ed_pccard_probe(device_t);
static int ed_pccard_attach(device_t);
static int ed_pccard_ax88x90(device_t dev);
static void ax88x90_geteprom(struct ed_softc *);
static int ed_pccard_memread(device_t dev, off_t offset, u_char *byte);
static int ed_pccard_memwrite(device_t dev, off_t offset, u_char byte);
#ifndef ED_NO_MIIBUS
static void ed_pccard_dlink_mii_reset(struct ed_softc *sc);
static u_int ed_pccard_dlink_mii_readbits(struct ed_softc *sc, int nbits);
static void ed_pccard_dlink_mii_writebits(struct ed_softc *sc, u_int val,
int nbits);
#endif
static int ed_pccard_Linksys(device_t dev);
static const struct ed_product {
struct pccard_product prod;
int flags;
@ -194,6 +175,25 @@ static const struct ed_product {
{ { NULL } }
};
/*
* PC Card (PCMCIA) specific code.
*/
static int ed_pccard_probe(device_t);
static int ed_pccard_attach(device_t);
static int ed_pccard_memread(device_t dev, off_t offset, u_char *byte);
static int ed_pccard_memwrite(device_t dev, off_t offset, u_char byte);
static int ed_pccard_dl100xx(device_t dev, const struct ed_product *);
#ifndef ED_NO_MIIBUS
static void ed_pccard_dlink_mii_reset(struct ed_softc *sc);
static u_int ed_pccard_dlink_mii_readbits(struct ed_softc *sc, int nbits);
static void ed_pccard_dlink_mii_writebits(struct ed_softc *sc, u_int val,
int nbits);
#endif
static int ed_pccard_ax88x90(device_t dev, const struct ed_product *);
static int
ed_pccard_probe(device_t dev)
{
@ -289,36 +289,35 @@ ed_pccard_attach(device_t dev)
} else {
sc->port_rid = 0;
}
if (pp->flags & NE2000DVF_DL100XX) {
error = ed_probe_Novell(dev, sc->port_rid, 0);
if (error == 0)
error = ed_pccard_Linksys(dev);
if (error == 0)
goto end2;
}
if (pp->flags & NE2000DVF_AX88X90) {
error = ed_pccard_ax88x90(dev);
if (error == 0)
goto end2;
}
error = ed_probe_Novell(dev, sc->port_rid, 0);
end2:
if (error) {
ed_release_resources(dev);
/* Allocate the port resource during setup. */
error = ed_alloc_port(dev, sc->port_rid, ED_NOVELL_IO_PORTS);
if (error)
return (error);
}
error = ed_alloc_irq(dev, 0, 0);
if (error) {
ed_release_resources(dev);
return (error);
}
if (error)
goto bad;
/*
* Determine which chipset we are. All the PC Card chipsets have the
* ASIC and NIC offsets in the same place.
*/
sc->asic_offset = ED_NOVELL_ASIC_OFFSET;
sc->nic_offset = ED_NOVELL_NIC_OFFSET;
error = ENXIO;
if (error != 0)
error = ed_pccard_dl100xx(dev, pp);
if (error != 0 && pp->flags & NE2000DVF_AX88X90)
error = ed_pccard_ax88x90(dev, pp);
if (error != 0)
error = ed_probe_Novell_generic(dev, device_get_flags(dev));
if (error)
goto bad;
error = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_NET | INTR_MPSAFE,
edintr, sc, &sc->irq_handle);
if (error) {
device_printf(dev, "setup intr failed %d \n", error);
ed_release_resources(dev);
return (error);
goto bad;
}
/*
@ -372,10 +371,8 @@ end2:
}
error = ed_attach(dev);
if (error) {
ed_release_resources(dev);
return (error);
}
if (error)
goto bad;
#ifndef ED_NO_MIIBUS
if (sc->chip_type == ED_CHIP_TYPE_DL10019 ||
sc->chip_type == ED_CHIP_TYPE_DL10022) {
@ -390,72 +387,9 @@ end2:
if (sc->modem_rid != -1)
ed_pccard_add_modem(dev);
return (0);
}
static void
ax88x90_geteprom(struct ed_softc *sc)
{
int prom[16],i;
u_char tmp;
struct {
unsigned char offset, value;
} pg_seq[] = {
/* Select Page0 */
{ED_P0_CR, ED_CR_RD2 | ED_CR_STP | ED_CR_PAGE_0},
{ED_P0_DCR, 0x01},
{ED_P0_RBCR0, 0x00}, /* Clear the count regs. */
{ED_P0_RBCR1, 0x00},
{ED_P0_IMR, 0x00}, /* Mask completion irq. */
{ED_P0_ISR, 0xff},
{ED_P0_RCR, ED_RCR_MON | ED_RCR_INTT}, /* Set To Monitor */
{ED_P0_TCR, ED_TCR_LB0}, /* loopback mode. */
{ED_P0_RBCR0, 32},
{ED_P0_RBCR1, 0x00},
{ED_P0_RSAR0, 0x00},
{ED_P0_RSAR1, 0x04},
{ED_P0_CR, ED_CR_RD0 | ED_CR_STA | ED_CR_PAGE_0},
};
/* XXX The Linux axnet_cs driver does the following differently */
/* Reset Card */
tmp = ed_asic_inb(sc, ED_NOVELL_RESET);
ed_asic_outb(sc, ED_NOVELL_RESET, tmp);
DELAY(5000);
ed_asic_outb(sc, ED_P0_CR, ED_CR_RD2 | ED_CR_STP | ED_CR_PAGE_0);
DELAY(5000);
/* Card Settings */
for (i = 0; i < sizeof(pg_seq) / sizeof(pg_seq[0]); i++)
ed_nic_outb(sc, pg_seq[i].offset, pg_seq[i].value);
/* Get Data */
for (i = 0; i < 16; i++)
prom[i] = ed_asic_inw(sc, 0);
/*
* Work around a bug I've seen on Linksys EC2T cards. On
* these cards, the node address is contained in the low order
* bytes of the prom, with the upper byte being 0. On other
* cards, the bytes are packed two per word. I'm unsure why
* this is the case, and why no other open source OS has a
* similar workaround. The Linksys EC2T card is still extremely
* popular on E-Bay, fetching way more than any other 10Mbps
* only card. I might be able to test to see if prom[7] and
* prom[15] == 0x5757, since that appears to be a reliable
* test. On the EC2T cards, I get 0x0057 in prom[14,15] instead.
*/
for (i = 0; i < ETHER_ADDR_LEN; i++)
if (prom[i] & 0xff00)
break;
if (i == ETHER_ADDR_LEN) {
for (i = 0; i < ETHER_ADDR_LEN; i++)
sc->enaddr[i] = prom[i] & 0xff;
} else {
for (i = 0; i < ETHER_ADDR_LEN; i += 2) {
sc->enaddr[i] = prom[i / 2] & 0xff;
sc->enaddr[i + 1] = (prom[i / 2] >> 8) & 0xff;
}
}
bad:
ed_release_resources(dev);
return (error);
}
static int
@ -513,12 +447,18 @@ ed_pccard_memread(device_t dev, off_t offset, u_char *byte)
* conditionally.
*/
static int
ed_pccard_Linksys(device_t dev)
ed_pccard_dl100xx(device_t dev, const struct ed_product *pp)
{
struct ed_softc *sc = device_get_softc(dev);
u_char sum;
uint8_t id;
int i;
int i, error;
if (!pp->flags & NE2000DVF_DL100XX)
return (ENXIO);
error = ed_probe_Novell_generic(dev, device_get_flags(dev));
if (error != 0)
return (error);
/*
* Linksys registers(offset from ASIC base)
@ -544,52 +484,6 @@ ed_pccard_Linksys(device_t dev)
return (0);
}
/*
* Special setup for AX88[17]90
*/
static int
ed_pccard_ax88x90(device_t dev)
{
int error;
int flags = device_get_flags(dev);
int iobase;
char *ts;
struct ed_softc *sc = device_get_softc(dev);
/* Allocate the port resource during setup. */
error = ed_alloc_port(dev, sc->port_rid, ED_NOVELL_IO_PORTS);
if (error)
return (error);
sc->asic_offset = ED_NOVELL_ASIC_OFFSET;
sc->nic_offset = ED_NOVELL_NIC_OFFSET;
sc->chip_type = ED_CHIP_TYPE_AX88190;
/* XXX
* Set Attribute Memory IOBASE Register. Is this a deficiency in
* the PC Card layer, or an ax88190 specific issue? The card
* definitely doesn't work without it.
*/
iobase = rman_get_start(sc->port_res);
ed_pccard_memwrite(dev, ED_AX88190_IOBASE0, iobase & 0xff);
ed_pccard_memwrite(dev, ED_AX88190_IOBASE1, (iobase >> 8) & 0xff);
ts = "AX88190";
if (ed_asic_inb(sc, ED_ASIX_TEST) != 0) {
ed_pccard_memwrite(dev, ED_AX88790_CSR, ED_AX88790_CSR_PWRDWN);
ts = "AX88790";
}
ax88x90_geteprom(sc);
ed_release_resources(dev);
error = ed_probe_Novell(dev, sc->port_rid, flags);
if (error == 0) {
sc->vendor = ED_VENDOR_NOVELL;
sc->type = ED_TYPE_NE2000;
sc->chip_type = ED_CHIP_TYPE_AX88190;
sc->type_str = ts;
}
return (error);
}
#ifndef ED_NO_MIIBUS
/* MII bit-twiddling routines for cards using Dlink chipset */
#define DLINK_MIISET(sc, x) ed_asic_outb(sc, ED_DLINK_MIIBUS, \
@ -663,6 +557,110 @@ ed_pccard_dlink_mii_readbits(struct ed_softc *sc, int nbits)
}
#endif
static void
ed_pccard_ax88x90_geteprom(struct ed_softc *sc)
{
int prom[16],i;
u_char tmp;
struct {
unsigned char offset, value;
} pg_seq[] = {
/* Select Page0 */
{ED_P0_CR, ED_CR_RD2 | ED_CR_STP | ED_CR_PAGE_0},
{ED_P0_DCR, 0x01},
{ED_P0_RBCR0, 0x00}, /* Clear the count regs. */
{ED_P0_RBCR1, 0x00},
{ED_P0_IMR, 0x00}, /* Mask completion irq. */
{ED_P0_ISR, 0xff},
{ED_P0_RCR, ED_RCR_MON | ED_RCR_INTT}, /* Set To Monitor */
{ED_P0_TCR, ED_TCR_LB0}, /* loopback mode. */
{ED_P0_RBCR0, 32},
{ED_P0_RBCR1, 0x00},
{ED_P0_RSAR0, 0x00},
{ED_P0_RSAR1, 0x04},
{ED_P0_CR, ED_CR_RD0 | ED_CR_STA | ED_CR_PAGE_0},
};
/* Reset Card */
tmp = ed_asic_inb(sc, ED_NOVELL_RESET);
ed_asic_outb(sc, ED_NOVELL_RESET, tmp);
DELAY(5000);
ed_asic_outb(sc, ED_P0_CR, ED_CR_RD2 | ED_CR_STP | ED_CR_PAGE_0);
DELAY(5000);
/* Card Settings */
for (i = 0; i < sizeof(pg_seq) / sizeof(pg_seq[0]); i++)
ed_nic_outb(sc, pg_seq[i].offset, pg_seq[i].value);
/* Get Data */
for (i = 0; i < 16; i++)
prom[i] = ed_asic_inw(sc, 0);
/*
* Work around a bug I've seen on Linksys EC2T cards. On
* these cards, the node address is contained in the low order
* bytes of the prom, with the upper byte being 0. On other
* cards, the bytes are packed two per word. I'm unsure why
* this is the case, and why no other open source OS has a
* similar workaround. The Linksys EC2T card is still extremely
* popular on E-Bay, fetching way more than any other 10Mbps
* only card. I might be able to test to see if prom[7] and
* prom[15] == 0x5757, since that appears to be a reliable
* test. On the EC2T cards, I get 0x0057 in prom[14,15] instead.
*/
for (i = 0; i < ETHER_ADDR_LEN; i++)
if (prom[i] & 0xff00)
break;
if (i == ETHER_ADDR_LEN) {
for (i = 0; i < ETHER_ADDR_LEN; i++)
sc->enaddr[i] = prom[i] & 0xff;
} else {
for (i = 0; i < ETHER_ADDR_LEN; i += 2) {
sc->enaddr[i] = prom[i / 2] & 0xff;
sc->enaddr[i + 1] = (prom[i / 2] >> 8) & 0xff;
}
}
}
/*
* Special setup for AX88[17]90
*/
static int
ed_pccard_ax88x90(device_t dev, const struct ed_product *pp)
{
int error;
int iobase;
char *ts;
struct ed_softc *sc = device_get_softc(dev);
if (!pp->flags & NE2000DVF_AX88X90)
return (ENXIO);
/* XXX
* Set Attribute Memory IOBASE Register. Is this a deficiency in
* the PC Card layer, or an ax88190 specific issue? The card
* definitely doesn't work without it.
*/
iobase = rman_get_start(sc->port_res);
ed_pccard_memwrite(dev, ED_AX88190_IOBASE0, iobase & 0xff);
ed_pccard_memwrite(dev, ED_AX88190_IOBASE1, (iobase >> 8) & 0xff);
ts = "AX88190";
if (ed_asic_inb(sc, ED_ASIX_TEST) != 0) {
ed_pccard_memwrite(dev, ED_AX88790_CSR, ED_AX88790_CSR_PWRDWN);
ts = "AX88790";
}
sc->chip_type = ED_CHIP_TYPE_AX88190;
ed_pccard_ax88x90_geteprom(sc);
error = ed_probe_Novell_generic(dev, device_get_flags(dev));
if (error == 0) {
sc->vendor = ED_VENDOR_NOVELL;
sc->type = ED_TYPE_NE2000;
sc->chip_type = ED_CHIP_TYPE_AX88190;
sc->type_str = ts;
}
return (error);
}
static device_method_t ed_pccard_methods[] = {
/* Device interface */
DEVMETHOD(device_probe, ed_pccard_probe),