From patchwork Tue Feb 2 21:38:54 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mario Limonciello X-Patchwork-Id: 8196151 Return-Path: X-Original-To: patchwork-platform-driver-x86@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork1.web.kernel.org (Postfix) with ESMTP id 9ACDF9FBE9 for ; Tue, 2 Feb 2016 21:44:20 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 9080F202D1 for ; Tue, 2 Feb 2016 21:44:19 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 5E6A4202BE for ; Tue, 2 Feb 2016 21:44:18 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1755472AbcBBVnK (ORCPT ); Tue, 2 Feb 2016 16:43:10 -0500 Received: from ausxippc101.us.dell.com ([143.166.85.207]:15386 "EHLO ausxippc101.us.dell.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1754822AbcBBVnC (ORCPT ); Tue, 2 Feb 2016 16:43:02 -0500 DomainKey-Signature: s=smtpout; d=dell.com; c=nofws; q=dns; h=X-LoopCount0:X-IronPort-AV:From:To:Cc:Subject:Date: Message-Id:X-Mailer:In-Reply-To:References; b=cvd1mSSXGRv/52F7KRkq14XThWSu2dzlLHl9qJRWQcijJjMB3JPf7qnQ N7TMzm4W1DUtc233lA8l+9PkN/Lw0YOGZKiEi1wHnhxVxnDhDZjB4AUIE niXoDezpE3lGfciDzWo+GO92b7Zqwe3lksJcYCg0hPEH+/SdJICKC8yai 0=; DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=dell.com; i=@dell.com; q=dns/txt; s=smtpout; t=1454449382; x=1485985382; h=from:to:cc:subject:date:message-id:in-reply-to: references; bh=6o+HwqYPVqlM+4k0gYGkJwVtuVz4g1SSBGeaN6cRxSk=; b=on51EZqiee7SrWmjq0/78iwXr9pVlfFTp0NyXYW9xsd/QHUpsTjvrtO3 DXCyfppUIN4MqPP2yYP7II8JDiPh6HOt55FCWOHoyBGXGzgcZ1D5rbcRd znUpzNVB7vmZeVBInHuTyuVCjOvVsy57H4bPEu+fQRwe0dK9JJhhlVMC2 U=; X-LoopCount0: from 10.209.151.17 X-IronPort-AV: E=Sophos;i="5.22,386,1449554400"; d="scan'208";a="760838661" From: Mario Limonciello To: dvhart@infradead.org Cc: LKML , platform-driver-x86@vger.kernel.org, Mario Limonciello Subject: [PATCH v3 3/6] alienware-wmi: Add initial support for alienware graphics amplifier. Date: Tue, 2 Feb 2016 15:38:54 -0600 Message-Id: <1454449137-16478-4-git-send-email-mario_limonciello@dell.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1454449137-16478-1-git-send-email-mario_limonciello@dell.com> References: <1454449137-16478-1-git-send-email-mario_limonciello@dell.com> Sender: platform-driver-x86-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: platform-driver-x86@vger.kernel.org X-Spam-Status: No, score=-7.2 required=5.0 tests=BAYES_00,DKIM_SIGNED, RCVD_IN_DNSWL_HI,RP_MATCHES_RCVD,T_DKIM_INVALID,UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP The alienware graphics amplifier is a device that provides external access to a full PCIe slot, USB hub, and additional control zone. This patch enables support for reading status whether the cable is plugged in as well as for setting the colors in the new zone on the amplifier. Signed-off-by: Mario Limonciello --- drivers/platform/x86/alienware-wmi.c | 106 ++++++++++++++++++++++++++++------- 1 file changed, 87 insertions(+), 19 deletions(-) diff --git a/drivers/platform/x86/alienware-wmi.c b/drivers/platform/x86/alienware-wmi.c index 8e8ea4f..7ada7ce 100644 --- a/drivers/platform/x86/alienware-wmi.c +++ b/drivers/platform/x86/alienware-wmi.c @@ -33,6 +33,7 @@ #define WMAX_METHOD_BRIGHTNESS 0x3 #define WMAX_METHOD_ZONE_CONTROL 0x4 #define WMAX_METHOD_HDMI_CABLE 0x5 +#define WMAX_METHOD_AMPLIFIER_CABLE 0x6 MODULE_AUTHOR("Mario Limonciello "); MODULE_DESCRIPTION("Alienware special feature control"); @@ -60,6 +61,7 @@ enum WMAX_CONTROL_STATES { struct quirk_entry { u8 num_zones; u8 hdmi_mux; + u8 amplifier; }; static struct quirk_entry *quirks; @@ -67,21 +69,25 @@ static struct quirk_entry *quirks; static struct quirk_entry quirk_unknown = { .num_zones = 2, .hdmi_mux = 0, + .amplifier = 0, }; static struct quirk_entry quirk_x51_r1_r2 = { .num_zones = 3, - .hdmi_mux = 0. + .hdmi_mux = 0, + .amplifier = 0, }; static struct quirk_entry quirk_x51_r3 = { .num_zones = 4, .hdmi_mux = 0, + .amplifier = 1, }; static struct quirk_entry quirk_asm100 = { .num_zones = 2, .hdmi_mux = 1, + .amplifier = 0, }; static int __init dmi_matched(const struct dmi_system_id *dmi) @@ -147,7 +153,7 @@ struct wmax_brightness_args { u32 percentage; }; -struct hdmi_args { +struct wmax_basic_args { u8 arg; }; @@ -232,16 +238,16 @@ static int alienware_update_led(struct platform_zone *zone) char *guid; struct acpi_buffer input; struct legacy_led_args legacy_args; - struct wmax_led_args wmax_args; + struct wmax_led_args wmax_basic_args; if (interface == WMAX) { - wmax_args.led_mask = 1 << zone->location; - wmax_args.colors = zone->colors; - wmax_args.state = lighting_control_state; + wmax_basic_args.led_mask = 1 << zone->location; + wmax_basic_args.colors = zone->colors; + wmax_basic_args.state = lighting_control_state; guid = WMAX_CONTROL_GUID; method_id = WMAX_METHOD_ZONE_CONTROL; - input.length = (acpi_size) sizeof(wmax_args); - input.pointer = &wmax_args; + input.length = (acpi_size) sizeof(wmax_basic_args); + input.pointer = &wmax_basic_args; } else { legacy_args.colors = zone->colors; legacy_args.brightness = global_brightness; @@ -449,11 +455,7 @@ static void alienware_zone_exit(struct platform_device *dev) kfree(zone_attrs); } -/* - The HDMI mux sysfs node indicates the status of the HDMI input mux. - It can toggle between standard system GPU output and HDMI input. -*/ -static acpi_status alienware_hdmi_command(struct hdmi_args *in_args, +static acpi_status alienware_wmax_command(struct wmax_basic_args *in_args, u32 command, int *out_data) { acpi_status status; @@ -481,16 +483,20 @@ static acpi_status alienware_hdmi_command(struct hdmi_args *in_args, } +/* + * The HDMI mux sysfs node indicates the status of the HDMI input mux. + * It can toggle between standard system GPU output and HDMI input. + */ static ssize_t show_hdmi_cable(struct device *dev, struct device_attribute *attr, char *buf) { acpi_status status; u32 out_data; - struct hdmi_args in_args = { + struct wmax_basic_args in_args = { .arg = 0, }; status = - alienware_hdmi_command(&in_args, WMAX_METHOD_HDMI_CABLE, + alienware_wmax_command(&in_args, WMAX_METHOD_HDMI_CABLE, (u32 *) &out_data); if (ACPI_SUCCESS(status)) { if (out_data == 0) @@ -509,11 +515,11 @@ static ssize_t show_hdmi_source(struct device *dev, { acpi_status status; u32 out_data; - struct hdmi_args in_args = { + struct wmax_basic_args in_args = { .arg = 0, }; status = - alienware_hdmi_command(&in_args, WMAX_METHOD_HDMI_STATUS, + alienware_wmax_command(&in_args, WMAX_METHOD_HDMI_STATUS, (u32 *) &out_data); if (ACPI_SUCCESS(status)) { @@ -533,7 +539,7 @@ static ssize_t toggle_hdmi_source(struct device *dev, const char *buf, size_t count) { acpi_status status; - struct hdmi_args args; + struct wmax_basic_args args; if (strcmp(buf, "gpu\n") == 0) args.arg = 1; else if (strcmp(buf, "input\n") == 0) @@ -542,7 +548,7 @@ static ssize_t toggle_hdmi_source(struct device *dev, args.arg = 3; pr_debug("alienware-wmi: setting hdmi to %d : %s", args.arg, buf); - status = alienware_hdmi_command(&args, WMAX_METHOD_HDMI_SOURCE, NULL); + status = alienware_wmax_command(&args, WMAX_METHOD_HDMI_SOURCE, NULL); if (ACPI_FAILURE(status)) pr_err("alienware-wmi: HDMI toggle failed: results: %u\n", @@ -585,6 +591,61 @@ error_create_hdmi: return ret; } +/* Alienware GFX amplifier support + * - Currently supports reading cable status + * - Leaving expansion room to possibly support dock/undock events later + */ +static ssize_t show_amplifier_status(struct device *dev, + struct device_attribute *attr, char *buf) +{ + acpi_status status; + u32 out_data; + struct wmax_basic_args in_args = { + .arg = 0, + }; + status = + alienware_wmax_command(&in_args, WMAX_METHOD_AMPLIFIER_CABLE, + (u32 *) &out_data); + if (ACPI_SUCCESS(status)) { + if (out_data == 0) + return scnprintf(buf, PAGE_SIZE, + "[unconnected] connected unknown\n"); + else if (out_data == 1) + return scnprintf(buf, PAGE_SIZE, + "unconnected [connected] unknown\n"); + } + pr_err("alienware-wmi: unknown amplifier cable status: %d\n", status); + return scnprintf(buf, PAGE_SIZE, "unconnected connected [unknown]\n"); +} + +static DEVICE_ATTR(status, S_IRUGO, show_amplifier_status, NULL); + +static struct attribute *amplifier_attrs[] = { + &dev_attr_status.attr, + NULL, +}; + +static struct attribute_group amplifier_attribute_group = { + .name = "amplifier", + .attrs = amplifier_attrs, +}; + +static void remove_amplifier(struct platform_device *dev) +{ + if (quirks->amplifier > 0) + sysfs_remove_group(&dev->dev.kobj, &lifier_attribute_group); +} + +static int create_amplifier(struct platform_device *dev) +{ + int ret; + + ret = sysfs_create_group(&dev->dev.kobj, &lifier_attribute_group); + if (ret) + remove_amplifier(dev); + return ret; +} + static int __init alienware_wmi_init(void) { int ret; @@ -620,6 +681,12 @@ static int __init alienware_wmi_init(void) goto fail_prep_hdmi; } + if (quirks->amplifier > 0) { + ret = create_amplifier(platform_device); + if (ret) + goto fail_prep_amplifier; + } + ret = alienware_zone_init(platform_device); if (ret) goto fail_prep_zones; @@ -628,6 +695,7 @@ static int __init alienware_wmi_init(void) fail_prep_zones: alienware_zone_exit(platform_device); +fail_prep_amplifier: fail_prep_hdmi: platform_device_del(platform_device); fail_platform_device2: