From c09b2237da24e9136fc8053e11244f52903e73e0 Mon Sep 17 00:00:00 2001 From: Corentin Chary Date: Tue, 20 Mar 2012 09:53:04 +0100 Subject: asus-wmi: on/off bit is not set when reading the value Signed-off-by: Corentin Chary Signed-off-by: Matthew Garrett --- drivers/platform/x86/asus-wmi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/platform/x86/asus-wmi.c') diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c index 72d731c21d4..2b883470a9d 100644 --- a/drivers/platform/x86/asus-wmi.c +++ b/drivers/platform/x86/asus-wmi.c @@ -411,7 +411,7 @@ static int kbd_led_read(struct asus_wmi *asus, int *level, int *env) if (retval >= 0) { if (level) - *level = retval & 0x80 ? retval & 0x7F : 0; + *level = retval & 0x7F; if (env) *env = (retval >> 8) & 0x7F; retval = 0; -- cgit v1.2.3-70-g09d2 From c87992d1fa51a6a3d8f0e980ca4d2bdec7e78a17 Mon Sep 17 00:00:00 2001 From: AceLan Kao Date: Tue, 20 Mar 2012 09:53:08 +0100 Subject: asus-wmi: add scalar board brightness adj. support Some ASUS ET2012E/I All-in-One machines that use a scalar board to control the brightness, and they only accept brightness up and down command. So, I introduced a get_scalar_command() function to pass the command to the scalar board through WMI. Besides, we have to store the brightness value locally, for we need the old value to know the brightness value is increasing or decreasing. BTW, since there is no way to retrieve the actual brightness(it would be a fixed value), and the max brightness value would be fixed to 1, so we have to keep passing the brightness up/down command when we reached the max brightness value or 0. Signed-off-by: AceLan Kao Signed-off-by: Corentin Chary Signed-off-by: Matthew Garrett --- drivers/platform/x86/asus-nb-wmi.c | 2 +- drivers/platform/x86/asus-wmi.c | 33 ++++++++++++--- drivers/platform/x86/asus-wmi.h | 10 ++++- drivers/platform/x86/eeepc-wmi.c | 85 +++++++++++++++++++++++++++----------- 4 files changed, 97 insertions(+), 33 deletions(-) (limited to 'drivers/platform/x86/asus-wmi.c') diff --git a/drivers/platform/x86/asus-nb-wmi.c b/drivers/platform/x86/asus-nb-wmi.c index 35011273602..1aea6b8019b 100644 --- a/drivers/platform/x86/asus-nb-wmi.c +++ b/drivers/platform/x86/asus-nb-wmi.c @@ -101,7 +101,7 @@ static struct asus_wmi_driver asus_nb_wmi_driver = { .keymap = asus_nb_wmi_keymap, .input_name = "Asus WMI hotkeys", .input_phys = ASUS_NB_WMI_FILE "/input0", - .quirks = asus_nb_wmi_quirks, + .detect_quirks = asus_nb_wmi_quirks, }; diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c index 2b883470a9d..eb114f8d39e 100644 --- a/drivers/platform/x86/asus-wmi.c +++ b/drivers/platform/x86/asus-wmi.c @@ -784,7 +784,8 @@ static int asus_new_rfkill(struct asus_wmi *asus, arfkill->dev_id = dev_id; arfkill->asus = asus; - if (dev_id == ASUS_WMI_DEVID_WLAN && asus->driver->hotplug_wireless) + if (dev_id == ASUS_WMI_DEVID_WLAN && + asus->driver->quirks->hotplug_wireless) *rfkill = rfkill_alloc(name, &asus->platform_device->dev, type, &asus_rfkill_wlan_ops, arfkill); else @@ -895,7 +896,7 @@ static int asus_wmi_rfkill_init(struct asus_wmi *asus) if (result && result != -ENODEV) goto exit; - if (!asus->driver->hotplug_wireless) + if (!asus->driver->quirks->hotplug_wireless) goto exit; result = asus_setup_pci_hotplug(asus); @@ -1116,13 +1117,33 @@ static int read_brightness(struct backlight_device *bd) return retval & ASUS_WMI_DSTS_BRIGHTNESS_MASK; } +static u32 get_scalar_command(struct backlight_device *bd) +{ + struct asus_wmi *asus = bl_get_data(bd); + u32 ctrl_param = 0; + + if ((asus->driver->brightness < bd->props.brightness) || + bd->props.brightness == bd->props.max_brightness) + ctrl_param = 0x00008001; + else if ((asus->driver->brightness > bd->props.brightness) || + bd->props.brightness == 0) + ctrl_param = 0x00008000; + + asus->driver->brightness = bd->props.brightness; + + return ctrl_param; +} + static int update_bl_status(struct backlight_device *bd) { struct asus_wmi *asus = bl_get_data(bd); u32 ctrl_param; int power, err; - ctrl_param = bd->props.brightness; + if (asus->driver->quirks->scalar_panel_brightness) + ctrl_param = get_scalar_command(bd); + else + ctrl_param = bd->props.brightness; err = asus_wmi_set_devstate(ASUS_WMI_DEVID_BRIGHTNESS, ctrl_param, NULL); @@ -1200,6 +1221,8 @@ static int asus_wmi_backlight_init(struct asus_wmi *asus) bd->props.power = power; backlight_update_status(bd); + asus->driver->brightness = bd->props.brightness; + return 0; } @@ -1622,8 +1645,8 @@ static int asus_wmi_add(struct platform_device *pdev) wdrv->platform_device = pdev; platform_set_drvdata(asus->platform_device, asus); - if (wdrv->quirks) - wdrv->quirks(asus->driver); + if (wdrv->detect_quirks) + wdrv->detect_quirks(asus->driver); err = asus_wmi_platform_init(asus); if (err) diff --git a/drivers/platform/x86/asus-wmi.h b/drivers/platform/x86/asus-wmi.h index 8147c10161c..ac7dd4eaebd 100644 --- a/drivers/platform/x86/asus-wmi.h +++ b/drivers/platform/x86/asus-wmi.h @@ -35,9 +35,14 @@ struct module; struct key_entry; struct asus_wmi; +struct quirk_entry { + bool hotplug_wireless; + bool scalar_panel_brightness; +}; + struct asus_wmi_driver { - bool hotplug_wireless; int wapf; + int brightness; const char *name; struct module *owner; @@ -47,13 +52,14 @@ struct asus_wmi_driver { const struct key_entry *keymap; const char *input_name; const char *input_phys; + struct quirk_entry *quirks; /* Returns new code, value, and autorelease values in arguments. * Return ASUS_WMI_KEY_IGNORE in code if event should be ignored. */ void (*key_filter) (struct asus_wmi_driver *driver, int *code, unsigned int *value, bool *autorelease); int (*probe) (struct platform_device *device); - void (*quirks) (struct asus_wmi_driver *driver); + void (*detect_quirks) (struct asus_wmi_driver *driver); struct platform_driver platform_driver; struct platform_device *platform_device; diff --git a/drivers/platform/x86/eeepc-wmi.c b/drivers/platform/x86/eeepc-wmi.c index 1d91eb2ace0..67186e6ca28 100644 --- a/drivers/platform/x86/eeepc-wmi.c +++ b/drivers/platform/x86/eeepc-wmi.c @@ -48,6 +48,7 @@ MODULE_LICENSE("GPL"); MODULE_ALIAS("wmi:"EEEPC_WMI_EVENT_GUID); +static struct quirk_entry *quirks; static bool hotplug_wireless; module_param(hotplug_wireless, bool, 0444); @@ -90,6 +91,60 @@ static const struct key_entry eeepc_wmi_keymap[] = { { KE_END, 0}, }; +static struct quirk_entry quirk_asus_unknown = { +}; + +static struct quirk_entry quirk_asus_1000h = { + .hotplug_wireless = true, +}; + +static struct quirk_entry quirk_asus_et2012_type3 = { + .scalar_panel_brightness = true, +}; + +static int dmi_matched(const struct dmi_system_id *dmi) +{ + char *model; + quirks = dmi->driver_data; + + model = (char *)dmi->matches[1].substr; + if (unlikely(strncmp(model, "ET2012", 6) == 0)) { + const struct dmi_device *dev = NULL; + char oemstring[30]; + while ((dev = dmi_find_device(DMI_DEV_TYPE_OEM_STRING, NULL, + dev))) { + if (sscanf(dev->name, "AEMS%24c", oemstring) == 1) { + if (oemstring[18] == '3') + quirks = &quirk_asus_et2012_type3; + break; + } + } + } + return 1; +} + +static struct dmi_system_id asus_quirks[] = { + { + .callback = dmi_matched, + .ident = "ASUSTeK Computer INC. 1000H", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer INC."), + DMI_MATCH(DMI_PRODUCT_NAME, "1000H"), + }, + .driver_data = &quirk_asus_1000h, + }, + { + .callback = dmi_matched, + .ident = "ASUSTeK Computer INC. ET2012E/I", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer INC."), + DMI_MATCH(DMI_PRODUCT_NAME, "ET2012"), + }, + .driver_data = &quirk_asus_unknown, + }, + {}, +}; + static void eeepc_wmi_key_filter(struct asus_wmi_driver *asus_wmi, int *code, unsigned int *value, bool *autorelease) { @@ -144,33 +199,13 @@ static int eeepc_wmi_probe(struct platform_device *pdev) return 0; } -static void eeepc_dmi_check(struct asus_wmi_driver *driver) -{ - const char *model; - - model = dmi_get_system_info(DMI_PRODUCT_NAME); - if (!model) - return; - - /* - * Whitelist for wlan hotplug - * - * Asus 1000H needs the current hotplug code to handle - * Fn+F2 correctly. We may add other Asus here later, but - * it seems that most of the laptops supported by asus-wmi - * don't need to be on this list - */ - if (strcmp(model, "1000H") == 0) { - driver->hotplug_wireless = true; - pr_info("wlan hotplug enabled\n"); - } -} - static void eeepc_wmi_quirks(struct asus_wmi_driver *driver) { - driver->hotplug_wireless = hotplug_wireless; driver->wapf = -1; - eeepc_dmi_check(driver); + driver->quirks = &quirk_asus_unknown; + driver->quirks->hotplug_wireless = hotplug_wireless; + dmi_check_system(asus_quirks); + driver->quirks = quirks; } static struct asus_wmi_driver asus_wmi_driver = { @@ -182,7 +217,7 @@ static struct asus_wmi_driver asus_wmi_driver = { .input_phys = EEEPC_WMI_FILE "/input0", .key_filter = eeepc_wmi_key_filter, .probe = eeepc_wmi_probe, - .quirks = eeepc_wmi_quirks, + .detect_quirks = eeepc_wmi_quirks, }; -- cgit v1.2.3-70-g09d2 From 6e0044bedc1fc94a61cc32fa25dcab9a4e4a9218 Mon Sep 17 00:00:00 2001 From: AceLan Kao Date: Tue, 20 Mar 2012 09:53:09 +0100 Subject: asus-wmi: store backlight power status for AIO machine Due to some implementation reasons, ASUS ET2012 All-in-One machines can't report the correct backlight power status, it will always return 1. To track the backlight power status correctly, we have to store the status by ourselves. BTW, by the BIOS design, the backlight power will be turn on/off sequently, no matter what the value of the parameter will be. More over, the brightness adjustment command will turn on the backlight power. Those behaviors will make us fail to track the backlight power status. For example, While we are trying to turn on the backlight power, we will send out the brightness adjustment command and then trying to figure out if we have to turn on the backlight power, then send out the command. But, the real case is that, the backlight power turns on while sending the brightness adjustment command, and then we send out the command to turn on the backlight power, it actually will turn off the backlight power and the backlight power status we recorded becomes wrong. So, we have to seperate these two commands by a if statement. Signed-off-by: AceLan Kao Signed-off-by: Corentin Chary Signed-off-by: Matthew Garrett --- drivers/platform/x86/asus-wmi.c | 33 ++++++++++++++++++++------------- drivers/platform/x86/asus-wmi.h | 2 ++ drivers/platform/x86/eeepc-wmi.c | 15 ++++++++++++--- 3 files changed, 34 insertions(+), 16 deletions(-) (limited to 'drivers/platform/x86/asus-wmi.c') diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c index eb114f8d39e..c4ad76ee7b5 100644 --- a/drivers/platform/x86/asus-wmi.c +++ b/drivers/platform/x86/asus-wmi.c @@ -1076,7 +1076,12 @@ static int asus_wmi_hwmon_init(struct asus_wmi *asus) */ static int read_backlight_power(struct asus_wmi *asus) { - int ret = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_BACKLIGHT); + int ret; + if (asus->driver->quirks->store_backlight_power) + ret = !asus->driver->panel_power; + else + ret = asus_wmi_get_devstate_simple(asus, + ASUS_WMI_DEVID_BACKLIGHT); if (ret < 0) return ret; @@ -1138,24 +1143,23 @@ static int update_bl_status(struct backlight_device *bd) { struct asus_wmi *asus = bl_get_data(bd); u32 ctrl_param; - int power, err; - - if (asus->driver->quirks->scalar_panel_brightness) - ctrl_param = get_scalar_command(bd); - else - ctrl_param = bd->props.brightness; - - err = asus_wmi_set_devstate(ASUS_WMI_DEVID_BRIGHTNESS, - ctrl_param, NULL); - - if (err < 0) - return err; + int power, err = 0; power = read_backlight_power(asus); if (power != -ENODEV && bd->props.power != power) { ctrl_param = !!(bd->props.power == FB_BLANK_UNBLANK); err = asus_wmi_set_devstate(ASUS_WMI_DEVID_BACKLIGHT, ctrl_param, NULL); + if (asus->driver->quirks->store_backlight_power) + asus->driver->panel_power = bd->props.power; + } else { + if (asus->driver->quirks->scalar_panel_brightness) + ctrl_param = get_scalar_command(bd); + else + ctrl_param = bd->props.brightness; + + err = asus_wmi_set_devstate(ASUS_WMI_DEVID_BRIGHTNESS, + ctrl_param, NULL); } return err; } @@ -1217,6 +1221,9 @@ static int asus_wmi_backlight_init(struct asus_wmi *asus) asus->backlight_device = bd; + if (asus->driver->quirks->store_backlight_power) + asus->driver->panel_power = power; + bd->props.brightness = read_brightness(bd); bd->props.power = power; backlight_update_status(bd); diff --git a/drivers/platform/x86/asus-wmi.h b/drivers/platform/x86/asus-wmi.h index ac7dd4eaebd..35003e4f131 100644 --- a/drivers/platform/x86/asus-wmi.h +++ b/drivers/platform/x86/asus-wmi.h @@ -38,11 +38,13 @@ struct asus_wmi; struct quirk_entry { bool hotplug_wireless; bool scalar_panel_brightness; + bool store_backlight_power; }; struct asus_wmi_driver { int wapf; int brightness; + int panel_power; const char *name; struct module *owner; diff --git a/drivers/platform/x86/eeepc-wmi.c b/drivers/platform/x86/eeepc-wmi.c index 67186e6ca28..9f8ccf9f590 100644 --- a/drivers/platform/x86/eeepc-wmi.c +++ b/drivers/platform/x86/eeepc-wmi.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #include "asus-wmi.h" @@ -98,8 +99,13 @@ static struct quirk_entry quirk_asus_1000h = { .hotplug_wireless = true, }; +static struct quirk_entry quirk_asus_et2012_type1 = { + .store_backlight_power = true, +}; + static struct quirk_entry quirk_asus_et2012_type3 = { .scalar_panel_brightness = true, + .store_backlight_power = true, }; static int dmi_matched(const struct dmi_system_id *dmi) @@ -111,10 +117,12 @@ static int dmi_matched(const struct dmi_system_id *dmi) if (unlikely(strncmp(model, "ET2012", 6) == 0)) { const struct dmi_device *dev = NULL; char oemstring[30]; - while ((dev = dmi_find_device(DMI_DEV_TYPE_OEM_STRING, NULL, - dev))) { + while ((dev = dmi_find_device(DMI_DEV_TYPE_OEM_STRING, + NULL, dev))) { if (sscanf(dev->name, "AEMS%24c", oemstring) == 1) { - if (oemstring[18] == '3') + if (oemstring[18] == '1') + quirks = &quirk_asus_et2012_type1; + else if (oemstring[18] == '3') quirks = &quirk_asus_et2012_type3; break; } @@ -202,6 +210,7 @@ static int eeepc_wmi_probe(struct platform_device *pdev) static void eeepc_wmi_quirks(struct asus_wmi_driver *driver) { driver->wapf = -1; + driver->panel_power = FB_BLANK_UNBLANK; driver->quirks = &quirk_asus_unknown; driver->quirks->hotplug_wireless = hotplug_wireless; dmi_check_system(asus_quirks); -- cgit v1.2.3-70-g09d2 From 6a2bcccdb3206950d28e343476d9050e23e79b7e Mon Sep 17 00:00:00 2001 From: Corentin Chary Date: Tue, 20 Mar 2012 09:53:10 +0100 Subject: asus-wmi: move WAPF variable into quirks_entry Some models work better with different values of wapf, so move the variable into quriks_entry to make it more easy to give a specific value to different models. Based on original patch from AceLan Kao Cc: AceLan Kao Signed-off-by: Corentin Chary Signed-off-by: Matthew Garrett --- drivers/platform/x86/asus-nb-wmi.c | 6 +++++- drivers/platform/x86/asus-wmi.c | 4 ++-- drivers/platform/x86/asus-wmi.h | 2 +- drivers/platform/x86/eeepc-wmi.c | 2 +- 4 files changed, 9 insertions(+), 5 deletions(-) (limited to 'drivers/platform/x86/asus-wmi.c') diff --git a/drivers/platform/x86/asus-nb-wmi.c b/drivers/platform/x86/asus-nb-wmi.c index 1aea6b8019b..b12038c492c 100644 --- a/drivers/platform/x86/asus-nb-wmi.c +++ b/drivers/platform/x86/asus-nb-wmi.c @@ -51,9 +51,13 @@ static uint wapf; module_param(wapf, uint, 0444); MODULE_PARM_DESC(wapf, "WAPF value"); +static struct quirk_entry quirk_asus_unknown = { +}; + static void asus_nb_wmi_quirks(struct asus_wmi_driver *driver) { - driver->wapf = wapf; + driver->quirks = &quirk_asus_unknown; + driver->quirks->wapf = wapf; } static const struct key_entry asus_nb_wmi_keymap[] = { diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c index c4ad76ee7b5..ff9cfd83b09 100644 --- a/drivers/platform/x86/asus-wmi.c +++ b/drivers/platform/x86/asus-wmi.c @@ -1471,9 +1471,9 @@ static int asus_wmi_platform_init(struct asus_wmi *asus) /* CWAP allow to define the behavior of the Fn+F2 key, * this method doesn't seems to be present on Eee PCs */ - if (asus->driver->wapf >= 0) + if (asus->driver->quirks->wapf >= 0) asus_wmi_set_devstate(ASUS_WMI_DEVID_CWAP, - asus->driver->wapf, NULL); + asus->driver->quirks->wapf, NULL); return asus_wmi_sysfs_init(asus->platform_device); } diff --git a/drivers/platform/x86/asus-wmi.h b/drivers/platform/x86/asus-wmi.h index 35003e4f131..d43b6674200 100644 --- a/drivers/platform/x86/asus-wmi.h +++ b/drivers/platform/x86/asus-wmi.h @@ -39,10 +39,10 @@ struct quirk_entry { bool hotplug_wireless; bool scalar_panel_brightness; bool store_backlight_power; + int wapf; }; struct asus_wmi_driver { - int wapf; int brightness; int panel_power; diff --git a/drivers/platform/x86/eeepc-wmi.c b/drivers/platform/x86/eeepc-wmi.c index 9f8ccf9f590..389ff888cb6 100644 --- a/drivers/platform/x86/eeepc-wmi.c +++ b/drivers/platform/x86/eeepc-wmi.c @@ -209,10 +209,10 @@ static int eeepc_wmi_probe(struct platform_device *pdev) static void eeepc_wmi_quirks(struct asus_wmi_driver *driver) { - driver->wapf = -1; driver->panel_power = FB_BLANK_UNBLANK; driver->quirks = &quirk_asus_unknown; driver->quirks->hotplug_wireless = hotplug_wireless; + driver->quirks->wapf = -1; dmi_check_system(asus_quirks); driver->quirks = quirks; } -- cgit v1.2.3-70-g09d2 From ade28abdcb474531bb7045c032a286812c7f6d2a Mon Sep 17 00:00:00 2001 From: Corentin Chary Date: Tue, 20 Mar 2012 09:53:14 +0100 Subject: asus-wmi: don't update power and brightness when using scalar But we can still do it on other boards, as this might happen if the backlight driver change when update_bl is called. Signed-off-by: Corentin Chary Signed-off-by: Matthew Garrett --- drivers/platform/x86/asus-wmi.c | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) (limited to 'drivers/platform/x86/asus-wmi.c') diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c index ff9cfd83b09..7d1684bdbf6 100644 --- a/drivers/platform/x86/asus-wmi.c +++ b/drivers/platform/x86/asus-wmi.c @@ -1152,15 +1152,21 @@ static int update_bl_status(struct backlight_device *bd) ctrl_param, NULL); if (asus->driver->quirks->store_backlight_power) asus->driver->panel_power = bd->props.power; - } else { - if (asus->driver->quirks->scalar_panel_brightness) - ctrl_param = get_scalar_command(bd); - else - ctrl_param = bd->props.brightness; - err = asus_wmi_set_devstate(ASUS_WMI_DEVID_BRIGHTNESS, - ctrl_param, NULL); + /* When using scalar brightness, updating the brightness + * will mess with the backlight power */ + if (asus->driver->quirks->scalar_panel_brightness) + return err; } + + if (asus->driver->quirks->scalar_panel_brightness) + ctrl_param = get_scalar_command(bd); + else + ctrl_param = bd->props.brightness; + + err = asus_wmi_set_devstate(ASUS_WMI_DEVID_BRIGHTNESS, + ctrl_param, NULL); + return err; } -- cgit v1.2.3-70-g09d2