aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRafael J. Wysocki <rafael.j.wysocki@intel.com>2015-07-17 16:53:43 -0400
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2015-07-17 16:53:43 -0400
commitc2efefb33abfb245395199137ece3c1e3df47f51 (patch)
treecfa516ab3d65e0a98416cbc1983dd060cdb1b640
parent21bdb584af8cca7c6df3c44cba268be050a234eb (diff)
ACPI / scan: Move sysfs-related device code to a separate file
To reduce the size of scan.c and improve the readability of it, move all code related to device sysfs, modalias creation etc. to a new file called device_sysfs.c. Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
-rw-r--r--drivers/acpi/Makefile2
-rw-r--r--drivers/acpi/device_sysfs.c521
-rw-r--r--drivers/acpi/internal.h9
-rw-r--r--drivers/acpi/scan.c483
4 files changed, 532 insertions, 483 deletions
diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
index 8321430d7f24..08ac1100e2dc 100644
--- a/drivers/acpi/Makefile
+++ b/drivers/acpi/Makefile
@@ -24,7 +24,7 @@ acpi-y += nvs.o
24# Power management related files 24# Power management related files
25acpi-y += wakeup.o 25acpi-y += wakeup.o
26acpi-$(CONFIG_ACPI_SYSTEM_POWER_STATES_SUPPORT) += sleep.o 26acpi-$(CONFIG_ACPI_SYSTEM_POWER_STATES_SUPPORT) += sleep.o
27acpi-y += device_pm.o 27acpi-y += device_sysfs.o device_pm.o
28acpi-$(CONFIG_ACPI_SLEEP) += proc.o 28acpi-$(CONFIG_ACPI_SLEEP) += proc.o
29 29
30 30
diff --git a/drivers/acpi/device_sysfs.c b/drivers/acpi/device_sysfs.c
new file mode 100644
index 000000000000..4ab4582e586b
--- /dev/null
+++ b/drivers/acpi/device_sysfs.c
@@ -0,0 +1,521 @@
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*/
42static 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 */
96static 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
140int __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 */
184int 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}
188EXPORT_SYMBOL_GPL(acpi_device_uevent_modalias);
189
190static 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 */
229int acpi_device_modalias(struct device *dev, char *buf, int size)
230{
231 return __acpi_device_modalias(acpi_companion_match(dev), buf, size);
232}
233EXPORT_SYMBOL_GPL(acpi_device_modalias);
234
235static ssize_t
236acpi_device_modalias_show(struct device *dev, struct device_attribute *attr, char *buf) {
237 return __acpi_device_modalias(to_acpi_device(dev), buf, 1024);
238}
239static DEVICE_ATTR(modalias, 0444, acpi_device_modalias_show, NULL);
240
241static 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
255static DEVICE_ATTR(real_power_state, 0444, real_power_state_show, NULL);
256
257static 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
265static DEVICE_ATTR(power_state, 0444, power_state_show, NULL);
266
267static ssize_t
268acpi_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
297static DEVICE_ATTR(eject, 0200, NULL, acpi_eject_store);
298
299static ssize_t
300acpi_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}
305static DEVICE_ATTR(hid, 0444, acpi_device_hid_show, NULL);
306
307static 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}
314static DEVICE_ATTR(uid, 0444, acpi_device_uid_show, NULL);
315
316static 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}
324static DEVICE_ATTR(adr, 0444, acpi_device_adr_show, NULL);
325
326static ssize_t
327acpi_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);
338end:
339 return result;
340}
341static DEVICE_ATTR(path, 0444, acpi_device_path_show, NULL);
342
343/* sysfs file that shows description text from the ACPI _STR method */
344static 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}
367static DEVICE_ATTR(description, 0444, description_show, NULL);
368
369static ssize_t
370acpi_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}
382static DEVICE_ATTR(sun, 0444, acpi_device_sun_show, NULL);
383
384static 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}
396static DEVICE_ATTR_RO(status);
397
398/**
399 * acpi_device_setup_files - Create sysfs attributes of an ACPI device.
400 * @dev: ACPI device object.
401 */
402int 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
478end:
479 return result;
480}
481
482/**
483 * acpi_device_remove_files - Remove sysfs attributes of an ACPI device.
484 * @dev: ACPI device object.
485 */
486void 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}
diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h
index 4683a96932b9..c529454532dc 100644
--- a/drivers/acpi/internal.h
+++ b/drivers/acpi/internal.h
@@ -93,12 +93,21 @@ int acpi_device_add(struct acpi_device *device,
93 void (*release)(struct device *)); 93 void (*release)(struct device *));
94void acpi_init_device_object(struct acpi_device *device, acpi_handle handle, 94void acpi_init_device_object(struct acpi_device *device, acpi_handle handle,
95 int type, unsigned long long sta); 95 int type, unsigned long long sta);
96int acpi_device_setup_files(struct acpi_device *dev);
97void acpi_device_remove_files(struct acpi_device *dev);
96void acpi_device_add_finalize(struct acpi_device *device); 98void acpi_device_add_finalize(struct acpi_device *device);
97void acpi_free_pnp_ids(struct acpi_device_pnp *pnp); 99void acpi_free_pnp_ids(struct acpi_device_pnp *pnp);
98bool acpi_device_is_present(struct acpi_device *adev); 100bool acpi_device_is_present(struct acpi_device *adev);
99bool acpi_device_is_battery(struct acpi_device *adev); 101bool acpi_device_is_battery(struct acpi_device *adev);
100 102
101/* -------------------------------------------------------------------------- 103/* --------------------------------------------------------------------------
104 Device Matching and Notification
105 -------------------------------------------------------------------------- */
106struct acpi_device *acpi_companion_match(const struct device *dev);
107int __acpi_device_uevent_modalias(struct acpi_device *adev,
108 struct kobj_uevent_env *env);
109
110/* --------------------------------------------------------------------------
102 Power Resource 111 Power Resource
103 -------------------------------------------------------------------------- */ 112 -------------------------------------------------------------------------- */
104int acpi_power_init(void); 113int acpi_power_init(void);
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
index ec256352f423..099831fc8449 100644
--- a/drivers/acpi/scan.c
+++ b/drivers/acpi/scan.c
@@ -115,117 +115,6 @@ int acpi_scan_add_handler_with_hotplug(struct acpi_scan_handler *handler,
115 return 0; 115 return 0;
116} 116}
117 117
118/**
119 * create_pnp_modalias - Create hid/cid(s) string for modalias and uevent
120 * @acpi_dev: ACPI device object.
121 * @modalias: Buffer to print into.
122 * @size: Size of the buffer.
123 *
124 * Creates hid/cid(s) string needed for modalias and uevent
125 * e.g. on a device with hid:IBM0001 and cid:ACPI0001 you get:
126 * char *modalias: "acpi:IBM0001:ACPI0001"
127 * Return: 0: no _HID and no _CID
128 * -EINVAL: output error
129 * -ENOMEM: output is truncated
130*/
131static int create_pnp_modalias(struct acpi_device *acpi_dev, char *modalias,
132 int size)
133{
134 int len;
135 int count;
136 struct acpi_hardware_id *id;
137
138 /*
139 * Since we skip ACPI_DT_NAMESPACE_HID from the modalias below, 0 should
140 * be returned if ACPI_DT_NAMESPACE_HID is the only ACPI/PNP ID in the
141 * device's list.
142 */
143 count = 0;
144 list_for_each_entry(id, &acpi_dev->pnp.ids, list)
145 if (strcmp(id->id, ACPI_DT_NAMESPACE_HID))
146 count++;
147
148 if (!count)
149 return 0;
150
151 len = snprintf(modalias, size, "acpi:");
152 if (len <= 0)
153 return len;
154
155 size -= len;
156
157 list_for_each_entry(id, &acpi_dev->pnp.ids, list) {
158 if (!strcmp(id->id, ACPI_DT_NAMESPACE_HID))
159 continue;
160
161 count = snprintf(&modalias[len], size, "%s:", id->id);
162 if (count < 0)
163 return -EINVAL;
164
165 if (count >= size)
166 return -ENOMEM;
167
168 len += count;
169 size -= count;
170 }
171 modalias[len] = '\0';
172 return len;
173}
174
175/**
176 * create_of_modalias - Creates DT compatible string for modalias and uevent
177 * @acpi_dev: ACPI device object.
178 * @modalias: Buffer to print into.
179 * @size: Size of the buffer.
180 *
181 * Expose DT compatible modalias as of:NnameTCcompatible. This function should
182 * only be called for devices having ACPI_DT_NAMESPACE_HID in their list of
183 * ACPI/PNP IDs.
184 */
185static int create_of_modalias(struct acpi_device *acpi_dev, char *modalias,
186 int size)
187{
188 struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER };
189 const union acpi_object *of_compatible, *obj;
190 int len, count;
191 int i, nval;
192 char *c;
193
194 acpi_get_name(acpi_dev->handle, ACPI_SINGLE_NAME, &buf);
195 /* DT strings are all in lower case */
196 for (c = buf.pointer; *c != '\0'; c++)
197 *c = tolower(*c);
198
199 len = snprintf(modalias, size, "of:N%sT", (char *)buf.pointer);
200 ACPI_FREE(buf.pointer);
201
202 if (len <= 0)
203 return len;
204
205 of_compatible = acpi_dev->data.of_compatible;
206 if (of_compatible->type == ACPI_TYPE_PACKAGE) {
207 nval = of_compatible->package.count;
208 obj = of_compatible->package.elements;
209 } else { /* Must be ACPI_TYPE_STRING. */
210 nval = 1;
211 obj = of_compatible;
212 }
213 for (i = 0; i < nval; i++, obj++) {
214 count = snprintf(&modalias[len], size, "C%s",
215 obj->string.pointer);
216 if (count < 0)
217 return -EINVAL;
218
219 if (count >= size)
220 return -ENOMEM;
221
222 len += count;
223 size -= count;
224 }
225 modalias[len] = '\0';
226 return len;
227}
228
229/* 118/*
230 * acpi_companion_match() - Can we match via ACPI companion device 119 * acpi_companion_match() - Can we match via ACPI companion device
231 * @dev: Device in question 120 * @dev: Device in question
@@ -247,7 +136,7 @@ static int create_of_modalias(struct acpi_device *acpi_dev, char *modalias,
247 * resources available from it but they will be matched normally using functions 136 * resources available from it but they will be matched normally using functions
248 * provided by their bus types (and analogously for their modalias). 137 * provided by their bus types (and analogously for their modalias).
249 */ 138 */
250static struct acpi_device *acpi_companion_match(const struct device *dev) 139struct acpi_device *acpi_companion_match(const struct device *dev)
251{ 140{
252 struct acpi_device *adev; 141 struct acpi_device *adev;
253 struct mutex *physical_node_lock; 142 struct mutex *physical_node_lock;
@@ -276,103 +165,6 @@ static struct acpi_device *acpi_companion_match(const struct device *dev)
276 return adev; 165 return adev;
277} 166}
278 167
279static int __acpi_device_uevent_modalias(struct acpi_device *adev,
280 struct kobj_uevent_env *env)
281{
282 int len;
283
284 if (!adev)
285 return -ENODEV;
286
287 if (list_empty(&adev->pnp.ids))
288 return 0;
289
290 if (add_uevent_var(env, "MODALIAS="))
291 return -ENOMEM;
292
293 len = create_pnp_modalias(adev, &env->buf[env->buflen - 1],
294 sizeof(env->buf) - env->buflen);
295 if (len < 0)
296 return len;
297
298 env->buflen += len;
299 if (!adev->data.of_compatible)
300 return 0;
301
302 if (len > 0 && add_uevent_var(env, "MODALIAS="))
303 return -ENOMEM;
304
305 len = create_of_modalias(adev, &env->buf[env->buflen - 1],
306 sizeof(env->buf) - env->buflen);
307 if (len < 0)
308 return len;
309
310 env->buflen += len;
311
312 return 0;
313}
314
315/*
316 * Creates uevent modalias field for ACPI enumerated devices.
317 * Because the other buses does not support ACPI HIDs & CIDs.
318 * e.g. for a device with hid:IBM0001 and cid:ACPI0001 you get:
319 * "acpi:IBM0001:ACPI0001"
320 */
321int acpi_device_uevent_modalias(struct device *dev, struct kobj_uevent_env *env)
322{
323 return __acpi_device_uevent_modalias(acpi_companion_match(dev), env);
324}
325EXPORT_SYMBOL_GPL(acpi_device_uevent_modalias);
326
327static int __acpi_device_modalias(struct acpi_device *adev, char *buf, int size)
328{
329 int len, count;
330
331 if (!adev)
332 return -ENODEV;
333
334 if (list_empty(&adev->pnp.ids))
335 return 0;
336
337 len = create_pnp_modalias(adev, buf, size - 1);
338 if (len < 0) {
339 return len;
340 } else if (len > 0) {
341 buf[len++] = '\n';
342 size -= len;
343 }
344 if (!adev->data.of_compatible)
345 return len;
346
347 count = create_of_modalias(adev, buf + len, size - 1);
348 if (count < 0) {
349 return count;
350 } else if (count > 0) {
351 len += count;
352 buf[len++] = '\n';
353 }
354
355 return len;
356}
357
358/*
359 * Creates modalias sysfs attribute for ACPI enumerated devices.
360 * Because the other buses does not support ACPI HIDs & CIDs.
361 * e.g. for a device with hid:IBM0001 and cid:ACPI0001 you get:
362 * "acpi:IBM0001:ACPI0001"
363 */
364int acpi_device_modalias(struct device *dev, char *buf, int size)
365{
366 return __acpi_device_modalias(acpi_companion_match(dev), buf, size);
367}
368EXPORT_SYMBOL_GPL(acpi_device_modalias);
369
370static ssize_t
371acpi_device_modalias_show(struct device *dev, struct device_attribute *attr, char *buf) {
372 return __acpi_device_modalias(to_acpi_device(dev), buf, 1024);
373}
374static DEVICE_ATTR(modalias, 0444, acpi_device_modalias_show, NULL);
375
376bool acpi_scan_is_offline(struct acpi_device *adev, bool uevent) 168bool acpi_scan_is_offline(struct acpi_device *adev, bool uevent)
377{ 169{
378 struct acpi_device_physical_node *pn; 170 struct acpi_device_physical_node *pn;
@@ -701,279 +493,6 @@ void acpi_device_hotplug(struct acpi_device *adev, u32 src)
701 unlock_device_hotplug(); 493 unlock_device_hotplug();
702} 494}
703 495
704static ssize_t real_power_state_show(struct device *dev,
705 struct device_attribute *attr, char *buf)
706{
707 struct acpi_device *adev = to_acpi_device(dev);
708 int state;
709 int ret;
710
711 ret = acpi_device_get_power(adev, &state);
712 if (ret)
713 return ret;
714
715 return sprintf(buf, "%s\n", acpi_power_state_string(state));
716}
717
718static DEVICE_ATTR(real_power_state, 0444, real_power_state_show, NULL);
719
720static ssize_t power_state_show(struct device *dev,
721 struct device_attribute *attr, char *buf)
722{
723 struct acpi_device *adev = to_acpi_device(dev);
724
725 return sprintf(buf, "%s\n", acpi_power_state_string(adev->power.state));
726}
727
728static DEVICE_ATTR(power_state, 0444, power_state_show, NULL);
729
730static ssize_t
731acpi_eject_store(struct device *d, struct device_attribute *attr,
732 const char *buf, size_t count)
733{
734 struct acpi_device *acpi_device = to_acpi_device(d);
735 acpi_object_type not_used;
736 acpi_status status;
737
738 if (!count || buf[0] != '1')
739 return -EINVAL;
740
741 if ((!acpi_device->handler || !acpi_device->handler->hotplug.enabled)
742 && !acpi_device->driver)
743 return -ENODEV;
744
745 status = acpi_get_type(acpi_device->handle, &not_used);
746 if (ACPI_FAILURE(status) || !acpi_device->flags.ejectable)
747 return -ENODEV;
748
749 get_device(&acpi_device->dev);
750 status = acpi_hotplug_schedule(acpi_device, ACPI_OST_EC_OSPM_EJECT);
751 if (ACPI_SUCCESS(status))
752 return count;
753
754 put_device(&acpi_device->dev);
755 acpi_evaluate_ost(acpi_device->handle, ACPI_OST_EC_OSPM_EJECT,
756 ACPI_OST_SC_NON_SPECIFIC_FAILURE, NULL);
757 return status == AE_NO_MEMORY ? -ENOMEM : -EAGAIN;
758}
759
760static DEVICE_ATTR(eject, 0200, NULL, acpi_eject_store);
761
762static ssize_t
763acpi_device_hid_show(struct device *dev, struct device_attribute *attr, char *buf) {
764 struct acpi_device *acpi_dev = to_acpi_device(dev);
765
766 return sprintf(buf, "%s\n", acpi_device_hid(acpi_dev));
767}
768static DEVICE_ATTR(hid, 0444, acpi_device_hid_show, NULL);
769
770static ssize_t acpi_device_uid_show(struct device *dev,
771 struct device_attribute *attr, char *buf)
772{
773 struct acpi_device *acpi_dev = to_acpi_device(dev);
774
775 return sprintf(buf, "%s\n", acpi_dev->pnp.unique_id);
776}
777static DEVICE_ATTR(uid, 0444, acpi_device_uid_show, NULL);
778
779static ssize_t acpi_device_adr_show(struct device *dev,
780 struct device_attribute *attr, char *buf)
781{
782 struct acpi_device *acpi_dev = to_acpi_device(dev);
783
784 return sprintf(buf, "0x%08x\n",
785 (unsigned int)(acpi_dev->pnp.bus_address));
786}
787static DEVICE_ATTR(adr, 0444, acpi_device_adr_show, NULL);
788
789static ssize_t
790acpi_device_path_show(struct device *dev, struct device_attribute *attr, char *buf) {
791 struct acpi_device *acpi_dev = to_acpi_device(dev);
792 struct acpi_buffer path = {ACPI_ALLOCATE_BUFFER, NULL};
793 int result;
794
795 result = acpi_get_name(acpi_dev->handle, ACPI_FULL_PATHNAME, &path);
796 if (result)
797 goto end;
798
799 result = sprintf(buf, "%s\n", (char*)path.pointer);
800 kfree(path.pointer);
801end:
802 return result;
803}
804static DEVICE_ATTR(path, 0444, acpi_device_path_show, NULL);
805
806/* sysfs file that shows description text from the ACPI _STR method */
807static ssize_t description_show(struct device *dev,
808 struct device_attribute *attr,
809 char *buf) {
810 struct acpi_device *acpi_dev = to_acpi_device(dev);
811 int result;
812
813 if (acpi_dev->pnp.str_obj == NULL)
814 return 0;
815
816 /*
817 * The _STR object contains a Unicode identifier for a device.
818 * We need to convert to utf-8 so it can be displayed.
819 */
820 result = utf16s_to_utf8s(
821 (wchar_t *)acpi_dev->pnp.str_obj->buffer.pointer,
822 acpi_dev->pnp.str_obj->buffer.length,
823 UTF16_LITTLE_ENDIAN, buf,
824 PAGE_SIZE);
825
826 buf[result++] = '\n';
827
828 return result;
829}
830static DEVICE_ATTR(description, 0444, description_show, NULL);
831
832static ssize_t
833acpi_device_sun_show(struct device *dev, struct device_attribute *attr,
834 char *buf) {
835 struct acpi_device *acpi_dev = to_acpi_device(dev);
836 acpi_status status;
837 unsigned long long sun;
838
839 status = acpi_evaluate_integer(acpi_dev->handle, "_SUN", NULL, &sun);
840 if (ACPI_FAILURE(status))
841 return -ENODEV;
842
843 return sprintf(buf, "%llu\n", sun);
844}
845static DEVICE_ATTR(sun, 0444, acpi_device_sun_show, NULL);
846
847static ssize_t status_show(struct device *dev, struct device_attribute *attr,
848 char *buf) {
849 struct acpi_device *acpi_dev = to_acpi_device(dev);
850 acpi_status status;
851 unsigned long long sta;
852
853 status = acpi_evaluate_integer(acpi_dev->handle, "_STA", NULL, &sta);
854 if (ACPI_FAILURE(status))
855 return -ENODEV;
856
857 return sprintf(buf, "%llu\n", sta);
858}
859static DEVICE_ATTR_RO(status);
860
861static int acpi_device_setup_files(struct acpi_device *dev)
862{
863 struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
864 acpi_status status;
865 int result = 0;
866
867 /*
868 * Devices gotten from FADT don't have a "path" attribute
869 */
870 if (dev->handle) {
871 result = device_create_file(&dev->dev, &dev_attr_path);
872 if (result)
873 goto end;
874 }
875
876 if (!list_empty(&dev->pnp.ids)) {
877 result = device_create_file(&dev->dev, &dev_attr_hid);
878 if (result)
879 goto end;
880
881 result = device_create_file(&dev->dev, &dev_attr_modalias);
882 if (result)
883 goto end;
884 }
885
886 /*
887 * If device has _STR, 'description' file is created
888 */
889 if (acpi_has_method(dev->handle, "_STR")) {
890 status = acpi_evaluate_object(dev->handle, "_STR",
891 NULL, &buffer);
892 if (ACPI_FAILURE(status))
893 buffer.pointer = NULL;
894 dev->pnp.str_obj = buffer.pointer;
895 result = device_create_file(&dev->dev, &dev_attr_description);
896 if (result)
897 goto end;
898 }
899
900 if (dev->pnp.type.bus_address)
901 result = device_create_file(&dev->dev, &dev_attr_adr);
902 if (dev->pnp.unique_id)
903 result = device_create_file(&dev->dev, &dev_attr_uid);
904
905 if (acpi_has_method(dev->handle, "_SUN")) {
906 result = device_create_file(&dev->dev, &dev_attr_sun);
907 if (result)
908 goto end;
909 }
910
911 if (acpi_has_method(dev->handle, "_STA")) {
912 result = device_create_file(&dev->dev, &dev_attr_status);
913 if (result)
914 goto end;
915 }
916
917 /*
918 * If device has _EJ0, 'eject' file is created that is used to trigger
919 * hot-removal function from userland.
920 */
921 if (acpi_has_method(dev->handle, "_EJ0")) {
922 result = device_create_file(&dev->dev, &dev_attr_eject);
923 if (result)
924 return result;
925 }
926
927 if (dev->flags.power_manageable) {
928 result = device_create_file(&dev->dev, &dev_attr_power_state);
929 if (result)
930 return result;
931
932 if (dev->power.flags.power_resources)
933 result = device_create_file(&dev->dev,
934 &dev_attr_real_power_state);
935 }
936
937end:
938 return result;
939}
940
941static void acpi_device_remove_files(struct acpi_device *dev)
942{
943 if (dev->flags.power_manageable) {
944 device_remove_file(&dev->dev, &dev_attr_power_state);
945 if (dev->power.flags.power_resources)
946 device_remove_file(&dev->dev,
947 &dev_attr_real_power_state);
948 }
949
950 /*
951 * If device has _STR, remove 'description' file
952 */
953 if (acpi_has_method(dev->handle, "_STR")) {
954 kfree(dev->pnp.str_obj);
955 device_remove_file(&dev->dev, &dev_attr_description);
956 }
957 /*
958 * If device has _EJ0, remove 'eject' file.
959 */
960 if (acpi_has_method(dev->handle, "_EJ0"))
961 device_remove_file(&dev->dev, &dev_attr_eject);
962
963 if (acpi_has_method(dev->handle, "_SUN"))
964 device_remove_file(&dev->dev, &dev_attr_sun);
965
966 if (dev->pnp.unique_id)
967 device_remove_file(&dev->dev, &dev_attr_uid);
968 if (dev->pnp.type.bus_address)
969 device_remove_file(&dev->dev, &dev_attr_adr);
970 device_remove_file(&dev->dev, &dev_attr_modalias);
971 device_remove_file(&dev->dev, &dev_attr_hid);
972 if (acpi_has_method(dev->handle, "_STA"))
973 device_remove_file(&dev->dev, &dev_attr_status);
974 if (dev->handle)
975 device_remove_file(&dev->dev, &dev_attr_path);
976}
977/* -------------------------------------------------------------------------- 496/* --------------------------------------------------------------------------
978 ACPI Bus operations 497 ACPI Bus operations
979 -------------------------------------------------------------------------- */ 498 -------------------------------------------------------------------------- */