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 | |
| 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')
| -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 | } |
