Exemplo n.º 1
0
static void
obio_hinted_child(device_t bus, const char *dname, int dunit)
{
	device_t		child;
	long			maddr;
	int			msize;
	int			irq;
	int			result;

	child = BUS_ADD_CHILD(bus, 0, dname, dunit);

	/*
	 * Set hard-wired resources for hinted child using
	 * specific RIDs.
	 */
	resource_long_value(dname, dunit, "maddr", &maddr);
	resource_int_value(dname, dunit, "msize", &msize);


	result = bus_set_resource(child, SYS_RES_MEMORY, 0,
	    maddr, msize);
	if (result != 0)
		device_printf(bus, "warning: bus_set_resource() failed\n");

	if (resource_int_value(dname, dunit, "irq", &irq) == 0) {
		result = bus_set_resource(child, SYS_RES_IRQ, 0, irq, 1);
		if (result != 0)
			device_printf(bus,
			    "warning: bus_set_resource() failed\n");
	}
}
Exemplo n.º 2
0
static bus_size_t
bcm_get_bus_size(void)
{
	long msize;

	if (resource_long_value("bhnd", 0, "msize", &msize) == 0)
		return ((u_long)msize);

	return (BHND_DEFAULT_ENUM_SIZE);
}
Exemplo n.º 3
0
static u_long
acpi_get_root_from_loader(void)
{
    long acpi_root;

    if (resource_long_value("acpi", 0, "rsdp", &acpi_root) == 0)
        return (acpi_root);

    return (0);
}
Exemplo n.º 4
0
static bus_addr_t
bcm_get_bus_addr(void)
{
	long maddr;

	if (resource_long_value("bhnd", 0, "maddr", &maddr) == 0)
		return ((u_long)maddr);

	return (BHND_DEFAULT_CHIPC_ADDR);
}
Exemplo n.º 5
0
static void
nexus_hinted_child(device_t bus, const char *dname, int dunit)
{
	device_t child;
	long	maddr;
	int	msize;
	int	order;
	int	result;
	int	irq;
	int	mem_hints_count;

	if ((resource_int_value(dname, dunit, "order", &order)) != 0)
		order = 1000;
	child = BUS_ADD_CHILD(bus, order, dname, dunit);
	if (child == NULL)
		return;

	/*
	 * Set hard-wired resources for hinted child using
	 * specific RIDs.
	 */
	mem_hints_count = 0;
	if (resource_long_value(dname, dunit, "maddr", &maddr) == 0)
		mem_hints_count++;
	if (resource_int_value(dname, dunit, "msize", &msize) == 0)
		mem_hints_count++;

	/* check if all info for mem resource has been provided */
	if ((mem_hints_count > 0) && (mem_hints_count < 2)) {
		printf("Either maddr or msize hint is missing for %s%d\n",
		    dname, dunit);
	} 
	else if (mem_hints_count) {
		dprintf("%s: discovered hinted child %s at maddr %p(%d)\n",
		    __func__, device_get_nameunit(child),
		    (void *)(intptr_t)maddr, msize);

		result = bus_set_resource(child, SYS_RES_MEMORY, 0, maddr, 
		    msize);
		if (result != 0) {
			device_printf(bus, 
			    "warning: bus_set_resource() failed\n");
		}
	}

	if (resource_int_value(dname, dunit, "irq", &irq) == 0) {
		result = bus_set_resource(child, SYS_RES_IRQ, 0, irq, 1);
		if (result != 0)
			device_printf(bus,
			    "warning: bus_set_resource() failed\n");
	}
}
ACPI_PHYSICAL_ADDRESS
AcpiOsGetRootPointer(void)
{
	u_long	ptr;

	if (i386_acpi_root == 0 &&
	    (resource_long_value("acpi", 0, "rsdp", (long *)&ptr) == 0 ||
	    AcpiFindRootPointer((ACPI_SIZE *)&ptr) == AE_OK) &&
	    ptr != 0)
		i386_acpi_root = ptr;

	return (i386_acpi_root);
}
Exemplo n.º 7
0
static int
atse_resource_long(device_t dev, const char *resname, long *v)
{
	int error;

	error = resource_long_value(device_get_name(dev), device_get_unit(dev),
	    resname, v);
	if (error != 0) {
		/* If it does not exist, we fail, so not ingoring ENOENT. */
		device_printf(dev, "could not fetch '%s' hint\n", resname);
		return (error);
	}

	return (0);
}
Exemplo n.º 8
0
static void
obio_hinted_child(device_t bus, const char *dname, int dunit)
{
	long			maddr;
	int			msize;
	int			irq;

	/*
	 * Set hard-wired resources for hinted child using
	 * specific RIDs.
	 */
	resource_long_value(dname, dunit, "maddr", &maddr);
	resource_int_value(dname, dunit, "msize", &msize);


	if (resource_int_value(dname, dunit, "irq", &irq) == 0) irq = -1;

	obio_add_res_child(bus, dname, dunit, maddr, msize, irq);
}
Exemplo n.º 9
0
static u_long
acpi_get_root_from_loader(void)
{
	long acpi_root;

	if (TUNABLE_ULONG_FETCH("acpi.rsdp", &acpi_root))
		return (acpi_root);

	/*
	 * The hints mechanism is unreliable (it fails if anybody ever
	 * compiled in hints to the kernel). It has been replaced
	 * by the tunable method, but is used here as a fallback to
	 * retain maximum compatibility between old loaders and new
	 * kernels. It can be removed after 11.0R.
	 */
	if (resource_long_value("acpi", 0, "rsdp", &acpi_root) == 0)
		return (acpi_root);

	return (0);
}
Exemplo n.º 10
0
static void
apb_hinted_child(device_t bus, const char *dname, int dunit)
{
	device_t		child;
	long			maddr;
	int			msize;
	int			irq;
	int			result;
	int			mem_hints_count;

	child = BUS_ADD_CHILD(bus, 0, dname, dunit);

	/*
	 * Set hard-wired resources for hinted child using
	 * specific RIDs.
	 */
	mem_hints_count = 0;
	if (resource_long_value(dname, dunit, "maddr", &maddr) == 0)
		mem_hints_count++;
	if (resource_int_value(dname, dunit, "msize", &msize) == 0)
		mem_hints_count++;

	/* check if all info for mem resource has been provided */
	if ((mem_hints_count > 0) && (mem_hints_count < 2)) {
		printf("Either maddr or msize hint is missing for %s%d\n",
		    dname, dunit);
	} else if (mem_hints_count) {
		result = bus_set_resource(child, SYS_RES_MEMORY, 0,
		    maddr, msize);
		if (result != 0)
			device_printf(bus, 
			    "warning: bus_set_resource() failed\n");
	}

	if (resource_int_value(dname, dunit, "irq", &irq) == 0) {
		result = bus_set_resource(child, SYS_RES_IRQ, 0, irq, 1);
		if (result != 0)
			device_printf(bus,
			    "warning: bus_set_resource() failed\n");
	}
}
Exemplo n.º 11
0
/*
 * Handle initialising the MAC address from a specific EEPROM
 * offset.
 *
 * This is done during (very) early boot.
 *
 * hint.ar71xx.0.eeprom_mac_addr=<address to read from>
 * hint.ar71xx.0.eeprom_mac_isascii=<0|1>
 */
