]> git.proxmox.com Git - mirror_ubuntu-zesty-kernel.git/blob - drivers/acpi/device_sysfs.c
Merge branches 'pm-cpu', 'pm-cpuidle' and 'pm-domains'
[mirror_ubuntu-zesty-kernel.git] / drivers / acpi / device_sysfs.c
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 }