예제 #1
0
파일: fdtbus.c 프로젝트: ChaosJohn/freebsd
static device_t
newbus_device_create(device_t dev_par, phandle_t node, char *name, char *type,
    char *compat)
{
	device_t child;
	struct fdtbus_devinfo *di;

	child = device_add_child(dev_par, NULL, -1);
	if (child == NULL) {
		free(name, M_OFWPROP);
		free(type, M_OFWPROP);
		free(compat, M_OFWPROP);
		return (NULL);
	}

	di = malloc(sizeof(*di), M_FDTBUS, M_WAITOK);
	di->di_node = node;
	di->di_name = name;
	di->di_type = type;
	di->di_compat = compat;

	resource_list_init(&di->di_res);

	if (fdt_reg_to_rl(node, &di->di_res)) {
		device_printf(child, "could not process 'reg' property\n");
		newbus_device_destroy(child);
		child = NULL;
		goto out;
	}

	if (fdt_intr_to_rl(node, &di->di_res, di->di_intr_sl)) {
		device_printf(child, "could not process 'interrupts' "
		    "property\n");
		newbus_device_destroy(child);
		child = NULL;
		goto out;
	}

	device_set_ivars(child, di);
	debugf("added child name='%s', node=%p\n", name, (void *)node);

out:
	return (child);
}
예제 #2
0
static int
simplebus_attach(device_t dev)
{
	device_t dev_child;
	struct simplebus_devinfo *di;
	struct simplebus_softc *sc;
	phandle_t dt_node, dt_child;

	sc = device_get_softc(dev);

	/*
	 * Walk simple-bus and add direct subordinates as our children.
	 */
	dt_node = ofw_bus_get_node(dev);
	for (dt_child = OF_child(dt_node); dt_child != 0;
	    dt_child = OF_peer(dt_child)) {

		/* Check and process 'status' property. */
		if (!(fdt_is_enabled(dt_child)))
			continue;

		if (!(fdt_pm_is_enabled(dt_child)))
			continue;

		di = malloc(sizeof(*di), M_SIMPLEBUS, M_WAITOK | M_ZERO);

		if (ofw_bus_gen_setup_devinfo(&di->di_ofw, dt_child) != 0) {
			free(di, M_SIMPLEBUS);
			device_printf(dev, "could not set up devinfo\n");
			continue;
		}

		resource_list_init(&di->di_res);
		if (fdt_reg_to_rl(dt_child, &di->di_res)) {
			device_printf(dev,
			    "%s: could not process 'reg' "
			    "property\n", di->di_ofw.obd_name);
			/* XXX should unmap */
			ofw_bus_gen_destroy_devinfo(&di->di_ofw);
			free(di, M_SIMPLEBUS);
			continue;
		}

		if (fdt_intr_to_rl(dt_child, &di->di_res, di->di_intr_sl)) {
			device_printf(dev, "%s: could not process "
			    "'interrupts' property\n", di->di_ofw.obd_name);
			resource_list_free(&di->di_res);
			/* XXX should unmap */
			ofw_bus_gen_destroy_devinfo(&di->di_ofw);
			free(di, M_SIMPLEBUS);
			continue;
		}

		/* Add newbus device for this FDT node */
		dev_child = device_add_child(dev, NULL, -1);
		if (dev_child == NULL) {
			device_printf(dev, "could not add child: %s\n",
			    di->di_ofw.obd_name);
			resource_list_free(&di->di_res);
			/* XXX should unmap */
			ofw_bus_gen_destroy_devinfo(&di->di_ofw);
			free(di, M_SIMPLEBUS);
			continue;
		}
#ifdef DEBUG
		device_printf(dev, "added child: %s\n\n", di->di_ofw.obd_name);
#endif
		device_set_ivars(dev_child, di);
	}

	return (bus_generic_attach(dev));
}
예제 #3
0
파일: fdtbus.c 프로젝트: ChaosJohn/freebsd
static device_t
newbus_pci_create(device_t dev_par, phandle_t dt_node, u_long par_base,
    u_long par_size)
{
	pcell_t reg[3 + 2];
	device_t dev_child;
	u_long start, end, count;
	struct fdtbus_devinfo *di;
	char *name, *type, *compat;
	int len;

	OF_getprop_alloc(dt_node, "device_type", 1, (void **)&type);
	if (!(type != NULL && strcmp(type, "pci") == 0)) {
		/* Only process 'pci' subnodes. */
		free(type, M_OFWPROP);
		return (NULL);
	}

	OF_getprop_alloc(dt_node, "name", 1, (void **)&name);
	OF_getprop_alloc(OF_parent(dt_node), "compatible", 1,
	    (void **)&compat);

	dev_child = device_add_child(dev_par, NULL, -1);
	if (dev_child == NULL) {
		free(name, M_OFWPROP);
		free(type, M_OFWPROP);
		free(compat, M_OFWPROP);
		return (NULL);
	}

	di = malloc(sizeof(*di), M_FDTBUS, M_WAITOK);
	di->di_node = dt_node;
	di->di_name = name;
	di->di_type = type;
	di->di_compat = compat;

	resource_list_init(&di->di_res);

	/*
	 * Produce and set SYS_RES_MEMORY resources.
	 */
	start = 0;
	count = 0;

	len = OF_getprop(dt_node, "reg", &reg, sizeof(reg));
	if (len > 0) {
		if (fdt_data_verify((void *)&reg[1], 2) != 0) {
			device_printf(dev_child, "'reg' address value out of "
			    "range\n");
			newbus_device_destroy(dev_child);
			dev_child = NULL;
			goto out;
		}
		start = fdt_data_get((void *)&reg[1], 2);

		if (fdt_data_verify((void *)&reg[3], 2) != 0) {
			device_printf(dev_child, "'reg' size value out of "
			    "range\n");
			newbus_device_destroy(dev_child);
			dev_child = NULL;
			goto out;
		}
		count = fdt_data_get((void *)&reg[3], 2);
	}

	/* Calculate address range relative to base. */
	par_base &= 0x000ffffful;
	start &= 0x000ffffful;
	start += par_base + fdt_immr_va;
	if (count == 0)
		count = par_size;
	end = start + count - 1;

	debugf("start = 0x%08lx, end = 0x%08lx, count = 0x%08lx\n",
	    start, end, count);

	if (count > par_size) {
		device_printf(dev_child, "'reg' size value out of range\n");
		newbus_device_destroy(dev_child);
		dev_child = NULL;
		goto out;
	}

	resource_list_add(&di->di_res, SYS_RES_MEMORY, 0, start, end, count);

	/*
	 * Set SYS_RES_IRQ resources.
	 */
	if (fdt_intr_to_rl(OF_parent(dt_node), &di->di_res, di->di_intr_sl)) {
		device_printf(dev_child, "could not process 'interrupts' "
		    "property\n");
		newbus_device_destroy(dev_child);
		dev_child = NULL;
		goto out;
	}

	device_set_ivars(dev_child, di);
	debugf("added child name='%s', node=%p\n", name,
	    (void *)dt_node);

out:
	return (dev_child);
}