static int
ar71xx_platform_read_eeprom_mac(void)
{
	long eeprom_mac_addr = 0;
	const char *mac;
	int i, readascii = 0;
	uint8_t macaddr[ETHER_ADDR_LEN];

	if (resource_long_value("ar71xx", 0, "eeprom_mac_addr",
	    &eeprom_mac_addr) != 0)
		return (-1);

	/* get a pointer to the EEPROM MAC address */

	mac = (const char *) MIPS_PHYS_TO_KSEG1(eeprom_mac_addr);

	/* Check if it's ASCII or not */
	if (resource_int_value("ar71xx", 0, "eeprom_mac_isascii",
	    &readascii) == 0 && readascii == 1) {
		printf("ar71xx: Overriding MAC from EEPROM (ascii)\n");
		for (i = 0; i < 6; i++) {
			macaddr[i] = strtol(&(mac[i*3]), NULL, 16);
		}
	} else {
		printf("ar71xx: Overriding MAC from EEPROM\n");
		for (i = 0; i < 6; i++) {
			macaddr[i] = mac[i];
		}
	}

	/* Set the default board MAC */
	(void) ar71xx_mac_addr_init(ar71xx_board_mac_addr,
	    macaddr,
	    0, /* offset */
	    0); /* is_local */
	printf("ar71xx: Board MAC: %6D\n", ar71xx_board_mac_addr, ":");
	return (0);
}
static int
psmcpnp_probe(device_t dev)
{
	struct resource *res;
	u_long irq;
	int rid;

	if (ISA_PNP_PROBE(device_get_parent(dev), dev, psmcpnp_ids))
		return ENXIO;

	/*
	 * The PnP BIOS and ACPI are supposed to assign an IRQ (12)
	 * to the PS/2 mouse device node. But, some buggy PnP BIOS
	 * declares the PS/2 mouse device node without an IRQ resource!
	 * If this happens, we shall refer to device hints.
	 * If we still don't find it there, use a hardcoded value... XXX
	 */
	rid = 0;
	irq = bus_get_resource_start(dev, SYS_RES_IRQ, rid);
	if (irq <= 0) {
		if (resource_long_value(PSM_DRIVER_NAME,
					device_get_unit(dev), "irq", &irq) != 0)
			irq = 12;	/* XXX */
		device_printf(dev, "irq resource info is missing; "
			      "assuming irq %ld\n", irq);
		bus_set_resource(dev, SYS_RES_IRQ, rid, irq, 1);
	}
	res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
				     RF_SHAREABLE);
	bus_release_resource(dev, SYS_RES_IRQ, rid, res);

	/* keep quiet */
	if (!bootverbose)
		device_quiet(dev);

	return ((res == NULL) ? ENXIO : 0);
}
Exemplo n.º 13
0
static void
ar71xx_pci_slot_fixup(device_t dev, u_int bus, u_int slot, u_int func)
{
	long int flash_addr;
	char buf[64];
	int size;

	/*
	 * Check whether the given slot has a hint to poke.
	 */
	if (bootverbose)
	device_printf(dev, "%s: checking dev %s, %d/%d/%d\n",
	    __func__, device_get_nameunit(dev), bus, slot, func);

	snprintf(buf, sizeof(buf), "bus.%d.%d.%d.ath_fixup_addr",
	    bus, slot, func);

	if (resource_long_value(device_get_name(dev), device_get_unit(dev),
	    buf, &flash_addr) == 0) {
		snprintf(buf, sizeof(buf), "bus.%d.%d.%d.ath_fixup_size",
		    bus, slot, func);
		if (resource_int_value(device_get_name(dev),
		    device_get_unit(dev), buf, &size) != 0) {
			device_printf(dev,
			    "%s: missing hint '%s', aborting EEPROM\n",
			    __func__, buf);
			return;
		}


		device_printf(dev, "found EEPROM at 0x%lx on %d.%d.%d\n",
		    flash_addr, bus, slot, func);
		ar71xx_pci_fixup(dev, bus, slot, func, flash_addr, size);
		ar71xx_pci_slot_create_eeprom_firmware(dev, bus, slot, func,
		    flash_addr, size);
	}
}
Exemplo n.º 14
0
/*
 * Iterate through a list of early-boot hints creating calibration
 * data firmware chunks for AHB (ie, non-PCI) devices with calibration
 * data.
 */
