#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: if_ep_eisa.c,v 1.44 2021/01/27 04:35:15 thorpej Exp $");
#include "opt_inet.h"
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/mbuf.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <sys/errno.h>
#include <sys/syslog.h>
#include <sys/select.h>
#include <sys/device.h>
#include <net/if.h>
#include <net/if_dl.h>
#include <net/if_ether.h>
#include <net/if_media.h>
#ifdef INET
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/in_var.h>
#include <netinet/ip.h>
#include <netinet/if_inarp.h>
#endif
#include <sys/cpu.h>
#include <sys/bus.h>
#include <sys/intr.h>
#include <dev/mii/miivar.h>
#include <dev/ic/elink3var.h>
#include <dev/ic/elink3reg.h>
#include <dev/eisa/eisareg.h>
#include <dev/eisa/eisavar.h>
#include <dev/eisa/eisadevs.h>
static int ep_eisa_match(device_t , cfdata_t , void *);
static void ep_eisa_attach(device_t , device_t , void *);
CFATTACH_DECL_NEW(ep_eisa, sizeof(struct ep_softc),
ep_eisa_match, ep_eisa_attach, NULL, NULL);
#define EP_EISA_CFG_BASE 0x0c80
#define EP_EISA_CFG_CONTROL 0x0004
#define EP_EISA_CFG_RESOURCE 0x0008
#define EP_EISA_CFG_SIZE 0x000a
#define EP_IOPORT_OFFSET 0x0000
#define EP_IOPORT_SIZE 0x0020
#define EISA_RESET 0x04
#define EISA_ERROR 0x02
#define EISA_ENABLE 0x01
struct ep_eisa_product {
u_short chipset;
int flags;
const char *name;
};
static const struct ep_eisa_product tcm5090 = {
.chipset = ELINK_CHIPSET_3C509,
.flags = 0,
.name = EISA_PRODUCT_TCM5090
};
static const struct ep_eisa_product tcm5091 = {
.chipset = ELINK_CHIPSET_3C509,
.flags = 0,
.name = EISA_PRODUCT_TCM5091
};
static const struct ep_eisa_product tcm5092 = {
.chipset = ELINK_CHIPSET_3C509,
.flags = 0,
.name = EISA_PRODUCT_TCM5092
};
static const struct ep_eisa_product tcm5093 = {
.chipset = ELINK_CHIPSET_3C509,
.flags = 0,
.name = EISA_PRODUCT_TCM5093
};
static const struct ep_eisa_product tcm5094 = {
.chipset = ELINK_CHIPSET_3C509,
.flags = 0,
.name = EISA_PRODUCT_TCM5094
};
static const struct ep_eisa_product tcm5095 = {
.chipset = ELINK_CHIPSET_3C509,
.flags = 0,
.name = EISA_PRODUCT_TCM5095
};
static const struct ep_eisa_product tcm5098 = {
.chipset = ELINK_CHIPSET_3C509,
.flags = 0,
.name = EISA_PRODUCT_TCM5098
};
static const struct ep_eisa_product tcm5920 = {
.chipset = ELINK_CHIPSET_VORTEX,
.flags = 0,
.name = EISA_PRODUCT_TCM5920
};
static const struct ep_eisa_product tcm5970 = {
.chipset = ELINK_CHIPSET_VORTEX,
.flags = 0,
.name = EISA_PRODUCT_TCM5970
};
static const struct ep_eisa_product tcm5971 = {
.chipset = ELINK_CHIPSET_VORTEX,
.flags = 0,
.name = EISA_PRODUCT_TCM5971
};
static const struct ep_eisa_product tcm5972 = {
.chipset = ELINK_CHIPSET_VORTEX,
.flags = 0,
.name = EISA_PRODUCT_TCM5972
};
static const struct device_compatible_entry compat_data[] = {
{ .compat = "TCM5090", .data = &tcm5090 },
{ .compat = "TCM5091", .data = &tcm5091 },
{ .compat = "TCM5092", .data = &tcm5092 },
{ .compat = "TCM5093", .data = &tcm5093 },
{ .compat = "TCM5094", .data = &tcm5094 },
{ .compat = "TCM5095", .data = &tcm5095 },
{ .compat = "TCM5098", .data = &tcm5098 },
{ .compat = "TCM5920", .data = &tcm5920 },
{ .compat = "TCM5970", .data = &tcm5970 },
{ .compat = "TCM5971", .data = &tcm5971 },
{ .compat = "TCM5972", .data = &tcm5972 },
DEVICE_COMPAT_EOL
};
static int
ep_eisa_match(device_t parent, cfdata_t match, void *aux)
{
struct eisa_attach_args *ea = aux;
return (eisa_compatible_match(ea, compat_data));
}
static void
ep_eisa_attach(device_t parent, device_t self, void *aux)
{
struct ep_softc *sc = device_private(self);
struct eisa_attach_args *ea = aux;
const struct device_compatible_entry *dce;
bus_space_tag_t iot = ea->ea_iot;
bus_space_handle_t ioh, ioh_cfg;
eisa_chipset_tag_t ec = ea->ea_ec;
eisa_intr_handle_t ih;
const char *intrstr;
const struct ep_eisa_product *eep;
u_int irq;
char intrbuf[EISA_INTRSTR_LEN];
if (bus_space_map(iot, EISA_SLOT_ADDR(ea->ea_slot) + EP_EISA_CFG_BASE,
EP_EISA_CFG_SIZE, 0, &ioh_cfg)) {
printf("\n");
panic("ep_eisa_attach: can't map eisa cfg i/o space");
}
if (bus_space_map(iot, EISA_SLOT_ADDR(ea->ea_slot) + EP_IOPORT_OFFSET,
EP_IOPORT_SIZE, 0, &ioh)) {
printf("\n");
panic("ep_eisa_attach: can't map i/o space");
}
sc->sc_dev = self;
sc->sc_ioh = ioh;
sc->sc_iot = iot;
bus_space_write_1(iot, ioh_cfg, EP_EISA_CFG_CONTROL, EISA_ENABLE);
delay(4000);
irq = bus_space_read_2(iot, ioh_cfg, EP_EISA_CFG_RESOURCE) >> 12;
dce = eisa_compatible_lookup(ea, compat_data);
KASSERT(dce != NULL);
eep = dce->data;
#if 0
bus_space_unmap(iot, ioh_cfg, EP_EISA_CFG_SIZE);
#endif
printf(": %s\n", eep->name);
sc->enable = NULL;
sc->disable = NULL;
sc->enabled = 1;
sc->bustype = ELINK_BUS_EISA;
sc->ep_flags = eep->flags;
if (eisa_intr_map(ec, irq, &ih)) {
aprint_error_dev(sc->sc_dev, "couldn't map interrupt (%u)\n",
irq);
return;
}
intrstr = eisa_intr_string(ec, ih, intrbuf, sizeof(intrbuf));
sc->sc_ih = eisa_intr_establish(ec, ih, IST_EDGE, IPL_NET,
epintr, sc);
if (sc->sc_ih == NULL) {
aprint_error_dev(sc->sc_dev, "couldn't establish interrupt");
if (intrstr != NULL)
aprint_error(" at %s", intrstr);
aprint_error("\n");
return;
}
if (intrstr != NULL)
aprint_normal_dev(sc->sc_dev, "interrupting at %s\n", intrstr);
epconfig(sc, eep->chipset, NULL);
}