diff options
Diffstat (limited to 'drivers/of/device.c')
| -rw-r--r-- | drivers/of/device.c | 165 |
1 files changed, 92 insertions, 73 deletions
diff --git a/drivers/of/device.c b/drivers/of/device.c index 224ae6bc67b..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,108 +35,65 @@ 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 devspec_show(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\n", ofdev->node->full_name); -} - -static ssize_t name_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct of_device *ofdev; - - ofdev = to_of_device(dev); - return sprintf(buf, "%s\n", ofdev->node->name); -} - -static ssize_t modalias_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct of_device *ofdev = to_of_device(dev); - ssize_t len = 0; - - len = of_device_get_modalias(ofdev, buf, PAGE_SIZE - 2); - buf[len] = '\n'; - buf[len+1] = 0; - return len+1; -} - -struct device_attribute of_platform_device_attrs[] = { - __ATTR_RO(devspec), - __ATTR_RO(name), - __ATTR_RO(modalias), - __ATTR_NULL -}; - -/** - * 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) -{ - struct of_device *ofdev; - - ofdev = to_of_device(dev); - of_node_put(ofdev->node); - kfree(ofdev); -} -EXPORT_SYMBOL(of_release_dev); - -int of_device_register(struct of_device *ofdev) -{ - BUG_ON(ofdev->node == NULL); - - device_initialize(&ofdev->dev); + /* 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->node)); + set_dev_node(&ofdev->dev, of_node_to_nid(ofdev->dev.of_node)); return device_add(&ofdev->dev); } + +int of_device_register(struct platform_device *pdev) +{ + device_initialize(&pdev->dev); + return of_device_add(pdev); +} EXPORT_SYMBOL(of_device_register); -void of_device_unregister(struct of_device *ofdev) +void of_device_unregister(struct platform_device *ofdev) { device_unregister(&ofdev->dev); } EXPORT_SYMBOL(of_device_unregister); -ssize_t of_device_get_modalias(struct of_device *ofdev, - char *str, ssize_t len) +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", - ofdev->node->name, ofdev->node->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(ofdev->node, "compatible", &cplen); + compat = of_get_property(dev->of_node, "compatible", &cplen); if (!compat) return csize; @@ -171,3 +128,65 @@ ssize_t of_device_get_modalias(struct of_device *ofdev, return tsize; } + +/** + * of_device_uevent - Display OF related uevent information + */ +void of_device_uevent(struct device *dev, struct kobj_uevent_env *env) +{ + 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); +} + +int of_device_uevent_modalias(struct device *dev, struct kobj_uevent_env *env) +{ + int sl; + + if ((!dev) || (!dev->of_node)) + return -ENODEV; + + /* Devicetree modalias is tricky, we add it in 2 steps */ + if (add_uevent_var(env, "MODALIAS=")) + return -ENOMEM; + + 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; + + return 0; +} |