static int
ar71xx_platform_check_eeprom_hints(device_t dev)
{
	char buf[64];
	long int addr;
	int size;
	int i;

	for (i = 0; i < 8; i++) {
		snprintf(buf, sizeof(buf), "map.%d.ath_fixup_addr", i);
		if (resource_long_value(device_get_name(dev),
		    device_get_unit(dev), buf, &addr) != 0)
			break;
		snprintf(buf, sizeof(buf), "map.%d.ath_fixup_size", i);
		if (resource_int_value(device_get_name(dev),
		    device_get_unit(dev), buf, &size) != 0)
			break;
		device_printf(dev, "map.%d.ath_fixup_addr=0x%08x; size=%d\n",
		    i, (int) addr, size);
		(void) ar71xx_platform_create_cal_data(dev, i, addr, size);
        }

        return (0);
}
Exemplo n.º 15
0
static int
ath_ahb_attach(device_t dev)
{
	struct ath_ahb_softc *psc = device_get_softc(dev);
	struct ath_softc *sc = &psc->sc_sc;
	int error = ENXIO;
	int rid;
	long eepromaddr;
	uint8_t *p;

	sc->sc_dev = dev;

	rid = 0;
	psc->sc_sr = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE);
	if (psc->sc_sr == NULL) {
		device_printf(dev, "cannot map register space\n");
		goto bad;
	}

        if (resource_long_value(device_get_name(dev), device_get_unit(dev),
            "eepromaddr", &eepromaddr) != 0) {
		device_printf(dev, "cannot fetch 'eepromaddr' from hints\n");
		goto bad0;
        }
	rid = 0;
	device_printf(sc->sc_dev, "eeprom @ %p\n", (void *) eepromaddr);
	psc->sc_eeprom = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid, (uintptr_t) eepromaddr,
	  (uintptr_t) eepromaddr + (uintptr_t) ((ATH_EEPROM_DATA_SIZE * 2) - 1), 0, RF_ACTIVE);
	if (psc->sc_eeprom == NULL) {
		device_printf(dev, "cannot map eeprom space\n");
		goto bad0;
	}

	/* XXX uintptr_t is a bandaid for ia64; to be fixed */
	sc->sc_st = (HAL_BUS_TAG)(uintptr_t) rman_get_bustag(psc->sc_sr);
	sc->sc_sh = (HAL_BUS_HANDLE) rman_get_bushandle(psc->sc_sr);
	/*
	 * Mark device invalid so any interrupts (shared or otherwise)
	 * that arrive before the HAL is setup are discarded.
	 */
	sc->sc_invalid = 1;

	/* Copy the EEPROM data out */
	sc->sc_eepromdata = malloc(ATH_EEPROM_DATA_SIZE * 2, M_TEMP, M_NOWAIT | M_ZERO);
	if (sc->sc_eepromdata == NULL) {
		device_printf(dev, "cannot allocate memory for eeprom data\n");
		goto bad1;
	}
	device_printf(sc->sc_dev, "eeprom data @ %p\n", (void *) rman_get_bushandle(psc->sc_eeprom));
	/* XXX why doesn't this work? -adrian */
