1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * drivers/acpi/device_sysfs.c - ACPI device sysfs attributes and modalias.
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * Copyright (C) 2015, Intel Corp.
6*4882a593Smuzhiyun * Author: Mika Westerberg <mika.westerberg@linux.intel.com>
7*4882a593Smuzhiyun * Author: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
8*4882a593Smuzhiyun *
9*4882a593Smuzhiyun * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
10*4882a593Smuzhiyun *
11*4882a593Smuzhiyun * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
12*4882a593Smuzhiyun */
13*4882a593Smuzhiyun
14*4882a593Smuzhiyun #include <linux/acpi.h>
15*4882a593Smuzhiyun #include <linux/device.h>
16*4882a593Smuzhiyun #include <linux/export.h>
17*4882a593Smuzhiyun #include <linux/nls.h>
18*4882a593Smuzhiyun
19*4882a593Smuzhiyun #include "internal.h"
20*4882a593Smuzhiyun
acpi_object_path(acpi_handle handle,char * buf)21*4882a593Smuzhiyun static ssize_t acpi_object_path(acpi_handle handle, char *buf)
22*4882a593Smuzhiyun {
23*4882a593Smuzhiyun struct acpi_buffer path = {ACPI_ALLOCATE_BUFFER, NULL};
24*4882a593Smuzhiyun int result;
25*4882a593Smuzhiyun
26*4882a593Smuzhiyun result = acpi_get_name(handle, ACPI_FULL_PATHNAME, &path);
27*4882a593Smuzhiyun if (result)
28*4882a593Smuzhiyun return result;
29*4882a593Smuzhiyun
30*4882a593Smuzhiyun result = sprintf(buf, "%s\n", (char *)path.pointer);
31*4882a593Smuzhiyun kfree(path.pointer);
32*4882a593Smuzhiyun return result;
33*4882a593Smuzhiyun }
34*4882a593Smuzhiyun
35*4882a593Smuzhiyun struct acpi_data_node_attr {
36*4882a593Smuzhiyun struct attribute attr;
37*4882a593Smuzhiyun ssize_t (*show)(struct acpi_data_node *, char *);
38*4882a593Smuzhiyun ssize_t (*store)(struct acpi_data_node *, const char *, size_t count);
39*4882a593Smuzhiyun };
40*4882a593Smuzhiyun
41*4882a593Smuzhiyun #define DATA_NODE_ATTR(_name) \
42*4882a593Smuzhiyun static struct acpi_data_node_attr data_node_##_name = \
43*4882a593Smuzhiyun __ATTR(_name, 0444, data_node_show_##_name, NULL)
44*4882a593Smuzhiyun
data_node_show_path(struct acpi_data_node * dn,char * buf)45*4882a593Smuzhiyun static ssize_t data_node_show_path(struct acpi_data_node *dn, char *buf)
46*4882a593Smuzhiyun {
47*4882a593Smuzhiyun return dn->handle ? acpi_object_path(dn->handle, buf) : 0;
48*4882a593Smuzhiyun }
49*4882a593Smuzhiyun
50*4882a593Smuzhiyun DATA_NODE_ATTR(path);
51*4882a593Smuzhiyun
52*4882a593Smuzhiyun static struct attribute *acpi_data_node_default_attrs[] = {
53*4882a593Smuzhiyun &data_node_path.attr,
54*4882a593Smuzhiyun NULL
55*4882a593Smuzhiyun };
56*4882a593Smuzhiyun
57*4882a593Smuzhiyun #define to_data_node(k) container_of(k, struct acpi_data_node, kobj)
58*4882a593Smuzhiyun #define to_attr(a) container_of(a, struct acpi_data_node_attr, attr)
59*4882a593Smuzhiyun
acpi_data_node_attr_show(struct kobject * kobj,struct attribute * attr,char * buf)60*4882a593Smuzhiyun static ssize_t acpi_data_node_attr_show(struct kobject *kobj,
61*4882a593Smuzhiyun struct attribute *attr, char *buf)
62*4882a593Smuzhiyun {
63*4882a593Smuzhiyun struct acpi_data_node *dn = to_data_node(kobj);
64*4882a593Smuzhiyun struct acpi_data_node_attr *dn_attr = to_attr(attr);
65*4882a593Smuzhiyun
66*4882a593Smuzhiyun return dn_attr->show ? dn_attr->show(dn, buf) : -ENXIO;
67*4882a593Smuzhiyun }
68*4882a593Smuzhiyun
69*4882a593Smuzhiyun static const struct sysfs_ops acpi_data_node_sysfs_ops = {
70*4882a593Smuzhiyun .show = acpi_data_node_attr_show,
71*4882a593Smuzhiyun };
72*4882a593Smuzhiyun
acpi_data_node_release(struct kobject * kobj)73*4882a593Smuzhiyun static void acpi_data_node_release(struct kobject *kobj)
74*4882a593Smuzhiyun {
75*4882a593Smuzhiyun struct acpi_data_node *dn = to_data_node(kobj);
76*4882a593Smuzhiyun complete(&dn->kobj_done);
77*4882a593Smuzhiyun }
78*4882a593Smuzhiyun
79*4882a593Smuzhiyun static struct kobj_type acpi_data_node_ktype = {
80*4882a593Smuzhiyun .sysfs_ops = &acpi_data_node_sysfs_ops,
81*4882a593Smuzhiyun .default_attrs = acpi_data_node_default_attrs,
82*4882a593Smuzhiyun .release = acpi_data_node_release,
83*4882a593Smuzhiyun };
84*4882a593Smuzhiyun
acpi_expose_nondev_subnodes(struct kobject * kobj,struct acpi_device_data * data)85*4882a593Smuzhiyun static void acpi_expose_nondev_subnodes(struct kobject *kobj,
86*4882a593Smuzhiyun struct acpi_device_data *data)
87*4882a593Smuzhiyun {
88*4882a593Smuzhiyun struct list_head *list = &data->subnodes;
89*4882a593Smuzhiyun struct acpi_data_node *dn;
90*4882a593Smuzhiyun
91*4882a593Smuzhiyun if (list_empty(list))
92*4882a593Smuzhiyun return;
93*4882a593Smuzhiyun
94*4882a593Smuzhiyun list_for_each_entry(dn, list, sibling) {
95*4882a593Smuzhiyun int ret;
96*4882a593Smuzhiyun
97*4882a593Smuzhiyun init_completion(&dn->kobj_done);
98*4882a593Smuzhiyun ret = kobject_init_and_add(&dn->kobj, &acpi_data_node_ktype,
99*4882a593Smuzhiyun kobj, "%s", dn->name);
100*4882a593Smuzhiyun if (!ret)
101*4882a593Smuzhiyun acpi_expose_nondev_subnodes(&dn->kobj, &dn->data);
102*4882a593Smuzhiyun else if (dn->handle)
103*4882a593Smuzhiyun acpi_handle_err(dn->handle, "Failed to expose (%d)\n", ret);
104*4882a593Smuzhiyun }
105*4882a593Smuzhiyun }
106*4882a593Smuzhiyun
acpi_hide_nondev_subnodes(struct acpi_device_data * data)107*4882a593Smuzhiyun static void acpi_hide_nondev_subnodes(struct acpi_device_data *data)
108*4882a593Smuzhiyun {
109*4882a593Smuzhiyun struct list_head *list = &data->subnodes;
110*4882a593Smuzhiyun struct acpi_data_node *dn;
111*4882a593Smuzhiyun
112*4882a593Smuzhiyun if (list_empty(list))
113*4882a593Smuzhiyun return;
114*4882a593Smuzhiyun
115*4882a593Smuzhiyun list_for_each_entry_reverse(dn, list, sibling) {
116*4882a593Smuzhiyun acpi_hide_nondev_subnodes(&dn->data);
117*4882a593Smuzhiyun kobject_put(&dn->kobj);
118*4882a593Smuzhiyun }
119*4882a593Smuzhiyun }
120*4882a593Smuzhiyun
121*4882a593Smuzhiyun /**
122*4882a593Smuzhiyun * create_pnp_modalias - Create hid/cid(s) string for modalias and uevent
123*4882a593Smuzhiyun * @acpi_dev: ACPI device object.
124*4882a593Smuzhiyun * @modalias: Buffer to print into.
125*4882a593Smuzhiyun * @size: Size of the buffer.
126*4882a593Smuzhiyun *
127*4882a593Smuzhiyun * Creates hid/cid(s) string needed for modalias and uevent
128*4882a593Smuzhiyun * e.g. on a device with hid:IBM0001 and cid:ACPI0001 you get:
129*4882a593Smuzhiyun * char *modalias: "acpi:IBM0001:ACPI0001"
130*4882a593Smuzhiyun * Return: 0: no _HID and no _CID
131*4882a593Smuzhiyun * -EINVAL: output error
132*4882a593Smuzhiyun * -ENOMEM: output is truncated
133*4882a593Smuzhiyun */
create_pnp_modalias(struct acpi_device * acpi_dev,char * modalias,int size)134*4882a593Smuzhiyun static int create_pnp_modalias(struct acpi_device *acpi_dev, char *modalias,
135*4882a593Smuzhiyun int size)
136*4882a593Smuzhiyun {
137*4882a593Smuzhiyun int len;
138*4882a593Smuzhiyun int count;
139*4882a593Smuzhiyun struct acpi_hardware_id *id;
140*4882a593Smuzhiyun
141*4882a593Smuzhiyun /* Avoid unnecessarily loading modules for non present devices. */
142*4882a593Smuzhiyun if (!acpi_device_is_present(acpi_dev))
143*4882a593Smuzhiyun return 0;
144*4882a593Smuzhiyun
145*4882a593Smuzhiyun /*
146*4882a593Smuzhiyun * Since we skip ACPI_DT_NAMESPACE_HID from the modalias below, 0 should
147*4882a593Smuzhiyun * be returned if ACPI_DT_NAMESPACE_HID is the only ACPI/PNP ID in the
148*4882a593Smuzhiyun * device's list.
149*4882a593Smuzhiyun */
150*4882a593Smuzhiyun count = 0;
151*4882a593Smuzhiyun list_for_each_entry(id, &acpi_dev->pnp.ids, list)
152*4882a593Smuzhiyun if (strcmp(id->id, ACPI_DT_NAMESPACE_HID))
153*4882a593Smuzhiyun count++;
154*4882a593Smuzhiyun
155*4882a593Smuzhiyun if (!count)
156*4882a593Smuzhiyun return 0;
157*4882a593Smuzhiyun
158*4882a593Smuzhiyun len = snprintf(modalias, size, "acpi:");
159*4882a593Smuzhiyun if (len <= 0)
160*4882a593Smuzhiyun return len;
161*4882a593Smuzhiyun
162*4882a593Smuzhiyun size -= len;
163*4882a593Smuzhiyun
164*4882a593Smuzhiyun list_for_each_entry(id, &acpi_dev->pnp.ids, list) {
165*4882a593Smuzhiyun if (!strcmp(id->id, ACPI_DT_NAMESPACE_HID))
166*4882a593Smuzhiyun continue;
167*4882a593Smuzhiyun
168*4882a593Smuzhiyun count = snprintf(&modalias[len], size, "%s:", id->id);
169*4882a593Smuzhiyun if (count < 0)
170*4882a593Smuzhiyun return -EINVAL;
171*4882a593Smuzhiyun
172*4882a593Smuzhiyun if (count >= size)
173*4882a593Smuzhiyun return -ENOMEM;
174*4882a593Smuzhiyun
175*4882a593Smuzhiyun len += count;
176*4882a593Smuzhiyun size -= count;
177*4882a593Smuzhiyun }
178*4882a593Smuzhiyun modalias[len] = '\0';
179*4882a593Smuzhiyun return len;
180*4882a593Smuzhiyun }
181*4882a593Smuzhiyun
182*4882a593Smuzhiyun /**
183*4882a593Smuzhiyun * create_of_modalias - Creates DT compatible string for modalias and uevent
184*4882a593Smuzhiyun * @acpi_dev: ACPI device object.
185*4882a593Smuzhiyun * @modalias: Buffer to print into.
186*4882a593Smuzhiyun * @size: Size of the buffer.
187*4882a593Smuzhiyun *
188*4882a593Smuzhiyun * Expose DT compatible modalias as of:NnameTCcompatible. This function should
189*4882a593Smuzhiyun * only be called for devices having ACPI_DT_NAMESPACE_HID in their list of
190*4882a593Smuzhiyun * ACPI/PNP IDs.
191*4882a593Smuzhiyun */
create_of_modalias(struct acpi_device * acpi_dev,char * modalias,int size)192*4882a593Smuzhiyun static int create_of_modalias(struct acpi_device *acpi_dev, char *modalias,
193*4882a593Smuzhiyun int size)
194*4882a593Smuzhiyun {
195*4882a593Smuzhiyun struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER };
196*4882a593Smuzhiyun const union acpi_object *of_compatible, *obj;
197*4882a593Smuzhiyun acpi_status status;
198*4882a593Smuzhiyun int len, count;
199*4882a593Smuzhiyun int i, nval;
200*4882a593Smuzhiyun char *c;
201*4882a593Smuzhiyun
202*4882a593Smuzhiyun status = acpi_get_name(acpi_dev->handle, ACPI_SINGLE_NAME, &buf);
203*4882a593Smuzhiyun if (ACPI_FAILURE(status))
204*4882a593Smuzhiyun return -ENODEV;
205*4882a593Smuzhiyun
206*4882a593Smuzhiyun /* DT strings are all in lower case */
207*4882a593Smuzhiyun for (c = buf.pointer; *c != '\0'; c++)
208*4882a593Smuzhiyun *c = tolower(*c);
209*4882a593Smuzhiyun
210*4882a593Smuzhiyun len = snprintf(modalias, size, "of:N%sT", (char *)buf.pointer);
211*4882a593Smuzhiyun ACPI_FREE(buf.pointer);
212*4882a593Smuzhiyun
213*4882a593Smuzhiyun if (len <= 0)
214*4882a593Smuzhiyun return len;
215*4882a593Smuzhiyun
216*4882a593Smuzhiyun of_compatible = acpi_dev->data.of_compatible;
217*4882a593Smuzhiyun if (of_compatible->type == ACPI_TYPE_PACKAGE) {
218*4882a593Smuzhiyun nval = of_compatible->package.count;
219*4882a593Smuzhiyun obj = of_compatible->package.elements;
220*4882a593Smuzhiyun } else { /* Must be ACPI_TYPE_STRING. */
221*4882a593Smuzhiyun nval = 1;
222*4882a593Smuzhiyun obj = of_compatible;
223*4882a593Smuzhiyun }
224*4882a593Smuzhiyun for (i = 0; i < nval; i++, obj++) {
225*4882a593Smuzhiyun count = snprintf(&modalias[len], size, "C%s",
226*4882a593Smuzhiyun obj->string.pointer);
227*4882a593Smuzhiyun if (count < 0)
228*4882a593Smuzhiyun return -EINVAL;
229*4882a593Smuzhiyun
230*4882a593Smuzhiyun if (count >= size)
231*4882a593Smuzhiyun return -ENOMEM;
232*4882a593Smuzhiyun
233*4882a593Smuzhiyun len += count;
234*4882a593Smuzhiyun size -= count;
235*4882a593Smuzhiyun }
236*4882a593Smuzhiyun modalias[len] = '\0';
237*4882a593Smuzhiyun return len;
238*4882a593Smuzhiyun }
239*4882a593Smuzhiyun
__acpi_device_uevent_modalias(struct acpi_device * adev,struct kobj_uevent_env * env)240*4882a593Smuzhiyun int __acpi_device_uevent_modalias(struct acpi_device *adev,
241*4882a593Smuzhiyun struct kobj_uevent_env *env)
242*4882a593Smuzhiyun {
243*4882a593Smuzhiyun int len;
244*4882a593Smuzhiyun
245*4882a593Smuzhiyun if (!adev)
246*4882a593Smuzhiyun return -ENODEV;
247*4882a593Smuzhiyun
248*4882a593Smuzhiyun if (list_empty(&adev->pnp.ids))
249*4882a593Smuzhiyun return 0;
250*4882a593Smuzhiyun
251*4882a593Smuzhiyun if (add_uevent_var(env, "MODALIAS="))
252*4882a593Smuzhiyun return -ENOMEM;
253*4882a593Smuzhiyun
254*4882a593Smuzhiyun if (adev->data.of_compatible)
255*4882a593Smuzhiyun len = create_of_modalias(adev, &env->buf[env->buflen - 1],
256*4882a593Smuzhiyun sizeof(env->buf) - env->buflen);
257*4882a593Smuzhiyun else
258*4882a593Smuzhiyun len = create_pnp_modalias(adev, &env->buf[env->buflen - 1],
259*4882a593Smuzhiyun sizeof(env->buf) - env->buflen);
260*4882a593Smuzhiyun if (len < 0)
261*4882a593Smuzhiyun return len;
262*4882a593Smuzhiyun
263*4882a593Smuzhiyun env->buflen += len;
264*4882a593Smuzhiyun
265*4882a593Smuzhiyun return 0;
266*4882a593Smuzhiyun }
267*4882a593Smuzhiyun
268*4882a593Smuzhiyun /**
269*4882a593Smuzhiyun * acpi_device_uevent_modalias - uevent modalias for ACPI-enumerated devices.
270*4882a593Smuzhiyun *
271*4882a593Smuzhiyun * Create the uevent modalias field for ACPI-enumerated devices.
272*4882a593Smuzhiyun *
273*4882a593Smuzhiyun * Because other buses do not support ACPI HIDs & CIDs, e.g. for a device with
274*4882a593Smuzhiyun * hid:IBM0001 and cid:ACPI0001 you get: "acpi:IBM0001:ACPI0001".
275*4882a593Smuzhiyun */
acpi_device_uevent_modalias(struct device * dev,struct kobj_uevent_env * env)276*4882a593Smuzhiyun int acpi_device_uevent_modalias(struct device *dev, struct kobj_uevent_env *env)
277*4882a593Smuzhiyun {
278*4882a593Smuzhiyun return __acpi_device_uevent_modalias(acpi_companion_match(dev), env);
279*4882a593Smuzhiyun }
280*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(acpi_device_uevent_modalias);
281*4882a593Smuzhiyun
__acpi_device_modalias(struct acpi_device * adev,char * buf,int size)282*4882a593Smuzhiyun static int __acpi_device_modalias(struct acpi_device *adev, char *buf, int size)
283*4882a593Smuzhiyun {
284*4882a593Smuzhiyun int len, count;
285*4882a593Smuzhiyun
286*4882a593Smuzhiyun if (!adev)
287*4882a593Smuzhiyun return -ENODEV;
288*4882a593Smuzhiyun
289*4882a593Smuzhiyun if (list_empty(&adev->pnp.ids))
290*4882a593Smuzhiyun return 0;
291*4882a593Smuzhiyun
292*4882a593Smuzhiyun len = create_pnp_modalias(adev, buf, size - 1);
293*4882a593Smuzhiyun if (len < 0) {
294*4882a593Smuzhiyun return len;
295*4882a593Smuzhiyun } else if (len > 0) {
296*4882a593Smuzhiyun buf[len++] = '\n';
297*4882a593Smuzhiyun size -= len;
298*4882a593Smuzhiyun }
299*4882a593Smuzhiyun if (!adev->data.of_compatible)
300*4882a593Smuzhiyun return len;
301*4882a593Smuzhiyun
302*4882a593Smuzhiyun count = create_of_modalias(adev, buf + len, size - 1);
303*4882a593Smuzhiyun if (count < 0) {
304*4882a593Smuzhiyun return count;
305*4882a593Smuzhiyun } else if (count > 0) {
306*4882a593Smuzhiyun len += count;
307*4882a593Smuzhiyun buf[len++] = '\n';
308*4882a593Smuzhiyun }
309*4882a593Smuzhiyun
310*4882a593Smuzhiyun return len;
311*4882a593Smuzhiyun }
312*4882a593Smuzhiyun
313*4882a593Smuzhiyun /**
314*4882a593Smuzhiyun * acpi_device_modalias - modalias sysfs attribute for ACPI-enumerated devices.
315*4882a593Smuzhiyun *
316*4882a593Smuzhiyun * Create the modalias sysfs attribute for ACPI-enumerated devices.
317*4882a593Smuzhiyun *
318*4882a593Smuzhiyun * Because other buses do not support ACPI HIDs & CIDs, e.g. for a device with
319*4882a593Smuzhiyun * hid:IBM0001 and cid:ACPI0001 you get: "acpi:IBM0001:ACPI0001".
320*4882a593Smuzhiyun */
acpi_device_modalias(struct device * dev,char * buf,int size)321*4882a593Smuzhiyun int acpi_device_modalias(struct device *dev, char *buf, int size)
322*4882a593Smuzhiyun {
323*4882a593Smuzhiyun return __acpi_device_modalias(acpi_companion_match(dev), buf, size);
324*4882a593Smuzhiyun }
325*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(acpi_device_modalias);
326*4882a593Smuzhiyun
327*4882a593Smuzhiyun static ssize_t
modalias_show(struct device * dev,struct device_attribute * attr,char * buf)328*4882a593Smuzhiyun modalias_show(struct device *dev, struct device_attribute *attr, char *buf)
329*4882a593Smuzhiyun {
330*4882a593Smuzhiyun return __acpi_device_modalias(to_acpi_device(dev), buf, 1024);
331*4882a593Smuzhiyun }
332*4882a593Smuzhiyun static DEVICE_ATTR_RO(modalias);
333*4882a593Smuzhiyun
real_power_state_show(struct device * dev,struct device_attribute * attr,char * buf)334*4882a593Smuzhiyun static ssize_t real_power_state_show(struct device *dev,
335*4882a593Smuzhiyun struct device_attribute *attr, char *buf)
336*4882a593Smuzhiyun {
337*4882a593Smuzhiyun struct acpi_device *adev = to_acpi_device(dev);
338*4882a593Smuzhiyun int state;
339*4882a593Smuzhiyun int ret;
340*4882a593Smuzhiyun
341*4882a593Smuzhiyun ret = acpi_device_get_power(adev, &state);
342*4882a593Smuzhiyun if (ret)
343*4882a593Smuzhiyun return ret;
344*4882a593Smuzhiyun
345*4882a593Smuzhiyun return sprintf(buf, "%s\n", acpi_power_state_string(state));
346*4882a593Smuzhiyun }
347*4882a593Smuzhiyun
348*4882a593Smuzhiyun static DEVICE_ATTR_RO(real_power_state);
349*4882a593Smuzhiyun
power_state_show(struct device * dev,struct device_attribute * attr,char * buf)350*4882a593Smuzhiyun static ssize_t power_state_show(struct device *dev,
351*4882a593Smuzhiyun struct device_attribute *attr, char *buf)
352*4882a593Smuzhiyun {
353*4882a593Smuzhiyun struct acpi_device *adev = to_acpi_device(dev);
354*4882a593Smuzhiyun
355*4882a593Smuzhiyun return sprintf(buf, "%s\n", acpi_power_state_string(adev->power.state));
356*4882a593Smuzhiyun }
357*4882a593Smuzhiyun
358*4882a593Smuzhiyun static DEVICE_ATTR_RO(power_state);
359*4882a593Smuzhiyun
360*4882a593Smuzhiyun static ssize_t
eject_store(struct device * d,struct device_attribute * attr,const char * buf,size_t count)361*4882a593Smuzhiyun eject_store(struct device *d, struct device_attribute *attr,
362*4882a593Smuzhiyun const char *buf, size_t count)
363*4882a593Smuzhiyun {
364*4882a593Smuzhiyun struct acpi_device *acpi_device = to_acpi_device(d);
365*4882a593Smuzhiyun acpi_object_type not_used;
366*4882a593Smuzhiyun acpi_status status;
367*4882a593Smuzhiyun
368*4882a593Smuzhiyun if (!count || buf[0] != '1')
369*4882a593Smuzhiyun return -EINVAL;
370*4882a593Smuzhiyun
371*4882a593Smuzhiyun if ((!acpi_device->handler || !acpi_device->handler->hotplug.enabled)
372*4882a593Smuzhiyun && !acpi_device->driver)
373*4882a593Smuzhiyun return -ENODEV;
374*4882a593Smuzhiyun
375*4882a593Smuzhiyun status = acpi_get_type(acpi_device->handle, ¬_used);
376*4882a593Smuzhiyun if (ACPI_FAILURE(status) || !acpi_device->flags.ejectable)
377*4882a593Smuzhiyun return -ENODEV;
378*4882a593Smuzhiyun
379*4882a593Smuzhiyun get_device(&acpi_device->dev);
380*4882a593Smuzhiyun status = acpi_hotplug_schedule(acpi_device, ACPI_OST_EC_OSPM_EJECT);
381*4882a593Smuzhiyun if (ACPI_SUCCESS(status))
382*4882a593Smuzhiyun return count;
383*4882a593Smuzhiyun
384*4882a593Smuzhiyun put_device(&acpi_device->dev);
385*4882a593Smuzhiyun acpi_evaluate_ost(acpi_device->handle, ACPI_OST_EC_OSPM_EJECT,
386*4882a593Smuzhiyun ACPI_OST_SC_NON_SPECIFIC_FAILURE, NULL);
387*4882a593Smuzhiyun return status == AE_NO_MEMORY ? -ENOMEM : -EAGAIN;
388*4882a593Smuzhiyun }
389*4882a593Smuzhiyun
390*4882a593Smuzhiyun static DEVICE_ATTR_WO(eject);
391*4882a593Smuzhiyun
392*4882a593Smuzhiyun static ssize_t
hid_show(struct device * dev,struct device_attribute * attr,char * buf)393*4882a593Smuzhiyun hid_show(struct device *dev, struct device_attribute *attr, char *buf)
394*4882a593Smuzhiyun {
395*4882a593Smuzhiyun struct acpi_device *acpi_dev = to_acpi_device(dev);
396*4882a593Smuzhiyun
397*4882a593Smuzhiyun return sprintf(buf, "%s\n", acpi_device_hid(acpi_dev));
398*4882a593Smuzhiyun }
399*4882a593Smuzhiyun static DEVICE_ATTR_RO(hid);
400*4882a593Smuzhiyun
uid_show(struct device * dev,struct device_attribute * attr,char * buf)401*4882a593Smuzhiyun static ssize_t uid_show(struct device *dev,
402*4882a593Smuzhiyun struct device_attribute *attr, char *buf)
403*4882a593Smuzhiyun {
404*4882a593Smuzhiyun struct acpi_device *acpi_dev = to_acpi_device(dev);
405*4882a593Smuzhiyun
406*4882a593Smuzhiyun return sprintf(buf, "%s\n", acpi_dev->pnp.unique_id);
407*4882a593Smuzhiyun }
408*4882a593Smuzhiyun static DEVICE_ATTR_RO(uid);
409*4882a593Smuzhiyun
adr_show(struct device * dev,struct device_attribute * attr,char * buf)410*4882a593Smuzhiyun static ssize_t adr_show(struct device *dev,
411*4882a593Smuzhiyun struct device_attribute *attr, char *buf)
412*4882a593Smuzhiyun {
413*4882a593Smuzhiyun struct acpi_device *acpi_dev = to_acpi_device(dev);
414*4882a593Smuzhiyun
415*4882a593Smuzhiyun if (acpi_dev->pnp.bus_address > U32_MAX)
416*4882a593Smuzhiyun return sprintf(buf, "0x%016llx\n", acpi_dev->pnp.bus_address);
417*4882a593Smuzhiyun else
418*4882a593Smuzhiyun return sprintf(buf, "0x%08llx\n", acpi_dev->pnp.bus_address);
419*4882a593Smuzhiyun }
420*4882a593Smuzhiyun static DEVICE_ATTR_RO(adr);
421*4882a593Smuzhiyun
path_show(struct device * dev,struct device_attribute * attr,char * buf)422*4882a593Smuzhiyun static ssize_t path_show(struct device *dev,
423*4882a593Smuzhiyun struct device_attribute *attr, char *buf)
424*4882a593Smuzhiyun {
425*4882a593Smuzhiyun struct acpi_device *acpi_dev = to_acpi_device(dev);
426*4882a593Smuzhiyun
427*4882a593Smuzhiyun return acpi_object_path(acpi_dev->handle, buf);
428*4882a593Smuzhiyun }
429*4882a593Smuzhiyun static DEVICE_ATTR_RO(path);
430*4882a593Smuzhiyun
431*4882a593Smuzhiyun /* sysfs file that shows description text from the ACPI _STR method */
description_show(struct device * dev,struct device_attribute * attr,char * buf)432*4882a593Smuzhiyun static ssize_t description_show(struct device *dev,
433*4882a593Smuzhiyun struct device_attribute *attr,
434*4882a593Smuzhiyun char *buf) {
435*4882a593Smuzhiyun struct acpi_device *acpi_dev = to_acpi_device(dev);
436*4882a593Smuzhiyun int result;
437*4882a593Smuzhiyun
438*4882a593Smuzhiyun if (acpi_dev->pnp.str_obj == NULL)
439*4882a593Smuzhiyun return 0;
440*4882a593Smuzhiyun
441*4882a593Smuzhiyun /*
442*4882a593Smuzhiyun * The _STR object contains a Unicode identifier for a device.
443*4882a593Smuzhiyun * We need to convert to utf-8 so it can be displayed.
444*4882a593Smuzhiyun */
445*4882a593Smuzhiyun result = utf16s_to_utf8s(
446*4882a593Smuzhiyun (wchar_t *)acpi_dev->pnp.str_obj->buffer.pointer,
447*4882a593Smuzhiyun acpi_dev->pnp.str_obj->buffer.length,
448*4882a593Smuzhiyun UTF16_LITTLE_ENDIAN, buf,
449*4882a593Smuzhiyun PAGE_SIZE - 1);
450*4882a593Smuzhiyun
451*4882a593Smuzhiyun buf[result++] = '\n';
452*4882a593Smuzhiyun
453*4882a593Smuzhiyun return result;
454*4882a593Smuzhiyun }
455*4882a593Smuzhiyun static DEVICE_ATTR_RO(description);
456*4882a593Smuzhiyun
457*4882a593Smuzhiyun static ssize_t
sun_show(struct device * dev,struct device_attribute * attr,char * buf)458*4882a593Smuzhiyun sun_show(struct device *dev, struct device_attribute *attr,
459*4882a593Smuzhiyun char *buf) {
460*4882a593Smuzhiyun struct acpi_device *acpi_dev = to_acpi_device(dev);
461*4882a593Smuzhiyun acpi_status status;
462*4882a593Smuzhiyun unsigned long long sun;
463*4882a593Smuzhiyun
464*4882a593Smuzhiyun status = acpi_evaluate_integer(acpi_dev->handle, "_SUN", NULL, &sun);
465*4882a593Smuzhiyun if (ACPI_FAILURE(status))
466*4882a593Smuzhiyun return -EIO;
467*4882a593Smuzhiyun
468*4882a593Smuzhiyun return sprintf(buf, "%llu\n", sun);
469*4882a593Smuzhiyun }
470*4882a593Smuzhiyun static DEVICE_ATTR_RO(sun);
471*4882a593Smuzhiyun
472*4882a593Smuzhiyun static ssize_t
hrv_show(struct device * dev,struct device_attribute * attr,char * buf)473*4882a593Smuzhiyun hrv_show(struct device *dev, struct device_attribute *attr,
474*4882a593Smuzhiyun char *buf) {
475*4882a593Smuzhiyun struct acpi_device *acpi_dev = to_acpi_device(dev);
476*4882a593Smuzhiyun acpi_status status;
477*4882a593Smuzhiyun unsigned long long hrv;
478*4882a593Smuzhiyun
479*4882a593Smuzhiyun status = acpi_evaluate_integer(acpi_dev->handle, "_HRV", NULL, &hrv);
480*4882a593Smuzhiyun if (ACPI_FAILURE(status))
481*4882a593Smuzhiyun return -EIO;
482*4882a593Smuzhiyun
483*4882a593Smuzhiyun return sprintf(buf, "%llu\n", hrv);
484*4882a593Smuzhiyun }
485*4882a593Smuzhiyun static DEVICE_ATTR_RO(hrv);
486*4882a593Smuzhiyun
status_show(struct device * dev,struct device_attribute * attr,char * buf)487*4882a593Smuzhiyun static ssize_t status_show(struct device *dev, struct device_attribute *attr,
488*4882a593Smuzhiyun char *buf) {
489*4882a593Smuzhiyun struct acpi_device *acpi_dev = to_acpi_device(dev);
490*4882a593Smuzhiyun acpi_status status;
491*4882a593Smuzhiyun unsigned long long sta;
492*4882a593Smuzhiyun
493*4882a593Smuzhiyun status = acpi_evaluate_integer(acpi_dev->handle, "_STA", NULL, &sta);
494*4882a593Smuzhiyun if (ACPI_FAILURE(status))
495*4882a593Smuzhiyun return -EIO;
496*4882a593Smuzhiyun
497*4882a593Smuzhiyun return sprintf(buf, "%llu\n", sta);
498*4882a593Smuzhiyun }
499*4882a593Smuzhiyun static DEVICE_ATTR_RO(status);
500*4882a593Smuzhiyun
501*4882a593Smuzhiyun /**
502*4882a593Smuzhiyun * acpi_device_setup_files - Create sysfs attributes of an ACPI device.
503*4882a593Smuzhiyun * @dev: ACPI device object.
504*4882a593Smuzhiyun */
acpi_device_setup_files(struct acpi_device * dev)505*4882a593Smuzhiyun int acpi_device_setup_files(struct acpi_device *dev)
506*4882a593Smuzhiyun {
507*4882a593Smuzhiyun struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
508*4882a593Smuzhiyun acpi_status status;
509*4882a593Smuzhiyun int result = 0;
510*4882a593Smuzhiyun
511*4882a593Smuzhiyun /*
512*4882a593Smuzhiyun * Devices gotten from FADT don't have a "path" attribute
513*4882a593Smuzhiyun */
514*4882a593Smuzhiyun if (dev->handle) {
515*4882a593Smuzhiyun result = device_create_file(&dev->dev, &dev_attr_path);
516*4882a593Smuzhiyun if (result)
517*4882a593Smuzhiyun goto end;
518*4882a593Smuzhiyun }
519*4882a593Smuzhiyun
520*4882a593Smuzhiyun if (!list_empty(&dev->pnp.ids)) {
521*4882a593Smuzhiyun result = device_create_file(&dev->dev, &dev_attr_hid);
522*4882a593Smuzhiyun if (result)
523*4882a593Smuzhiyun goto end;
524*4882a593Smuzhiyun
525*4882a593Smuzhiyun result = device_create_file(&dev->dev, &dev_attr_modalias);
526*4882a593Smuzhiyun if (result)
527*4882a593Smuzhiyun goto end;
528*4882a593Smuzhiyun }
529*4882a593Smuzhiyun
530*4882a593Smuzhiyun /*
531*4882a593Smuzhiyun * If device has _STR, 'description' file is created
532*4882a593Smuzhiyun */
533*4882a593Smuzhiyun if (acpi_has_method(dev->handle, "_STR")) {
534*4882a593Smuzhiyun status = acpi_evaluate_object(dev->handle, "_STR",
535*4882a593Smuzhiyun NULL, &buffer);
536*4882a593Smuzhiyun if (ACPI_FAILURE(status))
537*4882a593Smuzhiyun buffer.pointer = NULL;
538*4882a593Smuzhiyun dev->pnp.str_obj = buffer.pointer;
539*4882a593Smuzhiyun result = device_create_file(&dev->dev, &dev_attr_description);
540*4882a593Smuzhiyun if (result)
541*4882a593Smuzhiyun goto end;
542*4882a593Smuzhiyun }
543*4882a593Smuzhiyun
544*4882a593Smuzhiyun if (dev->pnp.type.bus_address)
545*4882a593Smuzhiyun result = device_create_file(&dev->dev, &dev_attr_adr);
546*4882a593Smuzhiyun if (dev->pnp.unique_id)
547*4882a593Smuzhiyun result = device_create_file(&dev->dev, &dev_attr_uid);
548*4882a593Smuzhiyun
549*4882a593Smuzhiyun if (acpi_has_method(dev->handle, "_SUN")) {
550*4882a593Smuzhiyun result = device_create_file(&dev->dev, &dev_attr_sun);
551*4882a593Smuzhiyun if (result)
552*4882a593Smuzhiyun goto end;
553*4882a593Smuzhiyun }
554*4882a593Smuzhiyun
555*4882a593Smuzhiyun if (acpi_has_method(dev->handle, "_HRV")) {
556*4882a593Smuzhiyun result = device_create_file(&dev->dev, &dev_attr_hrv);
557*4882a593Smuzhiyun if (result)
558*4882a593Smuzhiyun goto end;
559*4882a593Smuzhiyun }
560*4882a593Smuzhiyun
561*4882a593Smuzhiyun if (acpi_has_method(dev->handle, "_STA")) {
562*4882a593Smuzhiyun result = device_create_file(&dev->dev, &dev_attr_status);
563*4882a593Smuzhiyun if (result)
564*4882a593Smuzhiyun goto end;
565*4882a593Smuzhiyun }
566*4882a593Smuzhiyun
567*4882a593Smuzhiyun /*
568*4882a593Smuzhiyun * If device has _EJ0, 'eject' file is created that is used to trigger
569*4882a593Smuzhiyun * hot-removal function from userland.
570*4882a593Smuzhiyun */
571*4882a593Smuzhiyun if (acpi_has_method(dev->handle, "_EJ0")) {
572*4882a593Smuzhiyun result = device_create_file(&dev->dev, &dev_attr_eject);
573*4882a593Smuzhiyun if (result)
574*4882a593Smuzhiyun return result;
575*4882a593Smuzhiyun }
576*4882a593Smuzhiyun
577*4882a593Smuzhiyun if (dev->flags.power_manageable) {
578*4882a593Smuzhiyun result = device_create_file(&dev->dev, &dev_attr_power_state);
579*4882a593Smuzhiyun if (result)
580*4882a593Smuzhiyun return result;
581*4882a593Smuzhiyun
582*4882a593Smuzhiyun if (dev->power.flags.power_resources)
583*4882a593Smuzhiyun result = device_create_file(&dev->dev,
584*4882a593Smuzhiyun &dev_attr_real_power_state);
585*4882a593Smuzhiyun }
586*4882a593Smuzhiyun
587*4882a593Smuzhiyun acpi_expose_nondev_subnodes(&dev->dev.kobj, &dev->data);
588*4882a593Smuzhiyun
589*4882a593Smuzhiyun end:
590*4882a593Smuzhiyun return result;
591*4882a593Smuzhiyun }
592*4882a593Smuzhiyun
593*4882a593Smuzhiyun /**
594*4882a593Smuzhiyun * acpi_device_remove_files - Remove sysfs attributes of an ACPI device.
595*4882a593Smuzhiyun * @dev: ACPI device object.
596*4882a593Smuzhiyun */
acpi_device_remove_files(struct acpi_device * dev)597*4882a593Smuzhiyun void acpi_device_remove_files(struct acpi_device *dev)
598*4882a593Smuzhiyun {
599*4882a593Smuzhiyun acpi_hide_nondev_subnodes(&dev->data);
600*4882a593Smuzhiyun
601*4882a593Smuzhiyun if (dev->flags.power_manageable) {
602*4882a593Smuzhiyun device_remove_file(&dev->dev, &dev_attr_power_state);
603*4882a593Smuzhiyun if (dev->power.flags.power_resources)
604*4882a593Smuzhiyun device_remove_file(&dev->dev,
605*4882a593Smuzhiyun &dev_attr_real_power_state);
606*4882a593Smuzhiyun }
607*4882a593Smuzhiyun
608*4882a593Smuzhiyun /*
609*4882a593Smuzhiyun * If device has _STR, remove 'description' file
610*4882a593Smuzhiyun */
611*4882a593Smuzhiyun if (acpi_has_method(dev->handle, "_STR")) {
612*4882a593Smuzhiyun kfree(dev->pnp.str_obj);
613*4882a593Smuzhiyun device_remove_file(&dev->dev, &dev_attr_description);
614*4882a593Smuzhiyun }
615*4882a593Smuzhiyun /*
616*4882a593Smuzhiyun * If device has _EJ0, remove 'eject' file.
617*4882a593Smuzhiyun */
618*4882a593Smuzhiyun if (acpi_has_method(dev->handle, "_EJ0"))
619*4882a593Smuzhiyun device_remove_file(&dev->dev, &dev_attr_eject);
620*4882a593Smuzhiyun
621*4882a593Smuzhiyun if (acpi_has_method(dev->handle, "_SUN"))
622*4882a593Smuzhiyun device_remove_file(&dev->dev, &dev_attr_sun);
623*4882a593Smuzhiyun
624*4882a593Smuzhiyun if (acpi_has_method(dev->handle, "_HRV"))
625*4882a593Smuzhiyun device_remove_file(&dev->dev, &dev_attr_hrv);
626*4882a593Smuzhiyun
627*4882a593Smuzhiyun if (dev->pnp.unique_id)
628*4882a593Smuzhiyun device_remove_file(&dev->dev, &dev_attr_uid);
629*4882a593Smuzhiyun if (dev->pnp.type.bus_address)
630*4882a593Smuzhiyun device_remove_file(&dev->dev, &dev_attr_adr);
631*4882a593Smuzhiyun device_remove_file(&dev->dev, &dev_attr_modalias);
632*4882a593Smuzhiyun device_remove_file(&dev->dev, &dev_attr_hid);
633*4882a593Smuzhiyun if (acpi_has_method(dev->handle, "_STA"))
634*4882a593Smuzhiyun device_remove_file(&dev->dev, &dev_attr_status);
635*4882a593Smuzhiyun if (dev->handle)
636*4882a593Smuzhiyun device_remove_file(&dev->dev, &dev_attr_path);
637*4882a593Smuzhiyun }
638