aboutsummaryrefslogtreecommitdiff
path: root/drivers/of/device.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/of/device.c')
-rw-r--r--drivers/of/device.c180
1 files changed, 135 insertions, 45 deletions
diff --git a/drivers/of/device.c b/drivers/of/device.c
index 29681c4b700..dafb9736ab9 100644
--- a/drivers/of/device.c
+++ b/drivers/of/device.c
@@ -8,26 +8,26 @@
#include <linux/slab.h>
#include <asm/errno.h>
+#include "of_private.h"
/**
- * of_match_device - Tell if an of_device structure has a matching
- * of_match structure
+ * of_match_device - Tell if a struct device matches an of_device_id list
* @ids: array of of device match structures to search in
* @dev: the of device structure to match against
*
- * Used by a driver to check whether an of_device present in the
+ * Used by a driver to check whether an platform_device present in the
* system is in its list of supported devices.
*/
const struct of_device_id *of_match_device(const struct of_device_id *matches,
- const struct of_device *dev)
+ const struct device *dev)
{
- if (!dev->node)
+ if ((!matches) || (!dev->of_node))
return NULL;
- return of_match_node(matches, dev->node);
+ return of_match_node(matches, dev->of_node);
}
EXPORT_SYMBOL(of_match_device);
-struct of_device *of_dev_get(struct of_device *dev)
+struct platform_device *of_dev_get(struct platform_device *dev)
{
struct device *tmp;
@@ -35,68 +35,158 @@ struct of_device *of_dev_get(struct of_device *dev)
return NULL;
tmp = get_device(&dev->dev);
if (tmp)
- return to_of_device(tmp);
+ return to_platform_device(tmp);
else
return NULL;
}
EXPORT_SYMBOL(of_dev_get);
-void of_dev_put(struct of_device *dev)
+void of_dev_put(struct platform_device *dev)
{
if (dev)
put_device(&dev->dev);
}
EXPORT_SYMBOL(of_dev_put);
-static ssize_t dev_show_devspec(struct device *dev,
- struct device_attribute *attr, char *buf)
+int of_device_add(struct platform_device *ofdev)
{
- struct of_device *ofdev;
+ BUG_ON(ofdev->dev.of_node == NULL);
- ofdev = to_of_device(dev);
- return sprintf(buf, "%s", ofdev->node->full_name);
+ /* name and id have to be set so that the platform bus doesn't get
+ * confused on matching */
+ ofdev->name = dev_name(&ofdev->dev);
+ ofdev->id = -1;
+
+ /* device_add will assume that this device is on the same node as
+ * the parent. If there is no parent defined, set the node
+ * explicitly */
+ if (!ofdev->dev.parent)
+ set_dev_node(&ofdev->dev, of_node_to_nid(ofdev->dev.of_node));
+
+ return device_add(&ofdev->dev);
}
-static DEVICE_ATTR(devspec, S_IRUGO, dev_show_devspec, NULL);
+int of_device_register(struct platform_device *pdev)
+{
+ device_initialize(&pdev->dev);
+ return of_device_add(pdev);
+}
+EXPORT_SYMBOL(of_device_register);
-/**
- * of_release_dev - free an of device structure when all users of it are finished.
- * @dev: device that's been disconnected
- *
- * Will be called only by the device core when all users of this of device are
- * done.
- */
-void of_release_dev(struct device *dev)
+void of_device_unregister(struct platform_device *ofdev)
{
- struct of_device *ofdev;
+ device_unregister(&ofdev->dev);
+}
+EXPORT_SYMBOL(of_device_unregister);
- ofdev = to_of_device(dev);
- of_node_put(ofdev->node);
- kfree(ofdev);
+ssize_t of_device_get_modalias(struct device *dev, char *str, ssize_t len)
+{
+ const char *compat;
+ int cplen, i;
+ ssize_t tsize, csize, repend;
+
+ if ((!dev) || (!dev->of_node))
+ return -ENODEV;
+
+ /* Name & Type */
+ csize = snprintf(str, len, "of:N%sT%s", dev->of_node->name,
+ dev->of_node->type);
+
+ /* Get compatible property if any */
+ compat = of_get_property(dev->of_node, "compatible", &cplen);
+ if (!compat)
+ return csize;
+
+ /* Find true end (we tolerate multiple \0 at the end */
+ for (i = (cplen - 1); i >= 0 && !compat[i]; i--)
+ cplen--;
+ if (!cplen)
+ return csize;
+ cplen++;
+
+ /* Check space (need cplen+1 chars including final \0) */
+ tsize = csize + cplen;
+ repend = tsize;
+
+ if (csize >= len) /* @ the limit, all is already filled */
+ return tsize;
+
+ if (tsize >= len) { /* limit compat list */
+ cplen = len - csize - 1;
+ repend = len;
+ }
+
+ /* Copy and do char replacement */
+ memcpy(&str[csize + 1], compat, cplen);
+ for (i = csize; i < repend; i++) {
+ char c = str[i];
+ if (c == '\0')
+ str[i] = 'C';
+ else if (c == ' ')
+ str[i] = '_';
+ }
+
+ return tsize;
}
-EXPORT_SYMBOL(of_release_dev);
-int of_device_register(struct of_device *ofdev)
+/**
+ * of_device_uevent - Display OF related uevent information
+ */
+void of_device_uevent(struct device *dev, struct kobj_uevent_env *env)
{
- int rc;
+ const char *compat;
+ struct alias_prop *app;
+ int seen = 0, cplen, sl;
+
+ if ((!dev) || (!dev->of_node))
+ return;
+
+ add_uevent_var(env, "OF_NAME=%s", dev->of_node->name);
+ add_uevent_var(env, "OF_FULLNAME=%s", dev->of_node->full_name);
+ if (dev->of_node->type && strcmp("<NULL>", dev->of_node->type) != 0)
+ add_uevent_var(env, "OF_TYPE=%s", dev->of_node->type);
+
+ /* Since the compatible field can contain pretty much anything
+ * it's not really legal to split it out with commas. We split it
+ * up using a number of environment variables instead. */
+ compat = of_get_property(dev->of_node, "compatible", &cplen);
+ while (compat && *compat && cplen > 0) {
+ add_uevent_var(env, "OF_COMPATIBLE_%d=%s", seen, compat);
+ sl = strlen(compat) + 1;
+ compat += sl;
+ cplen -= sl;
+ seen++;
+ }
+ add_uevent_var(env, "OF_COMPATIBLE_N=%d", seen);
+
+ seen = 0;
+ mutex_lock(&of_aliases_mutex);
+ list_for_each_entry(app, &aliases_lookup, link) {
+ if (dev->of_node == app->np) {
+ add_uevent_var(env, "OF_ALIAS_%d=%s", seen,
+ app->alias);
+ seen++;
+ }
+ }
+ mutex_unlock(&of_aliases_mutex);
+}
- BUG_ON(ofdev->node == NULL);
+int of_device_uevent_modalias(struct device *dev, struct kobj_uevent_env *env)
+{
+ int sl;
- rc = device_register(&ofdev->dev);
- if (rc)
- return rc;
+ if ((!dev) || (!dev->of_node))
+ return -ENODEV;
- rc = device_create_file(&ofdev->dev, &dev_attr_devspec);
- if (rc)
- device_unregister(&ofdev->dev);
+ /* Devicetree modalias is tricky, we add it in 2 steps */
+ if (add_uevent_var(env, "MODALIAS="))
+ return -ENOMEM;
- return rc;
-}
-EXPORT_SYMBOL(of_device_register);
+ sl = of_device_get_modalias(dev, &env->buf[env->buflen-1],
+ sizeof(env->buf) - env->buflen);
+ if (sl >= (sizeof(env->buf) - env->buflen))
+ return -ENOMEM;
+ env->buflen += sl;
-void of_device_unregister(struct of_device *ofdev)
-{
- device_remove_file(&ofdev->dev, &dev_attr_devspec);
- device_unregister(&ofdev->dev);
+ return 0;
}
-EXPORT_SYMBOL(of_device_unregister);