#if 0
	bus_space_read_multi_1(
	    rman_get_bustag(psc->sc_eeprom),
	    rman_get_bushandle(psc->sc_eeprom),
	    0, (u_int8_t *) sc->sc_eepromdata, ATH_EEPROM_DATA_SIZE * 2);
#endif
	p = (void *) rman_get_bushandle(psc->sc_eeprom);
	memcpy(sc->sc_eepromdata, p, ATH_EEPROM_DATA_SIZE * 2);

	/*
	 * Arrange interrupt line.
	 */
	rid = 0;
	psc->sc_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_SHAREABLE|RF_ACTIVE);
	if (psc->sc_irq == NULL) {
		device_printf(dev, "could not map interrupt\n");
		goto bad1;
	}
	if (bus_setup_intr(dev, psc->sc_irq,
			   INTR_TYPE_NET | INTR_MPSAFE,
			   NULL, ath_intr, sc, &psc->sc_ih)) {
		device_printf(dev, "could not establish interrupt\n");
		goto bad2;
	}

	/*
	 * Setup DMA descriptor area.
	 */
	if (bus_dma_tag_create(bus_get_dma_tag(dev),	/* parent */
			       1, 0,			/* alignment, bounds */
			       BUS_SPACE_MAXADDR_32BIT,	/* lowaddr */
			       BUS_SPACE_MAXADDR,	/* highaddr */
			       NULL, NULL,		/* filter, filterarg */
			       0x3ffff,			/* maxsize XXX */
			       ATH_MAX_SCATTER,		/* nsegments */
			       0x3ffff,			/* maxsegsize XXX */
			       BUS_DMA_ALLOCNOW,	/* flags */
			       NULL,			/* lockfunc */
			       NULL,			/* lockarg */
			       &sc->sc_dmat)) {
		device_printf(dev, "cannot allocate DMA tag\n");
		goto bad3;
	}

	ATH_LOCK_INIT(sc);

	error = ath_attach(AR9130_DEVID, sc);
	if (error == 0)					/* success */
		return 0;

	ATH_LOCK_DESTROY(sc);
	bus_dma_tag_destroy(sc->sc_dmat);
bad3:
	bus_teardown_intr(dev, psc->sc_irq, psc->sc_ih);
bad2:
	bus_release_resource(dev, SYS_RES_IRQ, 0, psc->sc_irq);
bad1:
	bus_release_resource(dev, SYS_RES_MEMORY, 0, psc->sc_eeprom);
bad0:
	bus_release_resource(dev, SYS_RES_MEMORY, 0, psc->sc_sr);
bad:
	/* XXX?! */
	if (sc->sc_eepromdata)
		free(sc->sc_eepromdata, M_TEMP);
	return (error);
}
Exemplo n.º 16
0
static int
terasic_mtl_nexus_attach(device_t dev)
{
	struct terasic_mtl_softc *sc;
	u_long pixel_maddr, text_maddr, reg_maddr;
	u_long pixel_msize, text_msize, reg_msize;
	int error;

	sc = device_get_softc(dev);
	sc->mtl_dev = dev;
	sc->mtl_unit = device_get_unit(dev);

	/*
	 * Query non-standard hints to find the locations of our two memory
	 * regions.  Enforce certain alignment and size requirements.
	 */
	if (resource_long_value(device_get_name(dev), device_get_unit(dev),
	    "reg_maddr", &reg_maddr) != 0 || (reg_maddr % PAGE_SIZE != 0)) {
		device_printf(dev, "improper register address");
		return (ENXIO);
	}
	if (resource_long_value(device_get_name(dev), device_get_unit(dev),
	    "reg_msize", &reg_msize) != 0 || (reg_msize % PAGE_SIZE != 0)) {
		device_printf(dev, "improper register size");
		return (ENXIO);
	}
	if (resource_long_value(device_get_name(dev), device_get_unit(dev),
	    "pixel_maddr", &pixel_maddr) != 0 ||
	    (pixel_maddr % PAGE_SIZE != 0)) {
		device_printf(dev, "improper pixel frame buffer address");
		return (ENXIO);
	}
	if (resource_long_value(device_get_name(dev), device_get_unit(dev),
	    "pixel_msize", &pixel_msize) != 0 ||
	    (pixel_msize % PAGE_SIZE != 0)) {
		device_printf(dev, "improper pixel frame buffer size");
		return (ENXIO);
	}
	if (resource_long_value(device_get_name(dev), device_get_unit(dev),
	    "text_maddr", &text_maddr) != 0 ||
	    (text_maddr % PAGE_SIZE != 0)) {
		device_printf(dev, "improper text frame buffer address");
		return (ENXIO);
	}
	if (resource_long_value(device_get_name(dev), device_get_unit(dev),
	    "text_msize", &text_msize) != 0 ||
	    (text_msize % PAGE_SIZE != 0)) {
		device_printf(dev, "improper text frame buffer size");
		return (ENXIO);
	}

	/*
	 * Allocate resources.
	 */
	sc->mtl_reg_rid = 0;
	sc->mtl_reg_res = bus_alloc_resource(dev, SYS_RES_MEMORY,
	    &sc->mtl_reg_rid, reg_maddr, reg_maddr + reg_msize - 1,
	    reg_msize, RF_ACTIVE);
	if (sc->mtl_reg_res == NULL) {
		device_printf(dev, "couldn't map register memory\n");
		error = ENXIO;
		goto error;
	}
	device_printf(sc->mtl_dev, "registers at mem %p-%p\n",
	    (void *)reg_maddr, (void *)(reg_maddr + reg_msize));
	sc->mtl_pixel_rid = 0;
	sc->mtl_pixel_res = bus_alloc_resource(dev, SYS_RES_MEMORY,
	    &sc->mtl_pixel_rid, pixel_maddr, pixel_maddr + pixel_msize - 1,
	    pixel_msize, RF_ACTIVE);
	if (sc->mtl_pixel_res == NULL) {
		device_printf(dev, "couldn't map pixel memory\n");
		error = ENXIO;
		goto error;
	}
	device_printf(sc->mtl_dev, "pixel frame buffer at mem %p-%p\n",
	    (void *)pixel_maddr, (void *)(pixel_maddr + pixel_msize));
	sc->mtl_text_rid = 0;
	sc->mtl_text_res = bus_alloc_resource(dev, SYS_RES_MEMORY,
	    &sc->mtl_text_rid, text_maddr, text_maddr + text_msize - 1,
	    text_msize, RF_ACTIVE);
	if (sc->mtl_text_res == NULL) {
		device_printf(dev, "couldn't map text memory\n");
		error = ENXIO;
		goto error;
	}
	device_printf(sc->mtl_dev, "text frame buffer at mem %p-%p\n",
	    (void *)text_maddr, (void *)(text_maddr + text_msize));
	error = terasic_mtl_attach(sc);
	if (error == 0)
		return (0);
error:
	if (sc->mtl_text_res != NULL)
		bus_release_resource(dev, SYS_RES_MEMORY, sc->mtl_text_rid,
		    sc->mtl_text_res);
	if (sc->mtl_pixel_res != NULL)
		bus_release_resource(dev, SYS_RES_MEMORY, sc->mtl_pixel_rid,
		    sc->mtl_pixel_res);
	if (sc->mtl_reg_res != NULL)
		bus_release_resource(dev, SYS_RES_MEMORY, sc->mtl_reg_rid,
		    sc->mtl_reg_res);
	return (error);
}
Exemplo n.º 17
0
void
isa_hint_device_unit(device_t bus, device_t child, const char *name, int *unitp)
{
	const char *s;
	long value;
	int line, matches, unit;

	line = 0;
	for (;;) {
		if (resource_find_dev(&line, name, &unit, "at", NULL) != 0)
			break;

		/* Must have an "at" for isa. */
		resource_string_value(name, unit, "at", &s);
		if (!(strcmp(s, device_get_nameunit(bus)) == 0 ||
		    strcmp(s, device_get_name(bus)) == 0))
			continue;

		/*
		 * Check for matching resources.  We must have at
		 * least one match.  Since I/O and memory resources
		 * cannot be shared, if we get a match on either of
		 * those, ignore any mismatches in IRQs or DRQs.
		 *
		 * XXX: We may want to revisit this to be more lenient
		 * and wire as long as it gets one match.
		 */
		matches = 0;
		if (resource_long_value(name, unit, "port", &value) == 0) {
			/*
			 * Floppy drive controllers are notorious for
			 * having a wide variety of resources not all
			 * of which include the first port that is
			 * specified by the hint (typically 0x3f0)
			 * (see the comment above
			 * fdc_isa_alloc_resources() in fdc_isa.c).
			 * However, they do all seem to include port +
			 * 2 (e.g. 0x3f2) so for a floppy device, look
			 * for 'value + 2' in the port resources
			 * instead of the hint value.
			 */
			if (strcmp(name, "fdc") == 0)
				value += 2;
			if (isa_match_resource_hint(child, SYS_RES_IOPORT,
			    value))
				matches++;
			else
				continue;
		}
		if (resource_long_value(name, unit, "maddr", &value) == 0) {
			if (isa_match_resource_hint(child, SYS_RES_MEMORY,
			    value))
				matches++;
			else
				continue;
		}
		if (matches > 0)
			goto matched;
		if (resource_long_value(name, unit, "irq", &value) == 0) {
			if (isa_match_resource_hint(child, SYS_RES_IRQ, value))
				matches++;
			else
				continue;
		}
		if (resource_long_value(name, unit, "drq", &value) == 0) {
			if (isa_match_resource_hint(child, SYS_RES_DRQ, value))
				matches++;
			else
				continue;
		}

	matched:
		if (matches > 0) {
			/* We have a winner! */
			*unitp = unit;
			break;
		}
	}
}
Exemplo n.º 18
0
static int
ath_ahb_attach(device_t dev)
{
	struct ath_ahb_softc *psc = device_get_softc(dev);
	struct ath_softc *sc = &psc->sc_sc;
	int error = ENXIO;
	int rid;
	long eepromaddr;
	int eepromsize;
	uint8_t *p;
	int device_id, vendor_id;

	sc->sc_dev = dev;

	rid = 0;
	psc->sc_sr = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE);
	if (psc->sc_sr == NULL) {
		device_printf(dev, "cannot map register space\n");
		goto bad;
	}

	if (resource_long_value(device_get_name(dev), device_get_unit(dev),
	    "eepromaddr", &eepromaddr) != 0) {
		device_printf(dev, "cannot fetch 'eepromaddr' from hints\n");
		goto bad0;
	}

	/*
	 * The default EEPROM size is 2048 * 16 bit words.
	 * Later EEPROM/OTP/flash regions may be quite a bit bigger.
	 */
	if (resource_int_value(device_get_name(dev), device_get_unit(dev),
	    "eepromsize", &eepromsize) != 0) {
		eepromsize = ATH_EEPROM_DATA_SIZE * 2;
	}

	rid = 0;
	device_printf(sc->sc_dev, "eeprom @ %p (%d bytes)\n",
	    (void *) eepromaddr, eepromsize);
	/*
	 * XXX this assumes that the parent device is the nexus
	 * and will just pass through requests for all of memory.
	 *
	 * Later on, when this has to attach off of the actual
	 * AHB, this won't work.
	 *
	 * Ideally this would be done in machdep code in mips/atheros/
	 * and it'd expose the EEPROM via the firmware interface,
	 * so the ath/ath_ahb drivers can be loaded as modules
	 * after boot-time.
	 */
	psc->sc_eeprom = bus_alloc_resource(dev, SYS_RES_MEMORY,
	    &rid, (uintptr_t) eepromaddr,
	    (uintptr_t) eepromaddr + (uintptr_t) (eepromsize - 1), 0, RF_ACTIVE);
	if (psc->sc_eeprom == NULL) {
		device_printf(dev, "cannot map eeprom space\n");
		goto bad0;
	}

	sc->sc_st = (HAL_BUS_TAG) rman_get_bustag(psc->sc_sr);
	sc->sc_sh = (HAL_BUS_HANDLE) rman_get_bushandle(psc->sc_sr);
	/*
	 * Mark device invalid so any interrupts (shared or otherwise)
	 * that arrive before the HAL is setup are discarded.
	 */
	sc->sc_invalid = 1;

	/* Copy the EEPROM data out */
	sc->sc_eepromdata = malloc(eepromsize, M_TEMP, M_NOWAIT | M_ZERO);
	if (sc->sc_eepromdata == NULL) {
		device_printf(dev, "cannot allocate memory for eeprom data\n");
		goto bad1;
	}
	device_printf(sc->sc_dev, "eeprom data @ %p\n", (void *) rman_get_bushandle(psc->sc_eeprom));
	/* XXX why doesn't this work? -adrian */
