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 |