diff options
Diffstat (limited to 'drivers/of/device.c')
-rw-r--r-- | drivers/of/device.c | 84 |
1 files changed, 68 insertions, 16 deletions
diff --git a/drivers/of/device.c b/drivers/of/device.c index 29681c4b700b..8a1d93a2bb81 100644 --- a/drivers/of/device.c +++ b/drivers/of/device.c | |||
@@ -48,16 +48,32 @@ void of_dev_put(struct of_device *dev) | |||
48 | } | 48 | } |
49 | EXPORT_SYMBOL(of_dev_put); | 49 | EXPORT_SYMBOL(of_dev_put); |
50 | 50 | ||
51 | static ssize_t dev_show_devspec(struct device *dev, | 51 | static ssize_t devspec_show(struct device *dev, |
52 | struct device_attribute *attr, char *buf) | 52 | struct device_attribute *attr, char *buf) |
53 | { | 53 | { |
54 | struct of_device *ofdev; | 54 | struct of_device *ofdev; |
55 | 55 | ||
56 | ofdev = to_of_device(dev); | 56 | ofdev = to_of_device(dev); |
57 | return sprintf(buf, "%s", ofdev->node->full_name); | 57 | return sprintf(buf, "%s\n", ofdev->node->full_name); |
58 | } | 58 | } |
59 | 59 | ||
60 | static DEVICE_ATTR(devspec, S_IRUGO, dev_show_devspec, NULL); | 60 | static ssize_t modalias_show(struct device *dev, |
61 | struct device_attribute *attr, char *buf) | ||
62 | { | ||
63 | struct of_device *ofdev = to_of_device(dev); | ||
64 | ssize_t len = 0; | ||
65 | |||
66 | len = of_device_get_modalias(ofdev, buf, PAGE_SIZE - 2); | ||
67 | buf[len] = '\n'; | ||
68 | buf[len+1] = 0; | ||
69 | return len+1; | ||
70 | } | ||
71 | |||
72 | struct device_attribute of_platform_device_attrs[] = { | ||
73 | __ATTR_RO(devspec), | ||
74 | __ATTR_RO(modalias), | ||
75 | __ATTR_NULL | ||
76 | }; | ||
61 | 77 | ||
62 | /** | 78 | /** |
63 | * of_release_dev - free an of device structure when all users of it are finished. | 79 | * of_release_dev - free an of device structure when all users of it are finished. |
@@ -78,25 +94,61 @@ EXPORT_SYMBOL(of_release_dev); | |||
78 | 94 | ||
79 | int of_device_register(struct of_device *ofdev) | 95 | int of_device_register(struct of_device *ofdev) |
80 | { | 96 | { |
81 | int rc; | ||
82 | |||
83 | BUG_ON(ofdev->node == NULL); | 97 | BUG_ON(ofdev->node == NULL); |
84 | 98 | return device_register(&ofdev->dev); | |
85 | rc = device_register(&ofdev->dev); | ||
86 | if (rc) | ||
87 | return rc; | ||
88 | |||
89 | rc = device_create_file(&ofdev->dev, &dev_attr_devspec); | ||
90 | if (rc) | ||
91 | device_unregister(&ofdev->dev); | ||
92 | |||
93 | return rc; | ||
94 | } | 99 | } |
95 | EXPORT_SYMBOL(of_device_register); | 100 | EXPORT_SYMBOL(of_device_register); |
96 | 101 | ||
97 | void of_device_unregister(struct of_device *ofdev) | 102 | void of_device_unregister(struct of_device *ofdev) |
98 | { | 103 | { |
99 | device_remove_file(&ofdev->dev, &dev_attr_devspec); | ||
100 | device_unregister(&ofdev->dev); | 104 | device_unregister(&ofdev->dev); |
101 | } | 105 | } |
102 | EXPORT_SYMBOL(of_device_unregister); | 106 | EXPORT_SYMBOL(of_device_unregister); |
107 | |||
108 | ssize_t of_device_get_modalias(struct of_device *ofdev, | ||
109 | char *str, ssize_t len) | ||
110 | { | ||
111 | const char *compat; | ||
112 | int cplen, i; | ||
113 | ssize_t tsize, csize, repend; | ||
114 | |||
115 | /* Name & Type */ | ||
116 | csize = snprintf(str, len, "of:N%sT%s", | ||
117 | ofdev->node->name, ofdev->node->type); | ||
118 | |||
119 | /* Get compatible property if any */ | ||
120 | compat = of_get_property(ofdev->node, "compatible", &cplen); | ||
121 | if (!compat) | ||
122 | return csize; | ||
123 | |||
124 | /* Find true end (we tolerate multiple \0 at the end */ | ||
125 | for (i = (cplen - 1); i >= 0 && !compat[i]; i--) | ||
126 | cplen--; | ||
127 | if (!cplen) | ||
128 | return csize; | ||
129 | cplen++; | ||
130 | |||
131 | /* Check space (need cplen+1 chars including final \0) */ | ||
132 | tsize = csize + cplen; | ||
133 | repend = tsize; | ||
134 | |||
135 | if (csize >= len) /* @ the limit, all is already filled */ | ||
136 | return tsize; | ||
137 | |||
138 | if (tsize >= len) { /* limit compat list */ | ||
139 | cplen = len - csize - 1; | ||
140 | repend = len; | ||
141 | } | ||
142 | |||
143 | /* Copy and do char replacement */ | ||
144 | memcpy(&str[csize + 1], compat, cplen); | ||
145 | for (i = csize; i < repend; i++) { | ||
146 | char c = str[i]; | ||
147 | if (c == '\0') | ||
148 | str[i] = 'C'; | ||
149 | else if (c == ' ') | ||
150 | str[i] = '_'; | ||
151 | } | ||
152 | |||
153 | return tsize; | ||
154 | } | ||