#if 0
	bus_space_read_multi_1(
	    rman_get_bustag(psc->sc_eeprom),
	    rman_get_bushandle(psc->sc_eeprom),
	    0, (u_int8_t *) sc->sc_eepromdata, eepromsize);
#endif
	p = (void *) rman_get_bushandle(psc->sc_eeprom);
	memcpy(sc->sc_eepromdata, p, eepromsize);

	/*
	 * Arrange interrupt line.
	 */
	rid = 0;
	psc->sc_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_SHAREABLE|RF_ACTIVE);
	if (psc->sc_irq == NULL) {
		device_printf(dev, "could not map interrupt\n");
		goto bad1;
	}
	if (bus_setup_intr(dev, psc->sc_irq,
			   INTR_TYPE_NET | INTR_MPSAFE,
			   NULL, ath_ahb_intr, sc, &psc->sc_ih)) {
		device_printf(dev, "could not establish interrupt\n");
		goto bad2;
	}

	/*
	 * Setup DMA descriptor area.
	 */
	if (bus_dma_tag_create(bus_get_dma_tag(dev),	/* parent */
			       1, 0,			/* alignment, bounds */
			       BUS_SPACE_MAXADDR_32BIT,	/* lowaddr */
			       BUS_SPACE_MAXADDR,	/* highaddr */
			       NULL, NULL,		/* filter, filterarg */
			       0x3ffff,			/* maxsize XXX */
			       ATH_MAX_SCATTER,		/* nsegments */
			       0x3ffff,			/* maxsegsize XXX */
			       BUS_DMA_ALLOCNOW,	/* flags */
			       NULL,			/* lockfunc */
			       NULL,			/* lockarg */
			       &sc->sc_dmat)) {
		device_printf(dev, "cannot allocate DMA tag\n");
		goto bad3;
	}

	/*
	 * Check if a device/vendor ID is provided in hints.
	 */
	if (resource_int_value(device_get_name(dev), device_get_unit(dev),
	    "vendor_id", &vendor_id) != 0) {
		vendor_id = VENDOR_ATHEROS;
	}

	if (resource_int_value(device_get_name(dev), device_get_unit(dev),
	    "device_id", &device_id) != 0) {
		device_id = AR9130_DEVID;
	}

	ATH_LOCK_INIT(sc);
	ATH_PCU_LOCK_INIT(sc);
	ATH_RX_LOCK_INIT(sc);
	ATH_TX_LOCK_INIT(sc);
	ATH_TX_IC_LOCK_INIT(sc);
	ATH_TXSTATUS_LOCK_INIT(sc);

	error = ath_attach(device_id, sc);
	if (error == 0)					/* success */
		return 0;

	ATH_TXSTATUS_LOCK_DESTROY(sc);
	ATH_RX_LOCK_DESTROY(sc);
	ATH_TX_LOCK_DESTROY(sc);
	ATH_TX_IC_LOCK_DESTROY(sc);
	ATH_PCU_LOCK_DESTROY(sc);
	ATH_LOCK_DESTROY(sc);
	bus_dma_tag_destroy(sc->sc_dmat);
bad3:
	bus_teardown_intr(dev, psc->sc_irq, psc->sc_ih);
bad2:
	bus_release_resource(dev, SYS_RES_IRQ, 0, psc->sc_irq);
bad1:
	bus_release_resource(dev, SYS_RES_MEMORY, 0, psc->sc_eeprom);
bad0:
	bus_release_resource(dev, SYS_RES_MEMORY, 0, psc->sc_sr);
bad:
	/* XXX?! */
	if (sc->sc_eepromdata)
		free(sc->sc_eepromdata, M_TEMP);
	return (error);
}