Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Mario Limonciello and committed by
Matthew Garrett
bc2ef884 b998680e

+88 -30
+88 -30
drivers/platform/x86/alienware-wmi.c
··· 32 32 #define WMAX_METHOD_HDMI_STATUS 0x2 33 33 #define WMAX_METHOD_BRIGHTNESS 0x3 34 34 #define WMAX_METHOD_ZONE_CONTROL 0x4 35 + #define WMAX_METHOD_HDMI_CABLE 0x5 35 36 36 37 MODULE_AUTHOR("Mario Limonciello <mario_limonciello@dell.com>"); 37 38 MODULE_DESCRIPTION("Alienware special feature control"); ··· 423 422 The HDMI mux sysfs node indicates the status of the HDMI input mux. 424 423 It can toggle between standard system GPU output and HDMI input. 425 424 */ 426 - static ssize_t show_hdmi(struct device *dev, struct device_attribute *attr, 427 - char *buf) 425 + static acpi_status alienware_hdmi_command(struct hdmi_args *in_args, 426 + u32 command, int *out_data) 428 427 { 429 428 acpi_status status; 430 - struct acpi_buffer input; 431 429 union acpi_object *obj; 432 - u32 tmp = 0; 433 - struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; 430 + struct acpi_buffer input; 431 + struct acpi_buffer output; 432 + 433 + input.length = (acpi_size) sizeof(*in_args); 434 + input.pointer = in_args; 435 + if (out_data != NULL) { 436 + output.length = ACPI_ALLOCATE_BUFFER; 437 + output.pointer = NULL; 438 + status = wmi_evaluate_method(WMAX_CONTROL_GUID, 1, 439 + command, &input, &output); 440 + } else 441 + status = wmi_evaluate_method(WMAX_CONTROL_GUID, 1, 442 + command, &input, NULL); 443 + 444 + if (ACPI_SUCCESS(status) && out_data != NULL) { 445 + obj = (union acpi_object *)output.pointer; 446 + if (obj && obj->type == ACPI_TYPE_INTEGER) 447 + *out_data = (u32) obj->integer.value; 448 + } 449 + return status; 450 + 451 + } 452 + 453 + static ssize_t show_hdmi_cable(struct device *dev, 454 + struct device_attribute *attr, char *buf) 455 + { 456 + acpi_status status; 457 + u32 out_data; 434 458 struct hdmi_args in_args = { 435 459 .arg = 0, 436 460 }; 437 - input.length = (acpi_size) sizeof(in_args); 438 - input.pointer = &in_args; 439 - status = wmi_evaluate_method(WMAX_CONTROL_GUID, 1, 440 - WMAX_METHOD_HDMI_STATUS, &input, &output); 461 + status = 462 + alienware_hdmi_command(&in_args, WMAX_METHOD_HDMI_CABLE, 463 + (u32 *) &out_data); 464 + if (ACPI_SUCCESS(status)) { 465 + if (out_data == 0) 466 + return scnprintf(buf, PAGE_SIZE, 467 + "[unconnected] connected unknown\n"); 468 + else if (out_data == 1) 469 + return scnprintf(buf, PAGE_SIZE, 470 + "unconnected [connected] unknown\n"); 471 + } 472 + pr_err("alienware-wmi: unknown HDMI cable status: %d\n", status); 473 + return scnprintf(buf, PAGE_SIZE, "unconnected connected [unknown]\n"); 474 + } 475 + 476 + static ssize_t show_hdmi_source(struct device *dev, 477 + struct device_attribute *attr, char *buf) 478 + { 479 + acpi_status status; 480 + u32 out_data; 481 + struct hdmi_args in_args = { 482 + .arg = 0, 483 + }; 484 + status = 485 + alienware_hdmi_command(&in_args, WMAX_METHOD_HDMI_STATUS, 486 + (u32 *) &out_data); 441 487 442 488 if (ACPI_SUCCESS(status)) { 443 - obj = (union acpi_object *)output.pointer; 444 - if (obj && obj->type == ACPI_TYPE_INTEGER) 445 - tmp = (u32) obj->integer.value; 446 - if (tmp == 1) 489 + if (out_data == 1) 447 490 return scnprintf(buf, PAGE_SIZE, 448 491 "[input] gpu unknown\n"); 449 - else if (tmp == 2) 492 + else if (out_data == 2) 450 493 return scnprintf(buf, PAGE_SIZE, 451 494 "input [gpu] unknown\n"); 452 495 } 453 - pr_err("alienware-wmi: unknown HDMI status: %d\n", status); 496 + pr_err("alienware-wmi: unknown HDMI source status: %d\n", out_data); 454 497 return scnprintf(buf, PAGE_SIZE, "input gpu [unknown]\n"); 455 498 } 456 499 457 - static ssize_t toggle_hdmi(struct device *dev, struct device_attribute *attr, 458 - const char *buf, size_t count) 500 + static ssize_t toggle_hdmi_source(struct device *dev, 501 + struct device_attribute *attr, 502 + const char *buf, size_t count) 459 503 { 460 - struct acpi_buffer input; 461 504 acpi_status status; 462 505 struct hdmi_args args; 463 506 if (strcmp(buf, "gpu\n") == 0) ··· 511 466 else 512 467 args.arg = 3; 513 468 pr_debug("alienware-wmi: setting hdmi to %d : %s", args.arg, buf); 514 - input.length = (acpi_size) sizeof(args); 515 - input.pointer = &args; 516 - status = wmi_evaluate_method(WMAX_CONTROL_GUID, 1, 517 - WMAX_METHOD_HDMI_SOURCE, &input, NULL); 469 + 470 + status = alienware_hdmi_command(&args, WMAX_METHOD_HDMI_SOURCE, NULL); 471 + 518 472 if (ACPI_FAILURE(status)) 519 473 pr_err("alienware-wmi: HDMI toggle failed: results: %u\n", 520 474 status); 521 475 return count; 522 476 } 523 477 524 - static DEVICE_ATTR(hdmi, S_IRUGO | S_IWUSR, show_hdmi, toggle_hdmi); 478 + static DEVICE_ATTR(cable, S_IRUGO, show_hdmi_cable, NULL); 479 + static DEVICE_ATTR(source, S_IRUGO | S_IWUSR, show_hdmi_source, 480 + toggle_hdmi_source); 525 481 526 - static void remove_hdmi(struct platform_device *device) 482 + static struct attribute *hdmi_attrs[] = { 483 + &dev_attr_cable.attr, 484 + &dev_attr_source.attr, 485 + NULL, 486 + }; 487 + 488 + static struct attribute_group hdmi_attribute_group = { 489 + .name = "hdmi", 490 + .attrs = hdmi_attrs, 491 + }; 492 + 493 + static void remove_hdmi(struct platform_device *dev) 527 494 { 528 - device_remove_file(&device->dev, &dev_attr_hdmi); 495 + sysfs_remove_group(&dev->dev.kobj, &hdmi_attribute_group); 529 496 } 530 497 531 - static int create_hdmi(void) 498 + static int create_hdmi(struct platform_device *dev) 532 499 { 533 - int ret = -ENOMEM; 534 - ret = device_create_file(&platform_device->dev, &dev_attr_hdmi); 500 + int ret; 501 + 502 + ret = sysfs_create_group(&dev->dev.kobj, &hdmi_attribute_group); 535 503 if (ret) 536 504 goto error_create_hdmi; 537 505 return 0; 538 506 539 507 error_create_hdmi: 540 - remove_hdmi(platform_device); 508 + remove_hdmi(dev); 541 509 return ret; 542 510 } 543 511 ··· 584 526 goto fail_platform_device2; 585 527 586 528 if (interface == WMAX) { 587 - ret = create_hdmi(); 529 + ret = create_hdmi(platform_device); 588 530 if (ret) 589 531 goto fail_prep_hdmi; 590 532 }