#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: if_ate_mca.c,v 1.21 2008/04/28 20:23:53 martin Exp $");
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/device.h>
#include <sys/socket.h>
#include <sys/syslog.h>
#include <net/if.h>
#include <net/if_ether.h>
#include <net/if_media.h>
#include <sys/bus.h>
#include <sys/intr.h>
#include <dev/ic/mb86960reg.h>
#include <dev/ic/mb86960var.h>
#include <dev/mca/mcavar.h>
#include <dev/mca/mcadevs.h>
int ate_mca_match(device_t, cfdata_t, void *);
void ate_mca_attach(device_t, device_t, void *);
static void ate_mca_detect(bus_space_tag_t, bus_space_handle_t,
uint8_t enaddr[ETHER_ADDR_LEN]);
#define ATE_NPORTS 0x20
struct ate_softc {
struct mb86960_softc sc_mb86960;
void *sc_ih;
};
CFATTACH_DECL_NEW(ate_mca, sizeof(struct ate_softc),
ate_mca_match, ate_mca_attach, NULL, NULL);
static const struct ate_mca_product {
uint32_t at_prodid;
const char *at_name;
int at_type;
} ate_mca_products[] = {
{ MCA_PRODUCT_AT1720T, "ATI AT1720T", FE_TYPE_AT1700T },
{ MCA_PRODUCT_AT1720BT, "ATI AT1720BT", FE_TYPE_AT1700BT },
{ MCA_PRODUCT_AT1720AT, "ATI AT1720AT", FE_TYPE_AT1700AT },
{ MCA_PRODUCT_AT1720FT, "ATI AT1720FT", FE_TYPE_AT1700FT },
{ 0, NULL, 0 },
};
static const struct ate_mca_product *ate_mca_lookup(uint32_t);
static const struct ate_mca_product *
ate_mca_lookup(uint32_t id)
{
const struct ate_mca_product *atp;
for (atp = ate_mca_products; atp->at_name != NULL; atp++)
if (id == atp->at_prodid)
return atp;
return NULL;
}
int
ate_mca_match(device_t parent, cfdata_t cf, void *aux)
{
struct mca_attach_args *ma = aux;
if (ate_mca_lookup(ma->ma_id) != NULL)
return 1;
return 0;
}
static const int ats_iobase[] = {
0x400, 0x2400, 0x4400, 0x6400, 0x1400, 0x3400, 0x5400, 0x7400
};
static const int ats_irq[] = {
3, 4, 5, 9, 10, 11, 12, 15
};
void
ate_mca_attach(device_t parent, device_t self, void *aux)
{
struct ate_softc *isc = device_private(self);
struct mb86960_softc *sc = &isc->sc_mb86960;
struct mca_attach_args *ma = aux;
bus_space_tag_t iot = ma->ma_iot;
bus_space_handle_t ioh;
uint8_t myea[ETHER_ADDR_LEN];
int pos3, pos4;
int iobase, irq;
const struct ate_mca_product *atp;
sc->sc_dev = self;
pos3 = mca_conf_read(ma->ma_mc, ma->ma_slot, 3);
pos4 = mca_conf_read(ma->ma_mc, ma->ma_slot, 4);
atp = ate_mca_lookup(ma->ma_id);
#ifdef DIAGNOSTIC
if (atp == NULL) {
aprint_normal("\n");
aprint_error_dev(sc->sc_dev, "where did the card go?\n");
return;
}
#endif
iobase = ats_iobase[pos3 & 0x7];
irq = ats_irq[((pos4 & 0x40) >> 4) | ((pos3 & 0xc0) >> 6)];
aprint_normal(" slot %d irq %d: %s\n",
ma->ma_slot + 1, irq, atp->at_name);
if (bus_space_map(iot, iobase, ATE_NPORTS, 0, &ioh)) {
aprint_error_dev(sc->sc_dev, "can't map i/o space\n");
return;
}
sc->sc_bst = iot;
sc->sc_bsh = ioh;
ate_mca_detect(iot, ioh, myea);
sc->sc_stat |= FE_STAT_ENABLED;
mb86960_attach(sc, myea);
mb86960_config(sc, NULL, 0, 0);
isc->sc_ih = mca_intr_establish(ma->ma_mc, irq, IPL_NET,
mb86960_intr, sc);
if (isc->sc_ih == NULL) {
aprint_error_dev(sc->sc_dev,
"couldn't establish interrupt handler\n");
return;
}
}
static void
ate_mca_detect(bus_space_tag_t iot, bus_space_handle_t ioh,
uint8_t enaddr[ETHER_ADDR_LEN])
{
uint8_t eeprom[FE_EEPROM_SIZE];
mb86965_read_eeprom(iot, ioh, eeprom);
memcpy(enaddr, eeprom + FE_ATI_EEP_ADDR, ETHER_ADDR_LEN);
}