aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/kernel/of_device.c
diff options
context:
space:
mode:
authorSylvain Munaut <tnt@246tNt.com>2007-02-12 17:13:25 -0500
committerPaul Mackerras <paulus@samba.org>2007-04-12 13:55:13 -0400
commiteb0cb8a07e320ed3237789cc4f29858338d14d8e (patch)
tree455386938b4262543ec1861c340daf6f507d22cf /arch/powerpc/kernel/of_device.c
parente049d1ca3094f3d1d94617f456a9961202f96e3a (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.c112
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
123static 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
171int 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
123EXPORT_SYMBOL(of_match_node); 234EXPORT_SYMBOL(of_match_node);
124EXPORT_SYMBOL(of_match_device); 235EXPORT_SYMBOL(of_match_device);
125EXPORT_SYMBOL(of_device_register); 236EXPORT_SYMBOL(of_device_register);
@@ -127,3 +238,4 @@ EXPORT_SYMBOL(of_device_unregister);
127EXPORT_SYMBOL(of_dev_get); 238EXPORT_SYMBOL(of_dev_get);
128EXPORT_SYMBOL(of_dev_put); 239EXPORT_SYMBOL(of_dev_put);
129EXPORT_SYMBOL(of_release_dev); 240EXPORT_SYMBOL(of_release_dev);
241EXPORT_SYMBOL(of_device_uevent);