2 * drivers/acpi/device_sysfs.c - ACPI device sysfs attributes and modalias.
4 * Copyright (C) 2015, Intel Corp.
8 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
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.
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.
19 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
22 #include <linux/acpi.h>
23 #include <linux/device.h>
24 #include <linux/export.h>
25 #include <linux/nls.h>
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.
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
42 static int create_pnp_modalias(struct acpi_device *acpi_dev, char *modalias,
47 struct acpi_hardware_id *id;
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
55 list_for_each_entry(id, &acpi_dev->pnp.ids, list)
56 if (strcmp(id->id, ACPI_DT_NAMESPACE_HID))
62 len = snprintf(modalias, size, "acpi:");
68 list_for_each_entry(id, &acpi_dev->pnp.ids, list) {
69 if (!strcmp(id->id, ACPI_DT_NAMESPACE_HID))
72 count = snprintf(&modalias[len], size, "%s:", id->id);
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.
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
96 static int create_of_modalias(struct acpi_device *acpi_dev, char *modalias,
99 struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER };
100 const union acpi_object *of_compatible, *obj;
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++)
110 len = snprintf(modalias, size, "of:N%sT", (char *)buf.pointer);
111 ACPI_FREE(buf.pointer);
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. */
124 for (i = 0; i < nval; i++, obj++) {
125 count = snprintf(&modalias[len], size, "C%s",
126 obj->string.pointer);
136 modalias[len] = '\0';
140 int __acpi_device_uevent_modalias(struct acpi_device *adev,
141 struct kobj_uevent_env *env)
148 if (list_empty(&adev->pnp.ids))
151 if (add_uevent_var(env, "MODALIAS="))
154 len = create_pnp_modalias(adev, &env->buf[env->buflen - 1],
155 sizeof(env->buf) - env->buflen);
160 if (!adev->data.of_compatible)
163 if (len > 0 && add_uevent_var(env, "MODALIAS="))
166 len = create_of_modalias(adev, &env->buf[env->buflen - 1],
167 sizeof(env->buf) - env->buflen);
177 * acpi_device_uevent_modalias - uevent modalias for ACPI-enumerated devices.
179 * Create the uevent modalias field for ACPI-enumerated devices.
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".
184 int acpi_device_uevent_modalias(struct device *dev, struct kobj_uevent_env *env)
186 return __acpi_device_uevent_modalias(acpi_companion_match(dev), env);
188 EXPORT_SYMBOL_GPL(acpi_device_uevent_modalias);
190 static int __acpi_device_modalias(struct acpi_device *adev, char *buf, int size)
197 if (list_empty(&adev->pnp.ids))
200 len = create_pnp_modalias(adev, buf, size - 1);
203 } else if (len > 0) {
207 if (!adev->data.of_compatible)
210 count = create_of_modalias(adev, buf + len, size - 1);
213 } else if (count > 0) {
222 * acpi_device_modalias - modalias sysfs attribute for ACPI-enumerated devices.
224 * Create the modalias sysfs attribute for ACPI-enumerated devices.
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".
229 int acpi_device_modalias(struct device *dev, char *buf, int size)
231 return __acpi_device_modalias(acpi_companion_match(dev), buf, size);
233 EXPORT_SYMBOL_GPL(acpi_device_modalias);
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);
239 static DEVICE_ATTR(modalias, 0444, acpi_device_modalias_show, NULL);
241 static ssize_t real_power_state_show(struct device *dev,
242 struct device_attribute *attr, char *buf)
244 struct acpi_device *adev = to_acpi_device(dev);
248 ret = acpi_device_get_power(adev, &state);
252 return sprintf(buf, "%s\n", acpi_power_state_string(state));
255 static DEVICE_ATTR(real_power_state, 0444, real_power_state_show, NULL);
257 static ssize_t power_state_show(struct device *dev,
258 struct device_attribute *attr, char *buf)
260 struct acpi_device *adev = to_acpi_device(dev);
262 return sprintf(buf, "%s\n", acpi_power_state_string(adev->power.state));
265 static DEVICE_ATTR(power_state, 0444, power_state_show, NULL);
268 acpi_eject_store(struct device *d, struct device_attribute *attr,
269 const char *buf, size_t count)
271 struct acpi_device *acpi_device = to_acpi_device(d);
272 acpi_object_type not_used;
275 if (!count || buf[0] != '1')
278 if ((!acpi_device->handler || !acpi_device->handler->hotplug.enabled)
279 && !acpi_device->driver)
282 status = acpi_get_type(acpi_device->handle, ¬_used);
283 if (ACPI_FAILURE(status) || !acpi_device->flags.ejectable)
286 get_device(&acpi_device->dev);
287 status = acpi_hotplug_schedule(acpi_device, ACPI_OST_EC_OSPM_EJECT);
288 if (ACPI_SUCCESS(status))
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;
297 static DEVICE_ATTR(eject, 0200, NULL, acpi_eject_store);
300 acpi_device_hid_show(struct device *dev, struct device_attribute *attr, char *buf) {
301 struct acpi_device *acpi_dev = to_acpi_device(dev);
303 return sprintf(buf, "%s\n", acpi_device_hid(acpi_dev));
305 static DEVICE_ATTR(hid, 0444, acpi_device_hid_show, NULL);
307 static ssize_t acpi_device_uid_show(struct device *dev,
308 struct device_attribute *attr, char *buf)
310 struct acpi_device *acpi_dev = to_acpi_device(dev);
312 return sprintf(buf, "%s\n", acpi_dev->pnp.unique_id);
314 static DEVICE_ATTR(uid, 0444, acpi_device_uid_show, NULL);
316 static ssize_t acpi_device_adr_show(struct device *dev,
317 struct device_attribute *attr, char *buf)
319 struct acpi_device *acpi_dev = to_acpi_device(dev);
321 return sprintf(buf, "0x%08x\n",
322 (unsigned int)(acpi_dev->pnp.bus_address));
324 static DEVICE_ATTR(adr, 0444, acpi_device_adr_show, NULL);
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};
332 result = acpi_get_name(acpi_dev->handle, ACPI_FULL_PATHNAME, &path);
336 result = sprintf(buf, "%s\n", (char*)path.pointer);
341 static DEVICE_ATTR(path, 0444, acpi_device_path_show, NULL);
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,
347 struct acpi_device *acpi_dev = to_acpi_device(dev);
350 if (acpi_dev->pnp.str_obj == NULL)
354 * The _STR object contains a Unicode identifier for a device.
355 * We need to convert to utf-8 so it can be displayed.
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,
363 buf[result++] = '\n';
367 static DEVICE_ATTR(description, 0444, description_show, NULL);
370 acpi_device_sun_show(struct device *dev, struct device_attribute *attr,
372 struct acpi_device *acpi_dev = to_acpi_device(dev);
374 unsigned long long sun;
376 status = acpi_evaluate_integer(acpi_dev->handle, "_SUN", NULL, &sun);
377 if (ACPI_FAILURE(status))
380 return sprintf(buf, "%llu\n", sun);
382 static DEVICE_ATTR(sun, 0444, acpi_device_sun_show, NULL);
384 static ssize_t status_show(struct device *dev, struct device_attribute *attr,
386 struct acpi_device *acpi_dev = to_acpi_device(dev);
388 unsigned long long sta;
390 status = acpi_evaluate_integer(acpi_dev->handle, "_STA", NULL, &sta);
391 if (ACPI_FAILURE(status))
394 return sprintf(buf, "%llu\n", sta);
396 static DEVICE_ATTR_RO(status);
399 * acpi_device_setup_files - Create sysfs attributes of an ACPI device.
400 * @dev: ACPI device object.
402 int acpi_device_setup_files(struct acpi_device *dev)
404 struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
409 * Devices gotten from FADT don't have a "path" attribute
412 result = device_create_file(&dev->dev, &dev_attr_path);
417 if (!list_empty(&dev->pnp.ids)) {
418 result = device_create_file(&dev->dev, &dev_attr_hid);
422 result = device_create_file(&dev->dev, &dev_attr_modalias);
428 * If device has _STR, 'description' file is created
430 if (acpi_has_method(dev->handle, "_STR")) {
431 status = acpi_evaluate_object(dev->handle, "_STR",
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);
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);
446 if (acpi_has_method(dev->handle, "_SUN")) {
447 result = device_create_file(&dev->dev, &dev_attr_sun);
452 if (acpi_has_method(dev->handle, "_STA")) {
453 result = device_create_file(&dev->dev, &dev_attr_status);
459 * If device has _EJ0, 'eject' file is created that is used to trigger
460 * hot-removal function from userland.
462 if (acpi_has_method(dev->handle, "_EJ0")) {
463 result = device_create_file(&dev->dev, &dev_attr_eject);
468 if (dev->flags.power_manageable) {
469 result = device_create_file(&dev->dev, &dev_attr_power_state);
473 if (dev->power.flags.power_resources)
474 result = device_create_file(&dev->dev,
475 &dev_attr_real_power_state);
483 * acpi_device_remove_files - Remove sysfs attributes of an ACPI device.
484 * @dev: ACPI device object.
486 void acpi_device_remove_files(struct acpi_device *dev)
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);
496 * If device has _STR, remove 'description' file
498 if (acpi_has_method(dev->handle, "_STR")) {
499 kfree(dev->pnp.str_obj);
500 device_remove_file(&dev->dev, &dev_attr_description);
503 * If device has _EJ0, remove 'eject' file.
505 if (acpi_has_method(dev->handle, "_EJ0"))
506 device_remove_file(&dev->dev, &dev_attr_eject);
508 if (acpi_has_method(dev->handle, "_SUN"))
509 device_remove_file(&dev->dev, &dev_attr_sun);
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);
520 device_remove_file(&dev->dev, &dev_attr_path);