xref: /openbmc/linux/drivers/acpi/device_sysfs.c (revision ca55b2fe)
1 /*
2  * drivers/acpi/device_sysfs.c - ACPI device sysfs attributes and modalias.
3  *
4  * Copyright (C) 2015, Intel Corp.
5  * Author: Mika Westerberg <mika.westerberg@linux.intel.com>
6  * Author: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
7  *
8  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
9  *
10  *  This program is free software; you can redistribute it and/or modify
11  *  it under the terms of the GNU General Public License version 2 as published
12  *  by the Free Software Foundation.
13  *
14  *  This program is distributed in the hope that it will be useful, but
15  *  WITHOUT ANY WARRANTY; without even the implied warranty of
16  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  *  General Public License for more details.
18  *
19  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
20  */
21 
22 #include <linux/acpi.h>
23 #include <linux/device.h>
24 #include <linux/export.h>
25 #include <linux/nls.h>
26 
27 #include "internal.h"
28 
29 /**
30  * create_pnp_modalias - Create hid/cid(s) string for modalias and uevent
31  * @acpi_dev: ACPI device object.
32  * @modalias: Buffer to print into.
33  * @size: Size of the buffer.
34  *
35  * Creates hid/cid(s) string needed for modalias and uevent
36  * e.g. on a device with hid:IBM0001 and cid:ACPI0001 you get:
37  * char *modalias: "acpi:IBM0001:ACPI0001"
38  * Return: 0: no _HID and no _CID
39  *         -EINVAL: output error
40  *         -ENOMEM: output is truncated
41 */
42 static int create_pnp_modalias(struct acpi_device *acpi_dev, char *modalias,
43 			       int size)
44 {
45 	int len;
46 	int count;
47 	struct acpi_hardware_id *id;
48 
49 	/*
50 	 * Since we skip ACPI_DT_NAMESPACE_HID from the modalias below, 0 should
51 	 * be returned if ACPI_DT_NAMESPACE_HID is the only ACPI/PNP ID in the
52 	 * device's list.
53 	 */
54 	count = 0;
55 	list_for_each_entry(id, &acpi_dev->pnp.ids, list)
56 		if (strcmp(id->id, ACPI_DT_NAMESPACE_HID))
57 			count++;
58 
59 	if (!count)
60 		return 0;
61 
62 	len = snprintf(modalias, size, "acpi:");
63 	if (len <= 0)
64 		return len;
65 
66 	size -= len;
67 
68 	list_for_each_entry(id, &acpi_dev->pnp.ids, list) {
69 		if (!strcmp(id->id, ACPI_DT_NAMESPACE_HID))
70 			continue;
71 
72 		count = snprintf(&modalias[len], size, "%s:", id->id);
73 		if (count < 0)
74 			return -EINVAL;
75 
76 		if (count >= size)
77 			return -ENOMEM;
78 
79 		len += count;
80 		size -= count;
81 	}
82 	modalias[len] = '\0';
83 	return len;
84 }
85 
86 /**
87  * create_of_modalias - Creates DT compatible string for modalias and uevent
88  * @acpi_dev: ACPI device object.
89  * @modalias: Buffer to print into.
90  * @size: Size of the buffer.
91  *
92  * Expose DT compatible modalias as of:NnameTCcompatible.  This function should
93  * only be called for devices having ACPI_DT_NAMESPACE_HID in their list of
94  * ACPI/PNP IDs.
95  */
96 static int create_of_modalias(struct acpi_device *acpi_dev, char *modalias,
97 			      int size)
98 {
99 	struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER };
100 	const union acpi_object *of_compatible, *obj;
101 	int len, count;
102 	int i, nval;
103 	char *c;
104 
105 	acpi_get_name(acpi_dev->handle, ACPI_SINGLE_NAME, &buf);
106 	/* DT strings are all in lower case */
107 	for (c = buf.pointer; *c != '\0'; c++)
108 		*c = tolower(*c);
109 
110 	len = snprintf(modalias, size, "of:N%sT", (char *)buf.pointer);
111 	ACPI_FREE(buf.pointer);
112 
113 	if (len <= 0)
114 		return len;
115 
116 	of_compatible = acpi_dev->data.of_compatible;
117 	if (of_compatible->type == ACPI_TYPE_PACKAGE) {
118 		nval = of_compatible->package.count;
119 		obj = of_compatible->package.elements;
120 	} else { /* Must be ACPI_TYPE_STRING. */
121 		nval = 1;
122 		obj = of_compatible;
123 	}
124 	for (i = 0; i < nval; i++, obj++) {
125 		count = snprintf(&modalias[len], size, "C%s",
126 				 obj->string.pointer);
127 		if (count < 0)
128 			return -EINVAL;
129 
130 		if (count >= size)
131 			return -ENOMEM;
132 
133 		len += count;
134 		size -= count;
135 	}
136 	modalias[len] = '\0';
137 	return len;
138 }
139 
140 int __acpi_device_uevent_modalias(struct acpi_device *adev,
141 				  struct kobj_uevent_env *env)
142 {
143 	int len;
144 
145 	if (!adev)
146 		return -ENODEV;
147 
148 	if (list_empty(&adev->pnp.ids))
149 		return 0;
150 
151 	if (add_uevent_var(env, "MODALIAS="))
152 		return -ENOMEM;
153 
154 	len = create_pnp_modalias(adev, &env->buf[env->buflen - 1],
155 				  sizeof(env->buf) - env->buflen);
156 	if (len < 0)
157 		return len;
158 
159 	env->buflen += len;
160 	if (!adev->data.of_compatible)
161 		return 0;
162 
163 	if (len > 0 && add_uevent_var(env, "MODALIAS="))
164 		return -ENOMEM;
165 
166 	len = create_of_modalias(adev, &env->buf[env->buflen - 1],
167 				 sizeof(env->buf) - env->buflen);
168 	if (len < 0)
169 		return len;
170 
171 	env->buflen += len;
172 
173 	return 0;
174 }
175 
176 /**
177  * acpi_device_uevent_modalias - uevent modalias for ACPI-enumerated devices.
178  *
179  * Create the uevent modalias field for ACPI-enumerated devices.
180  *
181  * Because other buses do not support ACPI HIDs & CIDs, e.g. for a device with
182  * hid:IBM0001 and cid:ACPI0001 you get: "acpi:IBM0001:ACPI0001".
183  */
184 int acpi_device_uevent_modalias(struct device *dev, struct kobj_uevent_env *env)
185 {
186 	return __acpi_device_uevent_modalias(acpi_companion_match(dev), env);
187 }
188 EXPORT_SYMBOL_GPL(acpi_device_uevent_modalias);
189 
190 static int __acpi_device_modalias(struct acpi_device *adev, char *buf, int size)
191 {
192 	int len, count;
193 
194 	if (!adev)
195 		return -ENODEV;
196 
197 	if (list_empty(&adev->pnp.ids))
198 		return 0;
199 
200 	len = create_pnp_modalias(adev, buf, size - 1);
201 	if (len < 0) {
202 		return len;
203 	} else if (len > 0) {
204 		buf[len++] = '\n';
205 		size -= len;
206 	}
207 	if (!adev->data.of_compatible)
208 		return len;
209 
210 	count = create_of_modalias(adev, buf + len, size - 1);
211 	if (count < 0) {
212 		return count;
213 	} else if (count > 0) {
214 		len += count;
215 		buf[len++] = '\n';
216 	}
217 
218 	return len;
219 }
220 
221 /**
222  * acpi_device_modalias - modalias sysfs attribute for ACPI-enumerated devices.
223  *
224  * Create the modalias sysfs attribute for ACPI-enumerated devices.
225  *
226  * Because other buses do not support ACPI HIDs & CIDs, e.g. for a device with
227  * hid:IBM0001 and cid:ACPI0001 you get: "acpi:IBM0001:ACPI0001".
228  */
229 int acpi_device_modalias(struct device *dev, char *buf, int size)
230 {
231 	return __acpi_device_modalias(acpi_companion_match(dev), buf, size);
232 }
233 EXPORT_SYMBOL_GPL(acpi_device_modalias);
234 
235 static ssize_t
236 acpi_device_modalias_show(struct device *dev, struct device_attribute *attr, char *buf) {
237 	return __acpi_device_modalias(to_acpi_device(dev), buf, 1024);
238 }
239 static DEVICE_ATTR(modalias, 0444, acpi_device_modalias_show, NULL);
240 
241 static ssize_t real_power_state_show(struct device *dev,
242 				     struct device_attribute *attr, char *buf)
243 {
244 	struct acpi_device *adev = to_acpi_device(dev);
245 	int state;
246 	int ret;
247 
248 	ret = acpi_device_get_power(adev, &state);
249 	if (ret)
250 		return ret;
251 
252 	return sprintf(buf, "%s\n", acpi_power_state_string(state));
253 }
254 
255 static DEVICE_ATTR(real_power_state, 0444, real_power_state_show, NULL);
256 
257 static ssize_t power_state_show(struct device *dev,
258 				struct device_attribute *attr, char *buf)
259 {
260 	struct acpi_device *adev = to_acpi_device(dev);
261 
262 	return sprintf(buf, "%s\n", acpi_power_state_string(adev->power.state));
263 }
264 
265 static DEVICE_ATTR(power_state, 0444, power_state_show, NULL);
266 
267 static ssize_t
268 acpi_eject_store(struct device *d, struct device_attribute *attr,
269 		const char *buf, size_t count)
270 {
271 	struct acpi_device *acpi_device = to_acpi_device(d);
272 	acpi_object_type not_used;
273 	acpi_status status;
274 
275 	if (!count || buf[0] != '1')
276 		return -EINVAL;
277 
278 	if ((!acpi_device->handler || !acpi_device->handler->hotplug.enabled)
279 	    && !acpi_device->driver)
280 		return -ENODEV;
281 
282 	status = acpi_get_type(acpi_device->handle, &not_used);
283 	if (ACPI_FAILURE(status) || !acpi_device->flags.ejectable)
284 		return -ENODEV;
285 
286 	get_device(&acpi_device->dev);
287 	status = acpi_hotplug_schedule(acpi_device, ACPI_OST_EC_OSPM_EJECT);
288 	if (ACPI_SUCCESS(status))
289 		return count;
290 
291 	put_device(&acpi_device->dev);
292 	acpi_evaluate_ost(acpi_device->handle, ACPI_OST_EC_OSPM_EJECT,
293 			  ACPI_OST_SC_NON_SPECIFIC_FAILURE, NULL);
294 	return status == AE_NO_MEMORY ? -ENOMEM : -EAGAIN;
295 }
296 
297 static DEVICE_ATTR(eject, 0200, NULL, acpi_eject_store);
298 
299 static ssize_t
300 acpi_device_hid_show(struct device *dev, struct device_attribute *attr, char *buf) {
301 	struct acpi_device *acpi_dev = to_acpi_device(dev);
302 
303 	return sprintf(buf, "%s\n", acpi_device_hid(acpi_dev));
304 }
305 static DEVICE_ATTR(hid, 0444, acpi_device_hid_show, NULL);
306 
307 static ssize_t acpi_device_uid_show(struct device *dev,
308 				    struct device_attribute *attr, char *buf)
309 {
310 	struct acpi_device *acpi_dev = to_acpi_device(dev);
311 
312 	return sprintf(buf, "%s\n", acpi_dev->pnp.unique_id);
313 }
314 static DEVICE_ATTR(uid, 0444, acpi_device_uid_show, NULL);
315 
316 static ssize_t acpi_device_adr_show(struct device *dev,
317 				    struct device_attribute *attr, char *buf)
318 {
319 	struct acpi_device *acpi_dev = to_acpi_device(dev);
320 
321 	return sprintf(buf, "0x%08x\n",
322 		       (unsigned int)(acpi_dev->pnp.bus_address));
323 }
324 static DEVICE_ATTR(adr, 0444, acpi_device_adr_show, NULL);
325 
326 static ssize_t
327 acpi_device_path_show(struct device *dev, struct device_attribute *attr, char *buf) {
328 	struct acpi_device *acpi_dev = to_acpi_device(dev);
329 	struct acpi_buffer path = {ACPI_ALLOCATE_BUFFER, NULL};
330 	int result;
331 
332 	result = acpi_get_name(acpi_dev->handle, ACPI_FULL_PATHNAME, &path);
333 	if (result)
334 		goto end;
335 
336 	result = sprintf(buf, "%s\n", (char*)path.pointer);
337 	kfree(path.pointer);
338 end:
339 	return result;
340 }
341 static DEVICE_ATTR(path, 0444, acpi_device_path_show, NULL);
342 
343 /* sysfs file that shows description text from the ACPI _STR method */
344 static ssize_t description_show(struct device *dev,
345 				struct device_attribute *attr,
346 				char *buf) {
347 	struct acpi_device *acpi_dev = to_acpi_device(dev);
348 	int result;
349 
350 	if (acpi_dev->pnp.str_obj == NULL)
351 		return 0;
352 
353 	/*
354 	 * The _STR object contains a Unicode identifier for a device.
355 	 * We need to convert to utf-8 so it can be displayed.
356 	 */
357 	result = utf16s_to_utf8s(
358 		(wchar_t *)acpi_dev->pnp.str_obj->buffer.pointer,
359 		acpi_dev->pnp.str_obj->buffer.length,
360 		UTF16_LITTLE_ENDIAN, buf,
361 		PAGE_SIZE);
362 
363 	buf[result++] = '\n';
364 
365 	return result;
366 }
367 static DEVICE_ATTR(description, 0444, description_show, NULL);
368 
369 static ssize_t
370 acpi_device_sun_show(struct device *dev, struct device_attribute *attr,
371 		     char *buf) {
372 	struct acpi_device *acpi_dev = to_acpi_device(dev);
373 	acpi_status status;
374 	unsigned long long sun;
375 
376 	status = acpi_evaluate_integer(acpi_dev->handle, "_SUN", NULL, &sun);
377 	if (ACPI_FAILURE(status))
378 		return -ENODEV;
379 
380 	return sprintf(buf, "%llu\n", sun);
381 }
382 static DEVICE_ATTR(sun, 0444, acpi_device_sun_show, NULL);
383 
384 static ssize_t status_show(struct device *dev, struct device_attribute *attr,
385 				char *buf) {
386 	struct acpi_device *acpi_dev = to_acpi_device(dev);
387 	acpi_status status;
388 	unsigned long long sta;
389 
390 	status = acpi_evaluate_integer(acpi_dev->handle, "_STA", NULL, &sta);
391 	if (ACPI_FAILURE(status))
392 		return -ENODEV;
393 
394 	return sprintf(buf, "%llu\n", sta);
395 }
396 static DEVICE_ATTR_RO(status);
397 
398 /**
399  * acpi_device_setup_files - Create sysfs attributes of an ACPI device.
400  * @dev: ACPI device object.
401  */
402 int acpi_device_setup_files(struct acpi_device *dev)
403 {
404 	struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
405 	acpi_status status;
406 	int result = 0;
407 
408 	/*
409 	 * Devices gotten from FADT don't have a "path" attribute
410 	 */
411 	if (dev->handle) {
412 		result = device_create_file(&dev->dev, &dev_attr_path);
413 		if (result)
414 			goto end;
415 	}
416 
417 	if (!list_empty(&dev->pnp.ids)) {
418 		result = device_create_file(&dev->dev, &dev_attr_hid);
419 		if (result)
420 			goto end;
421 
422 		result = device_create_file(&dev->dev, &dev_attr_modalias);
423 		if (result)
424 			goto end;
425 	}
426 
427 	/*
428 	 * If device has _STR, 'description' file is created
429 	 */
430 	if (acpi_has_method(dev->handle, "_STR")) {
431 		status = acpi_evaluate_object(dev->handle, "_STR",
432 					NULL, &buffer);
433 		if (ACPI_FAILURE(status))
434 			buffer.pointer = NULL;
435 		dev->pnp.str_obj = buffer.pointer;
436 		result = device_create_file(&dev->dev, &dev_attr_description);
437 		if (result)
438 			goto end;
439 	}
440 
441 	if (dev->pnp.type.bus_address)
442 		result = device_create_file(&dev->dev, &dev_attr_adr);
443 	if (dev->pnp.unique_id)
444 		result = device_create_file(&dev->dev, &dev_attr_uid);
445 
446 	if (acpi_has_method(dev->handle, "_SUN")) {
447 		result = device_create_file(&dev->dev, &dev_attr_sun);
448 		if (result)
449 			goto end;
450 	}
451 
452 	if (acpi_has_method(dev->handle, "_STA")) {
453 		result = device_create_file(&dev->dev, &dev_attr_status);
454 		if (result)
455 			goto end;
456 	}
457 
458         /*
459          * If device has _EJ0, 'eject' file is created that is used to trigger
460          * hot-removal function from userland.
461          */
462 	if (acpi_has_method(dev->handle, "_EJ0")) {
463 		result = device_create_file(&dev->dev, &dev_attr_eject);
464 		if (result)
465 			return result;
466 	}
467 
468 	if (dev->flags.power_manageable) {
469 		result = device_create_file(&dev->dev, &dev_attr_power_state);
470 		if (result)
471 			return result;
472 
473 		if (dev->power.flags.power_resources)
474 			result = device_create_file(&dev->dev,
475 						    &dev_attr_real_power_state);
476 	}
477 
478 end:
479 	return result;
480 }
481 
482 /**
483  * acpi_device_remove_files - Remove sysfs attributes of an ACPI device.
484  * @dev: ACPI device object.
485  */
486 void acpi_device_remove_files(struct acpi_device *dev)
487 {
488 	if (dev->flags.power_manageable) {
489 		device_remove_file(&dev->dev, &dev_attr_power_state);
490 		if (dev->power.flags.power_resources)
491 			device_remove_file(&dev->dev,
492 					   &dev_attr_real_power_state);
493 	}
494 
495 	/*
496 	 * If device has _STR, remove 'description' file
497 	 */
498 	if (acpi_has_method(dev->handle, "_STR")) {
499 		kfree(dev->pnp.str_obj);
500 		device_remove_file(&dev->dev, &dev_attr_description);
501 	}
502 	/*
503 	 * If device has _EJ0, remove 'eject' file.
504 	 */
505 	if (acpi_has_method(dev->handle, "_EJ0"))
506 		device_remove_file(&dev->dev, &dev_attr_eject);
507 
508 	if (acpi_has_method(dev->handle, "_SUN"))
509 		device_remove_file(&dev->dev, &dev_attr_sun);
510 
511 	if (dev->pnp.unique_id)
512 		device_remove_file(&dev->dev, &dev_attr_uid);
513 	if (dev->pnp.type.bus_address)
514 		device_remove_file(&dev->dev, &dev_attr_adr);
515 	device_remove_file(&dev->dev, &dev_attr_modalias);
516 	device_remove_file(&dev->dev, &dev_attr_hid);
517 	if (acpi_has_method(dev->handle, "_STA"))
518 		device_remove_file(&dev->dev, &dev_attr_status);
519 	if (dev->handle)
520 		device_remove_file(&dev->dev, &dev_attr_path);
521 }
522