/* * $RISS: if_arl/dev/arl/if_arl_isa.c,v 1.7 2004/03/16 05:30:38 count Exp $ */ #include __FBSDID("$FreeBSD$"); #include "opt_inet.h" #ifdef INET #define ARLCACHE #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include 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("arl: 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(spreadingCode); GET_ARL_PARAM(priority); GET_ARL_PARAM(receiveMode); arcfg.registrationMode = 1; /* set default TMA mode */ 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);