diff options
author | Mario Limonciello <mario_limonciello@dell.com> | 2014-05-07 16:08:10 -0400 |
---|---|---|
committer | Matthew Garrett <matthew.garrett@nebula.com> | 2014-06-10 19:04:17 -0400 |
commit | bc2ef884320bdca8d2544d517ac5489bb1722896 (patch) | |
tree | 7b5555ad81590a3089a185aae941f591c5c9b43b /drivers/platform/x86 | |
parent | b998680e9adea22159b66bd59ecdf07624e201ed (diff) |
alienware-wmi: For WMAX HDMI method, introduce a way to query HDMI cable status
Since there are now multiple HDMI attributes associated with the WMAX method,
create a sysfs group for them instead.
Signed-off-by: Mario Limonciello <mario_limonciello@dell.com>
Signed-off-by: Matthew Garrett <matthew.garrett@nebula.com>
Diffstat (limited to 'drivers/platform/x86')
-rw-r--r-- | drivers/platform/x86/alienware-wmi.c | 118 |
1 files changed, 88 insertions, 30 deletions
diff --git a/drivers/platform/x86/alienware-wmi.c b/drivers/platform/x86/alienware-wmi.c index e5329eac86b7..297b6640213f 100644 --- a/drivers/platform/x86/alienware-wmi.c +++ b/drivers/platform/x86/alienware-wmi.c | |||
@@ -32,6 +32,7 @@ | |||
32 | #define WMAX_METHOD_HDMI_STATUS 0x2 | 32 | #define WMAX_METHOD_HDMI_STATUS 0x2 |
33 | #define WMAX_METHOD_BRIGHTNESS 0x3 | 33 | #define WMAX_METHOD_BRIGHTNESS 0x3 |
34 | #define WMAX_METHOD_ZONE_CONTROL 0x4 | 34 | #define WMAX_METHOD_ZONE_CONTROL 0x4 |
35 | #define WMAX_METHOD_HDMI_CABLE 0x5 | ||
35 | 36 | ||
36 | MODULE_AUTHOR("Mario Limonciello <mario_limonciello@dell.com>"); | 37 | MODULE_AUTHOR("Mario Limonciello <mario_limonciello@dell.com>"); |
37 | MODULE_DESCRIPTION("Alienware special feature control"); | 38 | MODULE_DESCRIPTION("Alienware special feature control"); |
@@ -422,41 +423,85 @@ static void alienware_zone_exit(struct platform_device *dev) | |||
422 | The HDMI mux sysfs node indicates the status of the HDMI input mux. | 423 | The HDMI mux sysfs node indicates the status of the HDMI input mux. |
423 | It can toggle between standard system GPU output and HDMI input. | 424 | It can toggle between standard system GPU output and HDMI input. |
424 | */ | 425 | */ |
425 | static ssize_t show_hdmi(struct device *dev, struct device_attribute *attr, | 426 | static acpi_status alienware_hdmi_command(struct hdmi_args *in_args, |
426 | char *buf) | 427 | u32 command, int *out_data) |
427 | { | 428 | { |
428 | acpi_status status; | 429 | acpi_status status; |
429 | struct acpi_buffer input; | ||
430 | union acpi_object *obj; | 430 | union acpi_object *obj; |
431 | u32 tmp = 0; | 431 | struct acpi_buffer input; |
432 | struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; | 432 | struct acpi_buffer output; |
433 | |||
434 | input.length = (acpi_size) sizeof(*in_args); | ||
435 | input.pointer = in_args; | ||
436 | if (out_data != NULL) { | ||
437 | output.length = ACPI_ALLOCATE_BUFFER; | ||
438 | output.pointer = NULL; | ||
439 | status = wmi_evaluate_method(WMAX_CONTROL_GUID, 1, | ||
440 | command, &input, &output); | ||
441 | } else | ||
442 | status = wmi_evaluate_method(WMAX_CONTROL_GUID, 1, | ||
443 | command, &input, NULL); | ||
444 | |||
445 | if (ACPI_SUCCESS(status) && out_data != NULL) { | ||
446 | obj = (union acpi_object *)output.pointer; | ||
447 | if (obj && obj->type == ACPI_TYPE_INTEGER) | ||
448 | *out_data = (u32) obj->integer.value; | ||
449 | } | ||
450 | return status; | ||
451 | |||
452 | } | ||
453 | |||
454 | static ssize_t show_hdmi_cable(struct device *dev, | ||
455 | struct device_attribute *attr, char *buf) | ||
456 | { | ||
457 | acpi_status status; | ||
458 | u32 out_data; | ||
433 | struct hdmi_args in_args = { | 459 | struct hdmi_args in_args = { |
434 | .arg = 0, | 460 | .arg = 0, |
435 | }; | 461 | }; |
436 | input.length = (acpi_size) sizeof(in_args); | 462 | status = |
437 | input.pointer = &in_args; | 463 | alienware_hdmi_command(&in_args, WMAX_METHOD_HDMI_CABLE, |
438 | status = wmi_evaluate_method(WMAX_CONTROL_GUID, 1, | 464 | (u32 *) &out_data); |
439 | WMAX_METHOD_HDMI_STATUS, &input, &output); | 465 | if (ACPI_SUCCESS(status)) { |
466 | if (out_data == 0) | ||
467 | return scnprintf(buf, PAGE_SIZE, | ||
468 | "[unconnected] connected unknown\n"); | ||
469 | else if (out_data == 1) | ||
470 | return scnprintf(buf, PAGE_SIZE, | ||
471 | "unconnected [connected] unknown\n"); | ||
472 | } | ||
473 | pr_err("alienware-wmi: unknown HDMI cable status: %d\n", status); | ||
474 | return scnprintf(buf, PAGE_SIZE, "unconnected connected [unknown]\n"); | ||
475 | } | ||
476 | |||
477 | static ssize_t show_hdmi_source(struct device *dev, | ||
478 | struct device_attribute *attr, char *buf) | ||
479 | { | ||
480 | acpi_status status; | ||
481 | u32 out_data; | ||
482 | struct hdmi_args in_args = { | ||
483 | .arg = 0, | ||
484 | }; | ||
485 | status = | ||
486 | alienware_hdmi_command(&in_args, WMAX_METHOD_HDMI_STATUS, | ||
487 | (u32 *) &out_data); | ||
440 | 488 | ||
441 | if (ACPI_SUCCESS(status)) { | 489 | if (ACPI_SUCCESS(status)) { |
442 | obj = (union acpi_object *)output.pointer; | 490 | if (out_data == 1) |
443 | if (obj && obj->type == ACPI_TYPE_INTEGER) | ||
444 | tmp = (u32) obj->integer.value; | ||
445 | if (tmp == 1) | ||
446 | return scnprintf(buf, PAGE_SIZE, | 491 | return scnprintf(buf, PAGE_SIZE, |
447 | "[input] gpu unknown\n"); | 492 | "[input] gpu unknown\n"); |
448 | else if (tmp == 2) | 493 | else if (out_data == 2) |
449 | return scnprintf(buf, PAGE_SIZE, | 494 | return scnprintf(buf, PAGE_SIZE, |
450 | "input [gpu] unknown\n"); | 495 | "input [gpu] unknown\n"); |
451 | } | 496 | } |
452 | pr_err("alienware-wmi: unknown HDMI status: %d\n", status); | 497 | pr_err("alienware-wmi: unknown HDMI source status: %d\n", out_data); |
453 | return scnprintf(buf, PAGE_SIZE, "input gpu [unknown]\n"); | 498 | return scnprintf(buf, PAGE_SIZE, "input gpu [unknown]\n"); |
454 | } | 499 | } |
455 | 500 | ||
456 | static ssize_t toggle_hdmi(struct device *dev, struct device_attribute *attr, | 501 | static ssize_t toggle_hdmi_source(struct device *dev, |
457 | const char *buf, size_t count) | 502 | struct device_attribute *attr, |
503 | const char *buf, size_t count) | ||
458 | { | 504 | { |
459 | struct acpi_buffer input; | ||
460 | acpi_status status; | 505 | acpi_status status; |
461 | struct hdmi_args args; | 506 | struct hdmi_args args; |
462 | if (strcmp(buf, "gpu\n") == 0) | 507 | if (strcmp(buf, "gpu\n") == 0) |
@@ -466,33 +511,46 @@ static ssize_t toggle_hdmi(struct device *dev, struct device_attribute *attr, | |||
466 | else | 511 | else |
467 | args.arg = 3; | 512 | args.arg = 3; |
468 | pr_debug("alienware-wmi: setting hdmi to %d : %s", args.arg, buf); | 513 | pr_debug("alienware-wmi: setting hdmi to %d : %s", args.arg, buf); |
469 | input.length = (acpi_size) sizeof(args); | 514 | |
470 | input.pointer = &args; | 515 | status = alienware_hdmi_command(&args, WMAX_METHOD_HDMI_SOURCE, NULL); |
471 | status = wmi_evaluate_method(WMAX_CONTROL_GUID, 1, | 516 | |
472 | WMAX_METHOD_HDMI_SOURCE, &input, NULL); | ||
473 | if (ACPI_FAILURE(status)) | 517 | if (ACPI_FAILURE(status)) |
474 | pr_err("alienware-wmi: HDMI toggle failed: results: %u\n", | 518 | pr_err("alienware-wmi: HDMI toggle failed: results: %u\n", |
475 | status); | 519 | status); |
476 | return count; | 520 | return count; |
477 | } | 521 | } |
478 | 522 | ||
479 | static DEVICE_ATTR(hdmi, S_IRUGO | S_IWUSR, show_hdmi, toggle_hdmi); | 523 | static DEVICE_ATTR(cable, S_IRUGO, show_hdmi_cable, NULL); |
524 | static DEVICE_ATTR(source, S_IRUGO | S_IWUSR, show_hdmi_source, | ||
525 | toggle_hdmi_source); | ||
526 | |||
527 | static struct attribute *hdmi_attrs[] = { | ||
528 | &dev_attr_cable.attr, | ||
529 | &dev_attr_source.attr, | ||
530 | NULL, | ||
531 | }; | ||
480 | 532 | ||
481 | static void remove_hdmi(struct platform_device *device) | 533 | static struct attribute_group hdmi_attribute_group = { |
534 | .name = "hdmi", | ||
535 | .attrs = hdmi_attrs, | ||
536 | }; | ||
537 | |||
538 | static void remove_hdmi(struct platform_device *dev) | ||
482 | { | 539 | { |
483 | device_remove_file(&device->dev, &dev_attr_hdmi); | 540 | sysfs_remove_group(&dev->dev.kobj, &hdmi_attribute_group); |
484 | } | 541 | } |
485 | 542 | ||
486 | static int create_hdmi(void) | 543 | static int create_hdmi(struct platform_device *dev) |
487 | { | 544 | { |
488 | int ret = -ENOMEM; | 545 | int ret; |
489 | ret = device_create_file(&platform_device->dev, &dev_attr_hdmi); | 546 | |
547 | ret = sysfs_create_group(&dev->dev.kobj, &hdmi_attribute_group); | ||
490 | if (ret) | 548 | if (ret) |
491 | goto error_create_hdmi; | 549 | goto error_create_hdmi; |
492 | return 0; | 550 | return 0; |
493 | 551 | ||
494 | error_create_hdmi: | 552 | error_create_hdmi: |
495 | remove_hdmi(platform_device); | 553 | remove_hdmi(dev); |
496 | return ret; | 554 | return ret; |
497 | } | 555 | } |
498 | 556 | ||
@@ -526,7 +584,7 @@ static int __init alienware_wmi_init(void) | |||
526 | goto fail_platform_device2; | 584 | goto fail_platform_device2; |
527 | 585 | ||
528 | if (interface == WMAX) { | 586 | if (interface == WMAX) { |
529 | ret = create_hdmi(); | 587 | ret = create_hdmi(platform_device); |
530 | if (ret) | 588 | if (ret) |
531 | goto fail_prep_hdmi; | 589 | goto fail_prep_hdmi; |
532 | } | 590 | } |