From bf8b29c8f7f8269e99eca8b19048ed5b34b51810 Mon Sep 17 00:00:00 2001 From: Henrique de Moraes Holschuh Date: Thu, 25 Feb 2010 21:28:56 -0300 Subject: thinkpad-acpi: document HKEY event 3006 Event 0x3006 is used to help power management of the ODD in the UltraBay. The EC generates this event when the ODD eject button is pressed (even if the bay is powered down). Normally, Linux doesn't need this as we keep the SATA link powered up (which wastes power). The EC powers up the bay by itself when the ODD eject button is pressed, and the SATA PHY reports the hotplug. However, we could also power that SATA link down (and for that matter, also power down the Ultrabay) if the ODD is left idle for a while with no disk inside, and use event 0x3006 to know when we need that SATA link powered back up. For now, just stop asking for more information when event 0x3006 is seen, there is no point in pestering users about it anymore. Signed-off-by: Henrique de Moraes Holschuh Cc: stable@kernel.org --- drivers/platform/x86/thinkpad_acpi.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'drivers/platform/x86') diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index eb603f1d55ca..049041a47f8d 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -3655,13 +3655,19 @@ static void hotkey_notify(struct ibm_struct *ibm, u32 event) break; case 3: /* 0x3000-0x3FFF: bay-related wakeups */ - if (hkey == TP_HKEY_EV_BAYEJ_ACK) { + switch (hkey) { + case TP_HKEY_EV_BAYEJ_ACK: hotkey_autosleep_ack = 1; printk(TPACPI_INFO "bay ejected\n"); hotkey_wakeup_hotunplug_complete_notify_change(); known_ev = true; - } else { + break; + case TP_HKEY_EV_OPTDRV_EJ: + /* FIXME: kick libata if SATA link offline */ + known_ev = true; + break; + default: known_ev = false; } break; -- cgit v1.2.3 From 7d1894d8d1c411d2dad95abfe0f65bacf68c4afa Mon Sep 17 00:00:00 2001 From: Henrique de Moraes Holschuh Date: Thu, 25 Feb 2010 21:28:56 -0300 Subject: thinkpad-acpi: R52 brightness_mode has been confirmed We can stop pestering users for confirmation of the brightness_mode default for firmware TP-76. While at it, add a few missing comments in that quirk table. Reported-by: Whoopie Signed-off-by: Henrique de Moraes Holschuh Cc: stable@kernel.org --- drivers/platform/x86/thinkpad_acpi.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/platform/x86') diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index 049041a47f8d..06657b71171c 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -6139,13 +6139,13 @@ static const struct tpacpi_quirk brightness_quirk_table[] __initconst = { TPACPI_Q_IBM('1', 'Y', TPACPI_BRGHT_Q_EC), /* T43/p ATI */ /* Models with ATI GPUs that can use ECNVRAM */ - TPACPI_Q_IBM('1', 'R', TPACPI_BRGHT_Q_EC), + TPACPI_Q_IBM('1', 'R', TPACPI_BRGHT_Q_EC), /* R50,51 T40-42 */ TPACPI_Q_IBM('1', 'Q', TPACPI_BRGHT_Q_ASK|TPACPI_BRGHT_Q_EC), - TPACPI_Q_IBM('7', '6', TPACPI_BRGHT_Q_ASK|TPACPI_BRGHT_Q_EC), + TPACPI_Q_IBM('7', '6', TPACPI_BRGHT_Q_EC), /* R52 */ TPACPI_Q_IBM('7', '8', TPACPI_BRGHT_Q_ASK|TPACPI_BRGHT_Q_EC), /* Models with Intel Extreme Graphics 2 */ - TPACPI_Q_IBM('1', 'U', TPACPI_BRGHT_Q_NOEC), + TPACPI_Q_IBM('1', 'U', TPACPI_BRGHT_Q_NOEC), /* X40 */ TPACPI_Q_IBM('1', 'V', TPACPI_BRGHT_Q_ASK|TPACPI_BRGHT_Q_EC), TPACPI_Q_IBM('1', 'W', TPACPI_BRGHT_Q_ASK|TPACPI_BRGHT_Q_EC), -- cgit v1.2.3 From b589ea4c44170d3f7a845684e2d1b3b9571663af Mon Sep 17 00:00:00 2001 From: Henrique de Moraes Holschuh Date: Thu, 25 Feb 2010 21:28:58 -0300 Subject: thinkpad-acpi: fix poll thread auto-start The driver was not starting the NVRAM polling thread if the input device was bound immediately after registration. This fixes: http://bugzilla.kernel.org/show_bug.cgi?id=15118 Reported-by: Florian Zumbiehl Signed-off-by: Henrique de Moraes Holschuh Cc: stable@kernel.org --- drivers/platform/x86/thinkpad_acpi.c | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) (limited to 'drivers/platform/x86') diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index 06657b71171c..933bcc477f4a 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -2607,16 +2607,11 @@ static int hotkey_inputdev_open(struct input_dev *dev) { switch (tpacpi_lifecycle) { case TPACPI_LIFE_INIT: - /* - * hotkey_init will call hotkey_poll_setup_safe - * at the appropriate moment - */ - return 0; - case TPACPI_LIFE_EXITING: - return -EBUSY; case TPACPI_LIFE_RUNNING: hotkey_poll_setup_safe(false); return 0; + case TPACPI_LIFE_EXITING: + return -EBUSY; } /* Should only happen if tpacpi_lifecycle is corrupt */ @@ -2627,7 +2622,7 @@ static int hotkey_inputdev_open(struct input_dev *dev) static void hotkey_inputdev_close(struct input_dev *dev) { /* disable hotkey polling when possible */ - if (tpacpi_lifecycle == TPACPI_LIFE_RUNNING && + if (tpacpi_lifecycle != TPACPI_LIFE_EXITING && !(hotkey_source_mask & hotkey_driver_mask)) hotkey_poll_setup_safe(false); } @@ -9038,6 +9033,9 @@ static int __init thinkpad_acpi_module_init(void) return ret; } } + + tpacpi_lifecycle = TPACPI_LIFE_RUNNING; + ret = input_register_device(tpacpi_inputdev); if (ret < 0) { printk(TPACPI_ERR "unable to register input device\n"); @@ -9047,7 +9045,6 @@ static int __init thinkpad_acpi_module_init(void) tp_features.input_device_registered = 1; } - tpacpi_lifecycle = TPACPI_LIFE_RUNNING; return 0; } -- cgit v1.2.3 From 7f0cf712a74fcc3ad21f0bde95bd32c2f2cc3888 Mon Sep 17 00:00:00 2001 From: Henrique de Moraes Holschuh Date: Thu, 25 Feb 2010 21:29:00 -0300 Subject: thinkpad-acpi: make driver events work in NVRAM poll mode Thadeu Lima de Souza Cascardo reports this: Brightness notification does not work until the user writes to hotkey_mask attribute. That's because the polling thread will only run if hotkey_user_mask is set and someone is reading the input device or if hotkey_driver_mask is set. In this second case, this condition is not tested after the mask is changed, because the brightness and volume drivers are started after the hotkey drivers. Fix tpacpi_hotkey_driver_mask_set() to call hotkey_poll_setup(), so that the poller kthread will be started when needed. Reported-by: Thadeu Lima de Souza Cascardo Tested-by: Thadeu Lima de Souza Cascardo Signed-off-by: Henrique de Moraes Holschuh Cc: Andrew Morton Cc: stable@kernel.org --- drivers/platform/x86/thinkpad_acpi.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) (limited to 'drivers/platform/x86') diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index 933bcc477f4a..5f450831e5f0 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -2082,6 +2082,7 @@ static struct attribute_set *hotkey_dev_attributes; static void tpacpi_driver_event(const unsigned int hkey_event); static void hotkey_driver_event(const unsigned int scancode); +static void hotkey_poll_setup(const bool may_warn); /* HKEY.MHKG() return bits */ #define TP_HOTKEY_TABLET_MASK (1 << 3) @@ -2264,6 +2265,8 @@ static int tpacpi_hotkey_driver_mask_set(const u32 mask) rc = hotkey_mask_set((hotkey_acpi_mask | hotkey_driver_mask) & ~hotkey_source_mask); + hotkey_poll_setup(true); + mutex_unlock(&hotkey_mutex); return rc; @@ -2548,7 +2551,7 @@ static void hotkey_poll_stop_sync(void) } /* call with hotkey_mutex held */ -static void hotkey_poll_setup(bool may_warn) +static void hotkey_poll_setup(const bool may_warn) { const u32 poll_driver_mask = hotkey_driver_mask & hotkey_source_mask; const u32 poll_user_mask = hotkey_user_mask & hotkey_source_mask; @@ -2579,7 +2582,7 @@ static void hotkey_poll_setup(bool may_warn) } } -static void hotkey_poll_setup_safe(bool may_warn) +static void hotkey_poll_setup_safe(const bool may_warn) { mutex_lock(&hotkey_mutex); hotkey_poll_setup(may_warn); @@ -2597,7 +2600,11 @@ static void hotkey_poll_set_freq(unsigned int freq) #else /* CONFIG_THINKPAD_ACPI_HOTKEY_POLL */ -static void hotkey_poll_setup_safe(bool __unused) +static void hotkey_poll_setup(const bool __unused) +{ +} + +static void hotkey_poll_setup_safe(const bool __unused) { } -- cgit v1.2.3 From 08fedfc903c78e380b0baa7b57c52d367794d0a5 Mon Sep 17 00:00:00 2001 From: Henrique de Moraes Holschuh Date: Thu, 25 Feb 2010 22:22:07 -0300 Subject: thinkpad-acpi: fix bluetooth/wwan resume Studying the DSDTs of various thinkpads, it looks like bit 3 of the argument to SBDC and SWAN is not "set radio to last state on resume". Rather, it seems to be "if this bit is set, enable radio on resume, otherwise disable it on resume". So, the proper way to prepare the radios for S3 suspend is: disable radio and clear bit 3 on the SBDC/SWAN call to to resume with radio disabled, and enable radio and set bit 3 on the SBDC/SWAN call to resume with the radio enabled. Also, for persistent devices, the rfkill core does not restore state, so we really need to get the firmware to do the right thing. We don't sync the radio state on suspend, instead we trust the BIOS to not do anything weird if we never touched the radio state since boot. Time will tell if that's a wise way of doing things... Signed-off-by: Henrique de Moraes Holschuh Cc: stable@kernel.org --- drivers/platform/x86/thinkpad_acpi.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) (limited to 'drivers/platform/x86') diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index 5f450831e5f0..3af4628d7dd1 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -3878,7 +3878,7 @@ enum { TP_ACPI_BLUETOOTH_HWPRESENT = 0x01, /* Bluetooth hw available */ TP_ACPI_BLUETOOTH_RADIOSSW = 0x02, /* Bluetooth radio enabled */ TP_ACPI_BLUETOOTH_RESUMECTRL = 0x04, /* Bluetooth state at resume: - off / last state */ + 0 = disable, 1 = enable */ }; enum { @@ -3924,10 +3924,11 @@ static int bluetooth_set_status(enum tpacpi_rfkill_state state) } #endif - /* We make sure to keep TP_ACPI_BLUETOOTH_RESUMECTRL off */ - status = TP_ACPI_BLUETOOTH_RESUMECTRL; if (state == TPACPI_RFK_RADIO_ON) - status |= TP_ACPI_BLUETOOTH_RADIOSSW; + status = TP_ACPI_BLUETOOTH_RADIOSSW + | TP_ACPI_BLUETOOTH_RESUMECTRL; + else + status = 0; if (!acpi_evalf(hkey_handle, NULL, "SBDC", "vd", status)) return -EIO; @@ -4078,7 +4079,7 @@ enum { TP_ACPI_WANCARD_HWPRESENT = 0x01, /* Wan hw available */ TP_ACPI_WANCARD_RADIOSSW = 0x02, /* Wan radio enabled */ TP_ACPI_WANCARD_RESUMECTRL = 0x04, /* Wan state at resume: - off / last state */ + 0 = disable, 1 = enable */ }; #define TPACPI_RFK_WWAN_SW_NAME "tpacpi_wwan_sw" @@ -4115,10 +4116,11 @@ static int wan_set_status(enum tpacpi_rfkill_state state) } #endif - /* We make sure to set TP_ACPI_WANCARD_RESUMECTRL */ - status = TP_ACPI_WANCARD_RESUMECTRL; if (state == TPACPI_RFK_RADIO_ON) - status |= TP_ACPI_WANCARD_RADIOSSW; + status = TP_ACPI_WANCARD_RADIOSSW + | TP_ACPI_WANCARD_RESUMECTRL; + else + status = 0; if (!acpi_evalf(hkey_handle, NULL, "SWAN", "vd", status)) return -EIO; -- cgit v1.2.3 From b525c06cdbd8a3963f0173ccd23f9147d4c384b5 Mon Sep 17 00:00:00 2001 From: Henrique de Moraes Holschuh Date: Thu, 25 Feb 2010 22:22:22 -0300 Subject: thinkpad-acpi: lock down video output state access Given the right combination of ThinkPad and X.org, just reading the video output control state is enough to hard-crash X.org. Until the day I somehow find out a model or BIOS cut date to not provide this feature to ThinkPads that can do video switching through X RandR, change permissions so that only processes with CAP_SYS_ADMIN can access any sort of video output control state. This bug could be considered a local DoS I suppose, as it allows any non-privledged local user to cause some versions of X.org to hard-crash some ThinkPads. Reported-by: Jidanni Signed-off-by: Henrique de Moraes Holschuh Cc: stable@kernel.org --- drivers/platform/x86/Kconfig | 10 ++++++++-- drivers/platform/x86/thinkpad_acpi.c | 15 +++++++++++++-- 2 files changed, 21 insertions(+), 4 deletions(-) (limited to 'drivers/platform/x86') diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index f526e735c5ab..11fce79b61d1 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -319,9 +319,15 @@ config THINKPAD_ACPI_VIDEO server running, phase of the moon, and the current mood of Schroedinger's cat. If you can use X.org's RandR to control your ThinkPad's video output ports instead of this feature, - don't think twice: do it and say N here to save some memory. + don't think twice: do it and say N here to save memory and avoid + bad interactions with X.org. - If you are not sure, say Y here. + NOTE: access to this feature is limited to processes with the + CAP_SYS_ADMIN capability, to avoid local DoS issues in platforms + where it interacts badly with X.org. + + If you are not sure, say Y here but do try to check if you could + be using X.org RandR instead. config THINKPAD_ACPI_HOTKEY_POLL bool "Support NVRAM polling for hot keys" diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index 3af4628d7dd1..5d02cc06d1a7 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -286,6 +286,7 @@ struct ibm_init_struct { char param[32]; int (*init) (struct ibm_init_struct *); + mode_t base_procfs_mode; struct ibm_struct *data; }; @@ -4629,6 +4630,10 @@ static int video_read(struct seq_file *m) return 0; } + /* Even reads can crash X.org, so... */ + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + status = video_outputsw_get(); if (status < 0) return status; @@ -4662,6 +4667,10 @@ static int video_write(char *buf) if (video_supported == TPACPI_VIDEO_NONE) return -ENODEV; + /* Even reads can crash X.org, let alone writes... */ + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + enable = 0; disable = 0; @@ -8487,9 +8496,10 @@ static int __init ibm_init(struct ibm_init_struct *iibm) "%s installed\n", ibm->name); if (ibm->read) { - mode_t mode; + mode_t mode = iibm->base_procfs_mode; - mode = S_IRUGO; + if (!mode) + mode = S_IRUGO; if (ibm->write) mode |= S_IWUSR; entry = proc_create_data(ibm->name, mode, proc_dir, @@ -8680,6 +8690,7 @@ static struct ibm_init_struct ibms_init[] __initdata = { #ifdef CONFIG_THINKPAD_ACPI_VIDEO { .init = video_init, + .base_procfs_mode = S_IRUSR, .data = &video_driver_data, }, #endif -- cgit v1.2.3 From 88cc83772a3c7756b9f2b4ba835545ad90a08409 Mon Sep 17 00:00:00 2001 From: Henrique de Moraes Holschuh Date: Sat, 27 Feb 2010 18:45:29 -0300 Subject: thinkpad-acpi: fix ALSA callback return status Clemens Ladisch reports that thinkpad-acpi improperly implements the ALSA API, and always returns 0 for success for the "put" callbacks while the API requires it to return "1" when the control value has been changed in the hardware/firmware. Rework the volume subdriver to be able to properly implement the ALSA API. Based on a patch by Clemens Ladisch . This fix is also needed on 2.6.33. Reported-by: Clemens Ladisch Signed-off-by: Henrique de Moraes Holschuh Cc: stable@kernel.org --- drivers/platform/x86/thinkpad_acpi.c | 39 +++++++++++++++++++++++++++--------- 1 file changed, 29 insertions(+), 10 deletions(-) (limited to 'drivers/platform/x86') diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index 5d02cc06d1a7..e7b0c3bcef89 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -6541,7 +6541,8 @@ static int volume_set_status(const u8 status) return volume_set_status_ec(status); } -static int volume_set_mute_ec(const bool mute) +/* returns < 0 on error, 0 on no change, 1 on change */ +static int __volume_set_mute_ec(const bool mute) { int rc; u8 s, n; @@ -6556,22 +6557,37 @@ static int volume_set_mute_ec(const bool mute) n = (mute) ? s | TP_EC_AUDIO_MUTESW_MSK : s & ~TP_EC_AUDIO_MUTESW_MSK; - if (n != s) + if (n != s) { rc = volume_set_status_ec(n); + if (!rc) + rc = 1; + } unlock: mutex_unlock(&volume_mutex); return rc; } +static int volume_alsa_set_mute(const bool mute) +{ + dbg_printk(TPACPI_DBG_MIXER, "ALSA: trying to %smute\n", + (mute) ? "" : "un"); + return __volume_set_mute_ec(mute); +} + static int volume_set_mute(const bool mute) { + int rc; + dbg_printk(TPACPI_DBG_MIXER, "trying to %smute\n", (mute) ? "" : "un"); - return volume_set_mute_ec(mute); + + rc = __volume_set_mute_ec(mute); + return (rc < 0) ? rc : 0; } -static int volume_set_volume_ec(const u8 vol) +/* returns < 0 on error, 0 on no change, 1 on change */ +static int __volume_set_volume_ec(const u8 vol) { int rc; u8 s, n; @@ -6588,19 +6604,22 @@ static int volume_set_volume_ec(const u8 vol) n = (s & ~TP_EC_AUDIO_LVL_MSK) | vol; - if (n != s) + if (n != s) { rc = volume_set_status_ec(n); + if (!rc) + rc = 1; + } unlock: mutex_unlock(&volume_mutex); return rc; } -static int volume_set_volume(const u8 vol) +static int volume_alsa_set_volume(const u8 vol) { dbg_printk(TPACPI_DBG_MIXER, - "trying to set volume level to %hu\n", vol); - return volume_set_volume_ec(vol); + "ALSA: trying to set volume level to %hu\n", vol); + return __volume_set_volume_ec(vol); } static void volume_alsa_notify_change(void) @@ -6647,7 +6666,7 @@ static int volume_alsa_vol_get(struct snd_kcontrol *kcontrol, static int volume_alsa_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - return volume_set_volume(ucontrol->value.integer.value[0]); + return volume_alsa_set_volume(ucontrol->value.integer.value[0]); } #define volume_alsa_mute_info snd_ctl_boolean_mono_info @@ -6670,7 +6689,7 @@ static int volume_alsa_mute_get(struct snd_kcontrol *kcontrol, static int volume_alsa_mute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - return volume_set_mute(!ucontrol->value.integer.value[0]); + return volume_alsa_set_mute(!ucontrol->value.integer.value[0]); } static struct snd_kcontrol_new volume_alsa_control_vol __devinitdata = { -- cgit v1.2.3 From ced69c59811f05b2f8378467cbb82ac6ed3c6a5a Mon Sep 17 00:00:00 2001 From: Alan Jenkins Date: Sat, 20 Feb 2010 11:02:24 +0000 Subject: eeepc-laptop: disable wireless hotplug for 1005PE The wireless hotplug code is not needed on this model, and it disables the wired ethernet card. (Like on the 1005HA and 1201N). References: Signed-off-by: Alan Jenkins Reported-by: Ansgar Burchardt CC: stable@kernel.org --- drivers/platform/x86/eeepc-laptop.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/platform/x86') diff --git a/drivers/platform/x86/eeepc-laptop.c b/drivers/platform/x86/eeepc-laptop.c index e2be6bb33d92..6a47bb7066d8 100644 --- a/drivers/platform/x86/eeepc-laptop.c +++ b/drivers/platform/x86/eeepc-laptop.c @@ -1277,7 +1277,8 @@ static void eeepc_dmi_check(struct eeepc_laptop *eeepc) * hotplug code. In fact, current hotplug code seems to unplug another * device... */ - if (strcmp(model, "1005HA") == 0 || strcmp(model, "1201N") == 0) { + if (strcmp(model, "1005HA") == 0 || strcmp(model, "1201N") == 0 || + strcmp(model, "1005PE") == 0) { eeepc->hotplug_disabled = true; pr_info("wlan hotplug disabled\n"); } -- cgit v1.2.3 From bc9d24a3aeb1532fc3e234907a8b6d671f7ed68f Mon Sep 17 00:00:00 2001 From: Alan Jenkins Date: Mon, 22 Feb 2010 16:03:58 +0000 Subject: eeepc-laptop: check wireless hotplug events Before we mark the wireless device as unplugged, check PCI config space to see whether the wireless device is really disabled (and vice versa). This works around newer models which don't want the hotplug code, where we end up disabling the wired network device. My old 701 still works correctly with this. I can also simulate an afflicted model by changing the hardcoded PCI bus/slot number in the driver, and it seems to work nicely (although it is a bit noisy). In future this type of hotplug support will be implemented by the PCI core. The existing blacklist and the new warning message will be removed at that point. Signed-off-by: Alan Jenkins Signed-off-by: Corentin Chary --- drivers/platform/x86/eeepc-laptop.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'drivers/platform/x86') diff --git a/drivers/platform/x86/eeepc-laptop.c b/drivers/platform/x86/eeepc-laptop.c index 6a47bb7066d8..9a844caa3756 100644 --- a/drivers/platform/x86/eeepc-laptop.c +++ b/drivers/platform/x86/eeepc-laptop.c @@ -578,6 +578,8 @@ static void eeepc_rfkill_hotplug(struct eeepc_laptop *eeepc) struct pci_dev *dev; struct pci_bus *bus; bool blocked = eeepc_wlan_rfkill_blocked(eeepc); + bool absent; + u32 l; if (eeepc->wlan_rfkill) rfkill_set_sw_state(eeepc->wlan_rfkill, blocked); @@ -591,6 +593,22 @@ static void eeepc_rfkill_hotplug(struct eeepc_laptop *eeepc) goto out_unlock; } + if (pci_bus_read_config_dword(bus, 0, PCI_VENDOR_ID, &l)) { + pr_err("Unable to read PCI config space?\n"); + goto out_unlock; + } + absent = (l == 0xffffffff); + + if (blocked != absent) { + pr_warning("BIOS says wireless lan is %s, " + "but the pci device is %s\n", + blocked ? "blocked" : "unblocked", + absent ? "absent" : "present"); + pr_warning("skipped wireless hotplug as probably " + "inappropriate for this model\n"); + goto out_unlock; + } + if (!blocked) { dev = pci_get_slot(bus, 0); if (dev) { -- cgit v1.2.3 From 0e875f4905817c03ba49447b49af093552e66e95 Mon Sep 17 00:00:00 2001 From: Corentin Chary Date: Sun, 10 Jan 2010 20:49:26 +0100 Subject: asus-laptop: add wireless and bluetooth status parameter These to parameter allow to set the status of wlan and bluetooth device when the module load. On some models, the device will always be down on boot, so the default behavior is to always enable these devices. Signed-off-by: Corentin Chary --- drivers/platform/x86/asus-laptop.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) (limited to 'drivers/platform/x86') diff --git a/drivers/platform/x86/asus-laptop.c b/drivers/platform/x86/asus-laptop.c index 61a1c7503658..1d799b3fc4e8 100644 --- a/drivers/platform/x86/asus-laptop.c +++ b/drivers/platform/x86/asus-laptop.c @@ -113,6 +113,19 @@ static uint wapf = 1; module_param(wapf, uint, 0644); MODULE_PARM_DESC(wapf, "WAPF value"); +static uint wireless_status = 1; +static uint bluetooth_status = 1; + +module_param(wireless_status, uint, 0644); +MODULE_PARM_DESC(wireless_status, "Set the wireless status on boot " + "(0 = disabled, 1 = enabled, -1 = don't do anything). " + "default is 1"); + +module_param(bluetooth_status, uint, 0644); +MODULE_PARM_DESC(bluetooth_status, "Set the wireless status on boot " + "(0 = disabled, 1 = enabled, -1 = don't do anything). " + "default is 1"); + #define ASUS_HANDLE(object, paths...) \ static acpi_handle object##_handle = NULL; \ static char *object##_paths[] = { paths } @@ -1272,8 +1285,10 @@ static int asus_hotk_add(struct acpi_device *device) asus_hotk_found = 1; /* WLED and BLED are on by default */ - write_status(bt_switch_handle, 1, BT_ON); - write_status(wl_switch_handle, 1, WL_ON); + if (bluetooth_status != -1) + write_status(bt_switch_handle, !!bluetooth_status, BT_ON); + if (wireless_status != -1) + write_status(wl_switch_handle, !!wireless_status, WL_ON); /* If the h/w switch is off, we need to check the real status */ write_status(NULL, read_status(BT_ON), BT_ON); -- cgit v1.2.3 From e5b50f6a2b00de266f03c2c7219b798648124ea5 Mon Sep 17 00:00:00 2001 From: Corentin Chary Date: Sat, 28 Nov 2009 10:19:55 +0100 Subject: asus-laptop: no need to check argument of set_brightness() We already tell the backlight class our maximum brightness value; it will validate the user requested values for us. Signed-off-by: Corentin Chary --- drivers/platform/x86/asus-laptop.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) (limited to 'drivers/platform/x86') diff --git a/drivers/platform/x86/asus-laptop.c b/drivers/platform/x86/asus-laptop.c index 1d799b3fc4e8..013ab86b1c8d 100644 --- a/drivers/platform/x86/asus-laptop.c +++ b/drivers/platform/x86/asus-laptop.c @@ -571,17 +571,11 @@ static int read_brightness(struct backlight_device *bd) static int set_brightness(struct backlight_device *bd, int value) { - int ret = 0; - - value = (0 < value) ? ((15 < value) ? 15 : value) : 0; - /* 0 <= value <= 15 */ - if (write_acpi_int(brightness_set_handle, NULL, value, NULL)) { pr_warning("Error changing brightness\n"); - ret = -EIO; + return -EIO; } - - return ret; + return 0; } static int update_bl_status(struct backlight_device *bd) -- cgit v1.2.3 From d8c6732382a24d2ef23665207263a17f04e3d75a Mon Sep 17 00:00:00 2001 From: Corentin Chary Date: Sat, 28 Nov 2009 10:27:51 +0100 Subject: asus-laptop: simplify write_acpi_int We only need a buffer for "INIT". Adds write_acpi_init_ret for it. Signed-off-by: Corentin Chary --- drivers/platform/x86/asus-laptop.c | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) (limited to 'drivers/platform/x86') diff --git a/drivers/platform/x86/asus-laptop.c b/drivers/platform/x86/asus-laptop.c index 013ab86b1c8d..7058cb56f338 100644 --- a/drivers/platform/x86/asus-laptop.c +++ b/drivers/platform/x86/asus-laptop.c @@ -352,8 +352,8 @@ static struct key_entry asus_keymap[] = { * * returns 0 if write is successful, -1 else. */ -static int write_acpi_int(acpi_handle handle, const char *method, int val, - struct acpi_buffer *output) +static int write_acpi_int_ret(acpi_handle handle, const char *method, int val, + struct acpi_buffer *output) { struct acpi_object_list params; /* list of input parameters (an int) */ union acpi_object in_obj; /* the only param we use */ @@ -374,6 +374,11 @@ static int write_acpi_int(acpi_handle handle, const char *method, int val, return -1; } +static int write_acpi_int(acpi_handle handle, const char *method, int val) +{ + return write_acpi_int_ret(handle, method, val, NULL); +} + static int read_wireless_status(int mask) { unsigned long long status; @@ -437,7 +442,7 @@ static void write_status(acpi_handle handle, int out, int mask) break; } - if (write_acpi_int(handle, NULL, out, NULL)) + if (write_acpi_int(handle, NULL, out)) pr_warning(" write failed %x\n", mask); } @@ -496,7 +501,7 @@ static int set_kled_lvl(int kblv) else kblv = 0; - if (write_acpi_int(kled_set_handle, NULL, kblv, NULL)) { + if (write_acpi_int(kled_set_handle, NULL, kblv)) { pr_warning("Keyboard LED display write failed\n"); return -EINVAL; } @@ -571,7 +576,7 @@ static int read_brightness(struct backlight_device *bd) static int set_brightness(struct backlight_device *bd, int value) { - if (write_acpi_int(brightness_set_handle, NULL, value, NULL)) { + if (write_acpi_int(brightness_set_handle, NULL, value)) { pr_warning("Error changing brightness\n"); return -EIO; } @@ -710,7 +715,7 @@ static ssize_t store_ledd(struct device *dev, struct device_attribute *attr, rv = parse_arg(buf, count, &value); if (rv > 0) { - if (write_acpi_int(ledd_set_handle, NULL, value, NULL)) + if (write_acpi_int(ledd_set_handle, NULL, value)) pr_warning("LED display write failed\n"); else hotk->ledd_status = (u32) value; @@ -755,7 +760,7 @@ static ssize_t store_bluetooth(struct device *dev, static void set_display(int value) { /* no sanity check needed for now */ - if (write_acpi_int(display_set_handle, NULL, value, NULL)) + if (write_acpi_int(display_set_handle, NULL, value)) pr_warning("Error setting display\n"); return; } @@ -814,7 +819,7 @@ static ssize_t store_disp(struct device *dev, struct device_attribute *attr, */ static void set_light_sens_switch(int value) { - if (write_acpi_int(ls_switch_handle, NULL, value, NULL)) + if (write_acpi_int(ls_switch_handle, NULL, value)) pr_warning("Error setting light sensor switch\n"); hotk->light_switch = value; } @@ -839,7 +844,7 @@ static ssize_t store_lssw(struct device *dev, struct device_attribute *attr, static void set_light_sens_level(int value) { - if (write_acpi_int(ls_level_handle, NULL, value, NULL)) + if (write_acpi_int(ls_level_handle, NULL, value)) pr_warning("Error setting light sensor level\n"); hotk->light_level = value; } @@ -1104,7 +1109,7 @@ static int asus_hotk_get_info(void) pr_warning("Couldn't get the DSDT table header\n"); /* We have to write 0 on init this far for all ASUS models */ - if (write_acpi_int(hotk->handle, "INIT", 0, &buffer)) { + if (write_acpi_int_ret(hotk->handle, "INIT", 0, &buffer)) { pr_err("Hotkey initialization failed\n"); return -ENODEV; } @@ -1119,7 +1124,7 @@ static int asus_hotk_get_info(void) (uint) bsts_result); /* This too ... */ - write_acpi_int(hotk->handle, "CWAP", wapf, NULL); + write_acpi_int(hotk->handle, "CWAP", wapf); /* * Try to match the object returned by INIT to the specific model. -- cgit v1.2.3 From 91687cc89af4c447483ec65097809c38c8622639 Mon Sep 17 00:00:00 2001 From: Corentin Chary Date: Sat, 28 Nov 2009 10:32:34 +0100 Subject: asus-laptop: use tabs to indent macros and remove unused ones Signed-off-by: Corentin Chary --- drivers/platform/x86/asus-laptop.c | 51 ++++++++++++++++---------------------- 1 file changed, 22 insertions(+), 29 deletions(-) (limited to 'drivers/platform/x86') diff --git a/drivers/platform/x86/asus-laptop.c b/drivers/platform/x86/asus-laptop.c index 7058cb56f338..5889bda5a03b 100644 --- a/drivers/platform/x86/asus-laptop.c +++ b/drivers/platform/x86/asus-laptop.c @@ -50,50 +50,43 @@ #include #include -#define ASUS_LAPTOP_VERSION "0.42" +#define ASUS_LAPTOP_VERSION "0.42" -#define ASUS_HOTK_NAME "Asus Laptop Support" -#define ASUS_HOTK_CLASS "hotkey" -#define ASUS_HOTK_DEVICE_NAME "Hotkey" -#define ASUS_HOTK_FILE KBUILD_MODNAME -#define ASUS_HOTK_PREFIX "\\_SB.ATKD." +#define ASUS_HOTK_NAME "Asus Laptop Support" +#define ASUS_HOTK_CLASS "hotkey" +#define ASUS_HOTK_DEVICE_NAME "Hotkey" +#define ASUS_HOTK_FILE KBUILD_MODNAME +#define ASUS_HOTK_PREFIX "\\_SB.ATKD." /* * Some events we use, same for all Asus */ -#define ATKD_BR_UP 0x10 -#define ATKD_BR_DOWN 0x20 -#define ATKD_LCD_ON 0x33 -#define ATKD_LCD_OFF 0x34 +#define ATKD_BR_UP 0x10 +#define ATKD_BR_DOWN 0x20 +#define ATKD_LCD_ON 0x33 +#define ATKD_LCD_OFF 0x34 /* * Known bits returned by \_SB.ATKD.HWRS */ -#define WL_HWRS 0x80 -#define BT_HWRS 0x100 +#define WL_HWRS 0x80 +#define BT_HWRS 0x100 /* * Flags for hotk status * WL_ON and BT_ON are also used for wireless_status() */ -#define WL_ON 0x01 /* internal Wifi */ -#define BT_ON 0x02 /* internal Bluetooth */ -#define MLED_ON 0x04 /* mail LED */ -#define TLED_ON 0x08 /* touchpad LED */ -#define RLED_ON 0x10 /* Record LED */ -#define PLED_ON 0x20 /* Phone LED */ -#define GLED_ON 0x40 /* Gaming LED */ -#define LCD_ON 0x80 /* LCD backlight */ -#define GPS_ON 0x100 /* GPS */ -#define KEY_ON 0x200 /* Keyboard backlight */ - -#define ASUS_LOG ASUS_HOTK_FILE ": " -#define ASUS_ERR KERN_ERR ASUS_LOG -#define ASUS_WARNING KERN_WARNING ASUS_LOG -#define ASUS_NOTICE KERN_NOTICE ASUS_LOG -#define ASUS_INFO KERN_INFO ASUS_LOG -#define ASUS_DEBUG KERN_DEBUG ASUS_LOG +#define WL_ON 0x01 /* internal Wifi */ +#define BT_ON 0x02 /* internal Bluetooth */ +#define MLED_ON 0x04 /* mail LED */ +#define TLED_ON 0x08 /* touchpad LED */ +#define RLED_ON 0x10 /* Record LED */ +#define PLED_ON 0x20 /* Phone LED */ +#define GLED_ON 0x40 /* Gaming LED */ +#define LCD_ON 0x80 /* LCD backlight */ +#define GPS_ON 0x100 /* GPS */ +#define KEY_ON 0x200 /* Keyboard backlight */ MODULE_AUTHOR("Julien Lerouge, Karol Kozimor, Corentin Chary"); MODULE_DESCRIPTION(ASUS_HOTK_NAME); -- cgit v1.2.3 From 619d8b1187f2e13f6f848b1b2a4d83c2c9e2a140 Mon Sep 17 00:00:00 2001 From: Corentin Chary Date: Sat, 28 Nov 2009 10:35:37 +0100 Subject: asus-laptop: remove unecessary hotk != NULL check Signed-off-by: Corentin Chary --- drivers/platform/x86/asus-laptop.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'drivers/platform/x86') diff --git a/drivers/platform/x86/asus-laptop.c b/drivers/platform/x86/asus-laptop.c index 5889bda5a03b..74463a07d48b 100644 --- a/drivers/platform/x86/asus-laptop.c +++ b/drivers/platform/x86/asus-laptop.c @@ -941,10 +941,6 @@ static void asus_hotk_notify(struct acpi_device *device, u32 event) static struct key_entry *key; u16 count; - /* TODO Find a better way to handle events count. */ - if (!hotk) - return; - /* * We need to tell the backlight device when the backlight power is * switched @@ -957,6 +953,7 @@ static void asus_hotk_notify(struct acpi_device *device, u32 event) lcd_blank(FB_BLANK_POWERDOWN); } + /* TODO Find a better way to handle events count. */ count = hotk->event_count[event % 128]++; acpi_bus_generate_proc_event(hotk->device, event, count); acpi_bus_generate_netlink_event(hotk->device->pnp.device_class, -- cgit v1.2.3 From 600ad5201d3b9b87159ede7359adccb98635fd48 Mon Sep 17 00:00:00 2001 From: Corentin Chary Date: Mon, 30 Nov 2009 21:42:42 +0100 Subject: asus-laptop: change initialization order Clean asus-laptop initialization to match new eeepc-laptop code. Signed-off-by: Corentin Chary --- drivers/platform/x86/asus-laptop.c | 369 ++++++++++++++++++------------------- 1 file changed, 180 insertions(+), 189 deletions(-) (limited to 'drivers/platform/x86') diff --git a/drivers/platform/x86/asus-laptop.c b/drivers/platform/x86/asus-laptop.c index 74463a07d48b..8834405be1fd 100644 --- a/drivers/platform/x86/asus-laptop.c +++ b/drivers/platform/x86/asus-laptop.c @@ -201,6 +201,8 @@ ASUS_HANDLE(kled_get, ASUS_HOTK_PREFIX "GLKB"); */ struct asus_hotk { char *name; /* laptop name */ + + struct platform_device *platform_device; struct acpi_device *device; /* the device we are in */ acpi_handle handle; /* the handle of the hotk device */ char status; /* status of the hotk, for LEDs, ... */ @@ -222,33 +224,6 @@ static struct acpi_table_header *asus_info; /* The actual device the driver binds to */ static struct asus_hotk *hotk; -/* - * The hotkey driver declaration - */ -static const struct acpi_device_id asus_device_ids[] = { - {"ATK0100", 0}, - {"ATK0101", 0}, - {"", 0}, -}; -MODULE_DEVICE_TABLE(acpi, asus_device_ids); - -static int asus_hotk_add(struct acpi_device *device); -static int asus_hotk_remove(struct acpi_device *device, int type); -static void asus_hotk_notify(struct acpi_device *device, u32 event); - -static struct acpi_driver asus_hotk_driver = { - .name = ASUS_HOTK_NAME, - .class = ASUS_HOTK_CLASS, - .owner = THIS_MODULE, - .ids = asus_device_ids, - .flags = ACPI_DRIVER_ALL_NOTIFY_EVENTS, - .ops = { - .add = asus_hotk_add, - .remove = asus_hotk_remove, - .notify = asus_hotk_notify, - }, -}; - /* The backlight device /sys/class/backlight */ static struct backlight_device *asus_backlight_device; @@ -936,7 +911,7 @@ static int asus_setkeycode(struct input_dev *dev, int scancode, int keycode) return -EINVAL; } -static void asus_hotk_notify(struct acpi_device *device, u32 event) +static void asus_acpi_notify(struct acpi_device *device, u32 event) { static struct key_entry *key; u16 count; @@ -1013,19 +988,49 @@ static struct attribute *asuspf_attributes[] = { NULL }; -static struct attribute_group asuspf_attribute_group = { +static struct attribute_group platform_attribute_group = { .attrs = asuspf_attributes }; -static struct platform_driver asuspf_driver = { +static int asus_platform_init(void) +{ + int result; + + hotk->platform_device = platform_device_alloc(ASUS_HOTK_FILE, -1); + if (!hotk->platform_device) + return -ENOMEM; + + result = platform_device_add(hotk->platform_device); + if (result) + goto fail_platform_device; + + result = sysfs_create_group(&hotk->platform_device->dev.kobj, + &platform_attribute_group); + if (result) + goto fail_sysfs; + return 0; + +fail_sysfs: + platform_device_del(hotk->platform_device); +fail_platform_device: + platform_device_put(hotk->platform_device); + return result; +} + +static void asus_platform_exit(void) +{ + sysfs_remove_group(&hotk->platform_device->dev.kobj, + &platform_attribute_group); + platform_device_unregister(hotk->platform_device); +} + +static struct platform_driver platform_driver = { .driver = { .name = ASUS_HOTK_FILE, .owner = THIS_MODULE, } }; -static struct platform_device *asuspf_device; - static void asus_hotk_add_fs(void) { ASUS_SET_DEVICE_ATTR(infos, 0444, show_infos, NULL); @@ -1196,7 +1201,7 @@ static int asus_hotk_get_info(void) return AE_OK; } -static int asus_input_init(void) +static int asus_input_init(struct device *dev) { const struct key_entry *key; int result; @@ -1207,6 +1212,7 @@ static int asus_input_init(void) return 0; } hotk->inputdev->name = "Asus Laptop extra buttons"; + hotk->inputdev->dev.parent = dev; hotk->inputdev->phys = ASUS_HOTK_FILE "/input0"; hotk->inputdev->id.bustype = BUS_HOST; hotk->inputdev->getkeycode = asus_getkeycode; @@ -1228,101 +1234,6 @@ static int asus_input_init(void) return result; } -static int asus_hotk_check(void) -{ - int result = 0; - - result = acpi_bus_get_status(hotk->device); - if (result) - return result; - - if (hotk->device->status.present) { - result = asus_hotk_get_info(); - } else { - pr_err("Hotkey device not present, aborting\n"); - return -EINVAL; - } - - return result; -} - -static int asus_hotk_found; - -static int asus_hotk_add(struct acpi_device *device) -{ - int result; - - pr_notice("Asus Laptop Support version %s\n", - ASUS_LAPTOP_VERSION); - - hotk = kzalloc(sizeof(struct asus_hotk), GFP_KERNEL); - if (!hotk) - return -ENOMEM; - - hotk->handle = device->handle; - strcpy(acpi_device_name(device), ASUS_HOTK_DEVICE_NAME); - strcpy(acpi_device_class(device), ASUS_HOTK_CLASS); - device->driver_data = hotk; - hotk->device = device; - - result = asus_hotk_check(); - if (result) - goto end; - - asus_hotk_add_fs(); - - asus_hotk_found = 1; - - /* WLED and BLED are on by default */ - if (bluetooth_status != -1) - write_status(bt_switch_handle, !!bluetooth_status, BT_ON); - if (wireless_status != -1) - write_status(wl_switch_handle, !!wireless_status, WL_ON); - - /* If the h/w switch is off, we need to check the real status */ - write_status(NULL, read_status(BT_ON), BT_ON); - write_status(NULL, read_status(WL_ON), WL_ON); - - /* LCD Backlight is on by default */ - write_status(NULL, 1, LCD_ON); - - /* Keyboard Backlight is on by default */ - if (kled_set_handle) - set_kled_lvl(1); - - /* LED display is off by default */ - hotk->ledd_status = 0xFFF; - - /* Set initial values of light sensor and level */ - hotk->light_switch = 0; /* Default to light sensor disabled */ - hotk->light_level = 5; /* level 5 for sensor sensitivity */ - - if (ls_switch_handle) - set_light_sens_switch(hotk->light_switch); - - if (ls_level_handle) - set_light_sens_level(hotk->light_level); - - /* GPS is on by default */ - write_status(NULL, 1, GPS_ON); - -end: - if (result) { - kfree(hotk->name); - kfree(hotk); - } - - return result; -} - -static int asus_hotk_remove(struct acpi_device *device, int type) -{ - kfree(hotk->name); - kfree(hotk); - - return 0; -} - static void asus_backlight_exit(void) { if (asus_backlight_device) @@ -1350,18 +1261,6 @@ static void asus_input_exit(void) input_unregister_device(hotk->inputdev); } -static void __exit asus_laptop_exit(void) -{ - asus_backlight_exit(); - asus_led_exit(); - asus_input_exit(); - - acpi_bus_unregister_driver(&asus_hotk_driver); - sysfs_remove_group(&asuspf_device->dev.kobj, &asuspf_attribute_group); - platform_device_unregister(asuspf_device); - platform_driver_unregister(&asuspf_driver); -} - static int asus_backlight_init(struct device *dev) { struct backlight_device *bd; @@ -1448,87 +1347,179 @@ out: return rv; } -static int __init asus_laptop_init(void) + +static bool asus_device_present; + +static int __devinit asus_acpi_init(struct acpi_device *device) { - int result; + int result = 0; - result = acpi_bus_register_driver(&asus_hotk_driver); - if (result < 0) + result = acpi_bus_get_status(hotk->device); + if (result) return result; - - /* - * This is a bit of a kludge. We only want this module loaded - * for ASUS systems, but there's currently no way to probe the - * ACPI namespace for ASUS HIDs. So we just return failure if - * we didn't find one, which will cause the module to be - * unloaded. - */ - if (!asus_hotk_found) { - acpi_bus_unregister_driver(&asus_hotk_driver); + if (!hotk->device->status.present) { + pr_err("Hotkey device not present, aborting\n"); return -ENODEV; } - result = asus_input_init(); + result = asus_hotk_get_info(); if (result) - goto fail_input; + return result; - /* Register platform stuff */ - result = platform_driver_register(&asuspf_driver); - if (result) - goto fail_platform_driver; + asus_hotk_add_fs(); - asuspf_device = platform_device_alloc(ASUS_HOTK_FILE, -1); - if (!asuspf_device) { - result = -ENOMEM; - goto fail_platform_device1; - } + /* WLED and BLED are on by default */ + write_status(bt_switch_handle, 1, BT_ON); + write_status(wl_switch_handle, 1, WL_ON); - result = platform_device_add(asuspf_device); - if (result) - goto fail_platform_device2; + /* If the h/w switch is off, we need to check the real status */ + write_status(NULL, read_status(BT_ON), BT_ON); + write_status(NULL, read_status(WL_ON), WL_ON); + + /* LCD Backlight is on by default */ + write_status(NULL, 1, LCD_ON); - result = sysfs_create_group(&asuspf_device->dev.kobj, - &asuspf_attribute_group); + /* Keyboard Backlight is on by default */ + if (kled_set_handle) + set_kled_lvl(1); + + /* LED display is off by default */ + hotk->ledd_status = 0xFFF; + + /* Set initial values of light sensor and level */ + hotk->light_switch = 0; /* Default to light sensor disabled */ + hotk->light_level = 5; /* level 5 for sensor sensitivity */ + + if (ls_switch_handle) + set_light_sens_switch(hotk->light_switch); + + if (ls_level_handle) + set_light_sens_level(hotk->light_level); + + /* GPS is on by default */ + write_status(NULL, 1, GPS_ON); + return result; +} + +static int __devinit asus_acpi_add(struct acpi_device *device) +{ + int result; + + pr_notice("Asus Laptop Support version %s\n", + ASUS_LAPTOP_VERSION); + hotk = kzalloc(sizeof(struct asus_hotk), GFP_KERNEL); + if (!hotk) + return -ENOMEM; + hotk->handle = device->handle; + strcpy(acpi_device_name(device), ASUS_HOTK_DEVICE_NAME); + strcpy(acpi_device_class(device), ASUS_HOTK_CLASS); + device->driver_data = hotk; + hotk->device = device; + + result = asus_acpi_init(device); if (result) - goto fail_sysfs; + goto fail_platform; - result = asus_led_init(&asuspf_device->dev); + /* + * Register the platform device first. It is used as a parent for the + * sub-devices below. + */ + result = asus_platform_init(); if (result) - goto fail_led; + goto fail_platform; if (!acpi_video_backlight_support()) { - result = asus_backlight_init(&asuspf_device->dev); + result = asus_backlight_init(&hotk->platform_device->dev); if (result) goto fail_backlight; } else - pr_info("Brightness ignored, must be controlled by " - "ACPI video driver\n"); + pr_info("Backlight controlled by ACPI video driver\n"); + result = asus_input_init(&hotk->platform_device->dev); + if (result) + goto fail_input; + + result = asus_led_init(&hotk->platform_device->dev); + if (result) + goto fail_led; + + asus_device_present = true; return 0; +fail_led: + asus_input_exit(); +fail_input: + asus_backlight_exit(); fail_backlight: - asus_led_exit(); + asus_platform_exit(); +fail_platform: + kfree(hotk->name); + kfree(hotk); -fail_led: - sysfs_remove_group(&asuspf_device->dev.kobj, - &asuspf_attribute_group); + return result; +} -fail_sysfs: - platform_device_del(asuspf_device); +static int asus_acpi_remove(struct acpi_device *device, int type) +{ + asus_backlight_exit(); + asus_led_exit(); + asus_input_exit(); + asus_platform_exit(); + + kfree(hotk->name); + kfree(hotk); + return 0; +} + +static const struct acpi_device_id asus_device_ids[] = { + {"ATK0100", 0}, + {"ATK0101", 0}, + {"", 0}, +}; +MODULE_DEVICE_TABLE(acpi, asus_device_ids); -fail_platform_device2: - platform_device_put(asuspf_device); +static struct acpi_driver asus_acpi_driver = { + .name = ASUS_HOTK_NAME, + .class = ASUS_HOTK_CLASS, + .owner = THIS_MODULE, + .ids = asus_device_ids, + .flags = ACPI_DRIVER_ALL_NOTIFY_EVENTS, + .ops = { + .add = asus_acpi_add, + .remove = asus_acpi_remove, + .notify = asus_acpi_notify, + }, +}; -fail_platform_device1: - platform_driver_unregister(&asuspf_driver); +static int __init asus_laptop_init(void) +{ + int result; -fail_platform_driver: - asus_input_exit(); + result = platform_driver_register(&platform_driver); + if (result < 0) + return result; -fail_input: + result = acpi_bus_register_driver(&asus_acpi_driver); + if (result < 0) + goto fail_acpi_driver; + if (!asus_device_present) { + result = -ENODEV; + goto fail_no_device; + } + return 0; +fail_no_device: + acpi_bus_unregister_driver(&asus_acpi_driver); +fail_acpi_driver: + platform_driver_unregister(&platform_driver); return result; } +static void __exit asus_laptop_exit(void) +{ + acpi_bus_unregister_driver(&asus_acpi_driver); + platform_driver_unregister(&platform_driver); +} + module_init(asus_laptop_init); module_exit(asus_laptop_exit); -- cgit v1.2.3 From 50a90c4d953fe4bb5a87ee5207c4243d25278189 Mon Sep 17 00:00:00 2001 From: Corentin Chary Date: Mon, 30 Nov 2009 21:55:12 +0100 Subject: asus-laptop: revise names asus-laptop now does a lot more than just hotkeys. Replace the "hotk" names used throughout the driver with some slightly more appropriate names. The actual strings used in kernel messages and sysfs are left unchanged. Signed-off-by: Corentin Chary --- drivers/platform/x86/asus-laptop.c | 221 +++++++++++++++++++------------------ 1 file changed, 111 insertions(+), 110 deletions(-) (limited to 'drivers/platform/x86') diff --git a/drivers/platform/x86/asus-laptop.c b/drivers/platform/x86/asus-laptop.c index 8834405be1fd..2505f15cbe6b 100644 --- a/drivers/platform/x86/asus-laptop.c +++ b/drivers/platform/x86/asus-laptop.c @@ -52,11 +52,11 @@ #define ASUS_LAPTOP_VERSION "0.42" -#define ASUS_HOTK_NAME "Asus Laptop Support" -#define ASUS_HOTK_CLASS "hotkey" -#define ASUS_HOTK_DEVICE_NAME "Hotkey" -#define ASUS_HOTK_FILE KBUILD_MODNAME -#define ASUS_HOTK_PREFIX "\\_SB.ATKD." +#define ASUS_LAPTOP_NAME "Asus Laptop Support" +#define ASUS_LAPTOP_CLASS "hotkey" +#define ASUS_LAPTOP_DEVICE_NAME "Hotkey" +#define ASUS_LAPTOP_FILE KBUILD_MODNAME +#define ASUS_LAPTOP_PREFIX "\\_SB.ATKD." /* @@ -89,7 +89,7 @@ #define KEY_ON 0x200 /* Keyboard backlight */ MODULE_AUTHOR("Julien Lerouge, Karol Kozimor, Corentin Chary"); -MODULE_DESCRIPTION(ASUS_HOTK_NAME); +MODULE_DESCRIPTION(ASUS_LAPTOP_NAME); MODULE_LICENSE("GPL"); /* @@ -124,27 +124,27 @@ MODULE_PARM_DESC(bluetooth_status, "Set the wireless status on boot " static char *object##_paths[] = { paths } /* LED */ -ASUS_HANDLE(mled_set, ASUS_HOTK_PREFIX "MLED"); -ASUS_HANDLE(tled_set, ASUS_HOTK_PREFIX "TLED"); -ASUS_HANDLE(rled_set, ASUS_HOTK_PREFIX "RLED"); /* W1JC */ -ASUS_HANDLE(pled_set, ASUS_HOTK_PREFIX "PLED"); /* A7J */ -ASUS_HANDLE(gled_set, ASUS_HOTK_PREFIX "GLED"); /* G1, G2 (probably) */ +ASUS_HANDLE(mled_set, ASUS_LAPTOP_PREFIX "MLED"); +ASUS_HANDLE(tled_set, ASUS_LAPTOP_PREFIX "TLED"); +ASUS_HANDLE(rled_set, ASUS_LAPTOP_PREFIX "RLED"); /* W1JC */ +ASUS_HANDLE(pled_set, ASUS_LAPTOP_PREFIX "PLED"); /* A7J */ +ASUS_HANDLE(gled_set, ASUS_LAPTOP_PREFIX "GLED"); /* G1, G2 (probably) */ /* LEDD */ -ASUS_HANDLE(ledd_set, ASUS_HOTK_PREFIX "SLCM"); +ASUS_HANDLE(ledd_set, ASUS_LAPTOP_PREFIX "SLCM"); /* * Bluetooth and WLAN * WLED and BLED are not handled like other XLED, because in some dsdt * they also control the WLAN/Bluetooth device. */ -ASUS_HANDLE(wl_switch, ASUS_HOTK_PREFIX "WLED"); -ASUS_HANDLE(bt_switch, ASUS_HOTK_PREFIX "BLED"); -ASUS_HANDLE(wireless_status, ASUS_HOTK_PREFIX "RSTS"); /* All new models */ +ASUS_HANDLE(wl_switch, ASUS_LAPTOP_PREFIX "WLED"); +ASUS_HANDLE(bt_switch, ASUS_LAPTOP_PREFIX "BLED"); +ASUS_HANDLE(wireless_status, ASUS_LAPTOP_PREFIX "RSTS"); /* All new models */ /* Brightness */ -ASUS_HANDLE(brightness_set, ASUS_HOTK_PREFIX "SPLV"); -ASUS_HANDLE(brightness_get, ASUS_HOTK_PREFIX "GPLV"); +ASUS_HANDLE(brightness_set, ASUS_LAPTOP_PREFIX "SPLV"); +ASUS_HANDLE(brightness_get, ASUS_LAPTOP_PREFIX "GPLV"); /* Backlight */ ASUS_HANDLE(lcd_switch, "\\_SB.PCI0.SBRG.EC0._Q10", /* All new models */ @@ -157,7 +157,7 @@ ASUS_HANDLE(lcd_switch, "\\_SB.PCI0.SBRG.EC0._Q10", /* All new models */ "\\Q10"); /* A2x, L2D, L3D, M2E */ /* Display */ -ASUS_HANDLE(display_set, ASUS_HOTK_PREFIX "SDSP"); +ASUS_HANDLE(display_set, ASUS_LAPTOP_PREFIX "SDSP"); ASUS_HANDLE(display_get, /* A6B, A6K A6R A7D F3JM L4R M6R A3G M6A M6V VX-1 V6J V6V W3Z */ "\\_SB.PCI0.P0P1.VGA.GETD", @@ -182,24 +182,24 @@ ASUS_HANDLE(display_get, /* A3F A6F A3N A3L M6N W3N W6A */ "\\SSTE"); -ASUS_HANDLE(ls_switch, ASUS_HOTK_PREFIX "ALSC"); /* Z71A Z71V */ -ASUS_HANDLE(ls_level, ASUS_HOTK_PREFIX "ALSL"); /* Z71A Z71V */ +ASUS_HANDLE(ls_switch, ASUS_LAPTOP_PREFIX "ALSC"); /* Z71A Z71V */ +ASUS_HANDLE(ls_level, ASUS_LAPTOP_PREFIX "ALSL"); /* Z71A Z71V */ /* GPS */ /* R2H use different handle for GPS on/off */ -ASUS_HANDLE(gps_on, ASUS_HOTK_PREFIX "SDON"); /* R2H */ -ASUS_HANDLE(gps_off, ASUS_HOTK_PREFIX "SDOF"); /* R2H */ -ASUS_HANDLE(gps_status, ASUS_HOTK_PREFIX "GPST"); +ASUS_HANDLE(gps_on, ASUS_LAPTOP_PREFIX "SDON"); /* R2H */ +ASUS_HANDLE(gps_off, ASUS_LAPTOP_PREFIX "SDOF"); /* R2H */ +ASUS_HANDLE(gps_status, ASUS_LAPTOP_PREFIX "GPST"); /* Keyboard light */ -ASUS_HANDLE(kled_set, ASUS_HOTK_PREFIX "SLKB"); -ASUS_HANDLE(kled_get, ASUS_HOTK_PREFIX "GLKB"); +ASUS_HANDLE(kled_set, ASUS_LAPTOP_PREFIX "SLKB"); +ASUS_HANDLE(kled_get, ASUS_LAPTOP_PREFIX "GLKB"); /* * This is the main structure, we can use it to store anything interesting * about the hotk device */ -struct asus_hotk { +struct asus_laptop { char *name; /* laptop name */ struct platform_device *platform_device; @@ -216,13 +216,13 @@ struct asus_hotk { /* * This header is made available to allow proper configuration given model, - * revision number , ... this info cannot go in struct asus_hotk because it is + * revision number , ... this info cannot go in struct asus_laptop because it is * available before the hotk */ static struct acpi_table_header *asus_info; /* The actual device the driver binds to */ -static struct asus_hotk *hotk; +static struct asus_laptop *asus; /* The backlight device /sys/class/backlight */ static struct backlight_device *asus_backlight_device; @@ -353,7 +353,7 @@ static int read_wireless_status(int mask) acpi_status rv = AE_OK; if (!wireless_status_handle) - return (hotk->status & mask) ? 1 : 0; + return (asus->status & mask) ? 1 : 0; rv = acpi_evaluate_integer(wireless_status_handle, NULL, NULL, &status); if (ACPI_FAILURE(rv)) @@ -361,7 +361,7 @@ static int read_wireless_status(int mask) else return (status & mask) ? 1 : 0; - return (hotk->status & mask) ? 1 : 0; + return (asus->status & mask) ? 1 : 0; } static int read_gps_status(void) @@ -375,7 +375,7 @@ static int read_gps_status(void) else return status ? 1 : 0; - return (hotk->status & GPS_ON) ? 1 : 0; + return (asus->status & GPS_ON) ? 1 : 0; } /* Generic LED functions */ @@ -387,12 +387,12 @@ static int read_status(int mask) else if (mask == GPS_ON) return read_gps_status(); - return (hotk->status & mask) ? 1 : 0; + return (asus->status & mask) ? 1 : 0; } static void write_status(acpi_handle handle, int out, int mask) { - hotk->status = (out) ? (hotk->status | mask) : (hotk->status & ~mask); + asus->status = (out) ? (asus->status | mask) : (asus->status & ~mask); switch (mask) { case MLED_ON: @@ -586,15 +586,15 @@ static ssize_t show_infos(struct device *dev, * to 1 */ - len += sprintf(page, ASUS_HOTK_NAME " " ASUS_LAPTOP_VERSION "\n"); - len += sprintf(page + len, "Model reference : %s\n", hotk->name); + len += sprintf(page, ASUS_LAPTOP_NAME " " ASUS_LAPTOP_VERSION "\n"); + len += sprintf(page + len, "Model reference : %s\n", asus->name); /* * The SFUN method probably allows the original driver to get the list * of features supported by a given model. For now, 0x0100 or 0x0800 * bit signifies that the laptop is equipped with a Wi-Fi MiniPCI card. * The significance of others is yet to be found. */ - rv = acpi_evaluate_integer(hotk->handle, "SFUN", NULL, &temp); + rv = acpi_evaluate_integer(asus->handle, "SFUN", NULL, &temp); if (!ACPI_FAILURE(rv)) len += sprintf(page + len, "SFUN value : %#x\n", (uint) temp); @@ -604,7 +604,7 @@ static ssize_t show_infos(struct device *dev, * The significance of others is yet to be found. * If we don't find the method, we assume the device are present. */ - rv = acpi_evaluate_integer(hotk->handle, "HRWS", NULL, &temp); + rv = acpi_evaluate_integer(asus->handle, "HRWS", NULL, &temp); if (!ACPI_FAILURE(rv)) len += sprintf(page + len, "HRWS value : %#x\n", (uint) temp); @@ -615,7 +615,7 @@ static ssize_t show_infos(struct device *dev, * Note: since not all the laptops provide this method, errors are * silently ignored. */ - rv = acpi_evaluate_integer(hotk->handle, "ASYM", NULL, &temp); + rv = acpi_evaluate_integer(asus->handle, "ASYM", NULL, &temp); if (!ACPI_FAILURE(rv)) len += sprintf(page + len, "ASYM value : %#x\n", (uint) temp); @@ -673,7 +673,7 @@ static ssize_t store_status(const char *buf, size_t count, static ssize_t show_ledd(struct device *dev, struct device_attribute *attr, char *buf) { - return sprintf(buf, "0x%08x\n", hotk->ledd_status); + return sprintf(buf, "0x%08x\n", asus->ledd_status); } static ssize_t store_ledd(struct device *dev, struct device_attribute *attr, @@ -686,7 +686,7 @@ static ssize_t store_ledd(struct device *dev, struct device_attribute *attr, if (write_acpi_int(ledd_set_handle, NULL, value)) pr_warning("LED display write failed\n"); else - hotk->ledd_status = (u32) value; + asus->ledd_status = (u32) value; } return rv; } @@ -789,13 +789,13 @@ static void set_light_sens_switch(int value) { if (write_acpi_int(ls_switch_handle, NULL, value)) pr_warning("Error setting light sensor switch\n"); - hotk->light_switch = value; + asus->light_switch = value; } static ssize_t show_lssw(struct device *dev, struct device_attribute *attr, char *buf) { - return sprintf(buf, "%d\n", hotk->light_switch); + return sprintf(buf, "%d\n", asus->light_switch); } static ssize_t store_lssw(struct device *dev, struct device_attribute *attr, @@ -814,13 +814,13 @@ static void set_light_sens_level(int value) { if (write_acpi_int(ls_level_handle, NULL, value)) pr_warning("Error setting light sensor level\n"); - hotk->light_level = value; + asus->light_level = value; } static ssize_t show_lslvl(struct device *dev, struct device_attribute *attr, char *buf) { - return sprintf(buf, "%d\n", hotk->light_level); + return sprintf(buf, "%d\n", asus->light_level); } static ssize_t store_lslvl(struct device *dev, struct device_attribute *attr, @@ -929,23 +929,23 @@ static void asus_acpi_notify(struct acpi_device *device, u32 event) } /* TODO Find a better way to handle events count. */ - count = hotk->event_count[event % 128]++; - acpi_bus_generate_proc_event(hotk->device, event, count); - acpi_bus_generate_netlink_event(hotk->device->pnp.device_class, - dev_name(&hotk->device->dev), event, + count = asus->event_count[event % 128]++; + acpi_bus_generate_proc_event(asus->device, event, count); + acpi_bus_generate_netlink_event(asus->device->pnp.device_class, + dev_name(&asus->device->dev), event, count); - if (hotk->inputdev) { + if (asus->inputdev) { key = asus_get_entry_by_scancode(event); if (!key) return ; switch (key->type) { case KE_KEY: - input_report_key(hotk->inputdev, key->keycode, 1); - input_sync(hotk->inputdev); - input_report_key(hotk->inputdev, key->keycode, 0); - input_sync(hotk->inputdev); + input_report_key(asus->inputdev, key->keycode, 1); + input_sync(asus->inputdev); + input_report_key(asus->inputdev, key->keycode, 0); + input_sync(asus->inputdev); break; } } @@ -996,42 +996,42 @@ static int asus_platform_init(void) { int result; - hotk->platform_device = platform_device_alloc(ASUS_HOTK_FILE, -1); - if (!hotk->platform_device) + asus->platform_device = platform_device_alloc(ASUS_LAPTOP_FILE, -1); + if (!asus->platform_device) return -ENOMEM; - result = platform_device_add(hotk->platform_device); + result = platform_device_add(asus->platform_device); if (result) goto fail_platform_device; - result = sysfs_create_group(&hotk->platform_device->dev.kobj, + result = sysfs_create_group(&asus->platform_device->dev.kobj, &platform_attribute_group); if (result) goto fail_sysfs; return 0; fail_sysfs: - platform_device_del(hotk->platform_device); + platform_device_del(asus->platform_device); fail_platform_device: - platform_device_put(hotk->platform_device); + platform_device_put(asus->platform_device); return result; } static void asus_platform_exit(void) { - sysfs_remove_group(&hotk->platform_device->dev.kobj, + sysfs_remove_group(&asus->platform_device->dev.kobj, &platform_attribute_group); - platform_device_unregister(hotk->platform_device); + platform_device_unregister(asus->platform_device); } static struct platform_driver platform_driver = { .driver = { - .name = ASUS_HOTK_FILE, + .name = ASUS_LAPTOP_FILE, .owner = THIS_MODULE, } }; -static void asus_hotk_add_fs(void) +static void asus_laptop_add_fs(void) { ASUS_SET_DEVICE_ATTR(infos, 0444, show_infos, NULL); @@ -1080,10 +1080,11 @@ static int asus_handle_init(char *name, acpi_handle * handle, ARRAY_SIZE(object##_paths)) /* - * This function is used to initialize the hotk with right values. In this - * method, we can make all the detection we want, and modify the hotk struct + * This function is used to initialize the context with right values. In this + * method, we can make all the detection we want, and modify the asus_laptop + * struct */ -static int asus_hotk_get_info(void) +static int asus_laptop_get_info(void) { struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; union acpi_object *model = NULL; @@ -1104,14 +1105,14 @@ static int asus_hotk_get_info(void) pr_warning("Couldn't get the DSDT table header\n"); /* We have to write 0 on init this far for all ASUS models */ - if (write_acpi_int_ret(hotk->handle, "INIT", 0, &buffer)) { + if (write_acpi_int_ret(asus->handle, "INIT", 0, &buffer)) { pr_err("Hotkey initialization failed\n"); return -ENODEV; } /* This needs to be called for some laptops to init properly */ status = - acpi_evaluate_integer(hotk->handle, "BSTS", NULL, &bsts_result); + acpi_evaluate_integer(asus->handle, "BSTS", NULL, &bsts_result); if (ACPI_FAILURE(status)) pr_warning("Error calling BSTS\n"); else if (bsts_result) @@ -1119,7 +1120,7 @@ static int asus_hotk_get_info(void) (uint) bsts_result); /* This too ... */ - write_acpi_int(hotk->handle, "CWAP", wapf); + write_acpi_int(asus->handle, "CWAP", wapf); /* * Try to match the object returned by INIT to the specific model. @@ -1141,8 +1142,8 @@ static int asus_hotk_get_info(void) break; } } - hotk->name = kstrdup(string, GFP_KERNEL); - if (!hotk->name) + asus->name = kstrdup(string, GFP_KERNEL); + if (!asus->name) return -ENOMEM; if (*string) @@ -1166,7 +1167,7 @@ static int asus_hotk_get_info(void) * If we don't find the method, we assume the device are present. */ status = - acpi_evaluate_integer(hotk->handle, "HRWS", NULL, &hwrs_result); + acpi_evaluate_integer(asus->handle, "HRWS", NULL, &hwrs_result); if (ACPI_FAILURE(status)) hwrs_result = WL_HWRS | BT_HWRS; @@ -1206,30 +1207,30 @@ static int asus_input_init(struct device *dev) const struct key_entry *key; int result; - hotk->inputdev = input_allocate_device(); - if (!hotk->inputdev) { + asus->inputdev = input_allocate_device(); + if (!asus->inputdev) { pr_info("Unable to allocate input device\n"); return 0; } - hotk->inputdev->name = "Asus Laptop extra buttons"; - hotk->inputdev->dev.parent = dev; - hotk->inputdev->phys = ASUS_HOTK_FILE "/input0"; - hotk->inputdev->id.bustype = BUS_HOST; - hotk->inputdev->getkeycode = asus_getkeycode; - hotk->inputdev->setkeycode = asus_setkeycode; + asus->inputdev->name = "Asus Laptop extra buttons"; + asus->inputdev->dev.parent = dev; + asus->inputdev->phys = ASUS_LAPTOP_FILE "/input0"; + asus->inputdev->id.bustype = BUS_HOST; + asus->inputdev->getkeycode = asus_getkeycode; + asus->inputdev->setkeycode = asus_setkeycode; for (key = asus_keymap; key->type != KE_END; key++) { switch (key->type) { case KE_KEY: - set_bit(EV_KEY, hotk->inputdev->evbit); - set_bit(key->keycode, hotk->inputdev->keybit); + set_bit(EV_KEY, asus->inputdev->evbit); + set_bit(key->keycode, asus->inputdev->keybit); break; } } - result = input_register_device(hotk->inputdev); + result = input_register_device(asus->inputdev); if (result) { pr_info("Unable to register input device\n"); - input_free_device(hotk->inputdev); + input_free_device(asus->inputdev); } return result; } @@ -1257,8 +1258,8 @@ static void asus_led_exit(void) static void asus_input_exit(void) { - if (hotk->inputdev) - input_unregister_device(hotk->inputdev); + if (asus->inputdev) + input_unregister_device(asus->inputdev); } static int asus_backlight_init(struct device *dev) @@ -1266,7 +1267,7 @@ static int asus_backlight_init(struct device *dev) struct backlight_device *bd; if (brightness_set_handle && lcd_switch_handle) { - bd = backlight_device_register(ASUS_HOTK_FILE, dev, + bd = backlight_device_register(ASUS_LAPTOP_FILE, dev, NULL, &asusbl_ops); if (IS_ERR(bd)) { pr_err("Could not register asus backlight device\n"); @@ -1354,19 +1355,19 @@ static int __devinit asus_acpi_init(struct acpi_device *device) { int result = 0; - result = acpi_bus_get_status(hotk->device); + result = acpi_bus_get_status(asus->device); if (result) return result; - if (!hotk->device->status.present) { + if (!asus->device->status.present) { pr_err("Hotkey device not present, aborting\n"); return -ENODEV; } - result = asus_hotk_get_info(); + result = asus_laptop_get_info(); if (result) return result; - asus_hotk_add_fs(); + asus_laptop_add_fs(); /* WLED and BLED are on by default */ write_status(bt_switch_handle, 1, BT_ON); @@ -1384,17 +1385,17 @@ static int