aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/acpi/scan.c249
1 files changed, 155 insertions, 94 deletions
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
index 8f3adf924e83..d2e3c3e3f9c9 100644
--- a/drivers/acpi/scan.c
+++ b/drivers/acpi/scan.c
@@ -114,7 +114,12 @@ int acpi_scan_add_handler_with_hotplug(struct acpi_scan_handler *handler,
114 return 0; 114 return 0;
115} 115}
116 116
117/* 117/**
118 * create_pnp_modalias - Create hid/cid(s) string for modalias and uevent
119 * @acpi_dev: ACPI device object.
120 * @modalias: Buffer to print into.
121 * @size: Size of the buffer.
122 *
118 * Creates hid/cid(s) string needed for modalias and uevent 123 * Creates hid/cid(s) string needed for modalias and uevent
119 * e.g. on a device with hid:IBM0001 and cid:ACPI0001 you get: 124 * e.g. on a device with hid:IBM0001 and cid:ACPI0001 you get:
120 * char *modalias: "acpi:IBM0001:ACPI0001" 125 * char *modalias: "acpi:IBM0001:ACPI0001"
@@ -122,68 +127,98 @@ int acpi_scan_add_handler_with_hotplug(struct acpi_scan_handler *handler,
122 * -EINVAL: output error 127 * -EINVAL: output error
123 * -ENOMEM: output is truncated 128 * -ENOMEM: output is truncated
124*/ 129*/
125static int create_modalias(struct acpi_device *acpi_dev, char *modalias, 130static int create_pnp_modalias(struct acpi_device *acpi_dev, char *modalias,
126 int size) 131 int size)
127{ 132{
128 int len; 133 int len;
129 int count; 134 int count;
130 struct acpi_hardware_id *id; 135 struct acpi_hardware_id *id;
131 136
132 if (list_empty(&acpi_dev->pnp.ids))
133 return 0;
134
135 /* 137 /*
136 * If the device has PRP0001 we expose DT compatible modalias 138 * Since we skip PRP0001 from the modalias below, 0 should be returned
137 * instead in form of of:NnameTCcompatible. 139 * if PRP0001 is the only ACPI/PNP ID in the device's list.
138 */ 140 */
139 if (acpi_dev->data.of_compatible) { 141 count = 0;
140 struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER }; 142 list_for_each_entry(id, &acpi_dev->pnp.ids, list)
141 const union acpi_object *of_compatible, *obj; 143 if (strcmp(id->id, "PRP0001"))
142 int i, nval; 144 count++;
143 char *c;
144
145 acpi_get_name(acpi_dev->handle, ACPI_SINGLE_NAME, &buf);
146 /* DT strings are all in lower case */
147 for (c = buf.pointer; *c != '\0'; c++)
148 *c = tolower(*c);
149
150 len = snprintf(modalias, size, "of:N%sT", (char *)buf.pointer);
151 ACPI_FREE(buf.pointer);
152
153 of_compatible = acpi_dev->data.of_compatible;
154 if (of_compatible->type == ACPI_TYPE_PACKAGE) {
155 nval = of_compatible->package.count;
156 obj = of_compatible->package.elements;
157 } else { /* Must be ACPI_TYPE_STRING. */
158 nval = 1;
159 obj = of_compatible;
160 }
161 for (i = 0; i < nval; i++, obj++) {
162 count = snprintf(&modalias[len], size, "C%s",
163 obj->string.pointer);
164 if (count < 0)
165 return -EINVAL;
166 if (count >= size)
167 return -ENOMEM;
168
169 len += count;
170 size -= count;
171 }
172 } else {
173 len = snprintf(modalias, size, "acpi:");
174 size -= len;
175 145
176 list_for_each_entry(id, &acpi_dev->pnp.ids, list) { 146 if (!count)
177 count = snprintf(&modalias[len], size, "%s:", id->id); 147 return 0;
178 if (count < 0) 148
179 return -EINVAL; 149 len = snprintf(modalias, size, "acpi:");
180 if (count >= size) 150 if (len <= 0)
181 return -ENOMEM; 151 return len;
182 len += count; 152
183 size -= count; 153 size -= len;
184 } 154
155 list_for_each_entry(id, &acpi_dev->pnp.ids, list) {
156 if (!strcmp(id->id, "PRP0001"))
157 continue;
158
159 count = snprintf(&modalias[len], size, "%s:", id->id);
160 if (count < 0)
161 return -EINVAL;
162
163 if (count >= size)
164 return -ENOMEM;
165
166 len += count;
167 size -= count;
185 } 168 }
169 modalias[len] = '\0';
170 return len;
171}
172
173/**
174 * create_of_modalias - Creates DT compatible string for modalias and uevent
175 * @acpi_dev: ACPI device object.
176 * @modalias: Buffer to print into.
177 * @size: Size of the buffer.
178 *
179 * Expose DT compatible modalias as of:NnameTCcompatible. This function should
180 * only be called for devices having PRP0001 in their list of ACPI/PNP IDs.
181 */
182static int create_of_modalias(struct acpi_device *acpi_dev, char *modalias,
183 int size)
184{
185 struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER };
186 const union acpi_object *of_compatible, *obj;
187 int len, count;
188 int i, nval;
189 char *c;
186 190
191 acpi_get_name(acpi_dev->handle, ACPI_SINGLE_NAME, &buf);
192 /* DT strings are all in lower case */
193 for (c = buf.pointer; *c != '\0'; c++)
194 *c = tolower(*c);
195
196 len = snprintf(modalias, size, "of:N%sT", (char *)buf.pointer);
197 ACPI_FREE(buf.pointer);
198
199 if (len <= 0)
200 return len;
201
202 of_compatible = acpi_dev->data.of_compatible;
203 if (of_compatible->type == ACPI_TYPE_PACKAGE) {
204 nval = of_compatible->package.count;
205 obj = of_compatible->package.elements;
206 } else { /* Must be ACPI_TYPE_STRING. */
207 nval = 1;
208 obj = of_compatible;
209 }
210 for (i = 0; i < nval; i++, obj++) {
211 count = snprintf(&modalias[len], size, "C%s",
212 obj->string.pointer);
213 if (count < 0)
214 return -EINVAL;
215
216 if (count >= size)
217 return -ENOMEM;
218
219 len += count;
220 size -= count;
221 }
187 modalias[len] = '\0'; 222 modalias[len] = '\0';
188 return len; 223 return len;
189} 224}
@@ -236,61 +271,100 @@ static struct acpi_device *acpi_companion_match(const struct device *dev)
236 return adev; 271 return adev;
237} 272}
238 273
239/* 274static int __acpi_device_uevent_modalias(struct acpi_device *adev,
240 * Creates uevent modalias field for ACPI enumerated devices. 275 struct kobj_uevent_env *env)
241 * Because the other buses does not support ACPI HIDs & CIDs.
242 * e.g. for a device with hid:IBM0001 and cid:ACPI0001 you get:
243 * "acpi:IBM0001:ACPI0001"
244 */
245int acpi_device_uevent_modalias(struct device *dev, struct kobj_uevent_env *env)
246{ 276{
247 int len; 277 int len;
248 278
249 if (!acpi_companion_match(dev)) 279 if (!adev)
250 return -ENODEV; 280 return -ENODEV;
251 281
282 if (list_empty(&adev->pnp.ids))
283 return 0;
284
252 if (add_uevent_var(env, "MODALIAS=")) 285 if (add_uevent_var(env, "MODALIAS="))
253 return -ENOMEM; 286 return -ENOMEM;
254 len = create_modalias(ACPI_COMPANION(dev), &env->buf[env->buflen - 1], 287
255 sizeof(env->buf) - env->buflen); 288 len = create_pnp_modalias(adev, &env->buf[env->buflen - 1],
256 if (len <= 0) 289 sizeof(env->buf) - env->buflen);
290 if (len < 0)
257 return len; 291 return len;
292
293 env->buflen += len;
294 if (!adev->data.of_compatible)
295 return 0;
296
297 if (len > 0 && add_uevent_var(env, "MODALIAS="))
298 return -ENOMEM;
299
300 len = create_of_modalias(adev, &env->buf[env->buflen - 1],
301 sizeof(env->buf) - env->buflen);
302 if (len < 0)
303 return len;
304
258 env->buflen += len; 305 env->buflen += len;
306
259 return 0; 307 return 0;
260} 308}
261EXPORT_SYMBOL_GPL(acpi_device_uevent_modalias);
262 309
263/* 310/*
264 * Creates modalias sysfs attribute for ACPI enumerated devices. 311 * Creates uevent modalias field for ACPI enumerated devices.
265 * Because the other buses does not support ACPI HIDs & CIDs. 312 * Because the other buses does not support ACPI HIDs & CIDs.
266 * e.g. for a device with hid:IBM0001 and cid:ACPI0001 you get: 313 * e.g. for a device with hid:IBM0001 and cid:ACPI0001 you get:
267 * "acpi:IBM0001:ACPI0001" 314 * "acpi:IBM0001:ACPI0001"
268 */ 315 */
269int acpi_device_modalias(struct device *dev, char *buf, int size) 316int acpi_device_uevent_modalias(struct device *dev, struct kobj_uevent_env *env)
270{ 317{
271 int len; 318 return __acpi_device_uevent_modalias(acpi_companion_match(dev), env);
319}
320EXPORT_SYMBOL_GPL(acpi_device_uevent_modalias);
321
322static int __acpi_device_modalias(struct acpi_device *adev, char *buf, int size)
323{
324 int len, count;
272 325
273 if (!acpi_companion_match(dev)) 326 if (!adev)
274 return -ENODEV; 327 return -ENODEV;
275 328
276 len = create_modalias(ACPI_COMPANION(dev), buf, size -1); 329 if (list_empty(&adev->pnp.ids))
277 if (len <= 0) 330 return 0;
331
332 len = create_pnp_modalias(adev, buf, size - 1);
333 if (len < 0) {
278 return len; 334 return len;
279 buf[len++] = '\n'; 335 } else if (len > 0) {
336 buf[len++] = '\n';
337 size -= len;
338 }
339 if (!adev->data.of_compatible)
340 return len;
341
342 count = create_of_modalias(adev, buf + len, size - 1);
343 if (count < 0) {
344 return count;
345 } else if (count > 0) {
346 len += count;
347 buf[len++] = '\n';
348 }
349
280 return len; 350 return len;
281} 351}
352
353/*
354 * Creates modalias sysfs attribute for ACPI enumerated devices.
355 * Because the other buses does not support ACPI HIDs & CIDs.
356 * e.g. for a device with hid:IBM0001 and cid:ACPI0001 you get:
357 * "acpi:IBM0001:ACPI0001"
358 */
359int acpi_device_modalias(struct device *dev, char *buf, int size)
360{
361 return __acpi_device_modalias(acpi_companion_match(dev), buf, size);
362}
282EXPORT_SYMBOL_GPL(acpi_device_modalias); 363EXPORT_SYMBOL_GPL(acpi_device_modalias);
283 364
284static ssize_t 365static ssize_t
285acpi_device_modalias_show(struct device *dev, struct device_attribute *attr, char *buf) { 366acpi_device_modalias_show(struct device *dev, struct device_attribute *attr, char *buf) {
286 struct acpi_device *acpi_dev = to_acpi_device(dev); 367 return __acpi_device_modalias(to_acpi_device(dev), buf, 1024);
287 int len;
288
289 len = create_modalias(acpi_dev, buf, 1024);
290 if (len <= 0)
291 return len;
292 buf[len++] = '\n';
293 return len;
294} 368}
295static DEVICE_ATTR(modalias, 0444, acpi_device_modalias_show, NULL); 369static DEVICE_ATTR(modalias, 0444, acpi_device_modalias_show, NULL);
296 370
@@ -1046,20 +1120,7 @@ static int acpi_bus_match(struct device *dev, struct device_driver *drv)
1046 1120
1047static int acpi_device_uevent(struct device *dev, struct kobj_uevent_env *env) 1121static int acpi_device_uevent(struct device *dev, struct kobj_uevent_env *env)
1048{ 1122{
1049 struct acpi_device *acpi_dev = to_acpi_device(dev); 1123 return __acpi_device_uevent_modalias(to_acpi_device(dev), env);
1050 int len;
1051
1052 if (list_empty(&acpi_dev->pnp.ids))
1053 return 0;
1054
1055 if (add_uevent_var(env, "MODALIAS="))
1056 return -ENOMEM;
1057 len = create_modalias(acpi_dev, &env->buf[env->buflen - 1],
1058 sizeof(env->buf) - env->buflen);
1059 if (len <= 0)
1060 return len;
1061 env->buflen += len;
1062 return 0;
1063} 1124}
1064 1125
1065static void acpi_device_notify(acpi_handle handle, u32 event, void *data) 1126static void acpi_device_notify(acpi_handle handle, u32 event, void *data)