Chromium Code Reviews| 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 #include "chromeos_acpi.h" | |
| 40 | |
| 39 MODULE_AUTHOR("Google Inc."); | 41 MODULE_AUTHOR("Google Inc."); |
| 40 MODULE_DESCRIPTION("Chrome OS Extras Driver"); | 42 MODULE_DESCRIPTION("Chrome OS Extras Driver"); |
| 41 MODULE_LICENSE("GPL"); | 43 MODULE_LICENSE("GPL"); |
| 42 | 44 |
| 43 #define MY_LOGPREFIX "chromeos_acpi: " | 45 #define MY_LOGPREFIX "chromeos_acpi: " |
| 44 #define MY_ERR KERN_ERR MY_LOGPREFIX | 46 #define MY_ERR KERN_ERR MY_LOGPREFIX |
| 45 #define MY_NOTICE KERN_NOTICE MY_LOGPREFIX | 47 #define MY_NOTICE KERN_NOTICE MY_LOGPREFIX |
| 46 #define MY_INFO KERN_INFO MY_LOGPREFIX | 48 #define MY_INFO KERN_INFO MY_LOGPREFIX |
| 47 | 49 |
| 48 /* ACPI method name for MLST; the response for this method is a | 50 /* ACPI method name for MLST; the response for this method is a |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 106 */ | 108 */ |
| 107 struct chromeos_acpi_dev { | 109 struct chromeos_acpi_dev { |
| 108 struct platform_device *p_dev; | 110 struct platform_device *p_dev; |
| 109 struct acpi_attribute *attributes; | 111 struct acpi_attribute *attributes; |
| 110 struct acpi_attribute_group *groups; | 112 struct acpi_attribute_group *groups; |
| 111 }; | 113 }; |
| 112 | 114 |
| 113 static struct chromeos_acpi_dev chromeos_acpi = { }; | 115 static struct chromeos_acpi_dev chromeos_acpi = { }; |
| 114 | 116 |
| 115 | 117 |
| 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 /* | 118 /* |
| 124 * To show attribute value just access the container structure's `value' | 119 * To show attribute value just access the container structure's `value' |
| 125 * field. | 120 * field. |
| 126 */ | 121 */ |
| 127 static ssize_t show_acpi_attribute(struct device *dev, | 122 static ssize_t show_acpi_attribute(struct device *dev, |
| 128 struct device_attribute *attr, char *buf) | 123 struct device_attribute *attr, char *buf) |
| 129 { | 124 { |
| 130 struct acpi_attribute *paa; | 125 struct acpi_attribute *paa; |
| 131 | 126 |
| 132 paa = container_of(attr, struct acpi_attribute, dev_attr); | 127 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); | 322 element->type); |
| 328 continue; | 323 continue; |
| 329 } | 324 } |
| 330 aag->ag.attrs[j++] = &paa->dev_attr.attr; | 325 aag->ag.attrs[j++] = &paa->dev_attr.attr; |
| 331 } | 326 } |
| 332 | 327 |
| 333 if (sysfs_create_group(&chromeos_acpi.p_dev->dev.kobj, &aag->ag)) | 328 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); | 329 printk(MY_ERR "failed to create group %s.%d\n", pm, instance); |
| 335 } | 330 } |
| 336 | 331 |
| 332 | |
| 333 #ifdef CONFIG_CHROMEOS | |
|
Olof Johansson
2011/03/14 21:24:32
It would be preferred to just change the Kconfig t
vb
2011/03/14 22:00:04
I am not sure I follow: this code is not needed un
Olof Johansson
2011/03/14 22:28:47
There's not much use in using CONFIG_CHROMEOS_ACPI
vb
2011/03/14 22:55:25
Ah, that's exactly the thing: the case like now, w
| |
| 337 /* | 334 /* |
| 338 * handle_single_int() extract a single int value | 335 * handle_single_int() extract a single int value |
| 339 * | 336 * |
| 340 * @po: package contents as returned by ACPI | 337 * @po: package contents as returned by ACPI |
| 341 * @found: integer pointer to store the value in | 338 * @found: integer pointer to store the value in |
| 342 * | 339 * |
| 343 */ | 340 */ |
| 344 static void handle_single_int(union acpi_object *po, int *found) | 341 static void handle_single_int(union acpi_object *po, int *found) |
| 345 { | 342 { |
| 346 union acpi_object *element = po->package.elements; | 343 union acpi_object *element = po->package.elements; |
| 347 | 344 |
| 348 if (!element) { | 345 if (!element) { |
| 349 WARN_ON(1); | 346 WARN_ON(1); |
| 350 return; | 347 return; |
| 351 } | 348 } |
| 352 | 349 |
| 353 if (element->type == ACPI_TYPE_INTEGER) | 350 if (element->type == ACPI_TYPE_INTEGER) |
| 354 *found = (int) element->integer.value; | 351 *found = (int) element->integer.value; |
| 355 else | 352 else |
| 356 printk(MY_ERR "acpi_object unexpected type %d, expected int\n", | 353 printk(MY_ERR "acpi_object unexpected type %d, expected int\n", |
| 357 element->type); | 354 element->type); |
| 358 } | 355 } |
| 359 | 356 #endif |
| 360 | 357 |
| 361 /* | 358 /* |
| 362 * handle_acpi_package() create sysfs group including attributes | 359 * handle_acpi_package() create sysfs group including attributes |
| 363 * representing an ACPI package. | 360 * representing an ACPI package. |
| 364 * | 361 * |
| 365 * @po: package contents as returned by ACPI | 362 * @po: package contents as returned by ACPI |
| 366 * @pm: name of the group | 363 * @pm: name of the group |
| 367 * | 364 * |
| 368 * Scalar objects included in the package get sys fs attributes created for | 365 * 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 | 366 * them. Nested packages are passed to a function creating a sys fs group per |
| (...skipping 16 matching lines...) Expand all Loading... | |
| 386 break; | 383 break; |
| 387 | 384 |
| 388 case ACPI_TYPE_STRING: | 385 case ACPI_TYPE_STRING: |
| 389 copy_size = min(element->string.length, | 386 copy_size = min(element->string.length, |
| 390 sizeof(attr_value) - 1); | 387 sizeof(attr_value) - 1); |
| 391 memcpy(attr_value, element->string.pointer, copy_size); | 388 memcpy(attr_value, element->string.pointer, copy_size); |
| 392 attr_value[copy_size] = '\0'; | 389 attr_value[copy_size] = '\0'; |
| 393 add_sysfs_attribute(attr_value, pm, count, j); | 390 add_sysfs_attribute(attr_value, pm, count, j); |
| 394 break; | 391 break; |
| 395 | 392 |
| 393 case ACPI_TYPE_BUFFER: { | |
| 394 char *base, *p; | |
| 395 int i; | |
| 396 unsigned room_left; | |
| 397 /* Include this many characters per line */ | |
| 398 unsigned char_per_line = 16; | |
| 399 unsigned string_buffer_size = | |
| 400 /* three characters to display one byte */ | |
| 401 element->buffer.length * 3 + | |
| 402 /* one newline per line, all rounded up, plust | |
|
Randall Spangler
2011/03/14 21:22:28
plust?
vb
2011/03/14 22:00:04
Done.
| |
| 403 * extra newline in the end, plus terminating | |
| 404 * zero, hence + 4 | |
| 405 */ | |
| 406 element->buffer.length/char_per_line + 4; | |
| 407 | |
| 408 if (string_buffer_size > sizeof(attr_value)) { | |
| 409 p = kzalloc(string_buffer_size, GFP_KERNEL); | |
| 410 if (!p) { | |
| 411 printk(MY_ERR "out of memory in %s!\n", | |
| 412 __func__); | |
| 413 break; | |
| 414 } | |
| 415 } else { | |
| 416 p = attr_value; | |
| 417 } | |
| 418 | |
| 419 base = p; | |
| 420 room_left = string_buffer_size; | |
| 421 for (i = 0; i < element->buffer.length; i++) { | |
| 422 int printed; | |
| 423 printed = snprintf(p, room_left, " %2.2x", | |
| 424 element->buffer.pointer[i]); | |
| 425 room_left -= printed; | |
| 426 p += printed; | |
| 427 if (((i + 1) % char_per_line) == 0) { | |
|
Randall Spangler
2011/03/14 21:22:28
Check for room_left != 0
If somehow printed==room
vb
2011/03/14 22:00:04
Done.
| |
| 428 room_left--; | |
| 429 *p++ = '\n'; | |
| 430 } | |
| 431 } | |
| 432 *p++ = '\n'; | |
|
Randall Spangler
2011/03/14 21:22:28
Same paranoia here - check room_left>=2
vb
2011/03/14 22:00:04
Done.
| |
| 433 *p++ = '\0'; | |
| 434 add_sysfs_attribute(base, pm, count, j); | |
| 435 if (string_buffer_size > sizeof(attr_value)) | |
| 436 kfree(p); | |
| 437 break; | |
| 438 } | |
|
Olof Johansson
2011/03/14 21:24:32
It is common practice to pass the binary data over
vb
2011/03/14 22:00:04
This would be a much larger change, because as of
Olof Johansson
2011/03/14 22:28:47
SGTM
vb
2011/03/14 22:55:25
opened
http://code.google.com/p/chromium-os/issue
| |
| 396 case ACPI_TYPE_PACKAGE: | 439 case ACPI_TYPE_PACKAGE: |
| 397 handle_nested_acpi_package(element, pm, count, j); | 440 handle_nested_acpi_package(element, pm, count, j); |
| 398 break; | 441 break; |
| 399 | 442 |
| 400 default: | 443 default: |
| 401 » » » printk(MY_ERR "ignoring type %d\n", element->type); | 444 » » » printk(MY_ERR "ignoring type %d (%s)\n", |
| 445 » » » element->type, pm); | |
| 402 break; | 446 break; |
| 403 } | 447 } |
| 404 } | 448 } |
| 405 } | 449 } |
| 406 | 450 |
| 407 | 451 |
| 408 /* | 452 /* |
| 409 * add_acpi_method() evaluate an ACPI method and create sysfs attributes. | 453 * add_acpi_method() evaluate an ACPI method and create sysfs attributes. |
| 410 * | 454 * |
| 411 * @device: ACPI device | 455 * @device: ACPI device |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 426 printk(MY_ERR "failed to retrieve %s (%d)\n", pm, status); | 470 printk(MY_ERR "failed to retrieve %s (%d)\n", pm, status); |
| 427 return; | 471 return; |
| 428 } | 472 } |
| 429 | 473 |
| 430 po = output.pointer; | 474 po = output.pointer; |
| 431 | 475 |
| 432 if (po->type != ACPI_TYPE_PACKAGE) | 476 if (po->type != ACPI_TYPE_PACKAGE) |
| 433 printk(MY_ERR "%s is not a package, ignored\n", pm); | 477 printk(MY_ERR "%s is not a package, ignored\n", pm); |
| 434 else | 478 else |
| 435 handle_acpi_package(po, pm); | 479 handle_acpi_package(po, pm); |
| 436 | 480 #ifdef CONFIG_CHROMEOS |
| 437 /* Need to export a couple of variables to chromeos.c */ | 481 /* Need to export a couple of variables to chromeos.c */ |
| 438 if (!strncmp(pm, "CHNV", 4)) | 482 if (!strncmp(pm, "CHNV", 4)) |
| 439 handle_single_int(po, &chromeos_acpi_chnv); | 483 handle_single_int(po, &chromeos_acpi_chnv); |
| 440 else if (!strncmp(pm, "CHSW", 4)) | 484 else if (!strncmp(pm, "CHSW", 4)) |
| 441 handle_single_int(po, &chromeos_acpi_chsw); | 485 handle_single_int(po, &chromeos_acpi_chsw); |
| 442 | 486 #endif |
| 443 kfree(output.pointer); | 487 kfree(output.pointer); |
| 444 } | 488 } |
| 445 | 489 |
| 446 /* | 490 /* |
| 447 * chromeos_process_mlst() Evaluate the MLST method and add methods listed | 491 * chromeos_process_mlst() Evaluate the MLST method and add methods listed |
| 448 * in the response. | 492 * in the response. |
| 449 * | 493 * |
| 450 * @device: ACPI device | 494 * @device: ACPI device |
| 451 * | 495 * |
| 452 * Returns: 0 if successful, non-zero if error. | 496 * Returns: 0 if successful, non-zero if error. |
| (...skipping 22 matching lines...) Expand all Loading... | |
| 475 kfree(output.pointer); | 519 kfree(output.pointer); |
| 476 return -EINVAL; | 520 return -EINVAL; |
| 477 } | 521 } |
| 478 | 522 |
| 479 for (j = 0; j < po->package.count; j++) { | 523 for (j = 0; j < po->package.count; j++) { |
| 480 union acpi_object *element = po->package.elements + j; | 524 union acpi_object *element = po->package.elements + j; |
| 481 int copy_size = 0; | 525 int copy_size = 0; |
| 482 char method[ACPI_NAME_SIZE + 1]; | 526 char method[ACPI_NAME_SIZE + 1]; |
| 483 | 527 |
| 484 if (element->type == ACPI_TYPE_STRING) { | 528 if (element->type == ACPI_TYPE_STRING) { |
| 485 » » » copy_size = min(element->string.length, ACPI_NAME_SIZE); | 529 » » » copy_size = min(element->string.length, |
| 530 » » » » » (u32)ACPI_NAME_SIZE); | |
|
Olof Johansson
2011/03/14 21:24:32
Is this cast needed?
vb
2011/03/14 22:00:04
yes, for some weird reason min() operates with poi
Olof Johansson
2011/03/14 22:28:47
Ah, yes, it's trying to be type safe. Ok.
| |
| 486 memcpy(method, element->string.pointer, copy_size); | 531 memcpy(method, element->string.pointer, copy_size); |
| 487 method[copy_size] = '\0'; | 532 method[copy_size] = '\0'; |
| 488 add_acpi_method(device, method); | 533 add_acpi_method(device, method); |
| 489 } else { | 534 } else { |
| 490 pr_debug(MY_LOGPREFIX "ignoring type %d\n", | 535 pr_debug(MY_LOGPREFIX "ignoring type %d\n", |
| 491 element->type); | 536 element->type); |
| 492 } | 537 } |
| 493 } | 538 } |
| 494 | 539 |
| 495 kfree(output.pointer); | 540 kfree(output.pointer); |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 531 } | 576 } |
| 532 | 577 |
| 533 ret = acpi_bus_register_driver(&chromeos_acpi_driver); | 578 ret = acpi_bus_register_driver(&chromeos_acpi_driver); |
| 534 if (ret < 0) { | 579 if (ret < 0) { |
| 535 printk(MY_ERR "failed to register driver (%d)\n", ret); | 580 printk(MY_ERR "failed to register driver (%d)\n", ret); |
| 536 platform_device_unregister(chromeos_acpi.p_dev); | 581 platform_device_unregister(chromeos_acpi.p_dev); |
| 537 chromeos_acpi.p_dev = NULL; | 582 chromeos_acpi.p_dev = NULL; |
| 538 return ret; | 583 return ret; |
| 539 } | 584 } |
| 540 | 585 |
| 586 #ifdef CONFIG_CHROMEOS | |
| 541 chromeos_acpi_available = true; | 587 chromeos_acpi_available = true; |
| 542 | 588 #endif |
| 543 return 0; | 589 return 0; |
| 544 } | 590 } |
| 545 subsys_initcall(chromeos_acpi_init); | 591 |
| 592 static void chromeos_acpi_exit(void) | |
| 593 { | |
| 594 » acpi_bus_unregister_driver(&chromeos_acpi_driver); | |
| 595 | |
| 596 » while (chromeos_acpi.groups) { | |
| 597 » » struct acpi_attribute_group *aag; | |
| 598 » » aag = chromeos_acpi.groups; | |
| 599 » » chromeos_acpi.groups = aag->next_acpi_attr_group; | |
| 600 » » sysfs_remove_group(&chromeos_acpi.p_dev->dev.kobj, &aag->ag); | |
| 601 » » kfree(aag); | |
| 602 » } | |
| 603 | |
| 604 » while (chromeos_acpi.attributes) { | |
| 605 » » struct acpi_attribute *aa = chromeos_acpi.attributes; | |
| 606 » » chromeos_acpi.attributes = aa->next_acpi_attr; | |
| 607 » » device_remove_file(&chromeos_acpi.p_dev->dev, &aa->dev_attr); | |
| 608 » » kfree(aa); | |
| 609 » } | |
| 610 | |
| 611 » platform_device_unregister(chromeos_acpi.p_dev); | |
| 612 » printk(MY_INFO "removed\n"); | |
|
Olof Johansson
2011/03/14 21:24:32
Shouldn't there be a chromeos_acpi_available=false
vb
2011/03/14 22:00:04
good point, added.
| |
| 613 } | |
| 614 | |
| 615 module_init(chromeos_acpi_init); | |
| 616 module_exit(chromeos_acpi_exit); | |
|
Olof Johansson
2011/03/14 21:24:32
You need a MODULE_LICENSE, MODULE_AUTHOR, etc here
vb
2011/03/14 22:00:04
They are there in the top of the file. You mean th
Olof Johansson
2011/03/14 22:28:47
Oops, missed them. Please move them to the bottom
vb
2011/03/14 22:55:25
Done.
| |
| 617 | |
| OLD | NEW |