diff options
author | Sylvain Munaut <tnt@246tNt.com> | 2007-02-12 17:13:25 -0500 |
---|---|---|
committer | Paul Mackerras <paulus@samba.org> | 2007-04-12 13:55:13 -0400 |
commit | eb0cb8a07e320ed3237789cc4f29858338d14d8e (patch) | |
tree | 455386938b4262543ec1861c340daf6f507d22cf /arch/powerpc/kernel/of_device.c | |
parent | e049d1ca3094f3d1d94617f456a9961202f96e3a (diff) |
[POWERPC] Add a unified uevent handler for bus based on of_device
This common uevent handler allow the several bus types based on
of_device to generate the uevent properly and avoiding
code duplication.
This handlers take a struct device as argument and can therefore
be used as the uevent call directly if no special treatment is
needed for the bus.
Signed-off-by: Sylvain Munaut <tnt@246tNt.com>
Signed-off-by: Paul Mackerras <paulus@samba.org>
Diffstat (limited to 'arch/powerpc/kernel/of_device.c')
-rw-r--r-- | arch/powerpc/kernel/of_device.c | 112 |
1 files changed, 112 insertions, 0 deletions
diff --git a/arch/powerpc/kernel/of_device.c b/arch/powerpc/kernel/of_device.c index e921514e655b..e8aa1f3675b7 100644 --- a/arch/powerpc/kernel/of_device.c +++ b/arch/powerpc/kernel/of_device.c | |||
@@ -120,6 +120,117 @@ void of_device_unregister(struct of_device *ofdev) | |||
120 | } | 120 | } |
121 | 121 | ||
122 | 122 | ||
123 | static ssize_t of_device_get_modalias(struct of_device *ofdev, | ||
124 | char *str, ssize_t len) | ||
125 | { | ||
126 | const char *compat; | ||
127 | int cplen, i; | ||
128 | ssize_t tsize, csize, repend; | ||
129 | |||
130 | /* Name & Type */ | ||
131 | csize = snprintf(str, len, "of:N%sT%s", | ||
132 | ofdev->node->name, ofdev->node->type); | ||
133 | |||
134 | /* Get compatible property if any */ | ||
135 | compat = get_property(ofdev->node, "compatible", &cplen); | ||
136 | if (!compat) | ||
137 | return csize; | ||
138 | |||
139 | /* Find true end (we tolerate multiple \0 at the end */ | ||
140 | for (i=(cplen-1); i>=0 && !compat[i]; i--) | ||
141 | cplen--; | ||
142 | if (!cplen) | ||
143 | return csize; | ||
144 | cplen++; | ||
145 | |||
146 | /* Check space (need cplen+1 chars including final \0) */ | ||
147 | tsize = csize + cplen; | ||
148 | repend = tsize; | ||
149 | |||
150 | if (csize>=len) /* @ the limit, all is already filled */ | ||
151 | return tsize; | ||
152 | |||
153 | if (tsize>=len) { /* limit compat list */ | ||
154 | cplen = len-csize-1; | ||
155 | repend = len; | ||
156 | } | ||
157 | |||
158 | /* Copy and do char replacement */ | ||
159 | memcpy(&str[csize+1], compat, cplen); | ||
160 | for (i=csize; i<repend; i++) { | ||
161 | char c = str[i]; | ||
162 | if (c=='\0') | ||
163 | str[i] = 'C'; | ||
164 | else if (c==' ') | ||
165 | str[i] = '_'; | ||
166 | } | ||
167 | |||
168 | return tsize; | ||
169 | } | ||
170 | |||
171 | int of_device_uevent(struct device *dev, | ||
172 | char **envp, int num_envp, char *buffer, int buffer_size) | ||
173 | { | ||
174 | struct of_device *ofdev; | ||
175 | const char *compat; | ||
176 | int i = 0, length = 0, seen = 0, cplen, sl; | ||
177 | |||
178 | if (!dev) | ||
179 | return -ENODEV; | ||
180 | |||
181 | ofdev = to_of_device(dev); | ||
182 | |||
183 | if (add_uevent_var(envp, num_envp, &i, | ||
184 | buffer, buffer_size, &length, | ||
185 | "OF_NAME=%s", ofdev->node->name)) | ||
186 | return -ENOMEM; | ||
187 | |||
188 | if (add_uevent_var(envp, num_envp, &i, | ||
189 | buffer, buffer_size, &length, | ||
190 | "OF_TYPE=%s", ofdev->node->type)) | ||
191 | return -ENOMEM; | ||
192 | |||
193 | /* Since the compatible field can contain pretty much anything | ||
194 | * it's not really legal to split it out with commas. We split it | ||
195 | * up using a number of environment variables instead. */ | ||
196 | |||
197 | compat = get_property(ofdev->node, "compatible", &cplen); | ||
198 | while (compat && *compat && cplen > 0) { | ||
199 | if (add_uevent_var(envp, num_envp, &i, | ||
200 | buffer, buffer_size, &length, | ||
201 | "OF_COMPATIBLE_%d=%s", seen, compat)) | ||
202 | return -ENOMEM; | ||
203 | |||
204 | sl = strlen (compat) + 1; | ||
205 | compat += sl; | ||
206 | cplen -= sl; | ||
207 | seen++; | ||
208 | } | ||
209 | |||
210 | if (add_uevent_var(envp, num_envp, &i, | ||
211 | buffer, buffer_size, &length, | ||
212 | "OF_COMPATIBLE_N=%d", seen)) | ||
213 | return -ENOMEM; | ||
214 | |||
215 | /* modalias is trickier, we add it in 2 steps */ | ||
216 | if (add_uevent_var(envp, num_envp, &i, | ||
217 | buffer, buffer_size, &length, | ||
218 | "MODALIAS=")) | ||
219 | return -ENOMEM; | ||
220 | |||
221 | sl = of_device_get_modalias(ofdev, &buffer[length-1], | ||
222 | buffer_size-length); | ||
223 | if (sl >= (buffer_size-length)) | ||
224 | return -ENOMEM; | ||
225 | |||
226 | length += sl; | ||
227 | |||
228 | envp[i] = NULL; | ||
229 | |||
230 | return 0; | ||
231 | } | ||
232 | |||
233 | |||
123 | EXPORT_SYMBOL(of_match_node); | 234 | EXPORT_SYMBOL(of_match_node); |
124 | EXPORT_SYMBOL(of_match_device); | 235 | EXPORT_SYMBOL(of_match_device); |
125 | EXPORT_SYMBOL(of_device_register); | 236 | EXPORT_SYMBOL(of_device_register); |
@@ -127,3 +238,4 @@ EXPORT_SYMBOL(of_device_unregister); | |||
127 | EXPORT_SYMBOL(of_dev_get); | 238 | EXPORT_SYMBOL(of_dev_get); |
128 | EXPORT_SYMBOL(of_dev_put); | 239 | EXPORT_SYMBOL(of_dev_put); |
129 | EXPORT_SYMBOL(of_release_dev); | 240 | EXPORT_SYMBOL(of_release_dev); |
241 | EXPORT_SYMBOL(of_device_uevent); | ||