OLD | NEW |
1 /* | 1 /* |
2 * chromeos_acpi.c - ChromeOS specific ACPI support | 2 * chromeos_acpi.c - ChromeOS specific ACPI support |
3 * | 3 * |
4 * | 4 * |
5 * Copyright (C) 2011 The Chromium OS Authors | 5 * Copyright (C) 2011 The Chromium OS Authors |
6 * | 6 * |
7 * This program is free software; you can redistribute it and/or modify | 7 * This program is free software; you can redistribute it and/or modify |
8 * it under the terms of the GNU General Public License as published by | 8 * it under the terms of the GNU General Public License as published by |
9 * the Free Software Foundation; either version 2 of the License, or | 9 * the Free Software Foundation; either version 2 of the License, or |
10 * (at your option) any later version. | 10 * (at your option) any later version. |
(...skipping 18 matching lines...) Expand all Loading... |
29 * All values are presented in the string form (numbers as decimal values) and | 29 * All values are presented in the string form (numbers as decimal values) and |
30 * can be accessed as the contents of the appropriate read only files in the | 30 * can be accessed as the contents of the appropriate read only files in the |
31 * sysfs directory tree originating in /sys/devices/platform/chromeos_acpi. | 31 * sysfs directory tree originating in /sys/devices/platform/chromeos_acpi. |
32 */ | 32 */ |
33 | 33 |
34 #include <linux/kernel.h> | 34 #include <linux/kernel.h> |
35 #include <linux/module.h> | 35 #include <linux/module.h> |
36 #include <linux/platform_device.h> | 36 #include <linux/platform_device.h> |
37 #include <linux/acpi.h> | 37 #include <linux/acpi.h> |
38 | 38 |
39 MODULE_AUTHOR("Google Inc."); | 39 #include "chromeos_acpi.h" |
40 MODULE_DESCRIPTION("Chrome OS Extras Driver"); | |
41 MODULE_LICENSE("GPL"); | |
42 | 40 |
43 #define MY_LOGPREFIX "chromeos_acpi: " | 41 #define MY_LOGPREFIX "chromeos_acpi: " |
44 #define MY_ERR KERN_ERR MY_LOGPREFIX | 42 #define MY_ERR KERN_ERR MY_LOGPREFIX |
45 #define MY_NOTICE KERN_NOTICE MY_LOGPREFIX | 43 #define MY_NOTICE KERN_NOTICE MY_LOGPREFIX |
46 #define MY_INFO KERN_INFO MY_LOGPREFIX | 44 #define MY_INFO KERN_INFO MY_LOGPREFIX |
47 | 45 |
48 /* ACPI method name for MLST; the response for this method is a | 46 /* ACPI method name for MLST; the response for this method is a |
49 * package of strings listing the methods which should be reflected in | 47 * package of strings listing the methods which should be reflected in |
50 * sysfs. */ | 48 * sysfs. */ |
51 #define MLST_METHOD "MLST" | 49 #define MLST_METHOD "MLST" |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
106 */ | 104 */ |
107 struct chromeos_acpi_dev { | 105 struct chromeos_acpi_dev { |
108 struct platform_device *p_dev; | 106 struct platform_device *p_dev; |
109 struct acpi_attribute *attributes; | 107 struct acpi_attribute *attributes; |
110 struct acpi_attribute_group *groups; | 108 struct acpi_attribute_group *groups; |
111 }; | 109 }; |
112 | 110 |
113 static struct chromeos_acpi_dev chromeos_acpi = { }; | 111 static struct chromeos_acpi_dev chromeos_acpi = { }; |
114 | 112 |
115 | 113 |
116 /* Values set at probe time */ | |
117 int chromeos_acpi_chnv = -1; | |
118 int chromeos_acpi_chsw = -1; | |
119 | |
120 bool chromeos_acpi_available; | |
121 | |
122 | |
123 /* | 114 /* |
124 * To show attribute value just access the container structure's `value' | 115 * To show attribute value just access the container structure's `value' |
125 * field. | 116 * field. |
126 */ | 117 */ |
127 static ssize_t show_acpi_attribute(struct device *dev, | 118 static ssize_t show_acpi_attribute(struct device *dev, |
128 struct device_attribute *attr, char *buf) | 119 struct device_attribute *attr, char *buf) |
129 { | 120 { |
130 struct acpi_attribute *paa; | 121 struct acpi_attribute *paa; |
131 | 122 |
132 paa = container_of(attr, struct acpi_attribute, dev_attr); | 123 paa = container_of(attr, struct acpi_attribute, dev_attr); |
(...skipping 194 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
327 element->type); | 318 element->type); |
328 continue; | 319 continue; |
329 } | 320 } |
330 aag->ag.attrs[j++] = &paa->dev_attr.attr; | 321 aag->ag.attrs[j++] = &paa->dev_attr.attr; |
331 } | 322 } |
332 | 323 |
333 if (sysfs_create_group(&chromeos_acpi.p_dev->dev.kobj, &aag->ag)) | 324 if (sysfs_create_group(&chromeos_acpi.p_dev->dev.kobj, &aag->ag)) |
334 printk(MY_ERR "failed to create group %s.%d\n", pm, instance); | 325 printk(MY_ERR "failed to create group %s.%d\n", pm, instance); |
335 } | 326 } |
336 | 327 |
| 328 |
| 329 #ifdef CONFIG_CHROMEOS |
337 /* | 330 /* |
338 * handle_single_int() extract a single int value | 331 * handle_single_int() extract a single int value |
339 * | 332 * |
340 * @po: package contents as returned by ACPI | 333 * @po: package contents as returned by ACPI |
341 * @found: integer pointer to store the value in | 334 * @found: integer pointer to store the value in |
342 * | 335 * |
343 */ | 336 */ |
344 static void handle_single_int(union acpi_object *po, int *found) | 337 static void handle_single_int(union acpi_object *po, int *found) |
345 { | 338 { |
346 union acpi_object *element = po->package.elements; | 339 union acpi_object *element = po->package.elements; |
347 | 340 |
348 if (!element) { | 341 if (!element) { |
349 WARN_ON(1); | 342 WARN_ON(1); |
350 return; | 343 return; |
351 } | 344 } |
352 | 345 |
353 if (element->type == ACPI_TYPE_INTEGER) | 346 if (element->type == ACPI_TYPE_INTEGER) |
354 *found = (int) element->integer.value; | 347 *found = (int) element->integer.value; |
355 else | 348 else |
356 printk(MY_ERR "acpi_object unexpected type %d, expected int\n", | 349 printk(MY_ERR "acpi_object unexpected type %d, expected int\n", |
357 element->type); | 350 element->type); |
358 } | 351 } |
359 | 352 #endif |
360 | 353 |
361 /* | 354 /* |
362 * handle_acpi_package() create sysfs group including attributes | 355 * handle_acpi_package() create sysfs group including attributes |
363 * representing an ACPI package. | 356 * representing an ACPI package. |
364 * | 357 * |
365 * @po: package contents as returned by ACPI | 358 * @po: package contents as returned by ACPI |
366 * @pm: name of the group | 359 * @pm: name of the group |
367 * | 360 * |
368 * Scalar objects included in the package get sys fs attributes created for | 361 * Scalar objects included in the package get sys fs attributes created for |
369 * them. Nested packages are passed to a function creating a sys fs group per | 362 * them. Nested packages are passed to a function creating a sys fs group per |
(...skipping 16 matching lines...) Expand all Loading... |
386 break; | 379 break; |
387 | 380 |
388 case ACPI_TYPE_STRING: | 381 case ACPI_TYPE_STRING: |
389 copy_size = min(element->string.length, | 382 copy_size = min(element->string.length, |
390 sizeof(attr_value) - 1); | 383 sizeof(attr_value) - 1); |
391 memcpy(attr_value, element->string.pointer, copy_size); | 384 memcpy(attr_value, element->string.pointer, copy_size); |
392 attr_value[copy_size] = '\0'; | 385 attr_value[copy_size] = '\0'; |
393 add_sysfs_attribute(attr_value, pm, count, j); | 386 add_sysfs_attribute(attr_value, pm, count, j); |
394 break; | 387 break; |
395 | 388 |
| 389 case ACPI_TYPE_BUFFER: { |
| 390 char *base, *p; |
| 391 int i; |
| 392 unsigned room_left; |
| 393 /* Include this many characters per line */ |
| 394 unsigned char_per_line = 16; |
| 395 unsigned string_buffer_size = |
| 396 /* three characters to display one byte */ |
| 397 element->buffer.length * 3 + |
| 398 /* one newline per line, all rounded up, plus |
| 399 * extra newline in the end, plus terminating |
| 400 * zero, hence + 4 |
| 401 */ |
| 402 element->buffer.length/char_per_line + 4; |
| 403 |
| 404 if (string_buffer_size > sizeof(attr_value)) { |
| 405 p = kzalloc(string_buffer_size, GFP_KERNEL); |
| 406 if (!p) { |
| 407 printk(MY_ERR "out of memory in %s!\n", |
| 408 __func__); |
| 409 break; |
| 410 } |
| 411 } else { |
| 412 p = attr_value; |
| 413 } |
| 414 |
| 415 base = p; |
| 416 room_left = string_buffer_size; |
| 417 for (i = 0; i < element->buffer.length; i++) { |
| 418 int printed; |
| 419 printed = snprintf(p, room_left, " %2.2x", |
| 420 element->buffer.pointer[i]); |
| 421 room_left -= printed; |
| 422 p += printed; |
| 423 if (((i + 1) % char_per_line) == 0) { |
| 424 if (!room_left) |
| 425 break; |
| 426 room_left--; |
| 427 *p++ = '\n'; |
| 428 } |
| 429 } |
| 430 if (room_left < 2) { |
| 431 printk(MY_ERR "%s: no room in the buffer!\n", |
| 432 __func__); |
| 433 *p = '\0'; |
| 434 } else { |
| 435 *p++ = '\n'; |
| 436 *p++ = '\0'; |
| 437 } |
| 438 add_sysfs_attribute(base, pm, count, j); |
| 439 if (string_buffer_size > sizeof(attr_value)) |
| 440 kfree(p); |
| 441 break; |
| 442 } |
396 case ACPI_TYPE_PACKAGE: | 443 case ACPI_TYPE_PACKAGE: |
397 handle_nested_acpi_package(element, pm, count, j); | 444 handle_nested_acpi_package(element, pm, count, j); |
398 break; | 445 break; |
399 | 446 |
400 default: | 447 default: |
401 » » » printk(MY_ERR "ignoring type %d\n", element->type); | 448 » » » printk(MY_ERR "ignoring type %d (%s)\n", |
| 449 » » » element->type, pm); |
402 break; | 450 break; |
403 } | 451 } |
404 } | 452 } |
405 } | 453 } |
406 | 454 |
407 | 455 |
408 /* | 456 /* |
409 * add_acpi_method() evaluate an ACPI method and create sysfs attributes. | 457 * add_acpi_method() evaluate an ACPI method and create sysfs attributes. |
410 * | 458 * |
411 * @device: ACPI device | 459 * @device: ACPI device |
(...skipping 14 matching lines...) Expand all Loading... |
426 printk(MY_ERR "failed to retrieve %s (%d)\n", pm, status); | 474 printk(MY_ERR "failed to retrieve %s (%d)\n", pm, status); |
427 return; | 475 return; |
428 } | 476 } |
429 | 477 |
430 po = output.pointer; | 478 po = output.pointer; |
431 | 479 |
432 if (po->type != ACPI_TYPE_PACKAGE) | 480 if (po->type != ACPI_TYPE_PACKAGE) |
433 printk(MY_ERR "%s is not a package, ignored\n", pm); | 481 printk(MY_ERR "%s is not a package, ignored\n", pm); |
434 else | 482 else |
435 handle_acpi_package(po, pm); | 483 handle_acpi_package(po, pm); |
436 | 484 #ifdef CONFIG_CHROMEOS |
437 /* Need to export a couple of variables to chromeos.c */ | 485 /* Need to export a couple of variables to chromeos.c */ |
438 if (!strncmp(pm, "CHNV", 4)) | 486 if (!strncmp(pm, "CHNV", 4)) |
439 handle_single_int(po, &chromeos_acpi_chnv); | 487 handle_single_int(po, &chromeos_acpi_chnv); |
440 else if (!strncmp(pm, "CHSW", 4)) | 488 else if (!strncmp(pm, "CHSW", 4)) |
441 handle_single_int(po, &chromeos_acpi_chsw); | 489 handle_single_int(po, &chromeos_acpi_chsw); |
442 | 490 #endif |
443 kfree(output.pointer); | 491 kfree(output.pointer); |
444 } | 492 } |
445 | 493 |
446 /* | 494 /* |
447 * chromeos_process_mlst() Evaluate the MLST method and add methods listed | 495 * chromeos_process_mlst() Evaluate the MLST method and add methods listed |
448 * in the response. | 496 * in the response. |
449 * | 497 * |
450 * @device: ACPI device | 498 * @device: ACPI device |
451 * | 499 * |
452 * Returns: 0 if successful, non-zero if error. | 500 * Returns: 0 if successful, non-zero if error. |
(...skipping 22 matching lines...) Expand all Loading... |
475 kfree(output.pointer); | 523 kfree(output.pointer); |
476 return -EINVAL; | 524 return -EINVAL; |
477 } | 525 } |
478 | 526 |
479 for (j = 0; j < po->package.count; j++) { | 527 for (j = 0; j < po->package.count; j++) { |
480 union acpi_object *element = po->package.elements + j; | 528 union acpi_object *element = po->package.elements + j; |
481 int copy_size = 0; | 529 int copy_size = 0; |
482 char method[ACPI_NAME_SIZE + 1]; | 530 char method[ACPI_NAME_SIZE + 1]; |
483 | 531 |
484 if (element->type == ACPI_TYPE_STRING) { | 532 if (element->type == ACPI_TYPE_STRING) { |
485 » » » copy_size = min(element->string.length, ACPI_NAME_SIZE); | 533 » » » copy_size = min(element->string.length, |
| 534 » » » » » (u32)ACPI_NAME_SIZE); |
486 memcpy(method, element->string.pointer, copy_size); | 535 memcpy(method, element->string.pointer, copy_size); |
487 method[copy_size] = '\0'; | 536 method[copy_size] = '\0'; |
488 add_acpi_method(device, method); | 537 add_acpi_method(device, method); |
489 } else { | 538 } else { |
490 pr_debug(MY_LOGPREFIX "ignoring type %d\n", | 539 pr_debug(MY_LOGPREFIX "ignoring type %d\n", |
491 element->type); | 540 element->type); |
492 } | 541 } |
493 } | 542 } |
494 | 543 |
495 kfree(output.pointer); | 544 kfree(output.pointer); |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
531 } | 580 } |
532 | 581 |
533 ret = acpi_bus_register_driver(&chromeos_acpi_driver); | 582 ret = acpi_bus_register_driver(&chromeos_acpi_driver); |
534 if (ret < 0) { | 583 if (ret < 0) { |
535 printk(MY_ERR "failed to register driver (%d)\n", ret); | 584 printk(MY_ERR "failed to register driver (%d)\n", ret); |
536 platform_device_unregister(chromeos_acpi.p_dev); | 585 platform_device_unregister(chromeos_acpi.p_dev); |
537 chromeos_acpi.p_dev = NULL; | 586 chromeos_acpi.p_dev = NULL; |
538 return ret; | 587 return ret; |
539 } | 588 } |
540 | 589 |
| 590 #ifdef CONFIG_CHROMEOS |
541 chromeos_acpi_available = true; | 591 chromeos_acpi_available = true; |
542 | 592 #endif |
543 return 0; | 593 return 0; |
544 } | 594 } |
545 subsys_initcall(chromeos_acpi_init); | 595 |
| 596 static void chromeos_acpi_exit(void) |
| 597 { |
| 598 #ifdef CONFIG_CHROMEOS |
| 599 » chromeos_acpi_available = false; |
| 600 #endif |
| 601 » acpi_bus_unregister_driver(&chromeos_acpi_driver); |
| 602 |
| 603 » while (chromeos_acpi.groups) { |
| 604 » » struct acpi_attribute_group *aag; |
| 605 » » aag = chromeos_acpi.groups; |
| 606 » » chromeos_acpi.groups = aag->next_acpi_attr_group; |
| 607 » » sysfs_remove_group(&chromeos_acpi.p_dev->dev.kobj, &aag->ag); |
| 608 » » kfree(aag); |
| 609 » } |
| 610 |
| 611 » while (chromeos_acpi.attributes) { |
| 612 » » struct acpi_attribute *aa = chromeos_acpi.attributes; |
| 613 » » chromeos_acpi.attributes = aa->next_acpi_attr; |
| 614 » » device_remove_file(&chromeos_acpi.p_dev->dev, &aa->dev_attr); |
| 615 » » kfree(aa); |
| 616 » } |
| 617 |
| 618 » platform_device_unregister(chromeos_acpi.p_dev); |
| 619 » printk(MY_INFO "removed\n"); |
| 620 } |
| 621 |
| 622 module_init(chromeos_acpi_init); |
| 623 module_exit(chromeos_acpi_exit); |
| 624 |
| 625 MODULE_LICENSE("GPL"); |
| 626 MODULE_AUTHOR("Google Inc."); |
| 627 MODULE_DESCRIPTION("Chrome OS ACPI Driver"); |
OLD | NEW |