1 // SPDX-License-Identifier: GPL-2.0-only
3 * drivers/acpi/device_sysfs.c - ACPI device sysfs attributes and modalias.
5 * Copyright (C) 2015, Intel Corp.
6 * Author: Mika Westerberg <mika.westerberg@linux.intel.com>
7 * Author: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
9 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
11 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
14 #include <linux/acpi.h>
15 #include <linux/device.h>
16 #include <linux/export.h>
17 #include <linux/nls.h>
21 static ssize_t
acpi_object_path(acpi_handle handle
, char *buf
)
23 struct acpi_buffer path
= {ACPI_ALLOCATE_BUFFER
, NULL
};
26 result
= acpi_get_name(handle
, ACPI_FULL_PATHNAME
, &path
);
30 result
= sprintf(buf
, "%s\n", (char *)path
.pointer
);
35 struct acpi_data_node_attr
{
36 struct attribute attr
;
37 ssize_t (*show
)(struct acpi_data_node
*, char *);
38 ssize_t (*store
)(struct acpi_data_node
*, const char *, size_t count
);
41 #define DATA_NODE_ATTR(_name) \
42 static struct acpi_data_node_attr data_node_##_name = \
43 __ATTR(_name, 0444, data_node_show_##_name, NULL)
45 static ssize_t
data_node_show_path(struct acpi_data_node
*dn
, char *buf
)
47 return dn
->handle
? acpi_object_path(dn
->handle
, buf
) : 0;
52 static struct attribute
*acpi_data_node_default_attrs
[] = {
56 ATTRIBUTE_GROUPS(acpi_data_node_default
);
58 #define to_data_node(k) container_of(k, struct acpi_data_node, kobj)
59 #define to_attr(a) container_of(a, struct acpi_data_node_attr, attr)
61 static ssize_t
acpi_data_node_attr_show(struct kobject
*kobj
,
62 struct attribute
*attr
, char *buf
)
64 struct acpi_data_node
*dn
= to_data_node(kobj
);
65 struct acpi_data_node_attr
*dn_attr
= to_attr(attr
);
67 return dn_attr
->show
? dn_attr
->show(dn
, buf
) : -ENXIO
;
70 static const struct sysfs_ops acpi_data_node_sysfs_ops
= {
71 .show
= acpi_data_node_attr_show
,
74 static void acpi_data_node_release(struct kobject
*kobj
)
76 struct acpi_data_node
*dn
= to_data_node(kobj
);
78 complete(&dn
->kobj_done
);
81 static const struct kobj_type acpi_data_node_ktype
= {
82 .sysfs_ops
= &acpi_data_node_sysfs_ops
,
83 .default_groups
= acpi_data_node_default_groups
,
84 .release
= acpi_data_node_release
,
87 static void acpi_expose_nondev_subnodes(struct kobject
*kobj
,
88 struct acpi_device_data
*data
)
90 struct list_head
*list
= &data
->subnodes
;
91 struct acpi_data_node
*dn
;
96 list_for_each_entry(dn
, list
, sibling
) {
99 init_completion(&dn
->kobj_done
);
100 ret
= kobject_init_and_add(&dn
->kobj
, &acpi_data_node_ktype
,
101 kobj
, "%s", dn
->name
);
103 acpi_expose_nondev_subnodes(&dn
->kobj
, &dn
->data
);
105 acpi_handle_err(dn
->handle
, "Failed to expose (%d)\n", ret
);
109 static void acpi_hide_nondev_subnodes(struct acpi_device_data
*data
)
111 struct list_head
*list
= &data
->subnodes
;
112 struct acpi_data_node
*dn
;
114 if (list_empty(list
))
117 list_for_each_entry_reverse(dn
, list
, sibling
) {
118 acpi_hide_nondev_subnodes(&dn
->data
);
119 kobject_put(&dn
->kobj
);
124 * create_pnp_modalias - Create hid/cid(s) string for modalias and uevent
125 * @acpi_dev: ACPI device object.
126 * @modalias: Buffer to print into.
127 * @size: Size of the buffer.
129 * Creates hid/cid(s) string needed for modalias and uevent
130 * e.g. on a device with hid:IBM0001 and cid:ACPI0001 you get:
131 * char *modalias: "acpi:IBM0001:ACPI0001"
132 * Return: 0: no _HID and no _CID
133 * -EINVAL: output error
134 * -ENOMEM: output is truncated
136 static int create_pnp_modalias(const struct acpi_device
*acpi_dev
, char *modalias
,
141 struct acpi_hardware_id
*id
;
143 /* Avoid unnecessarily loading modules for non present devices. */
144 if (!acpi_device_is_present(acpi_dev
))
148 * Since we skip ACPI_DT_NAMESPACE_HID from the modalias below, 0 should
149 * be returned if ACPI_DT_NAMESPACE_HID is the only ACPI/PNP ID in the
153 list_for_each_entry(id
, &acpi_dev
->pnp
.ids
, list
)
154 if (strcmp(id
->id
, ACPI_DT_NAMESPACE_HID
))
160 len
= snprintf(modalias
, size
, "acpi:");
166 list_for_each_entry(id
, &acpi_dev
->pnp
.ids
, list
) {
167 if (!strcmp(id
->id
, ACPI_DT_NAMESPACE_HID
))
170 count
= snprintf(&modalias
[len
], size
, "%s:", id
->id
);
183 * create_of_modalias - Creates DT compatible string for modalias and uevent
184 * @acpi_dev: ACPI device object.
185 * @modalias: Buffer to print into.
186 * @size: Size of the buffer.
188 * Expose DT compatible modalias as of:NnameTCcompatible. This function should
189 * only be called for devices having ACPI_DT_NAMESPACE_HID in their list of
192 static int create_of_modalias(const struct acpi_device
*acpi_dev
, char *modalias
,
195 struct acpi_buffer buf
= { ACPI_ALLOCATE_BUFFER
};
196 const union acpi_object
*of_compatible
, *obj
;
202 status
= acpi_get_name(acpi_dev
->handle
, ACPI_SINGLE_NAME
, &buf
);
203 if (ACPI_FAILURE(status
))
206 /* DT strings are all in lower case */
207 for (c
= buf
.pointer
; *c
!= '\0'; c
++)
210 len
= snprintf(modalias
, size
, "of:N%sT", (char *)buf
.pointer
);
211 ACPI_FREE(buf
.pointer
);
218 of_compatible
= acpi_dev
->data
.of_compatible
;
219 if (of_compatible
->type
== ACPI_TYPE_PACKAGE
) {
220 nval
= of_compatible
->package
.count
;
221 obj
= of_compatible
->package
.elements
;
222 } else { /* Must be ACPI_TYPE_STRING. */
226 for (i
= 0; i
< nval
; i
++, obj
++) {
227 count
= snprintf(&modalias
[len
], size
, "C%s",
228 obj
->string
.pointer
);
240 int __acpi_device_uevent_modalias(const struct acpi_device
*adev
,
241 struct kobj_uevent_env
*env
)
248 if (list_empty(&adev
->pnp
.ids
))
251 if (add_uevent_var(env
, "MODALIAS="))
254 if (adev
->data
.of_compatible
)
255 len
= create_of_modalias(adev
, &env
->buf
[env
->buflen
- 1],
256 sizeof(env
->buf
) - env
->buflen
);
258 len
= create_pnp_modalias(adev
, &env
->buf
[env
->buflen
- 1],
259 sizeof(env
->buf
) - env
->buflen
);
269 * acpi_device_uevent_modalias - uevent modalias for ACPI-enumerated devices.
270 * @dev: Struct device to get ACPI device node.
271 * @env: Environment variables of the kobject uevent.
273 * Create the uevent modalias field for ACPI-enumerated devices.
275 * Because other buses do not support ACPI HIDs & CIDs, e.g. for a device with
276 * hid:IBM0001 and cid:ACPI0001 you get: "acpi:IBM0001:ACPI0001".
278 int acpi_device_uevent_modalias(const struct device
*dev
, struct kobj_uevent_env
*env
)
280 return __acpi_device_uevent_modalias(acpi_companion_match(dev
), env
);
282 EXPORT_SYMBOL_GPL(acpi_device_uevent_modalias
);
284 static int __acpi_device_modalias(const struct acpi_device
*adev
, char *buf
, int size
)
291 if (list_empty(&adev
->pnp
.ids
))
294 len
= create_pnp_modalias(adev
, buf
, size
- 1);
297 } else if (len
> 0) {
301 if (!adev
->data
.of_compatible
)
304 count
= create_of_modalias(adev
, buf
+ len
, size
- 1);
307 } else if (count
> 0) {
316 * acpi_device_modalias - modalias sysfs attribute for ACPI-enumerated devices.
317 * @dev: Struct device to get ACPI device node.
318 * @buf: The buffer to save pnp_modalias and of_modalias.
319 * @size: Size of buffer.
321 * Create the modalias sysfs attribute for ACPI-enumerated devices.
323 * Because other buses do not support ACPI HIDs & CIDs, e.g. for a device with
324 * hid:IBM0001 and cid:ACPI0001 you get: "acpi:IBM0001:ACPI0001".
326 int acpi_device_modalias(struct device
*dev
, char *buf
, int size
)
328 return __acpi_device_modalias(acpi_companion_match(dev
), buf
, size
);
330 EXPORT_SYMBOL_GPL(acpi_device_modalias
);
333 modalias_show(struct device
*dev
, struct device_attribute
*attr
, char *buf
)
335 return __acpi_device_modalias(to_acpi_device(dev
), buf
, 1024);
337 static DEVICE_ATTR_RO(modalias
);
339 static ssize_t
real_power_state_show(struct device
*dev
,
340 struct device_attribute
*attr
, char *buf
)
342 struct acpi_device
*adev
= to_acpi_device(dev
);
346 ret
= acpi_device_get_power(adev
, &state
);
350 return sprintf(buf
, "%s\n", acpi_power_state_string(state
));
353 static DEVICE_ATTR_RO(real_power_state
);
355 static ssize_t
power_state_show(struct device
*dev
,
356 struct device_attribute
*attr
, char *buf
)
358 struct acpi_device
*adev
= to_acpi_device(dev
);
360 return sprintf(buf
, "%s\n", acpi_power_state_string(adev
->power
.state
));
363 static DEVICE_ATTR_RO(power_state
);
366 eject_store(struct device
*d
, struct device_attribute
*attr
,
367 const char *buf
, size_t count
)
369 struct acpi_device
*acpi_device
= to_acpi_device(d
);
370 acpi_object_type not_used
;
373 if (!count
|| buf
[0] != '1')
376 if ((!acpi_device
->handler
|| !acpi_device
->handler
->hotplug
.enabled
)
380 status
= acpi_get_type(acpi_device
->handle
, ¬_used
);
381 if (ACPI_FAILURE(status
) || !acpi_device
->flags
.ejectable
)
384 acpi_dev_get(acpi_device
);
385 status
= acpi_hotplug_schedule(acpi_device
, ACPI_OST_EC_OSPM_EJECT
);
386 if (ACPI_SUCCESS(status
))
389 acpi_dev_put(acpi_device
);
390 acpi_evaluate_ost(acpi_device
->handle
, ACPI_OST_EC_OSPM_EJECT
,
391 ACPI_OST_SC_NON_SPECIFIC_FAILURE
, NULL
);
392 return status
== AE_NO_MEMORY
? -ENOMEM
: -EAGAIN
;
395 static DEVICE_ATTR_WO(eject
);
398 hid_show(struct device
*dev
, struct device_attribute
*attr
, char *buf
)
400 struct acpi_device
*acpi_dev
= to_acpi_device(dev
);
402 return sprintf(buf
, "%s\n", acpi_device_hid(acpi_dev
));
404 static DEVICE_ATTR_RO(hid
);
406 static ssize_t
uid_show(struct device
*dev
,
407 struct device_attribute
*attr
, char *buf
)
409 struct acpi_device
*acpi_dev
= to_acpi_device(dev
);
411 return sprintf(buf
, "%s\n", acpi_device_uid(acpi_dev
));
413 static DEVICE_ATTR_RO(uid
);
415 static ssize_t
adr_show(struct device
*dev
,
416 struct device_attribute
*attr
, char *buf
)
418 struct acpi_device
*acpi_dev
= to_acpi_device(dev
);
420 if (acpi_dev
->pnp
.bus_address
> U32_MAX
)
421 return sprintf(buf
, "0x%016llx\n", acpi_dev
->pnp
.bus_address
);
423 return sprintf(buf
, "0x%08llx\n", acpi_dev
->pnp
.bus_address
);
425 static DEVICE_ATTR_RO(adr
);
427 static ssize_t
path_show(struct device
*dev
,
428 struct device_attribute
*attr
, char *buf
)
430 struct acpi_device
*acpi_dev
= to_acpi_device(dev
);
432 return acpi_object_path(acpi_dev
->handle
, buf
);
434 static DEVICE_ATTR_RO(path
);
436 /* sysfs file that shows description text from the ACPI _STR method */
437 static ssize_t
description_show(struct device
*dev
,
438 struct device_attribute
*attr
,
441 struct acpi_device
*acpi_dev
= to_acpi_device(dev
);
442 struct acpi_buffer buffer
= {ACPI_ALLOCATE_BUFFER
, NULL
};
443 union acpi_object
*str_obj
;
447 status
= acpi_evaluate_object_typed(acpi_dev
->handle
, "_STR",
450 if (ACPI_FAILURE(status
))
453 str_obj
= buffer
.pointer
;
456 * The _STR object contains a Unicode identifier for a device.
457 * We need to convert to utf-8 so it can be displayed.
459 result
= utf16s_to_utf8s(
460 (wchar_t *)str_obj
->buffer
.pointer
,
461 str_obj
->buffer
.length
,
462 UTF16_LITTLE_ENDIAN
, buf
,
465 buf
[result
++] = '\n';
471 static DEVICE_ATTR_RO(description
);
474 sun_show(struct device
*dev
, struct device_attribute
*attr
,
477 struct acpi_device
*acpi_dev
= to_acpi_device(dev
);
479 unsigned long long sun
;
481 status
= acpi_evaluate_integer(acpi_dev
->handle
, "_SUN", NULL
, &sun
);
482 if (ACPI_FAILURE(status
))
485 return sprintf(buf
, "%llu\n", sun
);
487 static DEVICE_ATTR_RO(sun
);
490 hrv_show(struct device
*dev
, struct device_attribute
*attr
,
493 struct acpi_device
*acpi_dev
= to_acpi_device(dev
);
495 unsigned long long hrv
;
497 status
= acpi_evaluate_integer(acpi_dev
->handle
, "_HRV", NULL
, &hrv
);
498 if (ACPI_FAILURE(status
))
501 return sprintf(buf
, "%llu\n", hrv
);
503 static DEVICE_ATTR_RO(hrv
);
505 static ssize_t
status_show(struct device
*dev
, struct device_attribute
*attr
,
508 struct acpi_device
*acpi_dev
= to_acpi_device(dev
);
510 unsigned long long sta
;
512 status
= acpi_evaluate_integer(acpi_dev
->handle
, "_STA", NULL
, &sta
);
513 if (ACPI_FAILURE(status
))
516 return sprintf(buf
, "%llu\n", sta
);
518 static DEVICE_ATTR_RO(status
);
520 static struct attribute
*acpi_attrs
[] = {
523 &dev_attr_modalias
.attr
,
524 &dev_attr_description
.attr
,
529 &dev_attr_status
.attr
,
530 &dev_attr_eject
.attr
,
531 &dev_attr_power_state
.attr
,
532 &dev_attr_real_power_state
.attr
,
536 static bool acpi_show_attr(struct acpi_device
*dev
, const struct device_attribute
*attr
)
539 * Devices gotten from FADT don't have a "path" attribute
541 if (attr
== &dev_attr_path
)
544 if (attr
== &dev_attr_hid
|| attr
== &dev_attr_modalias
)
545 return !list_empty(&dev
->pnp
.ids
);
547 if (attr
== &dev_attr_description
)
548 return acpi_has_method(dev
->handle
, "_STR");
550 if (attr
== &dev_attr_adr
)
551 return dev
->pnp
.type
.bus_address
;
553 if (attr
== &dev_attr_uid
)
554 return acpi_device_uid(dev
);
556 if (attr
== &dev_attr_sun
)
557 return acpi_has_method(dev
->handle
, "_SUN");
559 if (attr
== &dev_attr_hrv
)
560 return acpi_has_method(dev
->handle
, "_HRV");
562 if (attr
== &dev_attr_status
)
563 return acpi_has_method(dev
->handle
, "_STA");
566 * If device has _EJ0, 'eject' file is created that is used to trigger
567 * hot-removal function from userland.
569 if (attr
== &dev_attr_eject
)
570 return acpi_has_method(dev
->handle
, "_EJ0");
572 if (attr
== &dev_attr_power_state
)
573 return dev
->flags
.power_manageable
;
575 if (attr
== &dev_attr_real_power_state
)
576 return dev
->flags
.power_manageable
&& dev
->power
.flags
.power_resources
;
578 dev_warn_once(&dev
->dev
, "Unexpected attribute: %s\n", attr
->attr
.name
);
582 static umode_t
acpi_attr_is_visible(struct kobject
*kobj
,
583 struct attribute
*attr
,
586 struct acpi_device
*dev
= to_acpi_device(kobj_to_dev(kobj
));
588 if (acpi_show_attr(dev
, container_of(attr
, struct device_attribute
, attr
)))
594 static const struct attribute_group acpi_group
= {
596 .is_visible
= acpi_attr_is_visible
,
599 const struct attribute_group
*acpi_groups
[] = {
605 * acpi_device_setup_files - Create sysfs attributes of an ACPI device.
606 * @dev: ACPI device object.
608 void acpi_device_setup_files(struct acpi_device
*dev
)
610 acpi_expose_nondev_subnodes(&dev
->dev
.kobj
, &dev
->data
);
614 * acpi_device_remove_files - Remove sysfs attributes of an ACPI device.
615 * @dev: ACPI device object.
617 void acpi_device_remove_files(struct acpi_device
*dev
)
619 acpi_hide_nondev_subnodes(&dev
->data
);