From 6d41839e762f8b8b03dbb97fd0d41b244d0bc902 Mon Sep 17 00:00:00 2001 From: Alan Jenkins Date: Fri, 28 Aug 2009 12:56:32 +0000 Subject: eeepc-laptop: don't touch the pci slot if it was claimed by a different driver The whole point of registering as a PCI hotplug driver was to prevent conflict with pciehp. At the moment it happens to work because eeepc-laptop is loaded first, but it doesn't work the other way round. If pciehp is loaded first then we fail to claim the slot - we need to respect this and not handle hotplug events. Signed-off-by: Alan Jenkins Signed-off-by: Corentin Chary Signed-off-by: Len Brown --- drivers/platform/x86/eeepc-laptop.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/eeepc-laptop.c b/drivers/platform/x86/eeepc-laptop.c index 222ffb89..69d73ed 100644 --- a/drivers/platform/x86/eeepc-laptop.c +++ b/drivers/platform/x86/eeepc-laptop.c @@ -664,15 +664,20 @@ static int eeepc_get_adapter_status(struct hotplug_slot *hotplug_slot, static void eeepc_hotplug_work(struct work_struct *work) { struct pci_dev *dev; - struct pci_bus *bus = pci_find_bus(0, 1); - bool blocked; + struct pci_bus *bus; + bool blocked = eeepc_wlan_rfkill_blocked(); + + rfkill_set_sw_state(ehotk->wlan_rfkill, blocked); + if (ehotk->hotplug_slot == NULL) + return; + + bus = pci_find_bus(0, 1); if (!bus) { pr_warning("Unable to find PCI bus 1?\n"); return; } - blocked = eeepc_wlan_rfkill_blocked(); if (!blocked) { dev = pci_get_slot(bus, 0); if (dev) { @@ -693,8 +698,6 @@ static void eeepc_hotplug_work(struct work_struct *work) pci_dev_put(dev); } } - - rfkill_set_sw_state(ehotk->wlan_rfkill, blocked); } static void eeepc_rfkill_notify(acpi_handle handle, u32 event, void *data) -- cgit v1.1 From dcf443b5813074031a45b05ad9c57da98bcae329 Mon Sep 17 00:00:00 2001 From: Alan Jenkins Date: Fri, 28 Aug 2009 12:56:33 +0000 Subject: eeepc-laptop: use a mutex to serialize pci hotplug (resume vs. notify) Commit d0265f0 "eeepc-laptop: fix hot-unplug on resume" used a workqueue to protect pci hotplug against multiple simultaneous calls during resume. It seems to work, but a mutex would be more appropriate. This is in preparation to fix the potential pci hotplug race on unload. Signed-off-by: Alan Jenkins Signed-off-by: Corentin Chary Signed-off-by: Len Brown --- drivers/platform/x86/eeepc-laptop.c | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/eeepc-laptop.c b/drivers/platform/x86/eeepc-laptop.c index 69d73ed..1790103 100644 --- a/drivers/platform/x86/eeepc-laptop.c +++ b/drivers/platform/x86/eeepc-laptop.c @@ -143,7 +143,7 @@ struct eeepc_hotk { struct rfkill *bluetooth_rfkill; struct rfkill *wwan3g_rfkill; struct hotplug_slot *hotplug_slot; - struct work_struct hotplug_work; + struct mutex hotplug_lock; }; /* The actual device the driver binds to */ @@ -661,7 +661,7 @@ static int eeepc_get_adapter_status(struct hotplug_slot *hotplug_slot, return 0; } -static void eeepc_hotplug_work(struct work_struct *work) +static void eeepc_rfkill_hotplug(void) { struct pci_dev *dev; struct pci_bus *bus; @@ -669,13 +669,15 @@ static void eeepc_hotplug_work(struct work_struct *work) rfkill_set_sw_state(ehotk->wlan_rfkill, blocked); + mutex_lock(&ehotk->hotplug_lock); + if (ehotk->hotplug_slot == NULL) - return; + goto out_unlock; bus = pci_find_bus(0, 1); if (!bus) { pr_warning("Unable to find PCI bus 1?\n"); - return; + goto out_unlock; } if (!blocked) { @@ -683,7 +685,7 @@ static void eeepc_hotplug_work(struct work_struct *work) if (dev) { /* Device already present */ pci_dev_put(dev); - return; + goto out_unlock; } dev = pci_scan_single_device(bus, 0); if (dev) { @@ -698,6 +700,9 @@ static void eeepc_hotplug_work(struct work_struct *work) pci_dev_put(dev); } } + +out_unlock: + mutex_unlock(&ehotk->hotplug_lock); } static void eeepc_rfkill_notify(acpi_handle handle, u32 event, void *data) @@ -705,7 +710,7 @@ static void eeepc_rfkill_notify(acpi_handle handle, u32 event, void *data) if (event != ACPI_NOTIFY_BUS_CHECK) return; - schedule_work(&ehotk->hotplug_work); + eeepc_rfkill_hotplug(); } static void eeepc_hotk_notify(struct acpi_device *device, u32 event) @@ -896,7 +901,7 @@ static int eeepc_hotk_resume(struct acpi_device *device) rfkill_set_sw_state(ehotk->wlan_rfkill, wlan != 1); - schedule_work(&ehotk->hotplug_work); + eeepc_rfkill_hotplug(); } if (ehotk->bluetooth_rfkill) @@ -1097,7 +1102,7 @@ static int eeepc_rfkill_init(struct device *dev) { int result = 0; - INIT_WORK(&ehotk->hotplug_work, eeepc_hotplug_work); + mutex_init(&ehotk->hotplug_lock); eeepc_register_rfkill_notifier("\\_SB.PCI0.P0P6"); eeepc_register_rfkill_notifier("\\_SB.PCI0.P0P7"); -- cgit v1.1 From 07e84aa98f6b3a7278d3267f6f657955ed3eb973 Mon Sep 17 00:00:00 2001 From: Alan Jenkins Date: Fri, 28 Aug 2009 12:56:34 +0000 Subject: eeepc-laptop: fix pci hotplug race on load and unload Wifi rfkill state changes can race with pci hotplug cleanup. A simple fix is to refresh the hotplug state just before deregistering the pci hotplug slot. There is also potential for a hotplug notification to fire too early during setup, while the structures it uses are still being initialised. (This could only happen if the BIOS performs hotplug itself; a bug triggered by removing the battery while hibernated). Avoid this by registering the notifier later. The same refresh mechanism is used to handle rfkill state changes which can now race with registration. Signed-off-by: Alan Jenkins Signed-off-by: Corentin Chary Signed-off-by: Len Brown --- drivers/platform/x86/eeepc-laptop.c | 77 ++++++++++++++++++++++--------------- 1 file changed, 45 insertions(+), 32 deletions(-) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/eeepc-laptop.c b/drivers/platform/x86/eeepc-laptop.c index 1790103..8dd86f7 100644 --- a/drivers/platform/x86/eeepc-laptop.c +++ b/drivers/platform/x86/eeepc-laptop.c @@ -667,37 +667,37 @@ static void eeepc_rfkill_hotplug(void) struct pci_bus *bus; bool blocked = eeepc_wlan_rfkill_blocked(); - rfkill_set_sw_state(ehotk->wlan_rfkill, blocked); + if (ehotk->wlan_rfkill) + rfkill_set_sw_state(ehotk->wlan_rfkill, blocked); mutex_lock(&ehotk->hotplug_lock); - if (ehotk->hotplug_slot == NULL) - goto out_unlock; - - bus = pci_find_bus(0, 1); - if (!bus) { - pr_warning("Unable to find PCI bus 1?\n"); - goto out_unlock; - } - - if (!blocked) { - dev = pci_get_slot(bus, 0); - if (dev) { - /* Device already present */ - pci_dev_put(dev); + if (ehotk->hotplug_slot) { + bus = pci_find_bus(0, 1); + if (!bus) { + pr_warning("Unable to find PCI bus 1?\n"); goto out_unlock; } - dev = pci_scan_single_device(bus, 0); - if (dev) { - pci_bus_assign_resources(bus); - if (pci_bus_add_device(dev)) - pr_err("Unable to hotplug wifi\n"); - } - } else { - dev = pci_get_slot(bus, 0); - if (dev) { - pci_remove_bus_device(dev); - pci_dev_put(dev); + + if (!blocked) { + dev = pci_get_slot(bus, 0); + if (dev) { + /* Device already present */ + pci_dev_put(dev); + goto out_unlock; + } + dev = pci_scan_single_device(bus, 0); + if (dev) { + pci_bus_assign_resources(bus); + if (pci_bus_add_device(dev)) + pr_err("Unable to hotplug wifi\n"); + } + } else { + dev = pci_get_slot(bus, 0); + if (dev) { + pci_remove_bus_device(dev); + pci_dev_put(dev); + } } } @@ -1029,14 +1029,22 @@ static void eeepc_rfkill_exit(void) { eeepc_unregister_rfkill_notifier("\\_SB.PCI0.P0P6"); eeepc_unregister_rfkill_notifier("\\_SB.PCI0.P0P7"); - if (ehotk->wlan_rfkill) + if (ehotk->wlan_rfkill) { rfkill_unregister(ehotk->wlan_rfkill); + ehotk->wlan_rfkill = NULL; + } + /* + * Refresh pci hotplug in case the rfkill state was changed after + * eeepc_unregister_rfkill_notifier() + */ + eeepc_rfkill_hotplug(); + if (ehotk->hotplug_slot) + pci_hp_deregister(ehotk->hotplug_slot); + if (ehotk->bluetooth_rfkill) rfkill_unregister(ehotk->bluetooth_rfkill); if (ehotk->wwan3g_rfkill) rfkill_unregister(ehotk->wwan3g_rfkill); - if (ehotk->hotplug_slot) - pci_hp_deregister(ehotk->hotplug_slot); } static void eeepc_input_exit(void) @@ -1104,9 +1112,6 @@ static int eeepc_rfkill_init(struct device *dev) mutex_init(&ehotk->hotplug_lock); - eeepc_register_rfkill_notifier("\\_SB.PCI0.P0P6"); - eeepc_register_rfkill_notifier("\\_SB.PCI0.P0P7"); - result = eeepc_new_rfkill(&ehotk->wlan_rfkill, "eeepc-wlan", dev, RFKILL_TYPE_WLAN, CM_ASL_WLAN); @@ -1136,6 +1141,14 @@ static int eeepc_rfkill_init(struct device *dev) if (result == -EBUSY) result = 0; + eeepc_register_rfkill_notifier("\\_SB.PCI0.P0P6"); + eeepc_register_rfkill_notifier("\\_SB.PCI0.P0P7"); + /* + * Refresh pci hotplug in case the rfkill state was changed during + * setup. + */ + eeepc_rfkill_hotplug(); + exit: if (result && result != -ENODEV) eeepc_rfkill_exit(); -- cgit v1.1 From 1e7798547fe6920ae27fb92c9202353e9e4c55db Mon Sep 17 00:00:00 2001 From: Alan Jenkins Date: Fri, 28 Aug 2009 12:56:35 +0000 Subject: eeepc-laptop: fix ordering of init and exit functions 1. input and backlight devices were registered after acpi notifications are enabled. This left a window where eeepc_hotk_notify() might find these devices in an inconsistent (half-initialized) state. -> Move all device registration into eeepc_hotk_add(), which is called before enabling acpi notifications. 2. input and backlight devices were unregistered before acpi notifications are disabled. This left a window where eeepc_hotk_notify() might find these devices in an inconsistent (half-destroyed) state. -> Move all device unregistration into eeepc_hotk_remove(), which is called after disabling acpi notifications. 3. The acpi driver was not freed if an error occured further down in eeepc_laptop_init(). -> The rest of eeepc_laptop_init() has been moved to eeepc_hotk_add(), so this is no longer a problem. 4. The acpi driver was unregistered before the platform driver. This left a window where a sysfs access could attempt to read the ehotk structure after it had been freed by eeepc_hotk_remove(). -> The acpi driver is now unregistered as the last step in eeepc_laptop_exit(), so this is no longer a problem. Signed-off-by: Alan Jenkins Signed-off-by: Corentin Chary Signed-off-by: Len Brown --- drivers/platform/x86/eeepc-laptop.c | 120 ++++++++++++++++++------------------ 1 file changed, 59 insertions(+), 61 deletions(-) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/eeepc-laptop.c b/drivers/platform/x86/eeepc-laptop.c index 8dd86f7..cf47d1c 100644 --- a/drivers/platform/x86/eeepc-laptop.c +++ b/drivers/platform/x86/eeepc-laptop.c @@ -847,44 +847,6 @@ error_slot: return ret; } -static int eeepc_hotk_add(struct acpi_device *device) -{ - int result; - - if (!device) - return -EINVAL; - pr_notice(EEEPC_HOTK_NAME "\n"); - ehotk = kzalloc(sizeof(struct eeepc_hotk), GFP_KERNEL); - if (!ehotk) - return -ENOMEM; - ehotk->init_flag = DISABLE_ASL_WLAN | DISABLE_ASL_DISPLAYSWITCH; - ehotk->handle = device->handle; - strcpy(acpi_device_name(device), EEEPC_HOTK_DEVICE_NAME); - strcpy(acpi_device_class(device), EEEPC_HOTK_CLASS); - device->driver_data = ehotk; - ehotk->device = device; - result = eeepc_hotk_check(); - if (result) - goto ehotk_fail; - - return 0; - - ehotk_fail: - kfree(ehotk); - ehotk = NULL; - - return result; -} - -static int eeepc_hotk_remove(struct acpi_device *device, int type) -{ - if (!device || !acpi_driver_data(device)) - return -EINVAL; - - kfree(ehotk); - return 0; -} - static int eeepc_hotk_resume(struct acpi_device *device) { if (ehotk->wlan_rfkill) { @@ -1066,19 +1028,6 @@ static void eeepc_hwmon_exit(void) eeepc_hwmon_device = NULL; } -static void __exit eeepc_laptop_exit(void) -{ - eeepc_backlight_exit(); - eeepc_rfkill_exit(); - eeepc_input_exit(); - eeepc_hwmon_exit(); - acpi_bus_unregister_driver(&eeepc_hotk_driver); - sysfs_remove_group(&platform_device->dev.kobj, - &platform_attribute_group); - platform_device_unregister(platform_device); - platform_driver_unregister(&platform_driver); -} - static int eeepc_new_rfkill(struct rfkill **rfkill, const char *name, struct device *dev, enum rfkill_type type, int cm) @@ -1193,21 +1142,27 @@ static int eeepc_hwmon_init(struct device *dev) return result; } -static int __init eeepc_laptop_init(void) +static int eeepc_hotk_add(struct acpi_device *device) { struct device *dev; int result; - if (acpi_disabled) - return -ENODEV; - result = acpi_bus_register_driver(&eeepc_hotk_driver); - if (result < 0) - return result; - if (!ehotk) { - acpi_bus_unregister_driver(&eeepc_hotk_driver); - return -ENODEV; - } + if (!device) + return -EINVAL; + pr_notice(EEEPC_HOTK_NAME "\n"); + ehotk = kzalloc(sizeof(struct eeepc_hotk), GFP_KERNEL); + if (!ehotk) + return -ENOMEM; + ehotk->init_flag = DISABLE_ASL_WLAN | DISABLE_ASL_DISPLAYSWITCH; + ehotk->handle = device->handle; + strcpy(acpi_device_name(device), EEEPC_HOTK_DEVICE_NAME); + strcpy(acpi_device_class(device), EEEPC_HOTK_CLASS); + device->driver_data = ehotk; + ehotk->device = device; + result = eeepc_hotk_check(); + if (result) + goto fail_check; eeepc_enable_camera(); /* Register platform stuff */ @@ -1246,6 +1201,7 @@ static int __init eeepc_laptop_init(void) goto fail_rfkill; return 0; + fail_rfkill: eeepc_hwmon_exit(); fail_hwmon: @@ -1261,8 +1217,50 @@ fail_platform_device1: platform_driver_unregister(&platform_driver); fail_platform_driver: eeepc_input_exit(); +fail_check: + kfree(ehotk); + return result; } +static int eeepc_hotk_remove(struct acpi_device *device, int type) +{ + if (!device || !acpi_driver_data(device)) + return -EINVAL; + + eeepc_backlight_exit(); + eeepc_rfkill_exit(); + eeepc_input_exit(); + eeepc_hwmon_exit(); + sysfs_remove_group(&platform_device->dev.kobj, + &platform_attribute_group); + platform_device_unregister(platform_device); + platform_driver_unregister(&platform_driver); + + kfree(ehotk); + return 0; +} + +static int __init eeepc_laptop_init(void) +{ + int result; + + if (acpi_disabled) + return -ENODEV; + result = acpi_bus_register_driver(&eeepc_hotk_driver); + if (result < 0) + return result; + if (!ehotk) { + acpi_bus_unregister_driver(&eeepc_hotk_driver); + return -ENODEV; + } + return 0; +} + +static void __exit eeepc_laptop_exit(void) +{ + acpi_bus_unregister_driver(&eeepc_hotk_driver); +} + module_init(eeepc_laptop_init); module_exit(eeepc_laptop_exit); -- cgit v1.1 From f2a9d5e8a649c606f520b7a7b9f4f46fba79c327 Mon Sep 17 00:00:00 2001 From: Alan Jenkins Date: Fri, 28 Aug 2009 12:56:36 +0000 Subject: eeepc-laptop: make input device a child of the platform device Sysfs showed the ehotk input device as a "virtual" device - lies! The input device is provided by a physical device, the eeepc platform. This requires that we move the creation of the input device to come after platform device is created. Input initialization is moved from ehotk_check() [sic] to a new function called eeepc_input_init(). This brings the input device into line with the other eeepc-laptop devices. Also, refuse to load if we fail to register the input device. Signed-off-by: Alan Jenkins Signed-off-by: Corentin Chary Signed-off-by: Len Brown --- drivers/platform/x86/eeepc-laptop.c | 70 ++++++++++++++++++++++--------------- 1 file changed, 41 insertions(+), 29 deletions(-) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/eeepc-laptop.c b/drivers/platform/x86/eeepc-laptop.c index cf47d1c..298dac9 100644 --- a/drivers/platform/x86/eeepc-laptop.c +++ b/drivers/platform/x86/eeepc-laptop.c @@ -579,7 +579,6 @@ static void cmsg_quirks(void) static int eeepc_hotk_check(void) { - const struct key_entry *key; struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; int result; @@ -604,31 +603,6 @@ static int eeepc_hotk_check(void) pr_info("Get control methods supported: 0x%x\n", ehotk->cm_supported); } - ehotk->inputdev = input_allocate_device(); - if (!ehotk->inputdev) { - pr_info("Unable to allocate input device\n"); - return 0; - } - ehotk->inputdev->name = "Asus EeePC extra buttons"; - ehotk->inputdev->phys = EEEPC_HOTK_FILE "/input0"; - ehotk->inputdev->id.bustype = BUS_HOST; - ehotk->inputdev->getkeycode = eeepc_getkeycode; - ehotk->inputdev->setkeycode = eeepc_setkeycode; - - for (key = eeepc_keymap; key->type != KE_END; key++) { - switch (key->type) { - case KE_KEY: - set_bit(EV_KEY, ehotk->inputdev->evbit); - set_bit(key->keycode, ehotk->inputdev->keybit); - break; - } - } - result = input_register_device(ehotk->inputdev); - if (result) { - pr_info("Unable to register input device\n"); - input_free_device(ehotk->inputdev); - return 0; - } } else { pr_err("Hotkey device not present, aborting\n"); return -EINVAL; @@ -1142,6 +1116,40 @@ static int eeepc_hwmon_init(struct device *dev) return result; } +static int eeepc_input_init(struct device *dev) +{ + const struct key_entry *key; + int result; + + ehotk->inputdev = input_allocate_device(); + if (!ehotk->inputdev) { + pr_info("Unable to allocate input device\n"); + return -ENOMEM; + } + ehotk->inputdev->name = "Asus EeePC extra buttons"; + ehotk->inputdev->dev.parent = dev; + ehotk->inputdev->phys = EEEPC_HOTK_FILE "/input0"; + ehotk->inputdev->id.bustype = BUS_HOST; + ehotk->inputdev->getkeycode = eeepc_getkeycode; + ehotk->inputdev->setkeycode = eeepc_setkeycode; + + for (key = eeepc_keymap; key->type != KE_END; key++) { + switch (key->type) { + case KE_KEY: + set_bit(EV_KEY, ehotk->inputdev->evbit); + set_bit(key->keycode, ehotk->inputdev->keybit); + break; + } + } + result = input_register_device(ehotk->inputdev); + if (result) { + pr_info("Unable to register input device\n"); + input_free_device(ehotk->inputdev); + return result; + } + return 0; +} + static int eeepc_hotk_add(struct acpi_device *device) { struct device *dev; @@ -1162,7 +1170,7 @@ static int eeepc_hotk_add(struct acpi_device *device) result = eeepc_hotk_check(); if (result) - goto fail_check; + goto fail_platform_driver; eeepc_enable_camera(); /* Register platform stuff */ @@ -1192,6 +1200,10 @@ static int eeepc_hotk_add(struct acpi_device *device) pr_info("Backlight controlled by ACPI video " "driver\n"); + result = eeepc_input_init(dev); + if (result) + goto fail_input; + result = eeepc_hwmon_init(dev); if (result) goto fail_hwmon; @@ -1205,6 +1217,8 @@ static int eeepc_hotk_add(struct acpi_device *device) fail_rfkill: eeepc_hwmon_exit(); fail_hwmon: + eeepc_input_exit(); +fail_input: eeepc_backlight_exit(); fail_backlight: sysfs_remove_group(&platform_device->dev.kobj, @@ -1216,8 +1230,6 @@ fail_platform_device2: fail_platform_device1: platform_driver_unregister(&platform_driver); fail_platform_driver: - eeepc_input_exit(); -fail_check: kfree(ehotk); return result; -- cgit v1.1 From ffb03575284e0f72d7ea001178c793afa265b8b5 Mon Sep 17 00:00:00 2001 From: Alan Jenkins Date: Fri, 28 Aug 2009 12:56:37 +0000 Subject: eeepc-laptop: remove redundant rfkill_set_sw_state in resume handler rfkill_set_sw_state() will already be called by eeepc_rfkill_hotplug(). Signed-off-by: Alan Jenkins Signed-off-by: Corentin Chary Signed-off-by: Len Brown --- drivers/platform/x86/eeepc-laptop.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/eeepc-laptop.c b/drivers/platform/x86/eeepc-laptop.c index 298dac9..7f7573a 100644 --- a/drivers/platform/x86/eeepc-laptop.c +++ b/drivers/platform/x86/eeepc-laptop.c @@ -835,8 +835,7 @@ static int eeepc_hotk_resume(struct acpi_device *device) wlan = get_acpi(CM_ASL_WLAN); set_acpi(CM_ASL_WLAN, wlan); - rfkill_set_sw_state(ehotk->wlan_rfkill, wlan != 1); - + /* Refresh both rfkill state and pci hotplug */ eeepc_rfkill_hotplug(); } -- cgit v1.1 From a47461011a0f5110c497b9b163d1125d258418b2 Mon Sep 17 00:00:00 2001 From: Alan Jenkins Date: Fri, 28 Aug 2009 12:56:38 +0000 Subject: eeepc-laptop: check the 3G rfkill state on resume All the rfkill devices are treated as "persistent", 3G is no exception. This means their state may change over hibernation. Signed-off-by: Alan Jenkins Signed-off-by: Corentin Chary Signed-off-by: Len Brown --- drivers/platform/x86/eeepc-laptop.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/eeepc-laptop.c b/drivers/platform/x86/eeepc-laptop.c index 7f7573a..8a32004 100644 --- a/drivers/platform/x86/eeepc-laptop.c +++ b/drivers/platform/x86/eeepc-laptop.c @@ -842,6 +842,9 @@ static int eeepc_hotk_resume(struct acpi_device *device) if (ehotk->bluetooth_rfkill) rfkill_set_sw_state(ehotk->bluetooth_rfkill, get_acpi(CM_ASL_BLUETOOTH) != 1); + if (ehotk->wwan3g_rfkill) + rfkill_set_sw_state(ehotk->wwan3g_rfkill, + get_acpi(CM_ASL_3G) != 1); return 0; } -- cgit v1.1 From c1edd99f1c2b0285ce810d217180bf37bbae550e Mon Sep 17 00:00:00 2001 From: Alan Jenkins Date: Fri, 28 Aug 2009 12:56:39 +0000 Subject: eeepc-laptop: correct the description of the hibernation abort bug Actually it is only the LED which is affected. The bios bug does not disable the wifi. Signed-off-by: Alan Jenkins Signed-off-by: Corentin Chary Signed-off-by: Len Brown --- drivers/platform/x86/eeepc-laptop.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/eeepc-laptop.c b/drivers/platform/x86/eeepc-laptop.c index 8a32004..df68ae6 100644 --- a/drivers/platform/x86/eeepc-laptop.c +++ b/drivers/platform/x86/eeepc-laptop.c @@ -826,11 +826,10 @@ static int eeepc_hotk_resume(struct acpi_device *device) if (ehotk->wlan_rfkill) { bool wlan; - /* Workaround - it seems that _PTS disables the wireless - without notification or changing the value read by WLAN. - Normally this is fine because the correct value is restored - from the non-volatile storage on resume, but we need to do - it ourself if case suspend is aborted, or we lose wireless. + /* + * Work around bios bug - acpi _PTS turns off the wireless led + * during suspend. Normally it restores it on resume, but + * we should kick it ourselves in case suspend is aborted. */ wlan = get_acpi(CM_ASL_WLAN); set_acpi(CM_ASL_WLAN, wlan); -- cgit v1.1 From c200da5d2900df9c24fb8041870d92a4175bbef3 Mon Sep 17 00:00:00 2001 From: Alan Jenkins Date: Fri, 28 Aug 2009 12:56:40 +0000 Subject: eeepc-laptop: switch to dev_pm_ops This also involves switching the resume handler from the acpi device to the platform device. Using the more fine grained handlers allows two improvements: 1. We only need to recheck rfkill state after resume from hibernation. 2. The wireless LED workaround accounts for up to 1.1s out of 1.7s resuming devices (when wireless is enabled). We can limit the workaround to thaw(), so that it only delays suspend to disk. The workaround is only likely to help when hibernation is aborted. Suspend to ram cannot be aborted by the user. Device suspend errors may well happen before eeepc-laptop would even be frozen. Suspend errors which happen after that could be pretty funky anyway. Signed-off-by: Alan Jenkins Signed-off-by: Corentin Chary Signed-off-by: Len Brown --- drivers/platform/x86/eeepc-laptop.c | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/eeepc-laptop.c b/drivers/platform/x86/eeepc-laptop.c index df68ae6..1c94860 100644 --- a/drivers/platform/x86/eeepc-laptop.c +++ b/drivers/platform/x86/eeepc-laptop.c @@ -150,10 +150,19 @@ struct eeepc_hotk { static struct eeepc_hotk *ehotk; /* Platform device/driver */ +static int eeepc_hotk_thaw(struct device *device); +static int eeepc_hotk_restore(struct device *device); + +static struct dev_pm_ops eeepc_pm_ops = { + .thaw = eeepc_hotk_thaw, + .restore = eeepc_hotk_restore, +}; + static struct platform_driver platform_driver = { .driver = { .name = EEEPC_HOTK_FILE, .owner = THIS_MODULE, + .pm = &eeepc_pm_ops, } }; @@ -192,7 +201,6 @@ static struct key_entry eeepc_keymap[] = { */ static int eeepc_hotk_add(struct acpi_device *device); static int eeepc_hotk_remove(struct acpi_device *device, int type); -static int eeepc_hotk_resume(struct acpi_device *device); static void eeepc_hotk_notify(struct acpi_device *device, u32 event); static const struct acpi_device_id eeepc_device_ids[] = { @@ -209,7 +217,6 @@ static struct acpi_driver eeepc_hotk_driver = { .ops = { .add = eeepc_hotk_add, .remove = eeepc_hotk_remove, - .resume = eeepc_hotk_resume, .notify = eeepc_hotk_notify, }, }; @@ -821,7 +828,7 @@ error_slot: return ret; } -static int eeepc_hotk_resume(struct acpi_device *device) +static int eeepc_hotk_thaw(struct device *device) { if (ehotk->wlan_rfkill) { bool wlan; @@ -829,14 +836,20 @@ static int eeepc_hotk_resume(struct acpi_device *device) /* * Work around bios bug - acpi _PTS turns off the wireless led * during suspend. Normally it restores it on resume, but - * we should kick it ourselves in case suspend is aborted. + * we should kick it ourselves in case hibernation is aborted. */ wlan = get_acpi(CM_ASL_WLAN); set_acpi(CM_ASL_WLAN, wlan); + } + + return 0; +} - /* Refresh both rfkill state and pci hotplug */ +static int eeepc_hotk_restore(struct device *device) +{ + /* Refresh both wlan rfkill state and pci hotplug */ + if (ehotk->wlan_rfkill) eeepc_rfkill_hotplug(); - } if (ehotk->bluetooth_rfkill) rfkill_set_sw_state(ehotk->bluetooth_rfkill, -- cgit v1.1 From d1ec9c3d434d94e3674bcf433e8e8e7462b8e1c0 Mon Sep 17 00:00:00 2001 From: Corentin Chary Date: Fri, 28 Aug 2009 12:56:41 +0000 Subject: eeepc-laptop: add rfkill support for the Wimax in ASUS Eee PC 1000HG Signed-off-by: Corentin Chary Signed-off-by: Len Brown --- drivers/platform/x86/eeepc-laptop.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/eeepc-laptop.c b/drivers/platform/x86/eeepc-laptop.c index 1c94860..c9febf4 100644 --- a/drivers/platform/x86/eeepc-laptop.c +++ b/drivers/platform/x86/eeepc-laptop.c @@ -142,6 +142,7 @@ struct eeepc_hotk { struct rfkill *wlan_rfkill; struct rfkill *bluetooth_rfkill; struct rfkill *wwan3g_rfkill; + struct rfkill *wimax_rfkill; struct hotplug_slot *hotplug_slot; struct mutex hotplug_lock; }; @@ -857,6 +858,9 @@ static int eeepc_hotk_restore(struct device *device) if (ehotk->wwan3g_rfkill) rfkill_set_sw_state(ehotk->wwan3g_rfkill, get_acpi(CM_ASL_3G) != 1); + if (ehotk->wimax_rfkill) + rfkill_set_sw_state(ehotk->wimax_rfkill, + get_acpi(CM_ASL_WIMAX) != 1); return 0; } @@ -995,6 +999,8 @@ static void eeepc_rfkill_exit(void) rfkill_unregister(ehotk->bluetooth_rfkill); if (ehotk->wwan3g_rfkill) rfkill_unregister(ehotk->wwan3g_rfkill); + if (ehotk->wimax_rfkill) + rfkill_unregister(ehotk->wimax_rfkill); } static void eeepc_input_exit(void) @@ -1070,6 +1076,13 @@ static int eeepc_rfkill_init(struct device *dev) if (result && result != -ENODEV) goto exit; + result = eeepc_new_rfkill(&ehotk->wimax_rfkill, + "eeepc-wimax", dev, + RFKILL_TYPE_WIMAX, CM_ASL_WIMAX); + + if (result && result != -ENODEV) + goto exit; + result = eeepc_setup_pci_hotplug(); /* * If we get -EBUSY then something else is handling the PCI hotplug - -- cgit v1.1 From 1d4a3800c764d111d67462a14589ed1611b2f55e Mon Sep 17 00:00:00 2001 From: Corentin Chary Date: Fri, 28 Aug 2009 12:56:46 +0000 Subject: asus-laptop: Show HRWS in infos and fix output format Show HRWS in /sys/platform/devices/asus-laptop/infos. HRWS is a bitfield used to get information about Hardware available in the laptop. Also change sprintf format from 0x%04x to %#x. Signed-off-by: Corentin Chary Signed-off-by: Len Brown --- drivers/platform/x86/asus-laptop.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/asus-laptop.c b/drivers/platform/x86/asus-laptop.c index db657bb..2344950 100644 --- a/drivers/platform/x86/asus-laptop.c +++ b/drivers/platform/x86/asus-laptop.c @@ -516,7 +516,17 @@ static ssize_t show_infos(struct device *dev, */ rv = acpi_evaluate_integer(hotk->handle, "SFUN", NULL, &temp); if (!ACPI_FAILURE(rv)) - len += sprintf(page + len, "SFUN value : 0x%04x\n", + len += sprintf(page + len, "SFUN value : %#x\n", + (uint) temp); + /* + * 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. + */ + rv = acpi_evaluate_integer(hotk->handle, "HRWS", NULL, &temp); + if (!ACPI_FAILURE(rv)) + len += sprintf(page + len, "HRWS value : %#x\n", (uint) temp); /* * Another value for userspace: the ASYM method returns 0x02 for @@ -527,7 +537,7 @@ static ssize_t show_infos(struct device *dev, */ rv = acpi_evaluate_integer(hotk->handle, "ASYM", NULL, &temp); if (!ACPI_FAILURE(rv)) - len += sprintf(page + len, "ASYM value : 0x%04x\n", + len += sprintf(page + len, "ASYM value : %#x\n", (uint) temp); if (asus_info) { snprintf(buf, 16, "%d", asus_info->length); -- cgit v1.1 From abfa57e15acaa6e1ec567c250e5212bc55d79e43 Mon Sep 17 00:00:00 2001 From: Corentin Chary Date: Fri, 28 Aug 2009 12:56:47 +0000 Subject: asus-laptop: Add *_led_get() functions Add support for getting led brightness directly from the hardware. Currently we don't need it, but it is needed to support keyboard backlight/led. Signed-off-by: Corentin Chary Signed-off-by: Len Brown --- drivers/platform/x86/asus-laptop.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/asus-laptop.c b/drivers/platform/x86/asus-laptop.c index 2344950..88cc9a1 100644 --- a/drivers/platform/x86/asus-laptop.c +++ b/drivers/platform/x86/asus-laptop.c @@ -246,12 +246,15 @@ static struct workqueue_struct *led_workqueue; #define ASUS_LED(object, ledname) \ 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 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, \ + .brightness_get = object##_led_get, \ } ASUS_LED(mled, "mail"); @@ -399,6 +402,11 @@ static void write_status(acpi_handle handle, int out, int mask) { \ int value = object##_led_wk; \ write_status(object##_set_handle, value, (mask)); \ + } \ + static enum led_brightness object##_led_get( \ + struct led_classdev *led_cdev) \ + { \ + return led_cdev->brightness; \ } ASUS_LED_HANDLER(mled, MLED_ON); -- cgit v1.1 From f641375b65f64e83be8be68ae1ebce21ee4fd578 Mon Sep 17 00:00:00 2001 From: Corentin Chary Date: Fri, 28 Aug 2009 12:56:48 +0000 Subject: asus-laptop: Map X50R hotkeys Map some new hotkeys found on X50R. Signed-off-by: Corentin Chary Signed-off-by: Len Brown --- drivers/platform/x86/asus-laptop.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/asus-laptop.c b/drivers/platform/x86/asus-laptop.c index 88cc9a1..410e545 100644 --- a/drivers/platform/x86/asus-laptop.c +++ b/drivers/platform/x86/asus-laptop.c @@ -285,6 +285,9 @@ static struct key_entry asus_keymap[] = { {KE_KEY, 0x51, KEY_WWW}, {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, 0x6B, BTN_TOUCH}, /* Lock Mouse */ {KE_KEY, 0x82, KEY_CAMERA}, -- cgit v1.1 From 977c328d81e31fde70c5ba381d9cf7357451dd74 Mon Sep 17 00:00:00 2001 From: Corentin Chary Date: Fri, 28 Aug 2009 12:56:49 +0000 Subject: asus-laptop: set maximum led brightness Set the right maximum brightness which is one, because they can only be on or off. Signed-off-by: Corentin Chary Signed-off-by: Len Brown --- drivers/platform/x86/asus-laptop.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/asus-laptop.c b/drivers/platform/x86/asus-laptop.c index 410e545..652902e 100644 --- a/drivers/platform/x86/asus-laptop.c +++ b/drivers/platform/x86/asus-laptop.c @@ -243,7 +243,7 @@ static struct backlight_ops asusbl_ops = { * potentially bad time, such as a timer interrupt. */ static struct workqueue_struct *led_workqueue; -#define ASUS_LED(object, ledname) \ +#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( \ @@ -255,13 +255,14 @@ static struct workqueue_struct *led_workqueue; .name = "asus::" ledname, \ .brightness_set = object##_led_set, \ .brightness_get = object##_led_get, \ + .max_brightness = max \ } -ASUS_LED(mled, "mail"); -ASUS_LED(tled, "touchpad"); -ASUS_LED(rled, "record"); -ASUS_LED(pled, "phone"); -ASUS_LED(gled, "gaming"); +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); struct key_entry { char type; -- cgit v1.1 From b7d3fbc2ed624cc216adda0f2574570e6d6d6aed Mon Sep 17 00:00:00 2001 From: Corentin Chary Date: Fri, 28 Aug 2009 12:56:50 +0000 Subject: asus-laptop: Add support for Keyboard backlight Add support for keyboard backlight found in Asus U50VG. The SMC driver for the Apples does it via LED. To be consistent with that we create /sys/class/leds/asus::kbd_backlight/ to control the keyboard backlight. SLKB and GLKB are used to get/set the backlight. On the U50VG is supports 4 brightness level, but this may change with other models. SLKB take a 8 bit integer where the higher bit is used to toggle the backlight, and the over 7 bits control the brightness level. Signed-off-by: Corentin Chary Signed-off-by: Len Brown --- drivers/platform/x86/asus-laptop.c | 79 +++++++++++++++++++++++++++++++++++++- 1 file changed, 77 insertions(+), 2 deletions(-) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/asus-laptop.c b/drivers/platform/x86/asus-laptop.c index 652902e..0fb4e59 100644 --- a/drivers/platform/x86/asus-laptop.c +++ b/drivers/platform/x86/asus-laptop.c @@ -86,6 +86,7 @@ #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 @@ -172,6 +173,10 @@ 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"); +/* Keyboard light */ +ASUS_HANDLE(kled_set, ASUS_HOTK_PREFIX "SLKB"); +ASUS_HANDLE(kled_get, ASUS_HOTK_PREFIX "GLKB"); + /* * This is the main structure, we can use it to store anything interesting * about the hotk device @@ -263,6 +268,7 @@ 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; @@ -419,6 +425,60 @@ ASUS_LED_HANDLER(rled, RLED_ON); ASUS_LED_HANDLER(tled, TLED_ON); ASUS_LED_HANDLER(gled, GLED_ON); +/* + * Keyboard backlight + */ +static int get_kled_lvl(void) +{ + unsigned long long kblv; + struct acpi_object_list params; + union acpi_object in_obj; + acpi_status rv; + + params.count = 1; + params.pointer = &in_obj; + in_obj.type = ACPI_TYPE_INTEGER; + in_obj.integer.value = 2; + + rv = acpi_evaluate_integer(kled_get_handle, NULL, ¶ms, &kblv); + if (ACPI_FAILURE(rv)) { + pr_warning("Error reading kled level\n"); + return 0; + } + return kblv; +} + +static int set_kled_lvl(int kblv) +{ + if (kblv > 0) + kblv = (1 << 7) | (kblv & 0x7F); + else + kblv = 0; + + if (write_acpi_int(kled_set_handle, NULL, kblv, NULL)) { + pr_warning("Keyboard LED display write failed\n"); + return -EINVAL; + } + return 0; +} + +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); +} + +static void kled_led_update(struct work_struct *ignored) +{ + set_kled_lvl(kled_led_wk); +} + +static enum led_brightness kled_led_get(struct led_classdev *led_cdev) +{ + return get_kled_lvl(); +} + static int get_lcd_state(void) { return read_status(LCD_ON); @@ -1059,6 +1119,9 @@ static int asus_hotk_get_info(void) 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. @@ -1190,6 +1253,10 @@ static int asus_hotk_add(struct acpi_device *device) /* 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; @@ -1244,6 +1311,7 @@ static void asus_led_exit(void) ASUS_LED_UNREGISTER(pled); ASUS_LED_UNREGISTER(rled); ASUS_LED_UNREGISTER(gled); + ASUS_LED_UNREGISTER(kled); } static void asus_input_exit(void) @@ -1323,13 +1391,20 @@ static int asus_led_init(struct device *dev) if (rv) goto out4; + if (kled_set_handle && kled_get_handle) + rv = ASUS_LED_REGISTER(kled, dev); + if (rv) + goto out5; + led_workqueue = create_singlethread_workqueue("led_workqueue"); if (!led_workqueue) - goto out5; + goto out6; return 0; -out5: +out6: rv = -ENOMEM; + ASUS_LED_UNREGISTER(kled); +out5: ASUS_LED_UNREGISTER(gled); out4: ASUS_LED_UNREGISTER(pled); -- cgit v1.1 From dc79526078d2c0f01445e54e1d9fdf7c15ffd63d Mon Sep 17 00:00:00 2001 From: Corentin Chary Date: Fri, 28 Aug 2009 12:56:51 +0000 Subject: asus-laptop: handle keyboard backlight keys Add support for the Fn+F3/Fn+F4 keys and map them as KEY_KBDILLUMUP and KEY_KBDILLUMDOWN. Signed-off-by: Corentin Chary Signed-off-by: Len Brown --- drivers/platform/x86/asus-laptop.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/asus-laptop.c b/drivers/platform/x86/asus-laptop.c index 0fb4e59..dd926b9 100644 --- a/drivers/platform/x86/asus-laptop.c +++ b/drivers/platform/x86/asus-laptop.c @@ -301,6 +301,8 @@ static struct key_entry asus_keymap[] = { {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}, }; -- cgit v1.1 From 4644d0e5bd1412bbaed77e46c0c3376c6d060a74 Mon Sep 17 00:00:00 2001 From: Corentin Chary Date: Fri, 28 Aug 2009 12:56:52 +0000 Subject: asus-laptop: Add suport for another "Media" key Signed-off-by: Corentin Chary Signed-off-by: Len Brown --- drivers/platform/x86/asus-laptop.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/asus-laptop.c b/drivers/platform/x86/asus-laptop.c index dd926b9..0325f7c 100644 --- a/drivers/platform/x86/asus-laptop.c +++ b/drivers/platform/x86/asus-laptop.c @@ -288,6 +288,7 @@ static struct key_entry asus_keymap[] = { {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, 0x5C, KEY_SCREENLOCK}, /* Screenlock */ -- cgit v1.1 From 0aa20f7d720ed1feeb74df8c63a6427d9a2d3ebd Mon Sep 17 00:00:00 2001 From: Corentin Chary Date: Fri, 28 Aug 2009 12:56:53 +0000 Subject: asus-laptop: Add "calculator" hotkey Found on UX50V. Signed-off-by: Corentin Chary Signed-off-by: Len Brown --- drivers/platform/x86/asus-laptop.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/asus-laptop.c b/drivers/platform/x86/asus-laptop.c index 0325f7c..5b912cc 100644 --- a/drivers/platform/x86/asus-laptop.c +++ b/drivers/platform/x86/asus-laptop.c @@ -291,6 +291,7 @@ static struct key_entry asus_keymap[] = { {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}, -- cgit v1.1 From aeb41b852fe90764b75ef7a9f185ca94696af6ff Mon Sep 17 00:00:00 2001 From: Len Brown Date: Fri, 28 Aug 2009 19:03:11 -0400 Subject: eeepc-laptop: whitespace for checkpatch.pl checkpatch doesn't like tab+space for a return statement. WARNING: suspect code indent for conditional statements (8, 17) + if (!device) + return -EINVAL; Signed-off-by: Len Brown --- drivers/platform/x86/eeepc-laptop.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/eeepc-laptop.c b/drivers/platform/x86/eeepc-laptop.c index c9febf4..819c685 100644 --- a/drivers/platform/x86/eeepc-laptop.c +++ b/drivers/platform/x86/eeepc-laptop.c @@ -1183,7 +1183,7 @@ static int eeepc_hotk_add(struct acpi_device *device) int result; if (!device) - return -EINVAL; + return -EINVAL; pr_notice(EEEPC_HOTK_NAME "\n"); ehotk = kzalloc(sizeof(struct eeepc_hotk), GFP_KERNEL); if (!ehotk) @@ -1265,7 +1265,7 @@ fail_platform_driver: static int eeepc_hotk_remove(struct acpi_device *device, int type) { if (!device || !acpi_driver_data(device)) - return -EINVAL; + return -EINVAL; eeepc_backlight_exit(); eeepc_rfkill_exit(); -- cgit v1.1 From be96666065fd36ccfa09a13903d31d7ff5f4ef91 Mon Sep 17 00:00:00 2001 From: Corentin Chary Date: Sat, 29 Aug 2009 10:28:29 +0200 Subject: asus-laptop: Fix coding style for comments Signed-off-by: Corentin Chary Signed-off-by: Len Brown --- drivers/platform/x86/asus-laptop.c | 108 +++++++++++++++++++++---------------- 1 file changed, 63 insertions(+), 45 deletions(-) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/asus-laptop.c b/drivers/platform/x86/asus-laptop.c index 5b912cc..b39d2bb 100644 --- a/drivers/platform/x86/asus-laptop.c +++ b/drivers/platform/x86/asus-laptop.c @@ -77,16 +77,16 @@ * 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_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 @@ -99,7 +99,8 @@ MODULE_AUTHOR("Julien Lerouge, Karol Kozimor, Corentin Chary"); MODULE_DESCRIPTION(ASUS_HOTK_NAME); MODULE_LICENSE("GPL"); -/* WAPF defines the behavior of the Fn+Fx wlan key +/* + * WAPF defines the behavior of the Fn+Fx wlan key * The significance of values is yet to be found, but * most of the time: * 0x0 will do nothing @@ -126,7 +127,8 @@ ASUS_HANDLE(gled_set, ASUS_HOTK_PREFIX "GLED"); /* G1, G2 (probably) */ /* LEDD */ ASUS_HANDLE(ledd_set, ASUS_HOTK_PREFIX "SLCM"); -/* Bluetooth and WLAN +/* + * Bluetooth and WLAN * WLED and BLED are not handled like other XLED, because in some dsdt * they also control the WLAN/Bluetooth device. */ @@ -150,22 +152,32 @@ ASUS_HANDLE(lcd_switch, "\\_SB.PCI0.SBRG.EC0._Q10", /* All new models */ /* Display */ ASUS_HANDLE(display_set, ASUS_HOTK_PREFIX "SDSP"); -ASUS_HANDLE(display_get, "\\_SB.PCI0.P0P1.VGA.GETD", /* A6B, A6K A6R A7D F3JM L4R M6R A3G - M6A M6V VX-1 V6J V6V W3Z */ - "\\_SB.PCI0.P0P2.VGA.GETD", /* A3E A4K, A4D A4L A6J A7J A8J Z71V M9V - S5A M5A z33A W1Jc W2V G1 */ - "\\_SB.PCI0.P0P3.VGA.GETD", /* A6V A6Q */ - "\\_SB.PCI0.P0PA.VGA.GETD", /* A6T, A6M */ - "\\_SB.PCI0.PCI1.VGAC.NMAP", /* L3C */ - "\\_SB.PCI0.VGA.GETD", /* Z96F */ - "\\ACTD", /* A2D */ - "\\ADVG", /* A4G Z71A W1N W5A W5F M2N M3N M5N M6N S1N S5N */ - "\\DNXT", /* P30 */ - "\\INFB", /* A2H D1 L2D L3D L3H L2E L5D L5C M1A M2E L4L W3V */ - "\\SSTE"); /* A3F A6F A3N A3L M6N W3N W6A */ - -ASUS_HANDLE(ls_switch, ASUS_HOTK_PREFIX "ALSC"); /* Z71A Z71V */ -ASUS_HANDLE(ls_level, ASUS_HOTK_PREFIX "ALSL"); /* Z71A Z71V */ +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"); + +ASUS_HANDLE(ls_switch, ASUS_HOTK_PREFIX "ALSC"); /* Z71A Z71V */ +ASUS_HANDLE(ls_level, ASUS_HOTK_PREFIX "ALSL"); /* Z71A Z71V */ /* GPS */ /* R2H use different handle for GPS on/off */ @@ -182,14 +194,14 @@ ASUS_HANDLE(kled_get, ASUS_HOTK_PREFIX "GLKB"); * about the hotk device */ struct asus_hotk { - char *name; //laptop name - 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, ... - 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 + char *name; /* laptop name */ + 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, ... */ + 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; }; @@ -242,10 +254,12 @@ static struct backlight_ops asusbl_ops = { .update_status = update_bl_status, }; -/* These functions actually update the LED's, and are called from a +/* + * 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. */ + * potentially bad time, such as a timer interrupt. + */ static struct workqueue_struct *led_workqueue; #define ASUS_LED(object, ledname, max) \ @@ -318,8 +332,8 @@ static struct key_entry asus_keymap[] = { static int write_acpi_int(acpi_handle handle, const char *method, int val, struct acpi_buffer *output) { - struct acpi_object_list params; //list of input parameters (an int here) - union acpi_object in_obj; //the only param we use + struct acpi_object_list params; /* list of input parameters (an int) */ + union acpi_object in_obj; /* the only param we use */ acpi_status status; if (!handle) @@ -574,7 +588,7 @@ static ssize_t show_infos(struct device *dev, { int len = 0; unsigned long long temp; - char buf[16]; //enough for all info + char buf[16]; /* enough for all info */ acpi_status rv = AE_OK; /* @@ -734,8 +748,10 @@ static int read_display(void) unsigned long long value = 0; acpi_status rv = AE_OK; - /* In most of the case, we know how to set the display, but sometime - we can't read it */ + /* + * In most of the case, we know how to set the display, but sometime + * we can't read it + */ if (display_get_handle) { rv = acpi_evaluate_integer(display_get_handle, NULL, NULL, &value); @@ -1152,8 +1168,10 @@ static int asus_hotk_get_info(void) 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. */ + /* + * 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); -- cgit v1.1 From a8258069793609903b5ebf0bca3320249154c379 Mon Sep 17 00:00:00 2001 From: Alan Jenkins Date: Sat, 29 Aug 2009 10:28:30 +0200 Subject: eeepc-laptop: fix rfkill memory leak on unload rfkill_unregister() should always be followed by rfkill_destroy() Signed-off-by: Alan Jenkins Signed-off-by: Corentin Chary Signed-off-by: Len Brown --- drivers/platform/x86/eeepc-laptop.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/eeepc-laptop.c b/drivers/platform/x86/eeepc-laptop.c index 819c685..6f9a448 100644 --- a/drivers/platform/x86/eeepc-laptop.c +++ b/drivers/platform/x86/eeepc-laptop.c @@ -985,6 +985,7 @@ static void eeepc_rfkill_exit(void) eeepc_unregister_rfkill_notifier("\\_SB.PCI0.P0P7"); if (ehotk->wlan_rfkill) { rfkill_unregister(ehotk->wlan_rfkill); + rfkill_destroy(ehotk->wlan_rfkill); ehotk->wlan_rfkill = NULL; } /* @@ -995,12 +996,21 @@ static void eeepc_rfkill_exit(void) if (ehotk->hotplug_slot) pci_hp_deregister(ehotk->hotplug_slot); - if (ehotk->bluetooth_rfkill) + if (ehotk->bluetooth_rfkill) { rfkill_unregister(ehotk->bluetooth_rfkill); - if (ehotk->wwan3g_rfkill) + rfkill_destroy(ehotk->bluetooth_rfkill); + ehotk->bluetooth_rfkill = NULL; + } + if (ehotk->wwan3g_rfkill) { rfkill_unregister(ehotk->wwan3g_rfkill); - if (ehotk->wimax_rfkill) + rfkill_destroy(ehotk->wwan3g_rfkill); + ehotk->wwan3g_rfkill = NULL; + } + if (ehotk->wimax_rfkill) { rfkill_unregister(ehotk->wimax_rfkill); + rfkill_destroy(ehotk->wimax_rfkill); + ehotk->wimax_rfkill = NULL; + } } static void eeepc_input_exit(void) -- cgit v1.1 From 52cc96bd5b61775db2792780c610979fc02313eb Mon Sep 17 00:00:00 2001 From: Alan Jenkins Date: Sat, 29 Aug 2009 10:28:31 +0200 Subject: eeepc-laptop: allow rfkill hotplug to work on the 900A model The 900A provides hotplug notifications on a different ACPI object to other models. Reported-by: Trevor Signed-off-by: Alan Jenkins Signed-off-by: Corentin Chary Signed-off-by: Len Brown --- drivers/platform/x86/eeepc-laptop.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/platform') diff --git a/drivers/platform/x86/eeepc-laptop.c b/drivers/platform/x86/eeepc-laptop.c index 6f9a448..da3c08b 100644 --- a/drivers/platform/x86/eeepc-laptop.c +++ b/drivers/platform/x86/eeepc-laptop.c @@ -981,6 +981,7 @@ static void eeepc_backlight_exit(void) static void eeepc_rfkill_exit(void) { + eeepc_unregister_rfkill_notifier("\\_SB.PCI0.P0P5"); eeepc_unregister_rfkill_notifier("\\_SB.PCI0.P0P6"); eeepc_unregister_rfkill_notifier("\\_SB.PCI0.P0P7"); if (ehotk->wlan_rfkill) { @@ -1101,6 +1102,7 @@ static int eeepc_rfkill_init(struct device *dev) if (result == -EBUSY) result = 0; + eeepc_register_rfkill_notifier("\\_SB.PCI0.P0P5"); eeepc_register_rfkill_notifier("\\_SB.PCI0.P0P6"); eeepc_register_rfkill_notifier("\\_SB.PCI0.P0P7"); /* -- cgit v1.1