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') 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') 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') 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') 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') 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 --- Documentation/laptops/thinkpad-acpi.txt | 4 ++++ drivers/platform/x86/Kconfig | 10 ++++++++-- drivers/platform/x86/thinkpad_acpi.c | 15 +++++++++++++-- 3 files changed, 25 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/Documentation/laptops/thinkpad-acpi.txt b/Documentation/laptops/thinkpad-acpi.txt index 75afa1229fd7..39c0a09d0105 100644 --- a/Documentation/laptops/thinkpad-acpi.txt +++ b/Documentation/laptops/thinkpad-acpi.txt @@ -650,6 +650,10 @@ LCD, CRT or DVI (if available). The following commands are available: echo expand_toggle > /proc/acpi/ibm/video echo video_switch > /proc/acpi/ibm/video +NOTE: Access to this feature is restricted to processes owning the +CAP_SYS_ADMIN capability for safety reasons, as it can interact badly +enough with some versions of X.org to crash it. + Each video output device can be enabled or disabled individually. Reading /proc/acpi/ibm/video shows the status of each device. 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') 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') 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') 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') 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') 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') 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') 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') 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') 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') 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 __devinit asus_acpi_init(struct acpi_device *device) set_kled_lvl(1); /* LED display is off by default */ - hotk->ledd_status = 0xFFF; + asus->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); + set_light_sens_switch(asus->light_switch); if (ls_level_handle) - set_light_sens_level(hotk->light_level); + set_light_sens_level(asus->light_level); /* GPS is on by default */ write_status(NULL, 1, GPS_ON); @@ -1407,14 +1408,14 @@ static int __devinit asus_acpi_add(struct acpi_device *device) pr_notice("Asus Laptop Support version %s\n", ASUS_LAPTOP_VERSION); - hotk = kzalloc(sizeof(struct asus_hotk), GFP_KERNEL); - if (!hotk) + asus = kzalloc(sizeof(struct asus_laptop), GFP_KERNEL); + if (!asus) 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; + asus->handle = device->handle; + strcpy(acpi_device_name(device), ASUS_LAPTOP_DEVICE_NAME); + strcpy(acpi_device_class(device), ASUS_LAPTOP_CLASS); + device->driver_data = asus; + asus->device = device; result = asus_acpi_init(device); if (result) @@ -1429,17 +1430,17 @@ static int __devinit asus_acpi_add(struct acpi_device *device) goto fail_platform; if (!acpi_video_backlight_support()) { - result = asus_backlight_init(&hotk->platform_device->dev); + result = asus_backlight_init(&asus->platform_device->dev); if (result) goto fail_backlight; } else pr_info("Backlight controlled by ACPI video driver\n"); - result = asus_input_init(&hotk->platform_device->dev); + result = asus_input_init(&asus->platform_device->dev); if (result) goto fail_input; - result = asus_led_init(&hotk->platform_device->dev); + result = asus_led_init(&asus->platform_device->dev); if (result) goto fail_led; @@ -1453,8 +1454,8 @@ fail_input: fail_backlight: asus_platform_exit(); fail_platform: - kfree(hotk->name); - kfree(hotk); + kfree(asus->name); + kfree(asus); return result; } @@ -1466,8 +1467,8 @@ static int asus_acpi_remove(struct acpi_device *device, int type) asus_input_exit(); asus_platform_exit(); - kfree(hotk->name); - kfree(hotk); + kfree(asus->name); + kfree(asus); return 0; } @@ -1479,8 +1480,8 @@ static const struct acpi_device_id asus_device_ids[] = { MODULE_DEVICE_TABLE(acpi, asus_device_ids); static struct acpi_driver asus_acpi_driver = { - .name = ASUS_HOTK_NAME, - .class = ASUS_HOTK_CLASS, + .name = ASUS_LAPTOP_NAME, + .class = ASUS_LAPTOP_CLASS, .owner = THIS_MODULE, .ids = asus_device_ids, .flags = ACPI_DRIVER_ALL_NOTIFY_EVENTS, -- cgit v1.2.3 From 7c247645f305da2bb309fa439fd6cc0aa26f8722 Mon Sep 17 00:00:00 2001 From: Corentin Chary Date: Mon, 30 Nov 2009 22:13:54 +0100 Subject: asus-laptop: move backlight and dsdt info inside asus_laptop struct Prepare the use of "driver data" for callbacks. Signed-off-by: Corentin Chary --- drivers/platform/x86/asus-laptop.c | 69 +++++++++++++++++--------------------- 1 file changed, 30 insertions(+), 39 deletions(-) (limited to 'drivers') diff --git a/drivers/platform/x86/asus-laptop.c b/drivers/platform/x86/asus-laptop.c index 2505f15cbe6b..4ff30ca4df12 100644 --- a/drivers/platform/x86/asus-laptop.c +++ b/drivers/platform/x86/asus-laptop.c @@ -202,30 +202,24 @@ ASUS_HANDLE(kled_get, ASUS_LAPTOP_PREFIX "GLKB"); struct asus_laptop { char *name; /* laptop name */ + struct acpi_table_header *dsdt_info; struct platform_device *platform_device; - struct acpi_device *device; /* the device we are in */ + struct acpi_device *device; /* the device we are in */ + struct backlight_device *backlight_device; + struct input_dev *inputdev; + acpi_handle handle; /* the handle of the hotk device */ char status; /* status of the hotk, for LEDs, ... */ u32 ledd_status; /* status of the LED display */ u8 light_level; /* light sensor level */ u8 light_switch; /* light sensor switch value */ u16 event_count[128]; /* count for each event TODO make this better */ - struct input_dev *inputdev; u16 *keycode_map; }; -/* - * This header is made available to allow proper configuration given model, - * 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_laptop *asus; -/* The backlight device /sys/class/backlight */ -static struct backlight_device *asus_backlight_device; +static struct workqueue_struct *led_workqueue; /* * The backlight class declaration @@ -237,14 +231,6 @@ static struct backlight_ops asusbl_ops = { .update_status = update_bl_status, }; -/* - * These functions actually update the LED's, and are called from a - * workqueue. By doing this as separate work rather than when the LED - * subsystem asks, we avoid messing with the Asus ACPI stuff during a - * potentially bad time, such as a timer interrupt. - */ -static struct workqueue_struct *led_workqueue; - #define ASUS_LED(object, ledname, max) \ static void object##_led_set(struct led_classdev *led_cdev, \ enum led_brightness value); \ @@ -522,7 +508,7 @@ static int set_lcd_state(int value) static void lcd_blank(int blank) { - struct backlight_device *bd = asus_backlight_device; + struct backlight_device *bd = asus->backlight_device; if (bd) { bd->props.power = blank; @@ -619,22 +605,22 @@ static ssize_t show_infos(struct device *dev, if (!ACPI_FAILURE(rv)) len += sprintf(page + len, "ASYM value : %#x\n", (uint) temp); - if (asus_info) { - snprintf(buf, 16, "%d", asus_info->length); + if (asus->dsdt_info) { + snprintf(buf, 16, "%d", asus->dsdt_info->length); len += sprintf(page + len, "DSDT length : %s\n", buf); - snprintf(buf, 16, "%d", asus_info->checksum); + snprintf(buf, 16, "%d", asus->dsdt_info->checksum); len += sprintf(page + len, "DSDT checksum : %s\n", buf); - snprintf(buf, 16, "%d", asus_info->revision); + snprintf(buf, 16, "%d", asus->dsdt_info->revision); len += sprintf(page + len, "DSDT revision : %s\n", buf); - snprintf(buf, 7, "%s", asus_info->oem_id); + snprintf(buf, 7, "%s", asus->dsdt_info->oem_id); len += sprintf(page + len, "OEM id : %s\n", buf); - snprintf(buf, 9, "%s", asus_info->oem_table_id); + snprintf(buf, 9, "%s", asus->dsdt_info->oem_table_id); len += sprintf(page + len, "OEM table id : %s\n", buf); - snprintf(buf, 16, "%x", asus_info->oem_revision); + snprintf(buf, 16, "%x", asus->dsdt_info->oem_revision); len += sprintf(page + len, "OEM revision : 0x%s\n", buf); - snprintf(buf, 5, "%s", asus_info->asl_compiler_id); + snprintf(buf, 5, "%s", asus->dsdt_info->asl_compiler_id); len += sprintf(page + len, "ASL comp vendor id : %s\n", buf); - snprintf(buf, 16, "%x", asus_info->asl_compiler_revision); + snprintf(buf, 16, "%x", asus->dsdt_info->asl_compiler_revision); len += sprintf(page + len, "ASL comp revision : 0x%s\n", buf); } @@ -1084,7 +1070,7 @@ static int asus_handle_init(char *name, acpi_handle * handle, * method, we can make all the detection we want, and modify the asus_laptop * struct */ -static int asus_laptop_get_info(void) +static int asus_laptop_get_info(struct asus_laptop *asus) { struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; union acpi_object *model = NULL; @@ -1097,10 +1083,9 @@ static int asus_laptop_get_info(void) * models, but late enough to allow acpi_bus_register_driver() to fail * before doing anything ACPI-specific. Should we encounter a machine, * which needs special handling (i.e. its hotkey device has a different - * HID), this bit will be moved. A global variable asus_info contains - * the DSDT header. + * HID), this bit will be moved. */ - status = acpi_get_table(ACPI_SIG_DSDT, 1, &asus_info); + status = acpi_get_table(ACPI_SIG_DSDT, 1, &asus->dsdt_info); if (ACPI_FAILURE(status)) pr_warning("Couldn't get the DSDT table header\n"); @@ -1237,8 +1222,8 @@ static int asus_input_init(struct device *dev) static void asus_backlight_exit(void) { - if (asus_backlight_device) - backlight_device_unregister(asus_backlight_device); + if (asus->backlight_device) + backlight_device_unregister(asus->backlight_device); } #define ASUS_LED_UNREGISTER(object) \ @@ -1271,11 +1256,11 @@ static int asus_backlight_init(struct device *dev) NULL, &asusbl_ops); if (IS_ERR(bd)) { pr_err("Could not register asus backlight device\n"); - asus_backlight_device = NULL; + asus->backlight_device = NULL; return PTR_ERR(bd); } - asus_backlight_device = bd; + asus->backlight_device = bd; bd->props.max_brightness = 15; bd->props.brightness = read_brightness(NULL); @@ -1326,6 +1311,12 @@ static int asus_led_init(struct device *dev) if (rv) goto out5; + /* + * Functions that actually update the LED's are called from a + * workqueue. By doing this as separate work rather than when the LED + * subsystem asks, we avoid messing with the Asus ACPI stuff during a + * potentially bad time, such as a timer interrupt. + */ led_workqueue = create_singlethread_workqueue("led_workqueue"); if (!led_workqueue) goto out6; @@ -1363,7 +1354,7 @@ static int __devinit asus_acpi_init(struct acpi_device *device) return -ENODEV; } - result = asus_laptop_get_info(); + result = asus_laptop_get_info(asus); if (result) return result; -- cgit v1.2.3 From 9129d14d297e78bc21caffa44d55a5920a74862c Mon Sep 17 00:00:00 2001 From: Corentin Chary Date: Tue, 1 Dec 2009 22:39:41 +0100 Subject: asus-laptop: callbacks should use "driver data" parameter or field (Changelog stolen from Alan's patch for eeepc-laptop, but this patch does the same thing for asus-laptop) Callback methods should not refer to a variable like "asus" (formally "hotk"). Instead, they should extract the data they need either from a "driver data" parameter, or the "driver data" field of the object which they operate on. The "asus" variable can then be removed. In practice, drivers under "drivers/platform" can get away without using driver data, because it doesn't make sense to have more than one instance of them. However this makes it harder to review them for correctness. This is especially true for core ACPI developers who have not previously been exposed to this anti-pattern :-). This will serve as an example of best practice for new driver writers (whether they find it themselves, or have it pointed out during review :-). Signed-off-by: Corentin Chary --- drivers/platform/x86/asus-laptop.c | 362 +++++++++++++++++++++---------------- 1 file changed, 209 insertions(+), 153 deletions(-) (limited to 'drivers') diff --git a/drivers/platform/x86/asus-laptop.c b/drivers/platform/x86/asus-laptop.c index 4ff30ca4df12..58a4864096d9 100644 --- a/drivers/platform/x86/asus-laptop.c +++ b/drivers/platform/x86/asus-laptop.c @@ -195,6 +195,34 @@ ASUS_HANDLE(gps_status, ASUS_LAPTOP_PREFIX "GPST"); ASUS_HANDLE(kled_set, ASUS_LAPTOP_PREFIX "SLKB"); ASUS_HANDLE(kled_get, ASUS_LAPTOP_PREFIX "GLKB"); +/* + * Define a specific led structure to keep the main structure clean + */ +#define ASUS_DEFINE_LED(object) \ + int object##_wk; \ + struct work_struct object##_work; \ + struct led_classdev object; + + +#define led_to_asus(led_cdev, led) \ + container_of(container_of(led_cdev, struct asus_laptop_leds, \ + led), \ + struct asus_laptop, leds) +#define work_to_asus(work, led) \ + container_of(container_of(work, struct asus_laptop_leds, \ + led##_work), \ + struct asus_laptop, leds) + +struct asus_laptop_leds { + ASUS_DEFINE_LED(mled) + ASUS_DEFINE_LED(tled) + ASUS_DEFINE_LED(rled) + ASUS_DEFINE_LED(pled) + ASUS_DEFINE_LED(gled) + ASUS_DEFINE_LED(kled) + struct workqueue_struct *workqueue; +}; + /* * This is the main structure, we can use it to store anything interesting * about the hotk device @@ -206,7 +234,11 @@ struct asus_laptop { struct platform_device *platform_device; struct acpi_device *device; /* the device we are in */ struct backlight_device *backlight_device; + struct input_dev *inputdev; + struct key_entry *keymap; + + struct asus_laptop_leds leds; acpi_handle handle; /* the handle of the hotk device */ char status; /* status of the hotk, for LEDs, ... */ @@ -217,10 +249,6 @@ struct asus_laptop { u16 *keycode_map; }; -static struct asus_laptop *asus; - -static struct workqueue_struct *led_workqueue; - /* * The backlight class declaration */ @@ -237,8 +265,6 @@ static struct backlight_ops asusbl_ops = { static enum led_brightness object##_led_get( \ struct led_classdev *led_cdev); \ static void object##_led_update(struct work_struct *ignored); \ - static int object##_led_wk; \ - static DECLARE_WORK(object##_led_work, object##_led_update); \ static struct led_classdev object##_led = { \ .name = "asus::" ledname, \ .brightness_set = object##_led_set, \ @@ -261,7 +287,7 @@ struct key_entry { enum { KE_KEY, KE_END }; -static struct key_entry asus_keymap[] = { +static const struct key_entry asus_keymap[] = { {KE_KEY, 0x02, KEY_SCREENLOCK}, {KE_KEY, 0x05, KEY_WLAN}, {KE_KEY, 0x08, KEY_F13}, @@ -333,7 +359,7 @@ 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) +static int read_wireless_status(struct asus_laptop *asus, int mask) { unsigned long long status; acpi_status rv = AE_OK; @@ -350,7 +376,7 @@ static int read_wireless_status(int mask) return (asus->status & mask) ? 1 : 0; } -static int read_gps_status(void) +static int read_gps_status(struct asus_laptop *asus) { unsigned long long status; acpi_status rv = AE_OK; @@ -365,18 +391,19 @@ static int read_gps_status(void) } /* Generic LED functions */ -static int read_status(int mask) +static int read_status(struct asus_laptop *asus, int mask) { /* There is a special method for both wireless devices */ if (mask == BT_ON || mask == WL_ON) - return read_wireless_status(mask); + return read_wireless_status(asus, mask); else if (mask == GPS_ON) - return read_gps_status(); + return read_gps_status(asus); return (asus->status & mask) ? 1 : 0; } -static void write_status(acpi_handle handle, int out, int mask) +static void write_status(struct asus_laptop *asus, acpi_handle handle, + int out, int mask) { asus->status = (out) ? (asus->status | mask) : (asus->status & ~mask); @@ -405,13 +432,19 @@ static void write_status(acpi_handle handle, int out, int mask) static void object##_led_set(struct led_classdev *led_cdev, \ enum led_brightness value) \ { \ - object##_led_wk = (value > 0) ? 1 : 0; \ - queue_work(led_workqueue, &object##_led_work); \ + struct asus_laptop *asus = \ + led_to_asus(led_cdev, object); \ + \ + asus->leds.object##_wk = (value > 0) ? 1 : 0; \ + queue_work(asus->leds.workqueue, \ + &asus->leds.object##_work); \ } \ - static void object##_led_update(struct work_struct *ignored) \ + static void object##_led_update(struct work_struct *work) \ { \ - int value = object##_led_wk; \ - write_status(object##_set_handle, value, (mask)); \ + struct asus_laptop *asus = work_to_asus(work, object); \ + \ + int value = asus->leds.object##_wk; \ + write_status(asus, object##_set_handle, value, (mask)); \ } \ static enum led_brightness object##_led_get( \ struct led_classdev *led_cdev) \ @@ -448,7 +481,7 @@ static int get_kled_lvl(void) return kblv; } -static int set_kled_lvl(int kblv) +static int set_kled_lvl(struct asus_laptop *asus, int kblv) { if (kblv > 0) kblv = (1 << 7) | (kblv & 0x7F); @@ -465,13 +498,17 @@ static int set_kled_lvl(int kblv) static void kled_led_set(struct led_classdev *led_cdev, enum led_brightness value) { - kled_led_wk = value; - queue_work(led_workqueue, &kled_led_work); + struct asus_laptop *asus = led_to_asus(led_cdev, kled); + + asus->leds.kled_wk = value; + queue_work(asus->leds.workqueue, &asus->leds.kled_work); } -static void kled_led_update(struct work_struct *ignored) +static void kled_led_update(struct work_struct *work) { - set_kled_lvl(kled_led_wk); + struct asus_laptop *asus = work_to_asus(work, kled); + + set_kled_lvl(asus, asus->leds.kled_wk); } static enum led_brightness kled_led_get(struct led_classdev *led_cdev) @@ -479,19 +516,19 @@ static enum led_brightness kled_led_get(struct led_classdev *led_cdev) return get_kled_lvl(); } -static int get_lcd_state(void) +static int get_lcd_state(struct asus_laptop *asus) { - return read_status(LCD_ON); + return read_status(asus, LCD_ON); } -static int set_lcd_state(int value) +static int set_lcd_state(struct asus_laptop *asus, int value) { int lcd = 0; acpi_status status = 0; lcd = value ? 1 : 0; - if (lcd == get_lcd_state()) + if (lcd == get_lcd_state(asus)) return 0; if (lcd_switch_handle) { @@ -502,11 +539,11 @@ static int set_lcd_state(int value) pr_warning("Error switching LCD\n"); } - write_status(NULL, lcd, LCD_ON); + write_status(asus, NULL, lcd, LCD_ON); return 0; } -static void lcd_blank(int blank) +static void lcd_blank(struct asus_laptop *asus, int blank) { struct backlight_device *bd = asus->backlight_device; @@ -539,6 +576,7 @@ static int set_brightness(struct backlight_device *bd, int value) static int update_bl_status(struct backlight_device *bd) { + struct asus_laptop *asus = bl_get_data(bd); int rv; int value = bd->props.brightness; @@ -547,7 +585,7 @@ static int update_bl_status(struct backlight_device *bd) return rv; value = (bd->props.power == FB_BLANK_UNBLANK) ? 1 : 0; - return set_lcd_state(value); + return set_lcd_state(asus, value); } /* @@ -562,6 +600,7 @@ static int update_bl_status(struct backlight_device *bd) static ssize_t show_infos(struct device *dev, struct device_attribute *attr, char *page) { + struct asus_laptop *asus = dev_get_drvdata(dev); int len = 0; unsigned long long temp; char buf[16]; /* enough for all info */ @@ -638,7 +677,8 @@ static int parse_arg(const char *buf, unsigned long count, int *val) return count; } -static ssize_t store_status(const char *buf, size_t count, +static ssize_t store_status(struct asus_laptop *asus, + const char *buf, size_t count, acpi_handle handle, int mask) { int rv, value; @@ -648,7 +688,7 @@ static ssize_t store_status(const char *buf, size_t count, if (rv > 0) out = value ? 1 : 0; - write_status(handle, out, mask); + write_status(asus, handle, out, mask); return rv; } @@ -659,12 +699,15 @@ 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) { + struct asus_laptop *asus = dev_get_drvdata(dev); + return sprintf(buf, "0x%08x\n", asus->ledd_status); } static ssize_t store_ledd(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { + struct asus_laptop *asus = dev_get_drvdata(dev); int rv, value; rv = parse_arg(buf, count, &value); @@ -683,13 +726,17 @@ static ssize_t store_ledd(struct device *dev, struct device_attribute *attr, static ssize_t show_wlan(struct device *dev, struct device_attribute *attr, char *buf) { - return sprintf(buf, "%d\n", read_status(WL_ON)); + struct asus_laptop *asus = dev_get_drvdata(dev); + + return sprintf(buf, "%d\n", read_status(asus, WL_ON)); } static ssize_t store_wlan(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - return store_status(buf, count, wl_switch_handle, WL_ON); + struct asus_laptop *asus = dev_get_drvdata(dev); + + return store_status(asus, buf, count, wl_switch_handle, WL_ON); } /* @@ -698,20 +745,24 @@ static ssize_t store_wlan(struct device *dev, struct device_attribute *attr, static ssize_t show_bluetooth(struct device *dev, struct device_attribute *attr, char *buf) { - return sprintf(buf, "%d\n", read_status(BT_ON)); + struct asus_laptop *asus = dev_get_drvdata(dev); + + return sprintf(buf, "%d\n", read_status(asus, BT_ON)); } static ssize_t store_bluetooth(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - return store_status(buf, count, bt_switch_handle, BT_ON); + struct asus_laptop *asus = dev_get_drvdata(dev); + + return store_status(asus, buf, count, bt_switch_handle, BT_ON); } /* * Display */ -static void set_display(int value) +static void set_display(struct asus_laptop *asus, int value) { /* no sanity check needed for now */ if (write_acpi_int(display_set_handle, NULL, value)) @@ -719,7 +770,7 @@ static void set_display(int value) return; } -static int read_display(void) +static int read_display(struct asus_laptop *asus) { unsigned long long value = 0; acpi_status rv = AE_OK; @@ -747,7 +798,9 @@ static int read_display(void) static ssize_t show_disp(struct device *dev, struct device_attribute *attr, char *buf) { - return sprintf(buf, "%d\n", read_display()); + struct asus_laptop *asus = dev_get_drvdata(dev); + + return sprintf(buf, "%d\n", read_display(asus)); } /* @@ -760,18 +813,19 @@ static ssize_t show_disp(struct device *dev, static ssize_t store_disp(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { + struct asus_laptop *asus = dev_get_drvdata(dev); int rv, value; rv = parse_arg(buf, count, &value); if (rv > 0) - set_display(value); + set_display(asus, value); return rv; } /* * Light Sens */ -static void set_light_sens_switch(int value) +static void set_light_sens_switch(struct asus_laptop *asus, int value) { if (write_acpi_int(ls_switch_handle, NULL, value)) pr_warning("Error setting light sensor switch\n"); @@ -781,22 +835,25 @@ static void set_light_sens_switch(int value) static ssize_t show_lssw(struct device *dev, struct device_attribute *attr, char *buf) { + struct asus_laptop *asus = dev_get_drvdata(dev); + return sprintf(buf, "%d\n", asus->light_switch); } static ssize_t store_lssw(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { + struct asus_laptop *asus = dev_get_drvdata(dev); int rv, value; rv = parse_arg(buf, count, &value); if (rv > 0) - set_light_sens_switch(value ? 1 : 0); + set_light_sens_switch(asus, value ? 1 : 0); return rv; } -static void set_light_sens_level(int value) +static void set_light_sens_level(struct asus_laptop *asus, int value) { if (write_acpi_int(ls_level_handle, NULL, value)) pr_warning("Error setting light sensor level\n"); @@ -806,19 +863,22 @@ static void set_light_sens_level(int value) static ssize_t show_lslvl(struct device *dev, struct device_attribute *attr, char *buf) { + struct asus_laptop *asus = dev_get_drvdata(dev); + return sprintf(buf, "%d\n", asus->light_level); } static ssize_t store_lslvl(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { + struct asus_laptop *asus = dev_get_drvdata(dev); int rv, value; rv = parse_arg(buf, count, &value); if (rv > 0) { value = (0 < value) ? ((15 < value) ? 15 : value) : 0; /* 0 <= value <= 15 */ - set_light_sens_level(value); + set_light_sens_level(asus, value); } return rv; @@ -830,34 +890,40 @@ static ssize_t store_lslvl(struct device *dev, struct device_attribute *attr, static ssize_t show_gps(struct device *dev, struct device_attribute *attr, char *buf) { - return sprintf(buf, "%d\n", read_status(GPS_ON)); + struct asus_laptop *asus = dev_get_drvdata(dev); + + return sprintf(buf, "%d\n", read_status(asus, GPS_ON)); } static ssize_t store_gps(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - return store_status(buf, count, NULL, GPS_ON); + struct asus_laptop *asus = dev_get_drvdata(dev); + + return store_status(asus, buf, count, NULL, GPS_ON); } /* * Hotkey functions */ -static struct key_entry *asus_get_entry_by_scancode(int code) +static struct key_entry *asus_get_entry_by_scancode(struct asus_laptop *asus, + int code) { struct key_entry *key; - for (key = asus_keymap; key->type != KE_END; key++) + for (key = asus->keymap; key->type != KE_END; key++) if (code == key->code) return key; return NULL; } -static struct key_entry *asus_get_entry_by_keycode(int code) +static struct key_entry *asus_get_entry_by_keycode(struct asus_laptop *asus, + int code) { struct key_entry *key; - for (key = asus_keymap; key->type != KE_END; key++) + for (key = asus->keymap; key->type != KE_END; key++) if (code == key->keycode && key->type == KE_KEY) return key; @@ -866,7 +932,8 @@ static struct key_entry *asus_get_entry_by_keycode(int code) static int asus_getkeycode(struct input_dev *dev, int scancode, int *keycode) { - struct key_entry *key = asus_get_entry_by_scancode(scancode); + struct asus_laptop *asus = input_get_drvdata(dev); + struct key_entry *key = asus_get_entry_by_scancode(asus, scancode); if (key && key->type == KE_KEY) { *keycode = key->keycode; @@ -878,18 +945,19 @@ static int asus_getkeycode(struct input_dev *dev, int scancode, int *keycode) static int asus_setkeycode(struct input_dev *dev, int scancode, int keycode) { + struct asus_laptop *asus = input_get_drvdata(dev); struct key_entry *key; int old_keycode; if (keycode < 0 || keycode > KEY_MAX) return -EINVAL; - key = asus_get_entry_by_scancode(scancode); + key = asus_get_entry_by_scancode(asus, scancode); if (key && key->type == KE_KEY) { old_keycode = key->keycode; key->keycode = keycode; set_bit(keycode, dev->keybit); - if (!asus_get_entry_by_keycode(old_keycode)) + if (!asus_get_entry_by_keycode(asus, old_keycode)) clear_bit(old_keycode, dev->keybit); return 0; } @@ -899,6 +967,7 @@ static int asus_setkeycode(struct input_dev *dev, int scancode, int keycode) static void asus_acpi_notify(struct acpi_device *device, u32 event) { + struct asus_laptop *asus = acpi_driver_data(device); static struct key_entry *key; u16 count; @@ -907,11 +976,11 @@ static void asus_acpi_notify(struct acpi_device *device, u32 event) * switched */ if (event == ATKD_LCD_ON) { - write_status(NULL, 1, LCD_ON); - lcd_blank(FB_BLANK_UNBLANK); + write_status(asus, NULL, 1, LCD_ON); + lcd_blank(asus, FB_BLANK_UNBLANK); } else if (event == ATKD_LCD_OFF) { - write_status(NULL, 0, LCD_ON); - lcd_blank(FB_BLANK_POWERDOWN); + write_status(asus, NULL, 0, LCD_ON); + lcd_blank(asus, FB_BLANK_POWERDOWN); } /* TODO Find a better way to handle events count. */ @@ -922,7 +991,7 @@ static void asus_acpi_notify(struct acpi_device *device, u32 event) count); if (asus->inputdev) { - key = asus_get_entry_by_scancode(event); + key = asus_get_entry_by_scancode(asus, event); if (!key) return ; @@ -978,13 +1047,14 @@ static struct attribute_group platform_attribute_group = { .attrs = asuspf_attributes }; -static int asus_platform_init(void) +static int asus_platform_init(struct asus_laptop *asus) { int result; asus->platform_device = platform_device_alloc(ASUS_LAPTOP_FILE, -1); if (!asus->platform_device) return -ENOMEM; + platform_set_drvdata(asus->platform_device, asus); result = platform_device_add(asus->platform_device); if (result) @@ -1003,7 +1073,7 @@ fail_platform_device: return result; } -static void asus_platform_exit(void) +static void asus_platform_exit(struct asus_laptop *asus) { sysfs_remove_group(&asus->platform_device->dev.kobj, &platform_attribute_group); @@ -1012,12 +1082,12 @@ static void asus_platform_exit(void) static struct platform_driver platform_driver = { .driver = { - .name = ASUS_LAPTOP_FILE, - .owner = THIS_MODULE, - } + .name = ASUS_LAPTOP_FILE, + .owner = THIS_MODULE, + } }; -static void asus_laptop_add_fs(void) +static void asus_laptop_add_fs(struct asus_laptop *asus) { ASUS_SET_DEVICE_ATTR(infos, 0444, show_infos, NULL); @@ -1187,7 +1257,7 @@ static int asus_laptop_get_info(struct asus_laptop *asus) return AE_OK; } -static int asus_input_init(struct device *dev) +static int asus_input_init(struct asus_laptop *asus) { const struct key_entry *key; int result; @@ -1198,13 +1268,16 @@ static int asus_input_init(struct device *dev) return 0; } asus->inputdev->name = "Asus Laptop extra buttons"; - asus->inputdev->dev.parent = dev; + asus->inputdev->dev.parent = &asus->platform_device->dev; asus->inputdev->phys = ASUS_LAPTOP_FILE "/input0"; asus->inputdev->id.bustype = BUS_HOST; asus->inputdev->getkeycode = asus_getkeycode; asus->inputdev->setkeycode = asus_setkeycode; + input_set_drvdata(asus->inputdev, asus); - for (key = asus_keymap; key->type != KE_END; key++) { + asus->keymap = kmemdup(asus_keymap, sizeof(asus_keymap), + GFP_KERNEL); + for (key = asus->keymap; key->type != KE_END; key++) { switch (key->type) { case KE_KEY: set_bit(EV_KEY, asus->inputdev->evbit); @@ -1220,40 +1293,44 @@ static int asus_input_init(struct device *dev) return result; } -static void asus_backlight_exit(void) +static void asus_backlight_exit(struct asus_laptop *asus) { if (asus->backlight_device) backlight_device_unregister(asus->backlight_device); } -#define ASUS_LED_UNREGISTER(object) \ +#define ASUS_LED_UNREGISTER(object) \ if (object##_led.dev) \ led_classdev_unregister(&object##_led) -static void asus_led_exit(void) +static void asus_led_exit(struct asus_laptop *asus) { - destroy_workqueue(led_workqueue); ASUS_LED_UNREGISTER(mled); ASUS_LED_UNREGISTER(tled); ASUS_LED_UNREGISTER(pled); ASUS_LED_UNREGISTER(rled); ASUS_LED_UNREGISTER(gled); ASUS_LED_UNREGISTER(kled); + if (asus->leds.workqueue) { + destroy_workqueue(asus->leds.workqueue); + asus->leds.workqueue = NULL; + } } -static void asus_input_exit(void) +static void asus_input_exit(struct asus_laptop *asus) { if (asus->inputdev) input_unregister_device(asus->inputdev); } -static int asus_backlight_init(struct device *dev) +static int asus_backlight_init(struct asus_laptop *asus) { struct backlight_device *bd; + struct device *dev = &asus->platform_device->dev; if (brightness_set_handle && lcd_switch_handle) { bd = backlight_device_register(ASUS_LAPTOP_FILE, dev, - NULL, &asusbl_ops); + asus, &asusbl_ops); if (IS_ERR(bd)) { pr_err("Could not register asus backlight device\n"); asus->backlight_device = NULL; @@ -1270,79 +1347,55 @@ static int asus_backlight_init(struct device *dev) return 0; } -static int asus_led_register(acpi_handle handle, - struct led_classdev *ldev, struct device *dev) -{ - if (!handle) - return 0; - - return led_classdev_register(dev, ldev); -} - -#define ASUS_LED_REGISTER(object, device) \ - asus_led_register(object##_set_handle, &object##_led, device) - -static int asus_led_init(struct device *dev) +/* + * Ugly macro, need to fix that later + */ +#define ASUS_LED_REGISTER(asus, object, _name, max) \ + do { \ + struct led_classdev *ldev = &asus->leds.object; \ + if (!object##_set_handle) \ + break ; \ + \ + INIT_WORK(&asus->leds.object##_work, object##_led_update); \ + ldev->name = "asus::" _name; \ + ldev->brightness_set = object##_led_set; \ + ldev->max_brightness = max; \ + rv = led_classdev_register(&asus->platform_device->dev, ldev); \ + if (rv) \ + goto error; \ + } while (0) + +static int asus_led_init(struct asus_laptop *asus) { int rv; - rv = ASUS_LED_REGISTER(mled, dev); - if (rv) - goto out; - - rv = ASUS_LED_REGISTER(tled, dev); - if (rv) - goto out1; - - rv = ASUS_LED_REGISTER(rled, dev); - if (rv) - goto out2; - - rv = ASUS_LED_REGISTER(pled, dev); - if (rv) - goto out3; - - rv = ASUS_LED_REGISTER(gled, dev); - if (rv) - goto out4; - - if (kled_set_handle && kled_get_handle) - rv = ASUS_LED_REGISTER(kled, dev); - if (rv) - goto out5; - /* * Functions that actually update the LED's are called from a * workqueue. By doing this as separate work rather than when the LED * subsystem asks, we avoid messing with the Asus ACPI stuff during a * potentially bad time, such as a timer interrupt. */ - led_workqueue = create_singlethread_workqueue("led_workqueue"); - if (!led_workqueue) - goto out6; + asus->leds.workqueue = create_singlethread_workqueue("led_workqueue"); + if (!asus->leds.workqueue) + return -ENOMEM; - return 0; -out6: - rv = -ENOMEM; - ASUS_LED_UNREGISTER(kled); -out5: - ASUS_LED_UNREGISTER(gled); -out4: - ASUS_LED_UNREGISTER(pled); -out3: - ASUS_LED_UNREGISTER(rled); -out2: - ASUS_LED_UNREGISTER(tled); -out1: - ASUS_LED_UNREGISTER(mled); -out: + ASUS_LED_REGISTER(asus, mled, "mail", 1); + ASUS_LED_REGISTER(asus, tled, "touchpad", 1); + ASUS_LED_REGISTER(asus, rled, "record", 1); + ASUS_LED_REGISTER(asus, pled, "phone", 1); + ASUS_LED_REGISTER(asus, gled, "gaming", 1); + if (kled_set_handle && kled_get_handle) + ASUS_LED_REGISTER(asus, kled, "kbd_backlight", 3); +error: + if (rv) + asus_led_exit(asus); return rv; } static bool asus_device_present; -static int __devinit asus_acpi_init(struct acpi_device *device) +static int __devinit asus_acpi_init(struct asus_laptop *asus) { int result = 0; @@ -1358,22 +1411,22 @@ static int __devinit asus_acpi_init(struct acpi_device *device) if (result) return result; - asus_laptop_add_fs(); + asus_laptop_add_fs(asus); /* WLED and BLED are on by default */ - write_status(bt_switch_handle, 1, BT_ON); - write_status(wl_switch_handle, 1, WL_ON); + write_status(asus, bt_switch_handle, 1, BT_ON); + write_status(asus, wl_switch_handle, 1, 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); + write_status(asus, NULL, read_status(asus, BT_ON), BT_ON); + write_status(asus, NULL, read_status(asus, WL_ON), WL_ON); /* LCD Backlight is on by default */ - write_status(NULL, 1, LCD_ON); + write_status(asus, NULL, 1, LCD_ON); /* Keyboard Backlight is on by default */ if (kled_set_handle) - set_kled_lvl(1); + set_kled_lvl(asus, 1); /* LED display is off by default */ asus->ledd_status = 0xFFF; @@ -1383,18 +1436,19 @@ static int __devinit asus_acpi_init(struct acpi_device *device) hotk->light_level = 5; /* level 5 for sensor sensitivity */ if (ls_switch_handle) - set_light_sens_switch(asus->light_switch); + set_light_sens_switch(asus, asus->light_switch); if (ls_level_handle) - set_light_sens_level(asus->light_level); + set_light_sens_level(asus, asus->light_level); /* GPS is on by default */ - write_status(NULL, 1, GPS_ON); + write_status(asus, NULL, 1, GPS_ON); return result; } static int __devinit asus_acpi_add(struct acpi_device *device) { + struct asus_laptop *asus; int result; pr_notice("Asus Laptop Support version %s\n", @@ -1408,7 +1462,7 @@ static int __devinit asus_acpi_add(struct acpi_device *device) device->driver_data = asus; asus->device = device; - result = asus_acpi_init(device); + result = asus_acpi_init(asus); if (result) goto fail_platform; @@ -1416,22 +1470,22 @@ static int __devinit asus_acpi_add(struct acpi_device *device) * Register the platform device first. It is used as a parent for the * sub-devices below. */ - result = asus_platform_init(); + result = asus_platform_init(asus); if (result) goto fail_platform; if (!acpi_video_backlight_support()) { - result = asus_backlight_init(&asus->platform_device->dev); + result = asus_backlight_init(asus); if (result) goto fail_backlight; } else pr_info("Backlight controlled by ACPI video driver\n"); - result = asus_input_init(&asus->platform_device->dev); + result = asus_input_init(asus); if (result) goto fail_input; - result = asus_led_init(&asus->platform_device->dev); + result = asus_led_init(asus); if (result) goto fail_led; @@ -1439,11 +1493,11 @@ static int __devinit asus_acpi_add(struct acpi_device *device) return 0; fail_led: - asus_input_exit(); + asus_input_exit(asus); fail_input: - asus_backlight_exit(); + asus_backlight_exit(asus); fail_backlight: - asus_platform_exit(); + asus_platform_exit(asus); fail_platform: kfree(asus->name); kfree(asus); @@ -1453,10 +1507,12 @@ fail_platform: static int asus_acpi_remove(struct acpi_device *device, int type) { - asus_backlight_exit(); - asus_led_exit(); - asus_input_exit(); - asus_platform_exit(); + struct asus_laptop *asus = acpi_driver_data(device); + + asus_backlight_exit(asus); + asus_led_exit(asus); + asus_input_exit(asus); + asus_platform_exit(asus); kfree(asus->name); kfree(asus); -- cgit v1.2.3 From be4ee82d3e44c5940a7f77cae5ed3e942e80a723 Mon Sep 17 00:00:00 2001 From: Corentin Chary Date: Sun, 6 Dec 2009 16:27:09 +0100 Subject: asus-laptop: code movement The asus-laptop driver implements a number of interfaces like the backlight class driver. This change makes it easier to examine the implementation of one interface at at a time, without having to search through the file to find init() and exit() functions etc. Signed-off-by: Corentin Chary --- drivers/platform/x86/asus-laptop.c | 440 +++++++++++++++++++------------------ 1 file changed, 223 insertions(+), 217 deletions(-) (limited to 'drivers') diff --git a/drivers/platform/x86/asus-laptop.c b/drivers/platform/x86/asus-laptop.c index 58a4864096d9..940ce3d63229 100644 --- a/drivers/platform/x86/asus-laptop.c +++ b/drivers/platform/x86/asus-laptop.c @@ -58,36 +58,6 @@ #define ASUS_LAPTOP_FILE KBUILD_MODNAME #define ASUS_LAPTOP_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 - -/* - * Known bits returned by \_SB.ATKD.HWRS - */ -#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 */ - MODULE_AUTHOR("Julien Lerouge, Karol Kozimor, Corentin Chary"); MODULE_DESCRIPTION(ASUS_LAPTOP_NAME); MODULE_LICENSE("GPL"); @@ -119,6 +89,35 @@ MODULE_PARM_DESC(bluetooth_status, "Set the wireless status on boot " "(0 = disabled, 1 = enabled, -1 = don't do anything). " "default is 1"); +/* + * 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 + +/* + * Known bits returned by \_SB.ATKD.HWRS + */ +#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_HANDLE(object, paths...) \ static acpi_handle object##_handle = NULL; \ static char *object##_paths[] = { paths } @@ -249,36 +248,6 @@ struct asus_laptop { u16 *keycode_map; }; -/* - * The backlight class declaration - */ -static int read_brightness(struct backlight_device *bd); -static int update_bl_status(struct backlight_device *bd); -static struct backlight_ops asusbl_ops = { - .get_brightness = read_brightness, - .update_status = update_bl_status, -}; - -#define ASUS_LED(object, ledname, max) \ - static void object##_led_set(struct led_classdev *led_cdev, \ - enum led_brightness value); \ - static enum led_brightness object##_led_get( \ - struct led_classdev *led_cdev); \ - static void object##_led_update(struct work_struct *ignored); \ - static struct led_classdev object##_led = { \ - .name = "asus::" ledname, \ - .brightness_set = object##_led_set, \ - .brightness_get = object##_led_get, \ - .max_brightness = max \ - } - -ASUS_LED(mled, "mail", 1); -ASUS_LED(tled, "touchpad", 1); -ASUS_LED(rled, "record", 1); -ASUS_LED(pled, "phone", 1); -ASUS_LED(gled, "gaming", 1); -ASUS_LED(kled, "kbd_backlight", 3); - struct key_entry { char type; u8 code; @@ -427,6 +396,29 @@ static void write_status(struct asus_laptop *asus, acpi_handle handle, pr_warning(" write failed %x\n", mask); } +/* + * LEDs + */ +#define ASUS_LED(object, ledname, max) \ + static void object##_led_set(struct led_classdev *led_cdev, \ + enum led_brightness value); \ + static enum led_brightness object##_led_get( \ + struct led_classdev *led_cdev); \ + static void object##_led_update(struct work_struct *ignored); \ + static struct led_classdev object##_led = { \ + .name = "asus::" ledname, \ + .brightness_set = object##_led_set, \ + .brightness_get = object##_led_get, \ + .max_brightness = max \ + } + +ASUS_LED(mled, "mail", 1); +ASUS_LED(tled, "touchpad", 1); +ASUS_LED(rled, "record", 1); +ASUS_LED(pled, "phone", 1); +ASUS_LED(gled, "gaming", 1); +ASUS_LED(kled, "kbd_backlight", 3); + /* /sys/class/led handlers */ #define ASUS_LED_HANDLER(object, mask) \ static void object##_led_set(struct led_classdev *led_cdev, \ @@ -459,7 +451,7 @@ ASUS_LED_HANDLER(tled, TLED_ON); ASUS_LED_HANDLER(gled, GLED_ON); /* - * Keyboard backlight + * Keyboard backlight (also a LED) */ static int get_kled_lvl(void) { @@ -516,6 +508,70 @@ static enum led_brightness kled_led_get(struct led_classdev *led_cdev) return get_kled_lvl(); } +#define ASUS_LED_UNREGISTER(object) \ + if (object##_led.dev) \ + led_classdev_unregister(&object##_led) + +static void asus_led_exit(struct asus_laptop *asus) +{ + ASUS_LED_UNREGISTER(mled); + ASUS_LED_UNREGISTER(tled); + ASUS_LED_UNREGISTER(pled); + ASUS_LED_UNREGISTER(rled); + ASUS_LED_UNREGISTER(gled); + ASUS_LED_UNREGISTER(kled); + if (asus->leds.workqueue) { + destroy_workqueue(asus->leds.workqueue); + asus->leds.workqueue = NULL; + } +} + +/* Ugly macro, need to fix that later */ +#define ASUS_LED_REGISTER(asus, object, _name, max) \ + do { \ + struct led_classdev *ldev = &asus->leds.object; \ + if (!object##_set_handle) \ + break ; \ + \ + INIT_WORK(&asus->leds.object##_work, object##_led_update); \ + ldev->name = "asus::" _name; \ + ldev->brightness_set = object##_led_set; \ + ldev->max_brightness = max; \ + rv = led_classdev_register(&asus->platform_device->dev, ldev); \ + if (rv) \ + goto error; \ + } while (0) + +static int asus_led_init(struct asus_laptop *asus) +{ + int rv; + + /* + * Functions that actually update the LED's are called from a + * workqueue. By doing this as separate work rather than when the LED + * subsystem asks, we avoid messing with the Asus ACPI stuff during a + * potentially bad time, such as a timer interrupt. + */ + asus->leds.workqueue = create_singlethread_workqueue("led_workqueue"); + if (!asus->leds.workqueue) + return -ENOMEM; + + ASUS_LED_REGISTER(asus, mled, "mail", 1); + ASUS_LED_REGISTER(asus, tled, "touchpad", 1); + ASUS_LED_REGISTER(asus, rled, "record", 1); + ASUS_LED_REGISTER(asus, pled, "phone", 1); + ASUS_LED_REGISTER(asus, gled, "gaming", 1); + if (kled_set_handle && kled_get_handle) + ASUS_LED_REGISTER(asus, kled, "kbd_backlight", 3); +error: + if (rv) + asus_led_exit(asus); + return rv; +} + +/* + * Backlight device + */ static int get_lcd_state(struct asus_laptop *asus) { return read_status(asus, LCD_ON); @@ -588,6 +644,41 @@ static int update_bl_status(struct backlight_device *bd) return set_lcd_state(asus, value); } +static struct backlight_ops asusbl_ops = { + .get_brightness = read_brightness, + .update_status = update_bl_status, +}; + +static int asus_backlight_init(struct asus_laptop *asus) +{ + struct backlight_device *bd; + struct device *dev = &asus->platform_device->dev; + + if (brightness_set_handle && lcd_switch_handle) { + bd = backlight_device_register(ASUS_LAPTOP_FILE, dev, + asus, &asusbl_ops); + if (IS_ERR(bd)) { + pr_err("Could not register asus backlight device\n"); + asus->backlight_device = NULL; + return PTR_ERR(bd); + } + + asus->backlight_device = bd; + + bd->props.max_brightness = 15; + bd->props.brightness = read_brightness(NULL); + bd->props.power = FB_BLANK_UNBLANK; + backlight_update_status(bd); + } + return 0; +} + +static void asus_backlight_exit(struct asus_laptop *asus) +{ + if (asus->backlight_device) + backlight_device_unregister(asus->backlight_device); +} + /* * Platform device handlers */ @@ -904,7 +995,7 @@ static ssize_t store_gps(struct device *dev, struct device_attribute *attr, } /* - * Hotkey functions + * Input device (i.e. hotkeys) */ static struct key_entry *asus_get_entry_by_scancode(struct asus_laptop *asus, int code) @@ -965,10 +1056,72 @@ static int asus_setkeycode(struct input_dev *dev, int scancode, int keycode) return -EINVAL; } +static void asus_input_notify(struct asus_laptop *asus, int event) +{ + struct key_entry *key; + + key = asus_get_entry_by_scancode(asus, event); + if (!key) + return ; + + switch (key->type) { + case KE_KEY: + 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; + } +} + +static int asus_input_init(struct asus_laptop *asus) +{ + const struct key_entry *key; + int result; + + asus->inputdev = input_allocate_device(); + if (!asus->inputdev) { + pr_info("Unable to allocate input device\n"); + return 0; + } + asus->inputdev->name = "Asus Laptop extra buttons"; + asus->inputdev->dev.parent = &asus->platform_device->dev; + asus->inputdev->phys = ASUS_LAPTOP_FILE "/input0"; + asus->inputdev->id.bustype = BUS_HOST; + asus->inputdev->getkeycode = asus_getkeycode; + asus->inputdev->setkeycode = asus_setkeycode; + input_set_drvdata(asus->inputdev, asus); + + asus->keymap = kmemdup(asus_keymap, sizeof(asus_keymap), + GFP_KERNEL); + for (key = asus->keymap; key->type != KE_END; key++) { + switch (key->type) { + case KE_KEY: + set_bit(EV_KEY, asus->inputdev->evbit); + set_bit(key->keycode, asus->inputdev->keybit); + break; + } + } + result = input_register_device(asus->inputdev); + if (result) { + pr_info("Unable to register input device\n"); + input_free_device(asus->inputdev); + } + return result; +} + +static void asus_input_exit(struct asus_laptop *asus) +{ + if (asus->inputdev) + input_unregister_device(asus->inputdev); +} + +/* + * ACPI driver + */ static void asus_acpi_notify(struct acpi_device *device, u32 event) { struct asus_laptop *asus = acpi_driver_data(device); - static struct key_entry *key; u16 count; /* @@ -990,20 +1143,7 @@ static void asus_acpi_notify(struct acpi_device *device, u32 event) dev_name(&asus->device->dev), event, count); - if (asus->inputdev) { - key = asus_get_entry_by_scancode(asus, event); - if (!key) - return ; - - switch (key->type) { - case KE_KEY: - 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; - } - } + asus_input_notify(asus, event); } #define ASUS_CREATE_DEVICE_ATTR(_name) \ @@ -1257,142 +1397,6 @@ static int asus_laptop_get_info(struct asus_laptop *asus) return AE_OK; } -static int asus_input_init(struct asus_laptop *asus) -{ - const struct key_entry *key; - int result; - - asus->inputdev = input_allocate_device(); - if (!asus->inputdev) { - pr_info("Unable to allocate input device\n"); - return 0; - } - asus->inputdev->name = "Asus Laptop extra buttons"; - asus->inputdev->dev.parent = &asus->platform_device->dev; - asus->inputdev->phys = ASUS_LAPTOP_FILE "/input0"; - asus->inputdev->id.bustype = BUS_HOST; - asus->inputdev->getkeycode = asus_getkeycode; - asus->inputdev->setkeycode = asus_setkeycode; - input_set_drvdata(asus->inputdev, asus); - - asus->keymap = kmemdup(asus_keymap, sizeof(asus_keymap), - GFP_KERNEL); - for (key = asus->keymap; key->type != KE_END; key++) { - switch (key->type) { - case KE_KEY: - set_bit(EV_KEY, asus->inputdev->evbit); - set_bit(key->keycode, asus->inputdev->keybit); - break; - } - } - result = input_register_device(asus->inputdev); - if (result) { - pr_info("Unable to register input device\n"); - input_free_device(asus->inputdev); - } - return result; -} - -static void asus_backlight_exit(struct asus_laptop *asus) -{ - if (asus->backlight_device) - backlight_device_unregister(asus->backlight_device); -} - -#define ASUS_LED_UNREGISTER(object) \ - if (object##_led.dev) \ - led_classdev_unregister(&object##_led) - -static void asus_led_exit(struct asus_laptop *asus) -{ - ASUS_LED_UNREGISTER(mled); - ASUS_LED_UNREGISTER(tled); - ASUS_LED_UNREGISTER(pled); - ASUS_LED_UNREGISTER(rled); - ASUS_LED_UNREGISTER(gled); - ASUS_LED_UNREGISTER(kled); - if (asus->leds.workqueue) { - destroy_workqueue(asus->leds.workqueue); - asus->leds.workqueue = NULL; - } -} - -static void asus_input_exit(struct asus_laptop *asus) -{ - if (asus->inputdev) - input_unregister_device(asus->inputdev); -} - -static int asus_backlight_init(struct asus_laptop *asus) -{ - struct backlight_device *bd; - struct device *dev = &asus->platform_device->dev; - - if (brightness_set_handle && lcd_switch_handle) { - bd = backlight_device_register(ASUS_LAPTOP_FILE, dev, - asus, &asusbl_ops); - if (IS_ERR(bd)) { - pr_err("Could not register asus backlight device\n"); - asus->backlight_device = NULL; - return PTR_ERR(bd); - } - - asus->backlight_device = bd; - - bd->props.max_brightness = 15; - bd->props.brightness = read_brightness(NULL); - bd->props.power = FB_BLANK_UNBLANK; - backlight_update_status(bd); - } - return 0; -} - -/* - * Ugly macro, need to fix that later - */ -#define ASUS_LED_REGISTER(asus, object, _name, max) \ - do { \ - struct led_classdev *ldev = &asus->leds.object; \ - if (!object##_set_handle) \ - break ; \ - \ - INIT_WORK(&asus->leds.object##_work, object##_led_update); \ - ldev->name = "asus::" _name; \ - ldev->brightness_set = object##_led_set; \ - ldev->max_brightness = max; \ - rv = led_classdev_register(&asus->platform_device->dev, ldev); \ - if (rv) \ - goto error; \ - } while (0) - -static int asus_led_init(struct asus_laptop *asus) -{ - int rv; - - /* - * Functions that actually update the LED's are called from a - * workqueue. By doing this as separate work rather than when the LED - * subsystem asks, we avoid messing with the Asus ACPI stuff during a - * potentially bad time, such as a timer interrupt. - */ - asus->leds.workqueue = create_singlethread_workqueue("led_workqueue"); - if (!asus->leds.workqueue) - return -ENOMEM; - - ASUS_LED_REGISTER(asus, mled, "mail", 1); - ASUS_LED_REGISTER(asus, tled, "touchpad", 1); - ASUS_LED_REGISTER(asus, rled, "record", 1); - ASUS_LED_REGISTER(asus, pled, "phone", 1); - ASUS_LED_REGISTER(asus, gled, "gaming", 1); - if (kled_set_handle && kled_get_handle) - ASUS_LED_REGISTER(asus, kled, "kbd_backlight", 3); -error: - if (rv) - asus_led_exit(asus); - return rv; -} - - static bool asus_device_present; static int __devinit asus_acpi_init(struct asus_laptop *asus) @@ -1414,8 +1418,10 @@ static int __devinit asus_acpi_init(struct asus_laptop *asus) asus_laptop_add_fs(asus); /* WLED and BLED are on by default */ - write_status(asus, bt_switch_handle, 1, BT_ON); - write_status(asus, wl_switch_handle, 1, WL_ON); + if (bluetooth_status >= 0) + write_status(asus, bt_switch_handle, !!bluetooth_status, BT_ON); + if (wireless_status >= 0) + write_status(asus, wl_switch_handle, !!wireless_status, WL_ON); /* If the h/w switch is off, we need to check the real status */ write_status(asus, NULL, read_status(asus, BT_ON), BT_ON); @@ -1432,8 +1438,8 @@ static int __devinit asus_acpi_init(struct asus_laptop *asus) asus->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 */ + asus->light_switch = 0; /* Default to light sensor disabled */ + asus->light_level = 5; /* level 5 for sensor sensitivity */ if (ls_switch_handle) set_light_sens_switch(asus, asus->light_switch); -- cgit v1.2.3 From aa9df930d6eabbd8f2439eca6b2f77f81ce425f2 Mon Sep 17 00:00:00 2001 From: Corentin Chary Date: Wed, 13 Jan 2010 21:49:10 +0100 Subject: asus-laptop: stop using read_status for bluetooth and wlan Signed-off-by: Corentin Chary --- drivers/platform/x86/asus-laptop.c | 55 ++++++++++++++++++++------------------ 1 file changed, 29 insertions(+), 26 deletions(-) (limited to 'drivers') diff --git a/drivers/platform/x86/asus-laptop.c b/drivers/platform/x86/asus-laptop.c index 940ce3d63229..cee751e301a6 100644 --- a/drivers/platform/x86/asus-laptop.c +++ b/drivers/platform/x86/asus-laptop.c @@ -239,6 +239,9 @@ struct asus_laptop { struct asus_laptop_leds leds; + int wireless_status; + bool have_rsts; + acpi_handle handle; /* the handle of the hotk device */ char status; /* status of the hotk, for LEDs, ... */ u32 ledd_status; /* status of the LED display */ @@ -328,23 +331,6 @@ 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(struct asus_laptop *asus, int mask) -{ - unsigned long long status; - acpi_status rv = AE_OK; - - if (!wireless_status_handle) - return (asus->status & mask) ? 1 : 0; - - rv = acpi_evaluate_integer(wireless_status_handle, NULL, NULL, &status); - if (ACPI_FAILURE(rv)) - pr_warning("Error reading Wireless status\n"); - else - return (status & mask) ? 1 : 0; - - return (asus->status & mask) ? 1 : 0; -} - static int read_gps_status(struct asus_laptop *asus) { unsigned long long status; @@ -362,10 +348,7 @@ static int read_gps_status(struct asus_laptop *asus) /* Generic LED functions */ static int read_status(struct asus_laptop *asus, int mask) { - /* There is a special method for both wireless devices */ - if (mask == BT_ON || mask == WL_ON) - return read_wireless_status(asus, mask); - else if (mask == GPS_ON) + if (mask == GPS_ON) return read_gps_status(asus); return (asus->status & mask) ? 1 : 0; @@ -811,6 +794,25 @@ static ssize_t store_ledd(struct device *dev, struct device_attribute *attr, return rv; } +/* + * Wireless + */ +static int asus_wireless_status(struct asus_laptop *asus, int mask) +{ + unsigned long long status; + acpi_status rv = AE_OK; + + if (!asus->have_rsts) + return (asus->wireless_status & mask) ? 1 : 0; + + rv = acpi_evaluate_integer(wireless_status_handle, NULL, NULL, &status); + if (ACPI_FAILURE(rv)) { + pr_warning("Error reading Wireless status\n"); + return -EINVAL; + } + return !!(status & mask); +} + /* * WLAN */ @@ -819,7 +821,7 @@ static ssize_t show_wlan(struct device *dev, { struct asus_laptop *asus = dev_get_drvdata(dev); - return sprintf(buf, "%d\n", read_status(asus, WL_ON)); + return sprintf(buf, "%d\n", asus_wireless_status(asus, WL_ON)); } static ssize_t store_wlan(struct device *dev, struct device_attribute *attr, @@ -838,7 +840,7 @@ static ssize_t show_bluetooth(struct device *dev, { struct asus_laptop *asus = dev_get_drvdata(dev); - return sprintf(buf, "%d\n", read_status(asus, BT_ON)); + return sprintf(buf, "%d\n", asus_wireless_status(asus, BT_ON)); } static ssize_t store_bluetooth(struct device *dev, @@ -1371,7 +1373,8 @@ static int asus_laptop_get_info(struct asus_laptop *asus) if (hwrs_result & BT_HWRS) ASUS_HANDLE_INIT(bt_switch); - ASUS_HANDLE_INIT(wireless_status); + if (!ASUS_HANDLE_INIT(wireless_status)) + asus->have_rsts = true; ASUS_HANDLE_INIT(brightness_set); ASUS_HANDLE_INIT(brightness_get); @@ -1424,8 +1427,8 @@ static int __devinit asus_acpi_init(struct asus_laptop *asus) write_status(asus, wl_switch_handle, !!wireless_status, WL_ON); /* If the h/w switch is off, we need to check the real status */ - write_status(asus, NULL, read_status(asus, BT_ON), BT_ON); - write_status(asus, NULL, read_status(asus, WL_ON), WL_ON); + write_status(asus, NULL, asus_wireless_status(asus, BT_ON), BT_ON); + write_status(asus, NULL, asus_wireless_status(asus, WL_ON), WL_ON); /* LCD Backlight is on by default */ write_status(asus, NULL, 1, LCD_ON); -- cgit v1.2.3 From 6358bf2c4c309efc7c3cbc36466c32108c12c456 Mon Sep 17 00:00:00 2001 From: Corentin Chary Date: Wed, 13 Jan 2010 21:55:44 +0100 Subject: asus-laptop: stop using read_status and store_status for GPS Signed-off-by: Corentin Chary --- drivers/platform/x86/asus-laptop.c | 56 ++++++++++++++++++++++++-------------- 1 file changed, 35 insertions(+), 21 deletions(-) (limited to 'drivers') diff --git a/drivers/platform/x86/asus-laptop.c b/drivers/platform/x86/asus-laptop.c index cee751e301a6..ea51d7e4df21 100644 --- a/drivers/platform/x86/asus-laptop.c +++ b/drivers/platform/x86/asus-laptop.c @@ -331,26 +331,9 @@ 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_gps_status(struct asus_laptop *asus) -{ - unsigned long long status; - acpi_status rv = AE_OK; - - rv = acpi_evaluate_integer(gps_status_handle, NULL, NULL, &status); - if (ACPI_FAILURE(rv)) - pr_warning("Error reading GPS status\n"); - else - return status ? 1 : 0; - - return (asus->status & GPS_ON) ? 1 : 0; -} - /* Generic LED functions */ static int read_status(struct asus_laptop *asus, int mask) { - if (mask == GPS_ON) - return read_gps_status(asus); - return (asus->status & mask) ? 1 : 0; } @@ -979,21 +962,52 @@ static ssize_t store_lslvl(struct device *dev, struct device_attribute *attr, /* * GPS + * TODO: use rfkill */ +static int asus_gps_status(struct asus_laptop *asus) +{ + unsigned long long status; + acpi_status rv = AE_OK; + + rv = acpi_evaluate_integer(gps_status_handle, NULL, NULL, &status); + if (ACPI_FAILURE(rv)) { + pr_warning("Error reading GPS status\n"); + return -ENODEV; + } + return !!status; +} + +static int asus_gps_switch(struct asus_laptop *asus, int status) +{ + acpi_handle handle = status ? gps_on_handle : gps_off_handle; + + if (write_acpi_int(handle, NULL, 0x02)) + return -ENODEV; + return 0; +} + static ssize_t show_gps(struct device *dev, struct device_attribute *attr, char *buf) { struct asus_laptop *asus = dev_get_drvdata(dev); - return sprintf(buf, "%d\n", read_status(asus, GPS_ON)); + return sprintf(buf, "%d\n", asus_gps_status(asus)); } static ssize_t store_gps(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct asus_laptop *asus = dev_get_drvdata(dev); + struct asus_laptop *asus = dev_get_drvdata(dev); + int rv, value; + int ret; - return store_status(asus, buf, count, NULL, GPS_ON); + rv = parse_arg(buf, count, &value); + if (rv <= 0) + return -EINVAL; + ret = asus_gps_switch(asus, !!value); + if (ret) + return ret; + return rv; } /* @@ -1451,7 +1465,7 @@ static int __devinit asus_acpi_init(struct asus_laptop *asus) set_light_sens_level(asus, asus->light_level); /* GPS is on by default */ - write_status(asus, NULL, 1, GPS_ON); + asus_gps_switch(asus, 1); return result; } -- cgit v1.2.3 From 3e68ae7c2a9076a694e46f49ec26323a7757eaad Mon Sep 17 00:00:00 2001 From: Corentin Chary Date: Wed, 13 Jan 2010 22:10:39 +0100 Subject: asus-laptop: stop using read_status for lcd (anyway lcd code is scheduled for removal) Signed-off-by: Corentin Chary --- drivers/platform/x86/asus-laptop.c | 37 ++++++++++++++++++++----------------- 1 file changed, 20 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/platform/x86/asus-laptop.c b/drivers/platform/x86/asus-laptop.c index ea51d7e4df21..d726db380e47 100644 --- a/drivers/platform/x86/asus-laptop.c +++ b/drivers/platform/x86/asus-laptop.c @@ -241,6 +241,7 @@ struct asus_laptop { int wireless_status; bool have_rsts; + int lcd_state; acpi_handle handle; /* the handle of the hotk device */ char status; /* status of the hotk, for LEDs, ... */ @@ -538,30 +539,33 @@ error: /* * Backlight device */ -static int get_lcd_state(struct asus_laptop *asus) +static int asus_lcd_status(struct asus_laptop *asus) { - return read_status(asus, LCD_ON); + return asus->lcd_state; } -static int set_lcd_state(struct asus_laptop *asus, int value) +static int asus_lcd_set(struct asus_laptop *asus, int value) { int lcd = 0; acpi_status status = 0; - lcd = value ? 1 : 0; + lcd = !!value; - if (lcd == get_lcd_state(asus)) + if (lcd == asus_lcd_status(asus)) return 0; - if (lcd_switch_handle) { - status = acpi_evaluate_object(lcd_switch_handle, - NULL, NULL, NULL); + if (!lcd_switch_handle) + return -ENODEV; + + status = acpi_evaluate_object(lcd_switch_handle, + NULL, NULL, NULL); - if (ACPI_FAILURE(status)) - pr_warning("Error switching LCD\n"); + if (ACPI_FAILURE(status)) { + pr_warning("Error switching LCD\n"); + return -ENODEV; } - write_status(asus, NULL, lcd, LCD_ON); + asus->lcd_state = lcd; return 0; } @@ -569,6 +573,8 @@ static void lcd_blank(struct asus_laptop *asus, int blank) { struct backlight_device *bd = asus->backlight_device; + asus->lcd_state = (blank == FB_BLANK_UNBLANK); + if (bd) { bd->props.power = blank; backlight_update_status(bd); @@ -607,7 +613,7 @@ static int update_bl_status(struct backlight_device *bd) return rv; value = (bd->props.power == FB_BLANK_UNBLANK) ? 1 : 0; - return set_lcd_state(asus, value); + return asus_lcd_set(asus, value); } static struct backlight_ops asusbl_ops = { @@ -1144,13 +1150,10 @@ static void asus_acpi_notify(struct acpi_device *device, u32 event) * We need to tell the backlight device when the backlight power is * switched */ - if (event == ATKD_LCD_ON) { - write_status(asus, NULL, 1, LCD_ON); + if (event == ATKD_LCD_ON) lcd_blank(asus, FB_BLANK_UNBLANK); - } else if (event == ATKD_LCD_OFF) { - write_status(asus, NULL, 0, LCD_ON); + else if (event == ATKD_LCD_OFF) lcd_blank(asus, FB_BLANK_POWERDOWN); - } /* TODO Find a better way to handle events count. */ count = asus->event_count[event % 128]++; -- cgit v1.2.3 From 17e78f6260fbc8f55c279cca081c26c88d96ec00 Mon Sep 17 00:00:00 2001 From: Corentin Chary Date: Wed, 13 Jan 2010 22:21:33 +0100 Subject: asus-laptop: removing read_status/store_status/write_status and asus->status Signed-off-by: Corentin Chary --- drivers/platform/x86/asus-laptop.c | 81 +++++++++++--------------------------- 1 file changed, 24 insertions(+), 57 deletions(-) (limited to 'drivers') diff --git a/drivers/platform/x86/asus-laptop.c b/drivers/platform/x86/asus-laptop.c index d726db380e47..2349e88bbc75 100644 --- a/drivers/platform/x86/asus-laptop.c +++ b/drivers/platform/x86/asus-laptop.c @@ -107,16 +107,8 @@ MODULE_PARM_DESC(bluetooth_status, "Set the wireless status on boot " * 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 WL_RSTS 0x01 /* internal Wifi */ +#define BT_RSTS 0x02 /* internal Bluetooth */ #define ASUS_HANDLE(object, paths...) \ static acpi_handle object##_handle = NULL; \ @@ -244,7 +236,6 @@ struct asus_laptop { int lcd_state; acpi_handle handle; /* the handle of the hotk device */ - char status; /* status of the hotk, for LEDs, ... */ u32 ledd_status; /* status of the LED display */ u8 light_level; /* light sensor level */ u8 light_switch; /* light sensor switch value */ @@ -332,35 +323,18 @@ static int write_acpi_int(acpi_handle handle, const char *method, int val) return write_acpi_int_ret(handle, method, val, NULL); } -/* Generic LED functions */ -static int read_status(struct asus_laptop *asus, int mask) +/* Generic LED function */ +static void asus_led_set(struct asus_laptop *asus, acpi_handle handle, + int value) { - return (asus->status & mask) ? 1 : 0; -} - -static void write_status(struct asus_laptop *asus, acpi_handle handle, - int out, int mask) -{ - asus->status = (out) ? (asus->status | mask) : (asus->status & ~mask); - - switch (mask) { - case MLED_ON: - out = !(out & 0x1); - break; - case GLED_ON: - out = (out & 0x1) + 1; - break; - case GPS_ON: - handle = (out) ? gps_on_handle : gps_off_handle; - out = 0x02; - break; - default: - out &= 0x1; - break; - } + if (handle == mled_set_handle) + value = !value; + else if (handle == gled_set_handle) + value = !value + 1; + else + value = !!value; - if (write_acpi_int(handle, NULL, out)) - pr_warning(" write failed %x\n", mask); + write_acpi_int(handle, NULL, value); } /* @@ -403,7 +377,7 @@ ASUS_LED(kled, "kbd_backlight", 3); struct asus_laptop *asus = work_to_asus(work, object); \ \ int value = asus->leds.object##_wk; \ - write_status(asus, object##_set_handle, value, (mask)); \ + asus_led_set(asus, object##_set_handle, value); \ } \ static enum led_brightness object##_led_get( \ struct led_classdev *led_cdev) \ @@ -740,9 +714,9 @@ static int parse_arg(const char *buf, unsigned long count, int *val) return count; } -static ssize_t store_status(struct asus_laptop *asus, - const char *buf, size_t count, - acpi_handle handle, int mask) +static ssize_t sysfs_acpi_set(struct asus_laptop *asus, + const char *buf, size_t count, + acpi_handle handle) { int rv, value; int out = 0; @@ -751,8 +725,8 @@ static ssize_t store_status(struct asus_laptop *asus, if (rv > 0) out = value ? 1 : 0; - write_status(asus, handle, out, mask); - + if (write_acpi_int(handle, NULL, value)) + return -ENODEV; return rv; } @@ -810,7 +784,7 @@ static ssize_t show_wlan(struct device *dev, { struct asus_laptop *asus = dev_get_drvdata(dev); - return sprintf(buf, "%d\n", asus_wireless_status(asus, WL_ON)); + return sprintf(buf, "%d\n", asus_wireless_status(asus, WL_RSTS)); } static ssize_t store_wlan(struct device *dev, struct device_attribute *attr, @@ -818,7 +792,7 @@ static ssize_t store_wlan(struct device *dev, struct device_attribute *attr, { struct asus_laptop *asus = dev_get_drvdata(dev); - return store_status(asus, buf, count, wl_switch_handle, WL_ON); + return sysfs_acpi_set(asus, buf, count, wl_switch_handle); } /* @@ -829,7 +803,7 @@ static ssize_t show_bluetooth(struct device *dev, { struct asus_laptop *asus = dev_get_drvdata(dev); - return sprintf(buf, "%d\n", asus_wireless_status(asus, BT_ON)); + return sprintf(buf, "%d\n", asus_wireless_status(asus, BT_RSTS)); } static ssize_t store_bluetooth(struct device *dev, @@ -838,7 +812,7 @@ static ssize_t store_bluetooth(struct device *dev, { struct asus_laptop *asus = dev_get_drvdata(dev); - return store_status(asus, buf, count, bt_switch_handle, BT_ON); + return sysfs_acpi_set(asus, buf, count, bt_switch_handle); } /* @@ -1439,16 +1413,9 @@ static int __devinit asus_acpi_init(struct asus_laptop *asus) /* WLED and BLED are on by default */ if (bluetooth_status >= 0) - write_status(asus, bt_switch_handle, !!bluetooth_status, BT_ON); + write_acpi_int(bt_switch_handle, NULL, !!bluetooth_status); if (wireless_status >= 0) - write_status(asus, wl_switch_handle, !!wireless_status, WL_ON); - - /* If the h/w switch is off, we need to check the real status */ - write_status(asus, NULL, asus_wireless_status(asus, BT_ON), BT_ON); - write_status(asus, NULL, asus_wireless_status(asus, WL_ON), WL_ON); - - /* LCD Backlight is on by default */ - write_status(asus, NULL, 1, LCD_ON); + write_acpi_int(wl_switch_handle, NULL, !!wireless_status); /* Keyboard Backlight is on by default */ if (kled_set_handle) -- cgit v1.2.3 From 4d4415138060870670a18d0768fe1d597f505f98 Mon Sep 17 00:00:00 2001 From: Corentin Chary Date: Wed, 13 Jan 2010 22:26:24 +0100 Subject: asus-laptop: rename function talking directly to acpi with asus_xxx scheme Signed-off-by: Corentin Chary --- drivers/platform/x86/asus-laptop.c | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) (limited to 'drivers') diff --git a/drivers/platform/x86/asus-laptop.c b/drivers/platform/x86/asus-laptop.c index 2349e88bbc75..ae4f80886577 100644 --- a/drivers/platform/x86/asus-laptop.c +++ b/drivers/platform/x86/asus-laptop.c @@ -394,7 +394,7 @@ ASUS_LED_HANDLER(gled, GLED_ON); /* * Keyboard backlight (also a LED) */ -static int get_kled_lvl(void) +static int asus_kled_lvl(void) { unsigned long long kblv; struct acpi_object_list params; @@ -409,12 +409,12 @@ static int get_kled_lvl(void) rv = acpi_evaluate_integer(kled_get_handle, NULL, ¶ms, &kblv); if (ACPI_FAILURE(rv)) { pr_warning("Error reading kled level\n"); - return 0; + return -ENODEV; } return kblv; } -static int set_kled_lvl(struct asus_laptop *asus, int kblv) +static int asus_kled_set(struct asus_laptop *asus, int kblv) { if (kblv > 0) kblv = (1 << 7) | (kblv & 0x7F); @@ -441,12 +441,12 @@ static void kled_led_update(struct work_struct *work) { struct asus_laptop *asus = work_to_asus(work, kled); - set_kled_lvl(asus, asus->leds.kled_wk); + asus_kled_set(asus, asus->leds.kled_wk); } static enum led_brightness kled_led_get(struct led_classdev *led_cdev) { - return get_kled_lvl(); + return asus_kled_lvl(); } #define ASUS_LED_UNREGISTER(object) \ @@ -555,7 +555,7 @@ static void lcd_blank(struct asus_laptop *asus, int blank) } } -static int read_brightness(struct backlight_device *bd) +static int asus_read_brightness(struct backlight_device *bd) { unsigned long long value; acpi_status rv = AE_OK; @@ -567,7 +567,7 @@ static int read_brightness(struct backlight_device *bd) return value; } -static int set_brightness(struct backlight_device *bd, int value) +static int asus_set_brightness(struct backlight_device *bd, int value) { if (write_acpi_int(brightness_set_handle, NULL, value)) { pr_warning("Error changing brightness\n"); @@ -582,7 +582,7 @@ static int update_bl_status(struct backlight_device *bd) int rv; int value = bd->props.brightness; - rv = set_brightness(bd, value); + rv = asus_set_brightness(bd, value); if (rv) return rv; @@ -591,7 +591,7 @@ static int update_bl_status(struct backlight_device *bd) } static struct backlight_ops asusbl_ops = { - .get_brightness = read_brightness, + .get_brightness = asus_read_brightness, .update_status = update_bl_status, }; @@ -612,7 +612,7 @@ static int asus_backlight_init(struct asus_laptop *asus) asus->backlight_device = bd; bd->props.max_brightness = 15; - bd->props.brightness = read_brightness(NULL); + bd->props.brightness = asus_read_brightness(NULL); bd->props.power = FB_BLANK_UNBLANK; backlight_update_status(bd); } @@ -818,7 +818,7 @@ static ssize_t store_bluetooth(struct device *dev, /* * Display */ -static void set_display(struct asus_laptop *asus, int value) +static void asus_set_display(struct asus_laptop *asus, int value) { /* no sanity check needed for now */ if (write_acpi_int(display_set_handle, NULL, value)) @@ -874,14 +874,14 @@ static ssize_t store_disp(struct device *dev, struct device_attribute *attr, rv = parse_arg(buf, count, &value); if (rv > 0) - set_display(asus, value); + asus_set_display(asus, value); return rv; } /* * Light Sens */ -static void set_light_sens_switch(struct asus_laptop *asus, int value) +static void asus_als_switch(struct asus_laptop *asus, int value) { if (write_acpi_int(ls_switch_handle, NULL, value)) pr_warning("Error setting light sensor switch\n"); @@ -904,12 +904,12 @@ static ssize_t store_lssw(struct device *dev, struct device_attribute *attr, rv = parse_arg(buf, count, &value); if (rv > 0) - set_light_sens_switch(asus, value ? 1 : 0); + asus_als_switch(asus, value ? 1 : 0); return rv; } -static void set_light_sens_level(struct asus_laptop *asus, int value) +static void asus_als_level(struct asus_laptop *asus, int value) { if (write_acpi_int(ls_level_handle, NULL, value)) pr_warning("Error setting light sensor level\n"); @@ -934,7 +934,7 @@ static ssize_t store_lslvl(struct device *dev, struct device_attribute *attr, if (rv > 0) { value = (0 < value) ? ((15 < value) ? 15 : value) : 0; /* 0 <= value <= 15 */ - set_light_sens_level(asus, value); + asus_als_level(asus, value); } return rv; @@ -1419,7 +1419,7 @@ static int __devinit asus_acpi_init(struct asus_laptop *asus) /* Keyboard Backlight is on by default */ if (kled_set_handle) - set_kled_lvl(asus, 1); + asus_kled_set(asus, 1); /* LED display is off by default */ asus->ledd_status = 0xFFF; @@ -1429,10 +1429,10 @@ static int __devinit asus_acpi_init(struct asus_laptop *asus) asus->light_level = 5; /* level 5 for sensor sensitivity */ if (ls_switch_handle) - set_light_sens_switch(asus, asus->light_switch); + asus_als_switch(asus, asus->light_switch); if (ls_level_handle) - set_light_sens_level(asus, asus->light_level); + asus_als_level(asus, asus->light_level); /* GPS is on by default */ asus_gps_switch(asus, 1); -- cgit v1.2.3 From d99b577c729c4a29679fb1f605f9ccace154e0e5 Mon Sep 17 00:00:00 2001 From: Corentin Chary Date: Fri, 22 Jan 2010 21:20:57 +0100 Subject: asus-laptop: stop using ASUS_HANDLE and use relative methods instead Stop using ASUS_HANDLE because most of the time it is not needed. This macro was introduced to display_get and lcd_switch which are not part of the interface provided by Asus, and are scheduled for removal. Signed-off-by: Corentin Chary --- drivers/platform/x86/asus-laptop.c | 240 ++++++++++++++++++++----------------- 1 file changed, 129 insertions(+), 111 deletions(-) (limited to 'drivers') diff --git a/drivers/platform/x86/asus-laptop.c b/drivers/platform/x86/asus-laptop.c index ae4f80886577..671fad96c275 100644 --- a/drivers/platform/x86/asus-laptop.c +++ b/drivers/platform/x86/asus-laptop.c @@ -115,27 +115,27 @@ MODULE_PARM_DESC(bluetooth_status, "Set the wireless status on boot " static char *object##_paths[] = { paths } /* LED */ -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) */ +#define METHOD_MLED "MLED" +#define METHOD_TLED "TLED" +#define METHOD_RLED "RLED" /* W1JC */ +#define METHOD_PLED "PLED" /* A7J */ +#define METHOD_GLED "GLED" /* G1, G2 (probably) */ /* LEDD */ -ASUS_HANDLE(ledd_set, ASUS_LAPTOP_PREFIX "SLCM"); +#define METHOD_LEDD "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_LAPTOP_PREFIX "WLED"); -ASUS_HANDLE(bt_switch, ASUS_LAPTOP_PREFIX "BLED"); -ASUS_HANDLE(wireless_status, ASUS_LAPTOP_PREFIX "RSTS"); /* All new models */ +#define METHOD_WLAN "WLED" +#define METHOD_BLUETOOTH "BLED" +#define METHOD_WL_STATUS "RSTS" /* Brightness */ -ASUS_HANDLE(brightness_set, ASUS_LAPTOP_PREFIX "SPLV"); -ASUS_HANDLE(brightness_get, ASUS_LAPTOP_PREFIX "GPLV"); +#define METHOD_BRIGHTNESS_SET "SPLV" +#define METHOD_BRIGHTNESS_GET "GPLV" /* Backlight */ ASUS_HANDLE(lcd_switch, "\\_SB.PCI0.SBRG.EC0._Q10", /* All new models */ @@ -148,7 +148,7 @@ ASUS_HANDLE(lcd_switch, "\\_SB.PCI0.SBRG.EC0._Q10", /* All new models */ "\\Q10"); /* A2x, L2D, L3D, M2E */ /* Display */ -ASUS_HANDLE(display_set, ASUS_LAPTOP_PREFIX "SDSP"); +#define METHOD_SWITCH_DISPLAY "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", @@ -173,18 +173,18 @@ ASUS_HANDLE(display_get, /* A3F A6F A3N A3L M6N W3N W6A */ "\\SSTE"); -ASUS_HANDLE(ls_switch, ASUS_LAPTOP_PREFIX "ALSC"); /* Z71A Z71V */ -ASUS_HANDLE(ls_level, ASUS_LAPTOP_PREFIX "ALSL"); /* Z71A Z71V */ +#define METHOD_ALS_CONTROL "ALSC" /* Z71A Z71V */ +#define METHOD_ALS_LEVEL "ALSL" /* Z71A Z71V */ /* GPS */ /* R2H use different handle for GPS on/off */ -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"); +#define METHOD_GPS_ON "SDON" +#define METHOD_GPS_OFF "SDOF" +#define METHOD_GPS_STATUS "GPST" /* Keyboard light */ -ASUS_HANDLE(kled_set, ASUS_LAPTOP_PREFIX "SLKB"); -ASUS_HANDLE(kled_get, ASUS_LAPTOP_PREFIX "GLKB"); +#define METHOD_KBD_LIGHT_SET "SLKB" +#define METHOD_KBD_LIGHT_GET "GLKB" /* * Define a specific led structure to keep the main structure clean @@ -323,18 +323,44 @@ static int write_acpi_int(acpi_handle handle, const char *method, int val) return write_acpi_int_ret(handle, method, val, NULL); } +static int acpi_check_handle(acpi_handle handle, const char *method, + acpi_handle *ret) +{ + acpi_status status; + + if (method == NULL) + return -ENODEV; + + if (ret) + status = acpi_get_handle(handle, (char *)method, + ret); + else { + acpi_handle dummy; + + status = acpi_get_handle(handle, (char *)method, + &dummy); + } + + if (status != AE_OK) { + if (ret) + pr_warning("Error finding %s\n", method); + return -ENODEV; + } + return 0; +} + /* Generic LED function */ -static void asus_led_set(struct asus_laptop *asus, acpi_handle handle, +static void asus_led_set(struct asus_laptop *asus, char *method, int value) { - if (handle == mled_set_handle) + if (!strcmp(method, METHOD_MLED)) value = !value; - else if (handle == gled_set_handle) + else if (!strcmp(method, METHOD_GLED)) value = !value + 1; else value = !!value; - write_acpi_int(handle, NULL, value); + write_acpi_int(asus->handle, method, value); } /* @@ -361,7 +387,7 @@ ASUS_LED(gled, "gaming", 1); ASUS_LED(kled, "kbd_backlight", 3); /* /sys/class/led handlers */ -#define ASUS_LED_HANDLER(object, mask) \ +#define ASUS_LED_HANDLER(object, method) \ static void object##_led_set(struct led_classdev *led_cdev, \ enum led_brightness value) \ { \ @@ -377,7 +403,7 @@ ASUS_LED(kled, "kbd_backlight", 3); struct asus_laptop *asus = work_to_asus(work, object); \ \ int value = asus->leds.object##_wk; \ - asus_led_set(asus, object##_set_handle, value); \ + asus_led_set(asus, method, value); \ } \ static enum led_brightness object##_led_get( \ struct led_classdev *led_cdev) \ @@ -385,16 +411,16 @@ ASUS_LED(kled, "kbd_backlight", 3); return led_cdev->brightness; \ } -ASUS_LED_HANDLER(mled, MLED_ON); -ASUS_LED_HANDLER(pled, PLED_ON); -ASUS_LED_HANDLER(rled, RLED_ON); -ASUS_LED_HANDLER(tled, TLED_ON); -ASUS_LED_HANDLER(gled, GLED_ON); +ASUS_LED_HANDLER(mled, METHOD_MLED); +ASUS_LED_HANDLER(pled, METHOD_PLED); +ASUS_LED_HANDLER(rled, METHOD_RLED); +ASUS_LED_HANDLER(tled, METHOD_TLED); +ASUS_LED_HANDLER(gled, METHOD_GLED); /* * Keyboard backlight (also a LED) */ -static int asus_kled_lvl(void) +static int asus_kled_lvl(struct asus_laptop *asus) { unsigned long long kblv; struct acpi_object_list params; @@ -406,7 +432,8 @@ static int asus_kled_lvl(void) in_obj.type = ACPI_TYPE_INTEGER; in_obj.integer.value = 2; - rv = acpi_evaluate_integer(kled_get_handle, NULL, ¶ms, &kblv); + rv = acpi_evaluate_integer(asus->handle, METHOD_KBD_LIGHT_GET, + ¶ms, &kblv); if (ACPI_FAILURE(rv)) { pr_warning("Error reading kled level\n"); return -ENODEV; @@ -421,7 +448,7 @@ static int asus_kled_set(struct asus_laptop *asus, int kblv) else kblv = 0; - if (write_acpi_int(kled_set_handle, NULL, kblv)) { + if (write_acpi_int(asus->handle, METHOD_KBD_LIGHT_SET, kblv)) { pr_warning("Keyboard LED display write failed\n"); return -EINVAL; } @@ -446,7 +473,9 @@ static void kled_led_update(struct work_struct *work) static enum led_brightness kled_led_get(struct led_classdev *led_cdev) { - return asus_kled_lvl(); + struct asus_laptop *asus = led_to_asus(led_cdev, kled); + + return asus_kled_lvl(asus); } #define ASUS_LED_UNREGISTER(object) \ @@ -468,10 +497,11 @@ static void asus_led_exit(struct asus_laptop *asus) } /* Ugly macro, need to fix that later */ -#define ASUS_LED_REGISTER(asus, object, _name, max) \ +#define ASUS_LED_REGISTER(asus, object, _name, max, method) \ do { \ struct led_classdev *ldev = &asus->leds.object; \ - if (!object##_set_handle) \ + \ + if (method && acpi_check_handle(asus->handle, method, NULL)) \ break ; \ \ INIT_WORK(&asus->leds.object##_work, object##_led_update); \ @@ -497,13 +527,14 @@ static int asus_led_init(struct asus_laptop *asus) if (!asus->leds.workqueue) return -ENOMEM; - ASUS_LED_REGISTER(asus, mled, "mail", 1); - ASUS_LED_REGISTER(asus, tled, "touchpad", 1); - ASUS_LED_REGISTER(asus, rled, "record", 1); - ASUS_LED_REGISTER(asus, pled, "phone", 1); - ASUS_LED_REGISTER(asus, gled, "gaming", 1); - if (kled_set_handle && kled_get_handle) - ASUS_LED_REGISTER(asus, kled, "kbd_backlight", 3); + ASUS_LED_REGISTER(asus, mled, "mail", 1, METHOD_MLED); + ASUS_LED_REGISTER(asus, tled, "touchpad", 1, METHOD_TLED); + ASUS_LED_REGISTER(asus, rled, "record", 1, METHOD_RLED); + ASUS_LED_REGISTER(asus, pled, "phone", 1, METHOD_PLED); + ASUS_LED_REGISTER(asus, gled, "gaming", 1, METHOD_GLED); + if (!acpi_check_handle(asus->handle, METHOD_KBD_LIGHT_SET, NULL) && + !acpi_check_handle(asus->handle, METHOD_KBD_LIGHT_GET, NULL)) + ASUS_LED_REGISTER(asus, kled, "kbd_backlight", 3, NULL); error: if (rv) asus_led_exit(asus); @@ -557,10 +588,12 @@ static void lcd_blank(struct asus_laptop *asus, int blank) static int asus_read_brightness(struct backlight_device *bd) { + struct asus_laptop *asus = bl_get_data(bd); unsigned long long value; acpi_status rv = AE_OK; - rv = acpi_evaluate_integer(brightness_get_handle, NULL, NULL, &value); + rv = acpi_evaluate_integer(asus->handle, METHOD_BRIGHTNESS_GET, + NULL, &value); if (ACPI_FAILURE(rv)) pr_warning("Error reading brightness\n"); @@ -569,7 +602,9 @@ static int asus_read_brightness(struct backlight_device *bd) static int asus_set_brightness(struct backlight_device *bd, int value) { - if (write_acpi_int(brightness_set_handle, NULL, value)) { + struct asus_laptop *asus = bl_get_data(bd); + + if (write_acpi_int(asus->handle, METHOD_BRIGHTNESS_SET, value)) { pr_warning("Error changing brightness\n"); return -EIO; } @@ -600,7 +635,9 @@ static int asus_backlight_init(struct asus_laptop *asus) struct backlight_device *bd; struct device *dev = &asus->platform_device->dev; - if (brightness_set_handle && lcd_switch_handle) { + if (!acpi_check_handle(asus->handle, METHOD_BRIGHTNESS_GET, NULL) && + !acpi_check_handle(asus->handle, METHOD_BRIGHTNESS_SET, NULL) && + lcd_switch_handle) { bd = backlight_device_register(ASUS_LAPTOP_FILE, dev, asus, &asusbl_ops); if (IS_ERR(bd)) { @@ -612,8 +649,8 @@ static int asus_backlight_init(struct asus_laptop *asus) asus->backlight_device = bd; bd->props.max_brightness = 15; - bd->props.brightness = asus_read_brightness(NULL); bd->props.power = FB_BLANK_UNBLANK; + bd->props.brightness = asus_read_brightness(bd); backlight_update_status(bd); } return 0; @@ -716,7 +753,7 @@ static int parse_arg(const char *buf, unsigned long count, int *val) static ssize_t sysfs_acpi_set(struct asus_laptop *asus, const char *buf, size_t count, - acpi_handle handle) + const char *method) { int rv, value; int out = 0; @@ -725,7 +762,7 @@ static ssize_t sysfs_acpi_set(struct asus_laptop *asus, if (rv > 0) out = value ? 1 : 0; - if (write_acpi_int(handle, NULL, value)) + if (write_acpi_int(asus->handle, method, value)) return -ENODEV; return rv; } @@ -749,7 +786,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)) + if (write_acpi_int(asus->handle, METHOD_LEDD, value)) pr_warning("LED display write failed\n"); else asus->ledd_status = (u32) value; @@ -768,7 +805,8 @@ static int asus_wireless_status(struct asus_laptop *asus, int mask) if (!asus->have_rsts) return (asus->wireless_status & mask) ? 1 : 0; - rv = acpi_evaluate_integer(wireless_status_handle, NULL, NULL, &status); + rv = acpi_evaluate_integer(asus->handle, METHOD_WL_STATUS, + NULL, &status); if (ACPI_FAILURE(rv)) { pr_warning("Error reading Wireless status\n"); return -EINVAL; @@ -792,7 +830,7 @@ static ssize_t store_wlan(struct device *dev, struct device_attribute *attr, { struct asus_laptop *asus = dev_get_drvdata(dev); - return sysfs_acpi_set(asus, buf, count, wl_switch_handle); + return sysfs_acpi_set(asus, buf, count, METHOD_WLAN); } /* @@ -812,7 +850,7 @@ static ssize_t store_bluetooth(struct device *dev, { struct asus_laptop *asus = dev_get_drvdata(dev); - return sysfs_acpi_set(asus, buf, count, bt_switch_handle); + return sysfs_acpi_set(asus, buf, count, METHOD_BLUETOOTH); } /* @@ -821,7 +859,7 @@ static ssize_t store_bluetooth(struct device *dev, static void asus_set_display(struct asus_laptop *asus, int value) { /* no sanity check needed for now */ - if (write_acpi_int(display_set_handle, NULL, value)) + if (write_acpi_int(asus->handle, METHOD_SWITCH_DISPLAY, value)) pr_warning("Error setting display\n"); return; } @@ -883,7 +921,7 @@ static ssize_t store_disp(struct device *dev, struct device_attribute *attr, */ static void asus_als_switch(struct asus_laptop *asus, int value) { - if (write_acpi_int(ls_switch_handle, NULL, value)) + if (write_acpi_int(asus->handle, METHOD_ALS_CONTROL, value)) pr_warning("Error setting light sensor switch\n"); asus->light_switch = value; } @@ -911,7 +949,7 @@ static ssize_t store_lssw(struct device *dev, struct device_attribute *attr, static void asus_als_level(struct asus_laptop *asus, int value) { - if (write_acpi_int(ls_level_handle, NULL, value)) + if (write_acpi_int(asus->handle, METHOD_ALS_LEVEL, value)) pr_warning("Error setting light sensor level\n"); asus->light_level = value; } @@ -949,7 +987,8 @@ static int asus_gps_status(struct asus_laptop *asus) unsigned long long status; acpi_status rv = AE_OK; - rv = acpi_evaluate_integer(gps_status_handle, NULL, NULL, &status); + rv = acpi_evaluate_integer(asus->handle, METHOD_GPS_STATUS, + NULL, &status); if (ACPI_FAILURE(rv)) { pr_warning("Error reading GPS status\n"); return -ENODEV; @@ -959,9 +998,9 @@ static int asus_gps_status(struct asus_laptop *asus) static int asus_gps_switch(struct asus_laptop *asus, int status) { - acpi_handle handle = status ? gps_on_handle : gps_off_handle; + const char *meth = status ? METHOD_GPS_ON : METHOD_GPS_OFF; - if (write_acpi_int(handle, NULL, 0x02)) + if (write_acpi_int(asus->handle, meth, 0x02)) return -ENODEV; return 0; } @@ -1224,27 +1263,33 @@ static void asus_laptop_add_fs(struct asus_laptop *asus) { ASUS_SET_DEVICE_ATTR(infos, 0444, show_infos, NULL); - if (wl_switch_handle) + if (!acpi_check_handle(asus->handle, METHOD_WLAN, NULL)) ASUS_SET_DEVICE_ATTR(wlan, 0644, show_wlan, store_wlan); - if (bt_switch_handle) + if (!acpi_check_handle(asus->handle, METHOD_BLUETOOTH, NULL)) ASUS_SET_DEVICE_ATTR(bluetooth, 0644, show_bluetooth, store_bluetooth); - if (display_set_handle && display_get_handle) - ASUS_SET_DEVICE_ATTR(display, 0644, show_disp, store_disp); - else if (display_set_handle) - ASUS_SET_DEVICE_ATTR(display, 0200, NULL, store_disp); + if (!acpi_check_handle(asus->handle, METHOD_SWITCH_DISPLAY, NULL)) { + if (display_get_handle) + ASUS_SET_DEVICE_ATTR(display, 0644, show_disp, + store_disp); + else + ASUS_SET_DEVICE_ATTR(display, 0200, NULL, store_disp); + } - if (ledd_set_handle) + if (!acpi_check_handle(asus->handle, METHOD_LEDD, NULL)) ASUS_SET_DEVICE_ATTR(ledd, 0644, show_ledd, store_ledd); - if (ls_switch_handle && ls_level_handle) { + if (!acpi_check_handle(asus->handle, METHOD_ALS_CONTROL, NULL) && + !acpi_check_handle(asus->handle, METHOD_ALS_LEVEL, NULL)) { ASUS_SET_DEVICE_ATTR(ls_level, 0644, show_lslvl, store_lslvl); ASUS_SET_DEVICE_ATTR(ls_switch, 0644, show_lssw, store_lssw); } - if (gps_status_handle && gps_on_handle && gps_off_handle) + if (!acpi_check_handle(asus->handle, METHOD_GPS_ON, NULL) && + !acpi_check_handle(asus->handle, METHOD_GPS_OFF, NULL) && + !acpi_check_handle(asus->handle, METHOD_GPS_STATUS, NULL)) ASUS_SET_DEVICE_ATTR(gps, 0644, show_gps, store_gps); } @@ -1337,55 +1382,23 @@ static int asus_laptop_get_info(struct asus_laptop *asus) if (*string) pr_notice(" %s model detected\n", string); - ASUS_HANDLE_INIT(mled_set); - ASUS_HANDLE_INIT(tled_set); - ASUS_HANDLE_INIT(rled_set); - ASUS_HANDLE_INIT(pled_set); - ASUS_HANDLE_INIT(gled_set); - - ASUS_HANDLE_INIT(ledd_set); - - ASUS_HANDLE_INIT(kled_set); - ASUS_HANDLE_INIT(kled_get); - /* * The HWRS method return informations about the hardware. * 0x80 bit is for WLAN, 0x100 for Bluetooth. * The significance of others is yet to be found. - * If we don't find the method, we assume the device are present. */ status = acpi_evaluate_integer(asus->handle, "HRWS", NULL, &hwrs_result); - if (ACPI_FAILURE(status)) - hwrs_result = WL_HWRS | BT_HWRS; + if (!ACPI_FAILURE(status)) + pr_notice(" HRWS returned %x", (int)hwrs_result); - if (hwrs_result & WL_HWRS) - ASUS_HANDLE_INIT(wl_switch); - if (hwrs_result & BT_HWRS) - ASUS_HANDLE_INIT(bt_switch); - - if (!ASUS_HANDLE_INIT(wireless_status)) + if (!acpi_check_handle(asus->handle, METHOD_WL_STATUS, NULL)) asus->have_rsts = true; - ASUS_HANDLE_INIT(brightness_set); - ASUS_HANDLE_INIT(brightness_get); - + /* Scheduled for removal */ ASUS_HANDLE_INIT(lcd_switch); - - ASUS_HANDLE_INIT(display_set); ASUS_HANDLE_INIT(display_get); - /* - * There is a lot of models with "ALSL", but a few get - * a real light sens, so we need to check it. - */ - if (!ASUS_HANDLE_INIT(ls_switch)) - ASUS_HANDLE_INIT(ls_level); - - ASUS_HANDLE_INIT(gps_on); - ASUS_HANDLE_INIT(gps_off); - ASUS_HANDLE_INIT(gps_status); - kfree(model); return AE_OK; @@ -1413,12 +1426,14 @@ static int __devinit asus_acpi_init(struct asus_laptop *asus) /* WLED and BLED are on by default */ if (bluetooth_status >= 0) - write_acpi_int(bt_switch_handle, NULL, !!bluetooth_status); + write_acpi_int(asus->handle, METHOD_BLUETOOTH, + !!bluetooth_status); if (wireless_status >= 0) - write_acpi_int(wl_switch_handle, NULL, !!wireless_status); + write_acpi_int(asus->handle, METHOD_WLAN, + !!wireless_status); /* Keyboard Backlight is on by default */ - if (kled_set_handle) + if (!acpi_check_handle(asus->handle, METHOD_KBD_LIGHT_SET, NULL)) asus_kled_set(asus, 1); /* LED display is off by default */ @@ -1428,14 +1443,17 @@ static int __devinit asus_acpi_init(struct asus_laptop *asus) asus->light_switch = 0; /* Default to light sensor disabled */ asus->light_level = 5; /* level 5 for sensor sensitivity */ - if (ls_switch_handle) + if (!acpi_check_handle(asus->handle, METHOD_ALS_CONTROL, NULL) && + !acpi_check_handle(asus->handle, METHOD_ALS_LEVEL, NULL)) { asus_als_switch(asus, asus->light_switch); - - if (ls_level_handle) asus_als_level(asus, asus->light_level); + } /* GPS is on by default */ - asus_gps_switch(asus, 1); + if (!acpi_check_handle(asus->handle, METHOD_GPS_ON, NULL) && + !acpi_check_handle(asus->handle, METHOD_GPS_OFF, NULL) && + !acpi_check_handle(asus->handle, METHOD_GPS_STATUS, NULL)) + asus_gps_switch(asus, 1); return result; } -- cgit v1.2.3 From e5593bf18be79b4897c7ec8b392dc7f07cbc1b11 Mon Sep 17 00:00:00 2001 From: Corentin Chary Date: Sun, 17 Jan 2010 17:20:11 +0100 Subject: asus-laptop: add error check for write_acpi_int calls Also add to helpers for bluetooth and wlan. Signed-off-by: Corentin Chary --- drivers/platform/x86/asus-laptop.c | 33 +++++++++++++++++++++++++-------- 1 file changed, 25 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/platform/x86/asus-laptop.c b/drivers/platform/x86/asus-laptop.c index 671fad96c275..aad6b9300f5d 100644 --- a/drivers/platform/x86/asus-laptop.c +++ b/drivers/platform/x86/asus-laptop.c @@ -350,7 +350,7 @@ static int acpi_check_handle(acpi_handle handle, const char *method, } /* Generic LED function */ -static void asus_led_set(struct asus_laptop *asus, char *method, +static int asus_led_set(struct asus_laptop *asus, char *method, int value) { if (!strcmp(method, METHOD_MLED)) @@ -360,7 +360,7 @@ static void asus_led_set(struct asus_laptop *asus, char *method, else value = !!value; - write_acpi_int(asus->handle, method, value); + return write_acpi_int(asus->handle, method, value); } /* @@ -817,6 +817,15 @@ static int asus_wireless_status(struct asus_laptop *asus, int mask) /* * WLAN */ +static int asus_wlan_set(struct asus_laptop *asus, int status) +{ + if (write_acpi_int(asus->handle, METHOD_WLAN, !!status)) { + pr_warning("Error setting wlan status to %d", status); + return -EIO; + } + return 0; +} + static ssize_t show_wlan(struct device *dev, struct device_attribute *attr, char *buf) { @@ -836,6 +845,15 @@ static ssize_t store_wlan(struct device *dev, struct device_attribute *attr, /* * Bluetooth */ +static int asus_bluetooth_set(struct asus_laptop *asus, int status) +{ + if (write_acpi_int(asus->handle, METHOD_BLUETOOTH, !!status)) { + pr_warning("Error setting bluetooth status to %d", status); + return -EIO; + } + return 0; +} + static ssize_t show_bluetooth(struct device *dev, struct device_attribute *attr, char *buf) { @@ -1353,8 +1371,8 @@ static int asus_laptop_get_info(struct asus_laptop *asus) (uint) bsts_result); /* This too ... */ - write_acpi_int(asus->handle, "CWAP", wapf); - + if (write_acpi_int(asus->handle, "CWAP", wapf)) + pr_err("Error calling CWAP(%d)\n", wapf); /* * Try to match the object returned by INIT to the specific model. * Handle every possible object (or the lack of thereof) the DSDT @@ -1426,11 +1444,10 @@ static int __devinit asus_acpi_init(struct asus_laptop *asus) /* WLED and BLED are on by default */ if (bluetooth_status >= 0) - write_acpi_int(asus->handle, METHOD_BLUETOOTH, - !!bluetooth_status); + asus_bluetooth_set(asus, !!bluetooth_status); + if (wireless_status >= 0) - write_acpi_int(asus->handle, METHOD_WLAN, - !!wireless_status); + asus_wlan_set(asus, !!wireless_status); /* Keyboard Backlight is on by default */ if (!acpi_check_handle(asus->handle, METHOD_KBD_LIGHT_SET, NULL)) -- cgit v1.2.3 From d0930a2d42c5a28039d8cc2376a7dff4e59c5f7a Mon Sep 17 00:00:00 2001 From: Corentin Chary Date: Sun, 17 Jan 2010 17:21:13 +0100 Subject: asus-laptop: rename wireless_status to wlan_status to avoid confusion Signed-off-by: Corentin Chary --- drivers/platform/x86/asus-laptop.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/platform/x86/asus-laptop.c b/drivers/platform/x86/asus-laptop.c index aad6b9300f5d..bb8fb45c45e9 100644 --- a/drivers/platform/x86/asus-laptop.c +++ b/drivers/platform/x86/asus-laptop.c @@ -76,11 +76,11 @@ static uint wapf = 1; module_param(wapf, uint, 0644); MODULE_PARM_DESC(wapf, "WAPF value"); -static uint wireless_status = 1; +static uint wlan_status = 1; static uint bluetooth_status = 1; -module_param(wireless_status, uint, 0644); -MODULE_PARM_DESC(wireless_status, "Set the wireless status on boot " +module_param(wlan_status, uint, 0644); +MODULE_PARM_DESC(wlan_status, "Set the wireless status on boot " "(0 = disabled, 1 = enabled, -1 = don't do anything). " "default is 1"); @@ -1446,8 +1446,8 @@ static int __devinit asus_acpi_init(struct asus_laptop *asus) if (bluetooth_status >= 0) asus_bluetooth_set(asus, !!bluetooth_status); - if (wireless_status >= 0) - asus_wlan_set(asus, !!wireless_status); + if (wlan_status >= 0) + asus_wlan_set(asus, !!wlan_status); /* Keyboard Backlight is on by default */ if (!acpi_check_handle(asus->handle, METHOD_KBD_LIGHT_SET, NULL)) -- cgit v1.2.3 From 66a71dd1f7c4eee636867d381995b7e6ae489dc3 Mon Sep 17 00:00:00 2001 From: Corentin Chary Date: Mon, 25 Jan 2010 22:50:11 +0100 Subject: asus-laptop: switch to sparse keymap library This patch is based on Dmitry Torokhov's patch with some modifications and cleanups. Signed-off-by: Corentin Chary --- drivers/platform/x86/Kconfig | 1 + drivers/platform/x86/asus-laptop.c | 208 ++++++++++++------------------------- 2 files changed, 68 insertions(+), 141 deletions(-) (limited to 'drivers') diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index f526e735c5ab..7f5a222c2325 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -59,6 +59,7 @@ config ASUS_LAPTOP select NEW_LEDS select BACKLIGHT_CLASS_DEVICE depends on INPUT + select INPUT_SPARSEKMAP ---help--- This is the new Linux driver for Asus laptops. It may also support some MEDION, JVC or VICTOR laptops. It makes all the extra buttons generate diff --git a/drivers/platform/x86/asus-laptop.c b/drivers/platform/x86/asus-laptop.c index bb8fb45c45e9..8042568528e5 100644 --- a/drivers/platform/x86/asus-laptop.c +++ b/drivers/platform/x86/asus-laptop.c @@ -49,6 +49,7 @@ #include #include #include +#include #define ASUS_LAPTOP_VERSION "0.42" @@ -243,52 +244,45 @@ struct asus_laptop { u16 *keycode_map; }; -struct key_entry { - char type; - u8 code; - u16 keycode; -}; - -enum { KE_KEY, KE_END }; - static const struct key_entry asus_keymap[] = { - {KE_KEY, 0x02, KEY_SCREENLOCK}, - {KE_KEY, 0x05, KEY_WLAN}, - {KE_KEY, 0x08, KEY_F13}, - {KE_KEY, 0x17, KEY_ZOOM}, - {KE_KEY, 0x1f, KEY_BATTERY}, - {KE_KEY, 0x30, KEY_VOLUMEUP}, - {KE_KEY, 0x31, KEY_VOLUMEDOWN}, - {KE_KEY, 0x32, KEY_MUTE}, - {KE_KEY, 0x33, KEY_SWITCHVIDEOMODE}, - {KE_KEY, 0x34, KEY_SWITCHVIDEOMODE}, - {KE_KEY, 0x40, KEY_PREVIOUSSONG}, - {KE_KEY, 0x41, KEY_NEXTSONG}, - {KE_KEY, 0x43, KEY_STOPCD}, - {KE_KEY, 0x45, KEY_PLAYPAUSE}, - {KE_KEY, 0x4c, KEY_MEDIA}, - {KE_KEY, 0x50, KEY_EMAIL}, - {KE_KEY, 0x51, KEY_WWW}, - {KE_KEY, 0x55, KEY_CALC}, - {KE_KEY, 0x5C, KEY_SCREENLOCK}, /* Screenlock */ - {KE_KEY, 0x5D, KEY_WLAN}, - {KE_KEY, 0x5E, KEY_WLAN}, - {KE_KEY, 0x5F, KEY_WLAN}, - {KE_KEY, 0x60, KEY_SWITCHVIDEOMODE}, - {KE_KEY, 0x61, KEY_SWITCHVIDEOMODE}, - {KE_KEY, 0x62, KEY_SWITCHVIDEOMODE}, - {KE_KEY, 0x63, KEY_SWITCHVIDEOMODE}, - {KE_KEY, 0x6B, KEY_F13}, /* Lock Touchpad */ - {KE_KEY, 0x82, KEY_CAMERA}, - {KE_KEY, 0x88, KEY_WLAN }, - {KE_KEY, 0x8A, KEY_PROG1}, - {KE_KEY, 0x95, KEY_MEDIA}, - {KE_KEY, 0x99, KEY_PHONE}, - {KE_KEY, 0xc4, KEY_KBDILLUMUP}, - {KE_KEY, 0xc5, KEY_KBDILLUMDOWN}, + {KE_KEY, 0x02, { KEY_SCREENLOCK } }, + {KE_KEY, 0x05, { KEY_WLAN } }, + {KE_KEY, 0x08, { KEY_F13 } }, + {KE_KEY, 0x17, { KEY_ZOOM } }, + {KE_KEY, 0x1f, { KEY_BATTERY } }, + {KE_KEY, 0x30, { KEY_VOLUMEUP } }, + {KE_KEY, 0x31, { KEY_VOLUMEDOWN } }, + {KE_KEY, 0x32, { KEY_MUTE } }, + {KE_KEY, 0x33, { KEY_SWITCHVIDEOMODE } }, + {KE_KEY, 0x34, { KEY_SWITCHVIDEOMODE } }, + {KE_KEY, 0x40, { KEY_PREVIOUSSONG } }, + {KE_KEY, 0x41, { KEY_NEXTSONG } }, + {KE_KEY, 0x43, { KEY_STOPCD } }, + {KE_KEY, 0x45, { KEY_PLAYPAUSE } }, + {KE_KEY, 0x4c, { KEY_MEDIA } }, + {KE_KEY, 0x50, { KEY_EMAIL } }, + {KE_KEY, 0x51, { KEY_WWW } }, + {KE_KEY, 0x55, { KEY_CALC } }, + {KE_KEY, 0x5C, { KEY_SCREENLOCK } }, /* Screenlock */ + {KE_KEY, 0x5D, { KEY_WLAN } }, + {KE_KEY, 0x5E, { KEY_WLAN } }, + {KE_KEY, 0x5F, { KEY_WLAN } }, + {KE_KEY, 0x60, { KEY_SWITCHVIDEOMODE } }, + {KE_KEY, 0x61, { KEY_SWITCHVIDEOMODE } }, + {KE_KEY, 0x62, { KEY_SWITCHVIDEOMODE } }, + {KE_KEY, 0x63, { KEY_SWITCHVIDEOMODE } }, + {KE_KEY, 0x6B, { KEY_F13 } }, /* Lock Touchpad */ + {KE_KEY, 0x82, { KEY_CAMERA } }, + {KE_KEY, 0x88, { KEY_WLAN } }, + {KE_KEY, 0x8A, { KEY_PROG1 } }, + {KE_KEY, 0x95, { KEY_MEDIA } }, + {KE_KEY, 0x99, { KEY_PHONE } }, + {KE_KEY, 0xc4, { KEY_KBDILLUMUP } }, + {KE_KEY, 0xc5, { KEY_KBDILLUMDOWN } }, {KE_END, 0}, }; + /* * This function evaluates an ACPI method, given an int as parameter, the * method is searched within the scope of the handle, can be NULL. The output @@ -1050,123 +1044,55 @@ static ssize_t store_gps(struct device *dev, struct device_attribute *attr, /* * Input device (i.e. hotkeys) */ -static struct key_entry *asus_get_entry_by_scancode(struct asus_laptop *asus, - int code) -{ - struct key_entry *key; - - for (key = asus->keymap; key->type != KE_END; key++) - if (code == key->code) - return key; - - return NULL; -} - -static struct key_entry *asus_get_entry_by_keycode(struct asus_laptop *asus, - int code) -{ - struct key_entry *key; - - for (key = asus->keymap; key->type != KE_END; key++) - if (code == key->keycode && key->type == KE_KEY) - return key; - - return NULL; -} - -static int asus_getkeycode(struct input_dev *dev, int scancode, int *keycode) -{ - struct asus_laptop *asus = input_get_drvdata(dev); - struct key_entry *key = asus_get_entry_by_scancode(asus, scancode); - - if (key && key->type == KE_KEY) { - *keycode = key->keycode; - return 0; - } - - return -EINVAL; -} - -static int asus_setkeycode(struct input_dev *dev, int scancode, int keycode) -{ - struct asus_laptop *asus = input_get_drvdata(dev); - struct key_entry *key; - int old_keycode; - - if (keycode < 0 || keycode > KEY_MAX) - return -EINVAL; - - key = asus_get_entry_by_scancode(asus, scancode); - if (key && key->type == KE_KEY) { - old_keycode = key->keycode; - key->keycode = keycode; - set_bit(keycode, dev->keybit); - if (!asus_get_entry_by_keycode(asus, old_keycode)) - clear_bit(old_keycode, dev->keybit); - return 0; - } - - return -EINVAL; -} - static void asus_input_notify(struct asus_laptop *asus, int event) { - struct key_entry *key; - - key = asus_get_entry_by_scancode(asus, event); - if (!key) - return ; - - switch (key->type) { - case KE_KEY: - 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; - } + if (asus->inputdev) + sparse_keymap_report_event(asus->inputdev, event, 1, true); } static int asus_input_init(struct asus_laptop *asus) { - const struct key_entry *key; - int result; + struct input_dev *input; + int error; - asus->inputdev = input_allocate_device(); - if (!asus->inputdev) { + input = input_allocate_device(); + if (!input) { pr_info("Unable to allocate input device\n"); return 0; } - asus->inputdev->name = "Asus Laptop extra buttons"; - asus->inputdev->dev.parent = &asus->platform_device->dev; - asus->inputdev->phys = ASUS_LAPTOP_FILE "/input0"; - asus->inputdev->id.bustype = BUS_HOST; - asus->inputdev->getkeycode = asus_getkeycode; - asus->inputdev->setkeycode = asus_setkeycode; - input_set_drvdata(asus->inputdev, asus); - - asus->keymap = kmemdup(asus_keymap, sizeof(asus_keymap), - GFP_KERNEL); - for (key = asus->keymap; key->type != KE_END; key++) { - switch (key->type) { - case KE_KEY: - set_bit(EV_KEY, asus->inputdev->evbit); - set_bit(key->keycode, asus->inputdev->keybit); - break; - } + input->name = "Asus Laptop extra buttons"; + input->phys = ASUS_LAPTOP_FILE "/input0"; + input->id.bustype = BUS_HOST; + input->dev.parent = &asus->platform_device->dev; + input_set_drvdata(input, asus); + + error = sparse_keymap_setup(input, asus_keymap, NULL); + if (error) { + pr_err("Unable to setup input device keymap\n"); + goto err_keymap; } - result = input_register_device(asus->inputdev); - if (result) { + error = input_register_device(input); + if (error) { pr_info("Unable to register input device\n"); - input_free_device(asus->inputdev); + goto err_device; } - return result; + + asus->inputdev = input; + return 0; + +err_keymap: + sparse_keymap_free(input); +err_device: + input_free_device(input); + return error; } static void asus_input_exit(struct asus_laptop *asus) { - if (asus->inputdev) + if (asus->inputdev) { + sparse_keymap_free(asus->inputdev); input_unregister_device(asus->inputdev); + } } /* -- cgit v1.2.3 From 7f607d71065b6b089f59b78b54144c3fb93ad629 Mon Sep 17 00:00:00 2001 From: Corentin Chary Date: Sun, 17 Jan 2010 17:37:19 +0100 Subject: asus-laptop: add bluetooth keys found on M9V Reported by Andrey F. Ilchuk Signed-off-by: Corentin Chary --- drivers/platform/x86/asus-laptop.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/platform/x86/asus-laptop.c b/drivers/platform/x86/asus-laptop.c index 8042568528e5..4f3c4674498b 100644 --- a/drivers/platform/x86/asus-laptop.c +++ b/drivers/platform/x86/asus-laptop.c @@ -272,6 +272,8 @@ static const struct key_entry asus_keymap[] = { {KE_KEY, 0x62, { KEY_SWITCHVIDEOMODE } }, {KE_KEY, 0x63, { KEY_SWITCHVIDEOMODE } }, {KE_KEY, 0x6B, { KEY_F13 } }, /* Lock Touchpad */ + {KE_KEY, 0x7E, { KEY_BLUETOOTH } }, + {KE_KEY, 0x7D, { KEY_BLUETOOTH } }, {KE_KEY, 0x82, { KEY_CAMERA } }, {KE_KEY, 0x88, { KEY_WLAN } }, {KE_KEY, 0x8A, { KEY_PROG1 } }, -- cgit v1.2.3 From a539df5e1548751e352990c518e88af50e6111b8 Mon Sep 17 00:00:00 2001 From: Corentin Chary Date: Mon, 25 Jan 2010 22:53:21 +0100 Subject: asus-laptop: add backlight changes notifications We don't want to send KEY_BRIGHTNESSDOWN or KEY_BRIGHTNESSUP because it would be a lie to tell userspace that we want to change the brightness while it's actually done by the firmware. Signed-off-by: Corentin Chary --- drivers/platform/x86/asus-laptop.c | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/platform/x86/asus-laptop.c b/drivers/platform/x86/asus-laptop.c index 4f3c4674498b..516add3c340e 100644 --- a/drivers/platform/x86/asus-laptop.c +++ b/drivers/platform/x86/asus-laptop.c @@ -93,8 +93,10 @@ MODULE_PARM_DESC(bluetooth_status, "Set the wireless status on boot " /* * Some events we use, same for all Asus */ -#define ATKD_BR_UP 0x10 -#define ATKD_BR_DOWN 0x20 +#define ATKD_BR_UP 0x10 // (event & ~ATKD_BR_UP) = brightness level +#define ATKD_BR_DOWN 0x20 // (event & ~ATKD_BR_DOWN) = britghness level +#define ATKD_BR_MIN ATKD_BR_UP +#define ATKD_BR_MAX (ATKD_BR_DOWN | 0xF) // 0x2f #define ATKD_LCD_ON 0x33 #define ATKD_LCD_OFF 0x34 @@ -245,11 +247,13 @@ struct asus_laptop { }; static const struct key_entry asus_keymap[] = { + /* Lenovo SL Specific keycodes */ {KE_KEY, 0x02, { KEY_SCREENLOCK } }, {KE_KEY, 0x05, { KEY_WLAN } }, {KE_KEY, 0x08, { KEY_F13 } }, {KE_KEY, 0x17, { KEY_ZOOM } }, {KE_KEY, 0x1f, { KEY_BATTERY } }, + /* End of Lenovo SL Specific keycodes */ {KE_KEY, 0x30, { KEY_VOLUMEUP } }, {KE_KEY, 0x31, { KEY_VOLUMEDOWN } }, {KE_KEY, 0x32, { KEY_MUTE } }, @@ -626,6 +630,16 @@ static struct backlight_ops asusbl_ops = { .update_status = update_bl_status, }; +static int asus_backlight_notify(struct asus_laptop *asus) +{ + struct backlight_device *bd = asus->backlight_device; + int old = bd->props.brightness; + + backlight_force_update(bd, BACKLIGHT_UPDATE_HOTKEY); + + return old; +} + static int asus_backlight_init(struct asus_laptop *asus) { struct backlight_device *bd; @@ -656,6 +670,7 @@ static void asus_backlight_exit(struct asus_laptop *asus) { if (asus->backlight_device) backlight_device_unregister(asus->backlight_device); + asus->backlight_device = NULL; } /* @@ -1121,6 +1136,16 @@ static void asus_acpi_notify(struct acpi_device *device, u32 event) dev_name(&asus->device->dev), event, count); + /* Brightness events are special */ + if (event >= ATKD_BR_MIN && event <= ATKD_BR_MAX) { + + /* Ignore them completely if the acpi video driver is used */ + if (asus->backlight_device != NULL) { + /* Update the backlight device. */ + asus_backlight_notify(asus); + } + return ; + } asus_input_notify(asus, event); } -- cgit v1.2.3 From 75747129a994463e36c2516e8071771427d8494b Mon Sep 17 00:00:00 2001 From: Corentin Chary Date: Sun, 24 Jan 2010 11:15:42 +0100 Subject: asus-laptop: leds, remove dead code and fix asus_led_exit()/asus_led_init() These bug where introduced in "asus-laptop: code movement". Signed-off-by: Corentin Chary --- drivers/platform/x86/asus-laptop.c | 31 ++++++++++++++----------------- 1 file changed, 14 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/platform/x86/asus-laptop.c b/drivers/platform/x86/asus-laptop.c index 516add3c340e..ca144d251b00 100644 --- a/drivers/platform/x86/asus-laptop.c +++ b/drivers/platform/x86/asus-laptop.c @@ -371,13 +371,7 @@ static int asus_led_set(struct asus_laptop *asus, char *method, enum led_brightness value); \ static enum led_brightness object##_led_get( \ struct led_classdev *led_cdev); \ - static void object##_led_update(struct work_struct *ignored); \ - static struct led_classdev object##_led = { \ - .name = "asus::" ledname, \ - .brightness_set = object##_led_set, \ - .brightness_get = object##_led_get, \ - .max_brightness = max \ - } + static void object##_led_update(struct work_struct *ignored); ASUS_LED(mled, "mail", 1); ASUS_LED(tled, "touchpad", 1); @@ -478,18 +472,20 @@ static enum led_brightness kled_led_get(struct led_classdev *led_cdev) return asus_kled_lvl(asus); } -#define ASUS_LED_UNREGISTER(object) \ - if (object##_led.dev) \ - led_classdev_unregister(&object##_led) - static void asus_led_exit(struct asus_laptop *asus) { - ASUS_LED_UNREGISTER(mled); - ASUS_LED_UNREGISTER(tled); - ASUS_LED_UNREGISTER(pled); - ASUS_LED_UNREGISTER(rled); - ASUS_LED_UNREGISTER(gled); - ASUS_LED_UNREGISTER(kled); + if (asus->leds.mled.dev) + led_classdev_unregister(&asus->leds.mled); + if (asus->leds.tled.dev) + led_classdev_unregister(&asus->leds.tled); + if (asus->leds.pled.dev) + led_classdev_unregister(&asus->leds.pled); + if (asus->leds.rled.dev) + led_classdev_unregister(&asus->leds.rled); + if (asus->leds.gled.dev) + led_classdev_unregister(&asus->leds.gled); + if (asus->leds.kled.dev) + led_classdev_unregister(&asus->leds.kled); if (asus->leds.workqueue) { destroy_workqueue(asus->leds.workqueue); asus->leds.workqueue = NULL; @@ -507,6 +503,7 @@ static void asus_led_exit(struct asus_laptop *asus) INIT_WORK(&asus->leds.object##_work, object##_led_update); \ ldev->name = "asus::" _name; \ ldev->brightness_set = object##_led_set; \ + ldev->brightness_get = object##_led_get; \ ldev->max_brightness = max; \ rv = led_classdev_register(&asus->platform_device->dev, ldev); \ if (rv) \ -- cgit v1.2.3 From 47ee0e99524a7ee0185e3c38423cc17cc1318ddc Mon Sep 17 00:00:00 2001 From: Corentin Chary Date: Sun, 24 Jan 2010 11:17:15 +0100 Subject: asus-laptop: set initial lcd state There is no way to find the initial lcd state. A quick workaround is to set it "on" by default. Anyway this feature is scheduled for removal. Signed-off-by: Corentin Chary --- drivers/platform/x86/asus-laptop.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/platform/x86/asus-laptop.c b/drivers/platform/x86/asus-laptop.c index ca144d251b00..1d61094d3b5f 100644 --- a/drivers/platform/x86/asus-laptop.c +++ b/drivers/platform/x86/asus-laptop.c @@ -1421,6 +1421,8 @@ static int __devinit asus_acpi_init(struct asus_laptop *asus) !acpi_check_handle(asus->handle, METHOD_GPS_OFF, NULL) && !acpi_check_handle(asus->handle, METHOD_GPS_STATUS, NULL)) asus_gps_switch(asus, 1); + + asus->lcd_state = 1; /* LCD should be on when the module load */ return result; } -- cgit v1.2.3 From 18e1311ee71a67497a33521be61ddf6562fa22c0 Mon Sep 17 00:00:00 2001 From: Corentin Chary Date: Mon, 25 Jan 2010 23:29:24 +0100 Subject: asus-laptop: add gps rfkill The rfkill subsystem will enable gps by default. Signed-off-by: Corentin Chary --- drivers/platform/x86/Kconfig | 1 + drivers/platform/x86/asus-laptop.c | 65 ++++++++++++++++++++++++++++++++++---- 2 files changed, 59 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index 7f5a222c2325..527abf1b5bd1 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -59,6 +59,7 @@ config ASUS_LAPTOP select NEW_LEDS select BACKLIGHT_CLASS_DEVICE depends on INPUT + depends on RFKILL || RFKILL = n select INPUT_SPARSEKMAP ---help--- This is the new Linux driver for Asus laptops. It may also support some diff --git a/drivers/platform/x86/asus-laptop.c b/drivers/platform/x86/asus-laptop.c index 1d61094d3b5f..e1df92a22de9 100644 --- a/drivers/platform/x86/asus-laptop.c +++ b/drivers/platform/x86/asus-laptop.c @@ -50,6 +50,7 @@ #include #include #include +#include #define ASUS_LAPTOP_VERSION "0.42" @@ -238,6 +239,8 @@ struct asus_laptop { bool have_rsts; int lcd_state; + struct rfkill *gps_rfkill; + acpi_handle handle; /* the handle of the hotk device */ u32 ledd_status; /* status of the LED display */ u8 light_level; /* light sensor level */ @@ -1006,7 +1009,6 @@ static ssize_t store_lslvl(struct device *dev, struct device_attribute *attr, /* * GPS - * TODO: use rfkill */ static int asus_gps_status(struct asus_laptop *asus) { @@ -1052,9 +1054,57 @@ static ssize_t store_gps(struct device *dev, struct device_attribute *attr, ret = asus_gps_switch(asus, !!value); if (ret) return ret; + rfkill_set_sw_state(asus->gps_rfkill, !value); return rv; } +/* + * rfkill + */ +static int asus_gps_rfkill_set(void *data, bool blocked) +{ + acpi_handle handle = data; + + return asus_gps_switch(handle, !blocked); +} + +static const struct rfkill_ops asus_gps_rfkill_ops = { + .set_block = asus_gps_rfkill_set, +}; + +static void asus_rfkill_exit(struct asus_laptop *asus) +{ + if (asus->gps_rfkill) { + rfkill_unregister(asus->gps_rfkill); + rfkill_destroy(asus->gps_rfkill); + asus->gps_rfkill = NULL; + } +} + +static int asus_rfkill_init(struct asus_laptop *asus) +{ + int result; + + if (acpi_check_handle(asus->handle, METHOD_GPS_ON, NULL) || + acpi_check_handle(asus->handle, METHOD_GPS_OFF, NULL) || + acpi_check_handle(asus->handle, METHOD_GPS_STATUS, NULL)) + return 0; + + asus->gps_rfkill = rfkill_alloc("asus-gps", &asus->platform_device->dev, + RFKILL_TYPE_GPS, + &asus_gps_rfkill_ops, NULL); + if (!asus->gps_rfkill) + return -EINVAL; + + result = rfkill_register(asus->gps_rfkill); + if (result) { + rfkill_destroy(asus->gps_rfkill); + asus->gps_rfkill = NULL; + } + + return result; +} + /* * Input device (i.e. hotkeys) */ @@ -1416,12 +1466,6 @@ static int __devinit asus_acpi_init(struct asus_laptop *asus) asus_als_level(asus, asus->light_level); } - /* GPS is on by default */ - if (!acpi_check_handle(asus->handle, METHOD_GPS_ON, NULL) && - !acpi_check_handle(asus->handle, METHOD_GPS_OFF, NULL) && - !acpi_check_handle(asus->handle, METHOD_GPS_STATUS, NULL)) - asus_gps_switch(asus, 1); - asus->lcd_state = 1; /* LCD should be on when the module load */ return result; } @@ -1469,9 +1513,15 @@ static int __devinit asus_acpi_add(struct acpi_device *device) if (result) goto fail_led; + result = asus_rfkill_init(asus); + if (result) + goto fail_rfkill; + asus_device_present = true; return 0; +fail_rfkill: + asus_led_exit(asus); fail_led: asus_input_exit(asus); fail_input: @@ -1490,6 +1540,7 @@ static int asus_acpi_remove(struct acpi_device *device, int type) struct asus_laptop *asus = acpi_driver_data(device); asus_backlight_exit(asus); + asus_rfkill_exit(asus); asus_led_exit(asus); asus_input_exit(asus); asus_platform_exit(asus); -- cgit v1.2.3 From aee0afb8cb52178164accfec9cfc58bc27b597b3 Mon Sep 17 00:00:00 2001 From: Corentin Chary Date: Tue, 26 Jan 2010 21:01:34 +0100 Subject: asus-laptop: clean led code Remove all "templates" and add a generic struct asus_led instead. Signed-off-by: Corentin Chary --- drivers/platform/x86/asus-laptop.c | 235 ++++++++++++++++++------------------- 1 file changed, 115 insertions(+), 120 deletions(-) (limited to 'drivers') diff --git a/drivers/platform/x86/asus-laptop.c b/drivers/platform/x86/asus-laptop.c index e1df92a22de9..ae5302646c4e 100644 --- a/drivers/platform/x86/asus-laptop.c +++ b/drivers/platform/x86/asus-laptop.c @@ -193,29 +193,12 @@ ASUS_HANDLE(display_get, /* * Define a specific led structure to keep the main structure clean */ -#define ASUS_DEFINE_LED(object) \ - int object##_wk; \ - struct work_struct object##_work; \ - struct led_classdev object; - - -#define led_to_asus(led_cdev, led) \ - container_of(container_of(led_cdev, struct asus_laptop_leds, \ - led), \ - struct asus_laptop, leds) -#define work_to_asus(work, led) \ - container_of(container_of(work, struct asus_laptop_leds, \ - led##_work), \ - struct asus_laptop, leds) - -struct asus_laptop_leds { - ASUS_DEFINE_LED(mled) - ASUS_DEFINE_LED(tled) - ASUS_DEFINE_LED(rled) - ASUS_DEFINE_LED(pled) - ASUS_DEFINE_LED(gled) - ASUS_DEFINE_LED(kled) - struct workqueue_struct *workqueue; +struct asus_led { + int wk; + struct work_struct work; + struct led_classdev led; + struct asus_laptop *asus; + const char *method; }; /* @@ -233,7 +216,13 @@ struct asus_laptop { struct input_dev *inputdev; struct key_entry *keymap; - struct asus_laptop_leds leds; + struct asus_led mled; + struct asus_led tled; + struct asus_led rled; + struct asus_led pled; + struct asus_led gled; + struct asus_led kled; + struct workqueue_struct *led_workqueue; int wireless_status; bool have_rsts; @@ -353,7 +342,7 @@ static int acpi_check_handle(acpi_handle handle, const char *method, } /* Generic LED function */ -static int asus_led_set(struct asus_laptop *asus, char *method, +static int asus_led_set(struct asus_laptop *asus, const char *method, int value) { if (!strcmp(method, METHOD_MLED)) @@ -369,50 +358,29 @@ static int asus_led_set(struct asus_laptop *asus, char *method, /* * LEDs */ -#define ASUS_LED(object, ledname, max) \ - static void object##_led_set(struct led_classdev *led_cdev, \ - enum led_brightness value); \ - static enum led_brightness object##_led_get( \ - struct led_classdev *led_cdev); \ - static void object##_led_update(struct work_struct *ignored); - -ASUS_LED(mled, "mail", 1); -ASUS_LED(tled, "touchpad", 1); -ASUS_LED(rled, "record", 1); -ASUS_LED(pled, "phone", 1); -ASUS_LED(gled, "gaming", 1); -ASUS_LED(kled, "kbd_backlight", 3); - /* /sys/class/led handlers */ -#define ASUS_LED_HANDLER(object, method) \ - static void object##_led_set(struct led_classdev *led_cdev, \ - enum led_brightness value) \ - { \ - struct asus_laptop *asus = \ - led_to_asus(led_cdev, object); \ - \ - asus->leds.object##_wk = (value > 0) ? 1 : 0; \ - queue_work(asus->leds.workqueue, \ - &asus->leds.object##_work); \ - } \ - static void object##_led_update(struct work_struct *work) \ - { \ - struct asus_laptop *asus = work_to_asus(work, object); \ - \ - int value = asus->leds.object##_wk; \ - asus_led_set(asus, method, value); \ - } \ - static enum led_brightness object##_led_get( \ - struct led_classdev *led_cdev) \ - { \ - return led_cdev->brightness; \ - } +static void asus_led_cdev_set(struct led_classdev *led_cdev, + enum led_brightness value) +{ + struct asus_led *led = container_of(led_cdev, struct asus_led, led); + struct asus_laptop *asus = led->asus; + + led->wk = !!value; + queue_work(asus->led_workqueue, &led->work); +} + +static void asus_led_cdev_update(struct work_struct *work) +{ + struct asus_led *led = container_of(work, struct asus_led, work); + struct asus_laptop *asus = led->asus; -ASUS_LED_HANDLER(mled, METHOD_MLED); -ASUS_LED_HANDLER(pled, METHOD_PLED); -ASUS_LED_HANDLER(rled, METHOD_RLED); -ASUS_LED_HANDLER(tled, METHOD_TLED); -ASUS_LED_HANDLER(gled, METHOD_GLED); + asus_led_set(asus, led->method, led->wk); +} + +static enum led_brightness asus_led_cdev_get(struct led_classdev *led_cdev) +{ + return led_cdev->brightness; +} /* * Keyboard backlight (also a LED) @@ -452,70 +420,76 @@ static int asus_kled_set(struct asus_laptop *asus, int kblv) return 0; } -static void kled_led_set(struct led_classdev *led_cdev, - enum led_brightness value) +static void asus_kled_cdev_set(struct led_classdev *led_cdev, + enum led_brightness value) { - struct asus_laptop *asus = led_to_asus(led_cdev, kled); + struct asus_led *led = container_of(led_cdev, struct asus_led, led); + struct asus_laptop *asus = led->asus; - asus->leds.kled_wk = value; - queue_work(asus->leds.workqueue, &asus->leds.kled_work); + led->wk = value; + queue_work(asus->led_workqueue, &led->work); } -static void kled_led_update(struct work_struct *work) +static void asus_kled_cdev_update(struct work_struct *work) { - struct asus_laptop *asus = work_to_asus(work, kled); + struct asus_led *led = container_of(work, struct asus_led, work); + struct asus_laptop *asus = led->asus; - asus_kled_set(asus, asus->leds.kled_wk); + asus_kled_set(asus, led->wk); } -static enum led_brightness kled_led_get(struct led_classdev *led_cdev) +static enum led_brightness asus_kled_cdev_get(struct led_classdev *led_cdev) { - struct asus_laptop *asus = led_to_asus(led_cdev, kled); + struct asus_led *led = container_of(led_cdev, struct asus_led, led); + struct asus_laptop *asus = led->asus; return asus_kled_lvl(asus); } static void asus_led_exit(struct asus_laptop *asus) { - if (asus->leds.mled.dev) - led_classdev_unregister(&asus->leds.mled); - if (asus->leds.tled.dev) - led_classdev_unregister(&asus->leds.tled); - if (asus->leds.pled.dev) - led_classdev_unregister(&asus->leds.pled); - if (asus->leds.rled.dev) - led_classdev_unregister(&asus->leds.rled); - if (asus->leds.gled.dev) - led_classdev_unregister(&asus->leds.gled); - if (asus->leds.kled.dev) - led_classdev_unregister(&asus->leds.kled); - if (asus->leds.workqueue) { - destroy_workqueue(asus->leds.workqueue); - asus->leds.workqueue = NULL; + if (asus->mled.led.dev) + led_classdev_unregister(&asus->mled.led); + if (asus->tled.led.dev) + led_classdev_unregister(&asus->tled.led); + if (asus->pled.led.dev) + led_classdev_unregister(&asus->pled.led); + if (asus->rled.led.dev) + led_classdev_unregister(&asus->rled.led); + if (asus->gled.led.dev) + led_classdev_unregister(&asus->gled.led); + if (asus->kled.led.dev) + led_classdev_unregister(&asus->kled.led); + if (asus->led_workqueue) { + destroy_workqueue(asus->led_workqueue); + asus->led_workqueue = NULL; } } /* Ugly macro, need to fix that later */ -#define ASUS_LED_REGISTER(asus, object, _name, max, method) \ - do { \ - struct led_classdev *ldev = &asus->leds.object; \ - \ - if (method && acpi_check_handle(asus->handle, method, NULL)) \ - break ; \ - \ - INIT_WORK(&asus->leds.object##_work, object##_led_update); \ - ldev->name = "asus::" _name; \ - ldev->brightness_set = object##_led_set; \ - ldev->brightness_get = object##_led_get; \ - ldev->max_brightness = max; \ - rv = led_classdev_register(&asus->platform_device->dev, ldev); \ - if (rv) \ - goto error; \ - } while (0) +static int asus_led_register(struct asus_laptop *asus, + struct asus_led *led, + const char *name, const char *method) +{ + struct led_classdev *led_cdev = &led->led; + + if (!method || acpi_check_handle(asus->handle, method, NULL)) + return 0; /* Led not present */ + + led->asus = asus; + led->method = method; + + INIT_WORK(&led->work, asus_led_cdev_update); + led_cdev->name = name; + led_cdev->brightness_set = asus_led_cdev_set; + led_cdev->brightness_get = asus_led_cdev_get; + led_cdev->max_brightness = 1; + return led_classdev_register(&asus->platform_device->dev, led_cdev); +} static int asus_led_init(struct asus_laptop *asus) { - int rv; + int r; /* * Functions that actually update the LED's are called from a @@ -523,22 +497,43 @@ static int asus_led_init(struct asus_laptop *asus) * subsystem asks, we avoid messing with the Asus ACPI stuff during a * potentially bad time, such as a timer interrupt. */ - asus->leds.workqueue = create_singlethread_workqueue("led_workqueue"); - if (!asus->leds.workqueue) + asus->led_workqueue = create_singlethread_workqueue("led_workqueue"); + if (!asus->led_workqueue) return -ENOMEM; - ASUS_LED_REGISTER(asus, mled, "mail", 1, METHOD_MLED); - ASUS_LED_REGISTER(asus, tled, "touchpad", 1, METHOD_TLED); - ASUS_LED_REGISTER(asus, rled, "record", 1, METHOD_RLED); - ASUS_LED_REGISTER(asus, pled, "phone", 1, METHOD_PLED); - ASUS_LED_REGISTER(asus, gled, "gaming", 1, METHOD_GLED); + r = asus_led_register(asus, &asus->mled, "asus::mail", METHOD_MLED); + if (r) + goto error; + r = asus_led_register(asus, &asus->tled, "asus::touchpad", METHOD_TLED); + if (r) + goto error; + r = asus_led_register(asus, &asus->rled, "asus::record", METHOD_RLED); + if (r) + goto error; + r = asus_led_register(asus, &asus->pled, "asus::phone", METHOD_PLED); + if (r) + goto error; + r = asus_led_register(asus, &asus->gled, "asus::gaming", METHOD_GLED); + if (r) + goto error; if (!acpi_check_handle(asus->handle, METHOD_KBD_LIGHT_SET, NULL) && - !acpi_check_handle(asus->handle, METHOD_KBD_LIGHT_GET, NULL)) - ASUS_LED_REGISTER(asus, kled, "kbd_backlight", 3, NULL); + !acpi_check_handle(asus->handle, METHOD_KBD_LIGHT_GET, NULL)) { + struct asus_led *led = &asus->kled; + struct led_classdev *cdev = &led->led; + + led->asus = asus; + + INIT_WORK(&led->work, asus_kled_cdev_update); + cdev->name = "asus::kbd_backlight"; + cdev->brightness_set = asus_kled_cdev_set; + cdev->brightness_get = asus_kled_cdev_get; + cdev->max_brightness = 3; + r = led_classdev_register(&asus->platform_device->dev, cdev); + } error: - if (rv) + if (r) asus_led_exit(asus); - return rv; + return r; } /* -- cgit v1.2.3 From 2a1fd64cb70a42563d2313eb70c6495d2c88b36d Mon Sep 17 00:00:00 2001 From: Corentin Chary Date: Tue, 26 Jan 2010 21:02:23 +0100 Subject: asus-laptop: use device_create_file() instead of platform_group There is two reason to do that: - we don't want a "gps" file if the model doesn't have a gps - we don't want to use global variables anymore Signed-off-by: Corentin Chary --- drivers/platform/x86/asus-laptop.c | 166 +++++++++++++++++++------------------ 1 file changed, 84 insertions(+), 82 deletions(-) (limited to 'drivers') diff --git a/drivers/platform/x86/asus-laptop.c b/drivers/platform/x86/asus-laptop.c index ae5302646c4e..d0d117b0cf79 100644 --- a/drivers/platform/x86/asus-laptop.c +++ b/drivers/platform/x86/asus-laptop.c @@ -918,6 +918,8 @@ static ssize_t show_disp(struct device *dev, { struct asus_laptop *asus = dev_get_drvdata(dev); + if (!display_get_handle) + return -ENODEV; return sprintf(buf, "%d\n", read_display(asus)); } @@ -1191,77 +1193,113 @@ static void asus_acpi_notify(struct acpi_device *device, u32 event) asus_input_notify(asus, event); } -#define ASUS_CREATE_DEVICE_ATTR(_name) \ - struct device_attribute dev_attr_##_name = { \ - .attr = { \ - .name = __stringify(_name), \ - .mode = 0 }, \ - .show = NULL, \ - .store = NULL, \ +static DEVICE_ATTR(infos, S_IRUGO, show_infos, NULL); +static DEVICE_ATTR(wlan, S_IRUGO | S_IWUSR, show_wlan, store_wlan); +static DEVICE_ATTR(bluetooth, S_IRUGO | S_IWUSR, show_bluetooth, + store_bluetooth); +static DEVICE_ATTR(display, S_IRUGO | S_IWUSR, show_disp, store_disp); +static DEVICE_ATTR(ledd, S_IRUGO | S_IWUSR, show_ledd, store_ledd); +static DEVICE_ATTR(ls_level, S_IRUGO | S_IWUSR, show_lslvl, store_lslvl); +static DEVICE_ATTR(ls_switch, S_IRUGO | S_IWUSR, show_lssw, store_lssw); +static DEVICE_ATTR(gps, S_IRUGO | S_IWUSR, show_gps, store_gps); + +static void asus_sysfs_exit(struct asus_laptop *asus) +{ + struct platform_device *device = asus->platform_device; + + device_remove_file(&device->dev, &dev_attr_infos); + device_remove_file(&device->dev, &dev_attr_wlan); + device_remove_file(&device->dev, &dev_attr_bluetooth); + device_remove_file(&device->dev, &dev_attr_display); + device_remove_file(&device->dev, &dev_attr_ledd); + device_remove_file(&device->dev, &dev_attr_ls_switch); + device_remove_file(&device->dev, &dev_attr_ls_level); + device_remove_file(&device->dev, &dev_attr_gps); +} + +static int asus_sysfs_init(struct asus_laptop *asus) +{ + struct platform_device *device = asus->platform_device; + int err; + + err = device_create_file(&device->dev, &dev_attr_infos); + if (err) + return err; + + if (!acpi_check_handle(asus->handle, METHOD_WLAN, NULL)) { + err = device_create_file(&device->dev, &dev_attr_wlan); + if (err) + return err; } -#define ASUS_SET_DEVICE_ATTR(_name, _mode, _show, _store) \ - do { \ - dev_attr_##_name.attr.mode = _mode; \ - dev_attr_##_name.show = _show; \ - dev_attr_##_name.store = _store; \ - } while(0) - -static ASUS_CREATE_DEVICE_ATTR(infos); -static ASUS_CREATE_DEVICE_ATTR(wlan); -static ASUS_CREATE_DEVICE_ATTR(bluetooth); -static ASUS_CREATE_DEVICE_ATTR(display); -static ASUS_CREATE_DEVICE_ATTR(ledd); -static ASUS_CREATE_DEVICE_ATTR(ls_switch); -static ASUS_CREATE_DEVICE_ATTR(ls_level); -static ASUS_CREATE_DEVICE_ATTR(gps); - -static struct attribute *asuspf_attributes[] = { - &dev_attr_infos.attr, - &dev_attr_wlan.attr, - &dev_attr_bluetooth.attr, - &dev_attr_display.attr, - &dev_attr_ledd.attr, - &dev_attr_ls_switch.attr, - &dev_attr_ls_level.attr, - &dev_attr_gps.attr, - NULL -}; + if (!acpi_check_handle(asus->handle, METHOD_BLUETOOTH, NULL)) { + err = device_create_file(&device->dev, &dev_attr_bluetooth); + if (err) + return err; + } -static struct attribute_group platform_attribute_group = { - .attrs = asuspf_attributes -}; + if (!acpi_check_handle(asus->handle, METHOD_SWITCH_DISPLAY, NULL)) { + err = device_create_file(&device->dev, &dev_attr_display); + if (err) + return err; + } + + if (!acpi_check_handle(asus->handle, METHOD_LEDD, NULL)) { + err = device_create_file(&device->dev, &dev_attr_ledd); + if (err) + return err; + } + + if (!acpi_check_handle(asus->handle, METHOD_ALS_CONTROL, NULL) && + !acpi_check_handle(asus->handle, METHOD_ALS_LEVEL, NULL)) { + err = device_create_file(&device->dev, &dev_attr_ls_switch); + if (err) + return err; + err = device_create_file(&device->dev, &dev_attr_ls_level); + if (err) + return err; + } + + if (!acpi_check_handle(asus->handle, METHOD_GPS_ON, NULL) && + !acpi_check_handle(asus->handle, METHOD_GPS_OFF, NULL) && + !acpi_check_handle(asus->handle, METHOD_GPS_STATUS, NULL)) { + err = device_create_file(&device->dev, &dev_attr_gps); + if (err) + return err; + } + + return err; +} static int asus_platform_init(struct asus_laptop *asus) { - int result; + int err; asus->platform_device = platform_device_alloc(ASUS_LAPTOP_FILE, -1); if (!asus->platform_device) return -ENOMEM; platform_set_drvdata(asus->platform_device, asus); - result = platform_device_add(asus->platform_device); - if (result) + err = platform_device_add(asus->platform_device); + if (err) goto fail_platform_device; - result = sysfs_create_group(&asus->platform_device->dev.kobj, - &platform_attribute_group); - if (result) + err = asus_sysfs_init(asus); + if (err) goto fail_sysfs; return 0; fail_sysfs: + asus_sysfs_exit(asus); platform_device_del(asus->platform_device); fail_platform_device: platform_device_put(asus->platform_device); - return result; + return err; } static void asus_platform_exit(struct asus_laptop *asus) { - sysfs_remove_group(&asus->platform_device->dev.kobj, - &platform_attribute_group); + asus_sysfs_exit(asus); platform_device_unregister(asus->platform_device); } @@ -1272,40 +1310,6 @@ static struct platform_driver platform_driver = { } }; -static void asus_laptop_add_fs(struct asus_laptop *asus) -{ - ASUS_SET_DEVICE_ATTR(infos, 0444, show_infos, NULL); - - if (!acpi_check_handle(asus->handle, METHOD_WLAN, NULL)) - ASUS_SET_DEVICE_ATTR(wlan, 0644, show_wlan, store_wlan); - - if (!acpi_check_handle(asus->handle, METHOD_BLUETOOTH, NULL)) - ASUS_SET_DEVICE_ATTR(bluetooth, 0644, - show_bluetooth, store_bluetooth); - - if (!acpi_check_handle(asus->handle, METHOD_SWITCH_DISPLAY, NULL)) { - if (display_get_handle) - ASUS_SET_DEVICE_ATTR(display, 0644, show_disp, - store_disp); - else - ASUS_SET_DEVICE_ATTR(display, 0200, NULL, store_disp); - } - - if (!acpi_check_handle(asus->handle, METHOD_LEDD, NULL)) - ASUS_SET_DEVICE_ATTR(ledd, 0644, show_ledd, store_ledd); - - if (!acpi_check_handle(asus->handle, METHOD_ALS_CONTROL, NULL) && - !acpi_check_handle(asus->handle, METHOD_ALS_LEVEL, NULL)) { - ASUS_SET_DEVICE_ATTR(ls_level, 0644, show_lslvl, store_lslvl); - ASUS_SET_DEVICE_ATTR(ls_switch, 0644, show_lssw, store_lssw); - } - - if (!acpi_check_handle(asus->handle, METHOD_GPS_ON, NULL) && - !acpi_check_handle(asus->handle, METHOD_GPS_OFF, NULL) && - !acpi_check_handle(asus->handle, METHOD_GPS_STATUS, NULL)) - ASUS_SET_DEVICE_ATTR(gps, 0644, show_gps, store_gps); -} - static int asus_handle_init(char *name, acpi_handle * handle, char **paths, int num_paths) { @@ -1435,8 +1439,6 @@ static int __devinit asus_acpi_init(struct asus_laptop *asus) if (result) return result; - asus_laptop_add_fs(asus); - /* WLED and BLED are on by default */ if (bluetooth_status >= 0) asus_bluetooth_set(asus, !!bluetooth_status); -- cgit v1.2.3 From 060cbce6c4431465e83907102e1903ecea366db5 Mon Sep 17 00:00:00 2001 From: Corentin Chary Date: Thu, 28 Jan 2010 10:52:40 +0100 Subject: asus-laptop: fix style problems reported by checkpath.pl Signed-off-by: Corentin Chary --- drivers/platform/x86/asus-laptop.c | 94 +++++++++++++++++++------------------- 1 file changed, 47 insertions(+), 47 deletions(-) (limited to 'drivers') diff --git a/drivers/platform/x86/asus-laptop.c b/drivers/platform/x86/asus-laptop.c index d0d117b0cf79..791fcf321506 100644 --- a/drivers/platform/x86/asus-laptop.c +++ b/drivers/platform/x86/asus-laptop.c @@ -45,12 +45,12 @@ #include #include #include -#include -#include -#include +#include #include #include #include +#include +#include #define ASUS_LAPTOP_VERSION "0.42" @@ -94,10 +94,10 @@ MODULE_PARM_DESC(bluetooth_status, "Set the wireless status on boot " /* * Some events we use, same for all Asus */ -#define ATKD_BR_UP 0x10 // (event & ~ATKD_BR_UP) = brightness level -#define ATKD_BR_DOWN 0x20 // (event & ~ATKD_BR_DOWN) = britghness level +#define ATKD_BR_UP 0x10 /* (event & ~ATKD_BR_UP) = brightness level */ +#define ATKD_BR_DOWN 0x20 /* (event & ~ATKD_BR_DOWN) = britghness level */ #define ATKD_BR_MIN ATKD_BR_UP -#define ATKD_BR_MAX (ATKD_BR_DOWN | 0xF) // 0x2f +#define ATKD_BR_MAX (ATKD_BR_DOWN | 0xF) /* 0x2f */ #define ATKD_LCD_ON 0x33 #define ATKD_LCD_OFF 0x34 @@ -114,10 +114,6 @@ MODULE_PARM_DESC(bluetooth_status, "Set the wireless status on boot " #define WL_RSTS 0x01 /* internal Wifi */ #define BT_RSTS 0x02 /* internal Bluetooth */ -#define ASUS_HANDLE(object, paths...) \ - static acpi_handle object##_handle = NULL; \ - static char *object##_paths[] = { paths } - /* LED */ #define METHOD_MLED "MLED" #define METHOD_TLED "TLED" @@ -142,40 +138,44 @@ MODULE_PARM_DESC(bluetooth_status, "Set the wireless status on boot " #define METHOD_BRIGHTNESS_GET "GPLV" /* Backlight */ -ASUS_HANDLE(lcd_switch, "\\_SB.PCI0.SBRG.EC0._Q10", /* All new models */ - "\\_SB.PCI0.ISA.EC0._Q10", /* A1x */ - "\\_SB.PCI0.PX40.ECD0._Q10", /* L3C */ - "\\_SB.PCI0.PX40.EC0.Q10", /* M1A */ - "\\_SB.PCI0.LPCB.EC0._Q10", /* P30 */ - "\\_SB.PCI0.LPCB.EC0._Q0E", /* P30/P35 */ - "\\_SB.PCI0.PX40.Q10", /* S1x */ - "\\Q10"); /* A2x, L2D, L3D, M2E */ +static acpi_handle lcd_switch_handle; +static const char *lcd_switch_paths[] = { + "\\_SB.PCI0.SBRG.EC0._Q10", /* All new models */ + "\\_SB.PCI0.ISA.EC0._Q10", /* A1x */ + "\\_SB.PCI0.PX40.ECD0._Q10", /* L3C */ + "\\_SB.PCI0.PX40.EC0.Q10", /* M1A */ + "\\_SB.PCI0.LPCB.EC0._Q10", /* P30 */ + "\\_SB.PCI0.LPCB.EC0._Q0E", /* P30/P35 */ + "\\_SB.PCI0.PX40.Q10", /* S1x */ + "\\Q10"}; /* A2x, L2D, L3D, M2E */ /* Display */ #define METHOD_SWITCH_DISPLAY "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", - /* A3E A4K, A4D A4L A6J A7J A8J Z71V M9V S5A M5A z33A W1Jc W2V G1 */ - "\\_SB.PCI0.P0P2.VGA.GETD", - /* A6V A6Q */ - "\\_SB.PCI0.P0P3.VGA.GETD", - /* A6T, A6M */ - "\\_SB.PCI0.P0PA.VGA.GETD", - /* L3C */ - "\\_SB.PCI0.PCI1.VGAC.NMAP", - /* Z96F */ - "\\_SB.PCI0.VGA.GETD", - /* A2D */ - "\\ACTD", - /* A4G Z71A W1N W5A W5F M2N M3N M5N M6N S1N S5N */ - "\\ADVG", - /* P30 */ - "\\DNXT", - /* A2H D1 L2D L3D L3H L2E L5D L5C M1A M2E L4L W3V */ - "\\INFB", - /* A3F A6F A3N A3L M6N W3N W6A */ - "\\SSTE"); + +static acpi_handle display_get_handle; +static const char *display_get_paths[] = { + /* A6B, A6K A6R A7D F3JM L4R M6R A3G M6A M6V VX-1 V6J V6V W3Z */ + "\\_SB.PCI0.P0P1.VGA.GETD", + /* A3E A4K, A4D A4L A6J A7J A8J Z71V M9V S5A M5A z33A W1Jc W2V G1 */ + "\\_SB.PCI0.P0P2.VGA.GETD", + /* A6V A6Q */ + "\\_SB.PCI0.P0P3.VGA.GETD", + /* A6T, A6M */ + "\\_SB.PCI0.P0PA.VGA.GETD", + /* L3C */ + "\\_SB.PCI0.PCI1.VGAC.NMAP", + /* Z96F */ + "\\_SB.PCI0.VGA.GETD", + /* A2D */ + "\\ACTD", + /* A4G Z71A W1N W5A W5F M2N M3N M5N M6N S1N S5N */ + "\\ADVG", + /* P30 */ + "\\DNXT", + /* A2H D1 L2D L3D L3H L2E L5D L5C M1A M2E L4L W3V */ + "\\INFB", + /* A3F A6F A3N A3L M6N W3N W6A */ + "\\SSTE"}; #define METHOD_ALS_CONTROL "ALSC" /* Z71A Z71V */ #define METHOD_ALS_LEVEL "ALSL" /* Z71A Z71V */ @@ -426,7 +426,7 @@ static void asus_kled_cdev_set(struct led_classdev *led_cdev, struct asus_led *led = container_of(led_cdev, struct asus_led, led); struct asus_laptop *asus = led->asus; - led->wk = value; + led->wk = value; queue_work(asus->led_workqueue, &led->work); } @@ -474,7 +474,7 @@ static int asus_led_register(struct asus_laptop *asus, struct led_classdev *led_cdev = &led->led; if (!method || acpi_check_handle(asus->handle, method, NULL)) - return 0; /* Led not present */ + return 0; /* Led not present */ led->asus = asus; led->method = method; @@ -687,8 +687,8 @@ static ssize_t show_infos(struct device *dev, acpi_status rv = AE_OK; /* - * We use the easy way, we don't care of off and count, so we don't set eof - * to 1 + * We use the easy way, we don't care of off and count, + * so we don't set eof to 1 */ len += sprintf(page, ASUS_LAPTOP_NAME " " ASUS_LAPTOP_VERSION "\n"); @@ -904,7 +904,7 @@ static int read_display(struct asus_laptop *asus) pr_warning("Error reading display status\n"); } - value &= 0x0F; /* needed for some models, shouldn't hurt others */ + value &= 0x0F; /* needed for some models, shouldn't hurt others */ return value; } @@ -1041,7 +1041,7 @@ static ssize_t show_gps(struct device *dev, static ssize_t store_gps(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct asus_laptop *asus = dev_get_drvdata(dev); + struct asus_laptop *asus = dev_get_drvdata(dev); int rv, value; int ret; -- cgit v1.2.3 From 94d8f785dd1f021c1971df73e6437f000c0d9449 Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Mon, 1 Mar 2010 09:43:52 -0500 Subject: dell-laptop: Fix build error by making buffer_mutex static The following build bug (x86, allyesconfig): arch/x86/oprofile/built-in.o:(.data+0x250): multiple definition of `buffer_mutex' Was triggered in -tip testing, caused by this upstream commit: 116ee77: dell-laptop: Use buffer with 32-bit physical address There's multiple buffer_mutex's in the kernel. Make this new one static. Signed-off-by: Ingo Molnar --- drivers/platform/x86/dell-laptop.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/platform/x86/dell-laptop.c b/drivers/platform/x86/dell-laptop.c index b7f4d2705916..29d96a4f5769 100644 --- a/drivers/platform/x86/dell-laptop.c +++ b/drivers/platform/x86/dell-laptop.c @@ -132,8 +132,8 @@ static struct dmi_system_id __devinitdata dell_blacklist[] = { }; static struct calling_interface_buffer *buffer; -struct page *bufferpage; -DEFINE_MUTEX(buffer_mutex); +static struct page *bufferpage; +static DEFINE_MUTEX(buffer_mutex); static int hwswitch_state; -- cgit v1.2.3 From 92e00e47b61f558009ff81be42b412a76fd89d84 Mon Sep 17 00:00:00 2001 From: Matthew Garrett Date: Mon, 1 Mar 2010 09:46:43 -0500 Subject: dell-laptop: Fix errors on failure and exit paths Make sure that work is cancelled after removing the i8042 filter, and unregister the platform device rather than deleting it. Signed-off-by: Matthew Garrett Cc: Dmitry Torokhov --- drivers/platform/x86/dell-laptop.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/platform/x86/dell-laptop.c b/drivers/platform/x86/dell-laptop.c index 29d96a4f5769..ef614979afe9 100644 --- a/drivers/platform/x86/dell-laptop.c +++ b/drivers/platform/x86/dell-laptop.c @@ -580,6 +580,7 @@ static int __init dell_init(void) fail_backlight: i8042_remove_filter(dell_laptop_i8042_filter); + cancel_delayed_work_sync(&dell_rfkill_work); fail_filter: dell_cleanup_rfkill(); fail_rfkill: @@ -597,12 +598,12 @@ fail_platform_driver: static void __exit dell_exit(void) { - cancel_delayed_work_sync(&dell_rfkill_work); i8042_remove_filter(dell_laptop_i8042_filter); + cancel_delayed_work_sync(&dell_rfkill_work); backlight_device_unregister(dell_backlight_device); dell_cleanup_rfkill(); if (platform_device) { - platform_device_del(platform_device); + platform_device_unregister(platform_device); platform_driver_unregister(&platform_driver); } kfree(da_tokens); -- cgit v1.2.3 From b466301b842f3a54e219b5cc587f22233ecb1345 Mon Sep 17 00:00:00 2001 From: Frans Pop Date: Mon, 1 Mar 2010 09:50:46 -0500 Subject: toshiba-acpi: fix multimedia keys on some machines Some Toshibas only send ACPI events on key down, not key release. Ignore any release events and send key down and key up events on every ACPI key down event. Signed-off-by: Frans Pop --- drivers/platform/x86/toshiba_acpi.c | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/platform/x86/toshiba_acpi.c b/drivers/platform/x86/toshiba_acpi.c index 26c211724acf..405b969734d6 100644 --- a/drivers/platform/x86/toshiba_acpi.c +++ b/drivers/platform/x86/toshiba_acpi.c @@ -814,21 +814,23 @@ static void toshiba_acpi_notify(acpi_handle handle, u32 event, void *context) if (hci_result == HCI_SUCCESS) { if (value == 0x100) continue; - else if (value & 0x80) { - key = toshiba_acpi_get_entry_by_scancode - (value & ~0x80); - if (!key) { - printk(MY_INFO "Unknown key %x\n", - value & ~0x80); - continue; - } - input_report_key(toshiba_acpi.hotkey_dev, - key->keycode, 1); - input_sync(toshiba_acpi.hotkey_dev); - input_report_key(toshiba_acpi.hotkey_dev, - key->keycode, 0); - input_sync(toshiba_acpi.hotkey_dev); + /* act on key press; ignore key release */ + if (value & 0x80) + continue; + + key = toshiba_acpi_get_entry_by_scancode + (value); + if (!key) { + printk(MY_INFO "Unknown key %x\n", + value); + continue; } + input_report_key(toshiba_acpi.hotkey_dev, + key->keycode, 1); + input_sync(toshiba_acpi.hotkey_dev); + input_report_key(toshiba_acpi.hotkey_dev, + key->keycode, 0); + input_sync(toshiba_acpi.hotkey_dev); } else if (hci_result == HCI_NOT_SUPPORTED) { /* This is a workaround for an unresolved issue on * some machines where system events sporadically -- cgit v1.2.3 From 6268f50df8c36e15e43ae2a10951b2cffd0ecfc4 Mon Sep 17 00:00:00 2001 From: Roel Kluin Date: Mon, 1 Mar 2010 13:26:22 -0500 Subject: asus-acpi: remove duplicate comparison of asus_model strings These tests already occur elsewhere Signed-off-by: Roel Kluin Cc: Corentin Chary Cc: Karol Kozimor Cc: Len Brown Signed-off-by: Andrew Morton --- drivers/platform/x86/asus_acpi.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/platform/x86/asus_acpi.c b/drivers/platform/x86/asus_acpi.c index c1d2aeeea948..1381430e1105 100644 --- a/drivers/platform/x86/asus_acpi.c +++ b/drivers/platform/x86/asus_acpi.c @@ -1225,9 +1225,8 @@ static int asus_model_match(char *model) else if (strncmp(model, "M2N", 3) == 0 || strncmp(model, "M3N", 3) == 0 || strncmp(model, "M5N", 3) == 0 || - strncmp(model, "M6N", 3) == 0 || strncmp(model, "S1N", 3) == 0 || - strncmp(model, "S5N", 3) == 0 || strncmp(model, "W1N", 3) == 0) + strncmp(model, "S5N", 3) == 0) return xxN; else if (strncmp(model, "M1", 2) == 0) return M1A; -- cgit v1.2.3 From 881a6c25a8453388e3190de94a5e105439a9f806 Mon Sep 17 00:00:00 2001 From: Thadeu Lima de Souza Cascardo Date: Mon, 1 Mar 2010 16:15:58 -0500 Subject: classmate-laptop: Added some keys present in other devices Some new devices have extra keys, which we add to our list. Currently, they all generate events that allow us to use a simple table/array, without need for the sparse keymap. Signed-off-by: Thadeu Lima de Souza Cascardo --- drivers/platform/x86/classmate-laptop.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/platform/x86/classmate-laptop.c b/drivers/platform/x86/classmate-laptop.c index 8cb20e45bad6..035a7dd65a3f 100644 --- a/drivers/platform/x86/classmate-laptop.c +++ b/drivers/platform/x86/classmate-laptop.c @@ -507,6 +507,10 @@ static int cmpc_keys_codes[] = { KEY_BRIGHTNESSDOWN, KEY_BRIGHTNESSUP, KEY_VENDOR, + KEY_UNKNOWN, + KEY_CAMERA, + KEY_BACK, + KEY_FORWARD, KEY_MAX }; -- cgit v1.2.3 From 51c1410bd651609aafbcc3a2294df26a47bf6137 Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Tue, 2 Mar 2010 09:53:45 -0500 Subject: compal-laptop: Make it depend on CONFIG_RFKILL -tip testing found this build failure (x86 randconfig): drivers/built-in.o: In function `setup_rfkill': compal-laptop.c:(.text+0x36abe8): undefined reference to `rfkill_alloc' compal-laptop.c:(.text+0x36abfc): undefined reference to `rfkill_register' compal-laptop.c:(.text+0x36ac30): undefined reference to `rfkill_alloc' compal-laptop.c:(.text+0x36ac44): undefined reference to `rfkill_register' Which can happen with CONFIG_COMPAL_LAPTOP=y but COMPAL_LAPTOP=m. Signed-off-by: Ingo Molnar --- drivers/platform/x86/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index 92161c7ff4b7..cd2ee6fce1b4 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -179,6 +179,7 @@ config COMPAL_LAPTOP tristate "Compal Laptop Extras" depends on ACPI depends on BACKLIGHT_CLASS_DEVICE + depends on RFKILL ---help--- This is a driver for laptops built by Compal: -- cgit v1.2.3