diff options
Diffstat (limited to 'sys/dev/arl/if_arl_isa.c')
-rw-r--r-- | sys/dev/arl/if_arl_isa.c | 354 |
1 files changed, 354 insertions, 0 deletions
diff --git a/sys/dev/arl/if_arl_isa.c b/sys/dev/arl/if_arl_isa.c new file mode 100644 index 000000000000..434407d401d1 --- /dev/null +++ b/sys/dev/arl/if_arl_isa.c @@ -0,0 +1,354 @@ +/* + * $RISS: if_arl/dev/arl/if_arl_isa.c,v 1.4 2004/01/22 12:08:48 count Exp $ + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/socket.h> +#include <sys/kernel.h> +#include <sys/malloc.h> + +#include <sys/module.h> +#include <sys/bus.h> +#include <machine/bus.h> +#include <machine/resource.h> +#include <sys/rman.h> + +#include <net/ethernet.h> +#include <net/if.h> +#include <net/if_arp.h> +#include <net/if_mib.h> + +#include <isa/isavar.h> +#include <isa/pnpvar.h> +#include <isa/isa_common.h> + +#include <machine/clock.h> +#include <machine/md_var.h> +#include <vm/vm.h> +#include <vm/pmap.h> +#include <vm/vm_param.h> + +#include <dev/arl/if_arlreg.h> + +static void arl_isa_identify(driver_t *, device_t); +static int arl_isa_probe (device_t); +static int arl_isa_attach (device_t); +static int arl_isa_detach (device_t); +static char* arl_make_desc (u_int8_t, u_int8_t); + +#define ARL_MAX_ATYPE_LEN 10 +static struct arl_type { + u_int8_t type; + char* desc; +} +arl_type_list[] = { + { 0, "450" }, + { 1, "650" }, + { 0xb, "670" }, + { 0xc, "670E" }, + { 0xd, "650E" }, + { 0xe, "440LT" }, + { 0x2e, "655" }, + { 0x6b, "IC2200" }, + { 0, 0 } +}; + +#define ARL_MAX_RTYPE_LEN 10 +struct radio_type { + u_int8_t type; + char* desc; +} radio_type_list [] = { + { 1, "092/094" }, + { 2, "020" }, + { 3, "092A" }, + { 4, "020B" }, + { 5, "095" }, + { 6, "024" }, + { 7, "025B" }, + { 8, "024B" }, + { 9, "024C" }, + {10, "025C" }, + {11, "024-1A" }, + {12, "025-1A" }, +}; + + +static char* +arl_make_desc(hw_type, radio_mod) + u_int8_t hw_type; + u_int8_t radio_mod; +{ + static char desc[80]; + char atype[ARL_MAX_ATYPE_LEN], rtype[ARL_MAX_RTYPE_LEN]; + int i; + + *atype = *rtype = 0; + + /* arl type */ + for(i = 0; arl_type_list[i].desc; i++) { + if (arl_type_list[i].type == hw_type) + break; + } + + if (arl_type_list[i].desc) + strncpy(atype, arl_type_list[i].desc, ARL_MAX_ATYPE_LEN); + else + snprintf(atype, ARL_MAX_ATYPE_LEN, "(0x%x)", hw_type); + + /* radio type */ + for(i = 0; radio_type_list[i].desc; i++) + if (radio_type_list[i].type == radio_mod) + break; + + if (radio_type_list[i].desc) + strncpy(rtype, radio_type_list[i].desc, ARL_MAX_RTYPE_LEN); + else + snprintf(rtype, ARL_MAX_RTYPE_LEN, "(0x%x)", radio_mod); + + snprintf(desc, 80, "ArLan type %s, radio module %s", atype, rtype); + + return desc; +} + +#define ARL_ADDR2VEC(addr) (1 << ((addr - ARL_BASE_START) / ARL_BASE_STEP)) + +static void +arl_isa_identify (driver_t *driver, device_t parent) +{ + device_t child; + struct arl_softc *sc; + int chunk, found, i; + u_int16_t free_mem = 0xFFFF; + + if (bootverbose) + printf("in identify\n"); + + /* Try avoid already added devices */ + for (i = 0; (child = device_find_child(parent, "arl", i)) != NULL; i++) { + chunk = bus_get_resource_start(child, SYS_RES_MEMORY, 0); + if (bootverbose) + device_printf(child, "found at iomem = 0x%0x\n", chunk); + if (chunk >= ARL_BASE_START && chunk <= ARL_BASE_END) + free_mem ^= ARL_ADDR2VEC(chunk); + } + + if (bootverbose) + printf("arl: free mem vector = 0x%x\n", free_mem); + + for (chunk = ARL_BASE_START; chunk <= ARL_BASE_END; chunk += ARL_BASE_STEP) { + /* If device 'arl' with this chunk was found early - skip it */ + if ( !(free_mem & ARL_ADDR2VEC(chunk)) ) + continue; + + found = 0; + child = BUS_ADD_CHILD(parent, ISA_ORDER_SPECULATIVE, "arl", -1); + device_set_driver(child, driver); + sc = device_get_softc(child); + bzero(sc, sizeof(*sc)); + + bus_set_resource(child, SYS_RES_MEMORY, sc->mem_rid, chunk, + ARL_BASE_STEP); + + if (arl_alloc_memory(child, sc->mem_rid, ARL_BASE_STEP) == 0) { + ar = (struct arl_private *) rman_get_virtual(sc->mem_res); + if (!bcmp(ar->textRegion, ARLAN_SIGN, sizeof(ARLAN_SIGN) - 1)) + found++; + } + + if (bootverbose) + device_printf(child, "%sfound at 0x%x\n", + !found ? "not " : "", chunk); + + arl_release_resources(child); + if (!found) { + bus_delete_resource(child, SYS_RES_MEMORY, sc->mem_rid); + device_delete_child(parent, child); + } + + } +} + +static int +arl_isa_probe (device_t dev) +{ + struct arl_softc *sc = device_get_softc(dev); + int error; + u_char *ptr; + u_int8_t irq; + + if (isa_get_vendorid(dev)) + return (ENXIO); + + if (bootverbose) + device_printf(dev, "in probe\n"); + + bzero(sc, sizeof(struct arl_softc)); + + sc->arl_unit = device_get_unit(dev); + + error = arl_alloc_memory(dev, 0, ARL_BASE_STEP); + if (error) { + if (bootverbose) + device_printf(dev, "Error allocating memory (%d)\n", error); + return (error); + } + + ar = (struct arl_private *) rman_get_virtual(sc->mem_res); + if (bcmp(ar->textRegion, ARLAN_SIGN, sizeof(ARLAN_SIGN) - 1)) { + if (bootverbose) + device_printf(dev, "not found\n"); + error = ENOENT; + goto bad; + } + + irq = ar->irqLevel; + if (irq == 2) + irq = 9; + + error = bus_set_resource(dev, SYS_RES_IRQ, 0, irq, 1); + if (error) + goto bad; + + error = arl_alloc_irq(dev, 0, 0); + if (error) { + if (bootverbose) + device_printf(dev, "Can't allocate IRQ %d\n", irq); + goto bad; + } + + ar->controlRegister = 1; /* freeze board */ + + /* Memory test */ + for (ptr = (u_char *) ar; + ptr < ((u_char *) ar + ARL_BASE_STEP - 1); ptr++) { + u_char c; + + c = *ptr; *ptr = ~(*ptr); + if (*ptr != (u_char)~c) { + device_printf(dev, "board memory failed at [%lx]\n", + rman_get_start(sc->mem_res) + (ptr - (u_char *)ar)); + break; /* skip memory test */ + } + } + + bzero((void *) ar, ARL_BASE_STEP - 1); /* clear board ram */ + + if (arl_wait_reset(sc, 100, ARDELAY)) { + error = ENXIO; + goto bad; + } + + if (ar->diagnosticInfo == 0xFF) { + /* Copy arp to arpcom struct */ + bcopy(ar->lanCardNodeId, sc->arpcom.ac_enaddr, + ETHER_ADDR_LEN); + + /* copy values to local cache */ + bzero(&arcfg, sizeof(arcfg)); + + bcopy(ar->lanCardNodeId, arcfg.lanCardNodeId, + sizeof(ar->lanCardNodeId)); + bcopy(ar->specifiedRouter, arcfg.specifiedRouter, + sizeof(ar->specifiedRouter)); + + GET_ARL_PARAM(hardwareType); + GET_ARL_PARAM(majorHardwareVersion); + GET_ARL_PARAM(minorHardwareVersion); + GET_ARL_PARAM(radioModule); + GET_ARL_PARAM(channelSet); + if (!arcfg.channelSet) + arcfg.channelSet = ar->defaultChannelSet; + GET_ARL_PARAM(channelNumber); + GET_ARL_PARAM(registrationMode); + GET_ARL_PARAM(spreadingCode); + GET_ARL_PARAM(priority); + GET_ARL_PARAM(receiveMode); + arcfg.txRetry = 0; /* use default */ + + strncpy(arcfg.name, ar->name, ARLAN_NAME_SIZE); + bcopy(ar->systemId, arcfg.sid, 4 * sizeof(ar->systemId[0])); + + device_set_desc_copy(dev, arl_make_desc(ar->hardwareType, ar->radioModule)); + error = 0; + } else { + if (bootverbose) + device_printf(dev, "board self-test failed (0x%x)!\n", + ar->diagnosticInfo); + error = ENXIO; + } + +bad: + arl_release_resources(dev); + + return (error); +} + +static int +arl_isa_attach (device_t dev) +{ + struct arl_softc *sc = device_get_softc(dev); + int error; + + if (bootverbose) + device_printf(dev, "in attach\n"); + + arl_alloc_memory(dev, sc->mem_rid, ARL_BASE_STEP); + arl_alloc_irq(dev, sc->irq_rid, 0); + + error = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_NET, + arl_intr, sc, &sc->irq_handle); + if (error) { + arl_release_resources(dev); + return (error); + } + +#if __FreeBSD_version < 502108 + device_printf(dev, "Ethernet address %6D\n", sc->arpcom.ac_enaddr, ":"); +#endif + + return arl_attach(dev); +} + +static int +arl_isa_detach(device_t dev) +{ + struct arl_softc *sc = device_get_softc(dev); + + arl_stop(sc); + /* ifmedia_removeall(&sc->an_ifmedia); */ +#if __FreeBSD_version < 500100 + ether_ifdetach(&sc->arpcom.ac_if, ETHER_BPF_SUPPORTED); +#else + ether_ifdetach(&sc->arpcom.ac_if); +#endif + bus_teardown_intr(dev, sc->irq_res, sc->irq_handle); + arl_release_resources(dev); + + return (0); +} + +static device_method_t arl_isa_methods[] = { + /* Device interface */ + DEVMETHOD(device_identify, arl_isa_identify), + DEVMETHOD(device_probe, arl_isa_probe), + DEVMETHOD(device_attach, arl_isa_attach), + DEVMETHOD(device_detach, arl_isa_detach), + + { 0, 0 } +}; + +static driver_t arl_isa_driver = { + "arl", + arl_isa_methods, + sizeof(struct arl_softc) +}; + +extern devclass_t arl_devclass; + +DRIVER_MODULE(arl, isa, arl_isa_driver, arl_devclass, 0, 0); +MODULE_DEPEND(arl, isa, 1, 1, 1); +MODULE_DEPEND(arl, ether, 1, 1, 1); |