Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 55347cc9 authored by Joachim Fenkes's avatar Joachim Fenkes Committed by Paul Mackerras
Browse files

[POWERPC] ibmebus: Add device creation and bus probing based on of_device



The devtree root is now searched for devices matching a built-in whitelist
during boot, so these devices appear on the bus from the beginning.  It is
still possible to manually add/remove devices to/from the bus by using the
probe/remove sysfs interface.  Also, when a device driver registers itself,
the devtree is matched against its matchlist.

Signed-off-by: default avatarJoachim Fenkes <fenkes@de.ibm.com>
Signed-off-by: default avatarPaul Mackerras <paulus@samba.org>
parent a988c0a6
Loading
Loading
Loading
Loading
+82 −18
Original line number Original line Diff line number Diff line
@@ -51,6 +51,13 @@ static struct device ibmebus_bus_device = { /* fake "parent" device */


struct bus_type ibmebus_bus_type;
struct bus_type ibmebus_bus_type;


/* These devices will automatically be added to the bus during init */
static struct of_device_id builtin_matches[] = {
	{ .compatible = "IBM,lhca" },
	{ .compatible = "IBM,lhea" },
	{},
};

static void *ibmebus_alloc_coherent(struct device *dev,
static void *ibmebus_alloc_coherent(struct device *dev,
				    size_t size,
				    size_t size,
				    dma_addr_t *dma_handle,
				    dma_addr_t *dma_handle,
@@ -125,6 +132,67 @@ static struct dma_mapping_ops ibmebus_dma_ops = {
	.dma_supported  = ibmebus_dma_supported,
	.dma_supported  = ibmebus_dma_supported,
};
};


static int ibmebus_match_path(struct device *dev, void *data)
{
	struct device_node *dn = to_of_device(dev)->node;
	return (dn->full_name &&
		(strcasecmp((char *)data, dn->full_name) == 0));
}

static int ibmebus_match_node(struct device *dev, void *data)
{
	return to_of_device(dev)->node == data;
}

static int ibmebus_create_device(struct device_node *dn)
{
	struct of_device *dev;
	int ret;

	dev = of_device_alloc(dn, NULL, &ibmebus_bus_device);
	if (!dev)
		return -ENOMEM;

	dev->dev.bus = &ibmebus_bus_type;
	dev->dev.archdata.dma_ops = &ibmebus_dma_ops;

	ret = of_device_register(dev);
	if (ret) {
		of_device_free(dev);
		return ret;
	}

	return 0;
}

static int ibmebus_create_devices(const struct of_device_id *matches)
{
	struct device_node *root, *child;
	int ret = 0;

	root = of_find_node_by_path("/");

	for (child = NULL; (child = of_get_next_child(root, child)); ) {
		if (!of_match_node(matches, child))
			continue;

		if (bus_find_device(&ibmebus_bus_type, NULL, child,
				    ibmebus_match_node))
			continue;

		ret = ibmebus_create_device(child);
		if (ret) {
			printk(KERN_ERR "%s: failed to create device (%i)",
			       __FUNCTION__, ret);
			of_node_put(child);
			break;
		}
	}

	of_node_put(root);
	return ret;
}

int ibmebus_register_driver(struct ibmebus_driver *drv)
int ibmebus_register_driver(struct ibmebus_driver *drv)
{
{
	return 0;
	return 0;
@@ -173,18 +241,6 @@ static struct device_attribute ibmebus_dev_attrs[] = {
	__ATTR_NULL
	__ATTR_NULL
};
};


static int ibmebus_match_path(struct device *dev, void *data)
{
	int rc;
	struct device_node *dn =
		of_node_get(to_ibmebus_dev(dev)->ofdev.node);

	rc = (dn->full_name && (strcasecmp((char*)data, dn->full_name) == 0));

	of_node_put(dn);
	return rc;
}

static char *ibmebus_chomp(const char *in, size_t count)
static char *ibmebus_chomp(const char *in, size_t count)
{
{
	char *out = kmalloc(count + 1, GFP_KERNEL);
	char *out = kmalloc(count + 1, GFP_KERNEL);
@@ -204,9 +260,8 @@ static ssize_t ibmebus_store_probe(struct bus_type *bus,
				   const char *buf, size_t count)
				   const char *buf, size_t count)
{
{
	struct device_node *dn = NULL;
	struct device_node *dn = NULL;
	struct ibmebus_dev *dev;
	char *path;
	char *path;
	ssize_t rc;
	ssize_t rc = 0;


	path = ibmebus_chomp(buf, count);
	path = ibmebus_chomp(buf, count);
	if (!path)
	if (!path)
@@ -221,9 +276,8 @@ static ssize_t ibmebus_store_probe(struct bus_type *bus,
	}
	}


	if ((dn = of_find_node_by_path(path))) {
	if ((dn = of_find_node_by_path(path))) {
/*		dev = ibmebus_register_device_node(dn); */
		rc = ibmebus_create_device(dn);
		of_node_put(dn);
		of_node_put(dn);
		rc = IS_ERR(dev) ? PTR_ERR(dev) : count;
	} else {
	} else {
		printk(KERN_WARNING "%s: no such device node: %s\n",
		printk(KERN_WARNING "%s: no such device node: %s\n",
		       __FUNCTION__, path);
		       __FUNCTION__, path);
@@ -232,7 +286,9 @@ static ssize_t ibmebus_store_probe(struct bus_type *bus,


out:
out:
	kfree(path);
	kfree(path);
	if (rc)
		return rc;
		return rc;
	return count;
}
}


static ssize_t ibmebus_store_remove(struct bus_type *bus,
static ssize_t ibmebus_store_remove(struct bus_type *bus,
@@ -247,7 +303,7 @@ static ssize_t ibmebus_store_remove(struct bus_type *bus,


	if ((dev = bus_find_device(&ibmebus_bus_type, NULL, path,
	if ((dev = bus_find_device(&ibmebus_bus_type, NULL, path,
				   ibmebus_match_path))) {
				   ibmebus_match_path))) {
/*		ibmebus_unregister_device(dev); */
		of_device_unregister(to_of_device(dev));


		kfree(path);
		kfree(path);
		return count;
		return count;
@@ -267,6 +323,7 @@ static struct bus_attribute ibmebus_bus_attrs[] = {
};
};


struct bus_type ibmebus_bus_type = {
struct bus_type ibmebus_bus_type = {
	.uevent    = of_device_uevent,
	.dev_attrs = ibmebus_dev_attrs,
	.dev_attrs = ibmebus_dev_attrs,
	.bus_attrs = ibmebus_bus_attrs
	.bus_attrs = ibmebus_bus_attrs
};
};
@@ -294,6 +351,13 @@ static int __init ibmebus_bus_init(void)
		return err;
		return err;
	}
	}


	err = ibmebus_create_devices(builtin_matches);
	if (err) {
		device_unregister(&ibmebus_bus_device);
		bus_unregister(&ibmebus_bus_type);
		return err;
	}

	return 0;
	return 0;
}
}
postcore_initcall(ibmebus_bus_init);
postcore_initcall(ibmebus_bus_init);