From patchwork Tue Jun 16 19:28:42 2009 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Corentin Chary X-Patchwork-Id: 30659 X-Patchwork-Delegate: lenb@kernel.org Received: from vger.kernel.org (vger.kernel.org [209.132.176.167]) by demeter.kernel.org (8.14.2/8.14.2) with ESMTP id n5GJVQiH004683 for ; Tue, 16 Jun 2009 19:31:28 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751798AbZFPTbY (ORCPT ); Tue, 16 Jun 2009 15:31:24 -0400 Received: (majordomo@vger.kernel.org) by vger.kernel.org id S1752647AbZFPTbX (ORCPT ); Tue, 16 Jun 2009 15:31:23 -0400 Received: from iksaif.net ([88.191.73.63]:60962 "EHLO iksaif.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751798AbZFPTbW (ORCPT ); Tue, 16 Jun 2009 15:31:22 -0400 Received: from localhost.localdomain (cxr69-11-88-180-139-205.fbx.proxad.net [88.180.139.205]) (Authenticated sender: corentincj@iksaif.net) by iksaif.net (Postfix) with ESMTPA id 92B97C90020; Tue, 16 Jun 2009 21:33:51 +0200 (CEST) From: Corentin Chary To: lenb@kernel.org Cc: linux-acpi@vger.kernel.org, Matthew Garrett , Matthew Garrett , Corentin Chary , Len Brown Subject: [PATCH 01/15] eeepc-laptop: Register as a pci-hotplug device Date: Tue, 16 Jun 2009 21:28:42 +0200 Message-Id: <1245180536-28009-2-git-send-email-corentincj@iksaif.net> X-Mailer: git-send-email 1.6.3.1 In-Reply-To: <1245180536-28009-1-git-send-email-corentincj@iksaif.net> References: <1245180536-28009-1-git-send-email-corentincj@iksaif.net> Sender: linux-acpi-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-acpi@vger.kernel.org From: Matthew Garrett The eee contains a logically (but not physically) hotpluggable PCIe slot. Currently this is handled by adding or removing the PCI device in response to rfkill events, but if a user has forced pciehp to bind to it (with the force=1 argument) then both drivers will try to handle the event and hilarity (in the form of oopses) will ensue. This can be avoided by having eee-laptop register the slot as a hotplug slot. Only one of pciehp and eee-laptop will successfully register this, avoiding the problem. Signed-off-by: Matthew Garrett Signed-off-by: Corentin Chary Tested-by: Darren Salt Signed-off-by: Len Brown --- drivers/platform/x86/Kconfig | 1 + drivers/platform/x86/eeepc-laptop.c | 87 +++++++++++++++++++++++++++++++++++ 2 files changed, 88 insertions(+), 0 deletions(-) diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index 284ebac..afbe441 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -341,6 +341,7 @@ config EEEPC_LAPTOP select BACKLIGHT_CLASS_DEVICE select HWMON select RFKILL + select HOTPLUG_PCI ---help--- This driver supports the Fn-Fx keys on Eee PC laptops. It also adds the ability to switch camera/wlan on/off. diff --git a/drivers/platform/x86/eeepc-laptop.c b/drivers/platform/x86/eeepc-laptop.c index 353a898..a0845b2 100644 --- a/drivers/platform/x86/eeepc-laptop.c +++ b/drivers/platform/x86/eeepc-laptop.c @@ -31,6 +31,7 @@ #include #include #include +#include #define EEEPC_LAPTOP_VERSION "0.1" @@ -132,6 +133,7 @@ struct eeepc_hotk { u16 *keycode_map; struct rfkill *eeepc_wlan_rfkill; struct rfkill *eeepc_bluetooth_rfkill; + struct hotplug_slot *hotplug_slot; }; /* The actual device the driver binds to */ @@ -197,6 +199,15 @@ static struct acpi_driver eeepc_hotk_driver = { }, }; +/* PCI hotplug ops */ +static int eeepc_get_adapter_status(struct hotplug_slot *slot, u8 *value); + +static struct hotplug_slot_ops eeepc_hotplug_slot_ops = { + .owner = THIS_MODULE, + .get_adapter_status = eeepc_get_adapter_status, + .get_power_status = eeepc_get_adapter_status, +}; + /* The backlight device /sys/class/backlight */ static struct backlight_device *eeepc_backlight_device; @@ -529,6 +540,19 @@ static int notify_brn(void) return -1; } +static int eeepc_get_adapter_status(struct hotplug_slot *hotplug_slot, + u8 *value) +{ + int val = get_acpi(CM_ASL_WLAN); + + if (val == 1 || val == 0) + *value = val; + else + return -EINVAL; + + return 0; +} + static void eeepc_rfkill_notify(acpi_handle handle, u32 event, void *data) { enum rfkill_state state; @@ -655,6 +679,54 @@ static void eeepc_unregister_rfkill_notifier(char *node) } } +static void eeepc_cleanup_pci_hotplug(struct hotplug_slot *hotplug_slot) +{ + kfree(hotplug_slot->info); + kfree(hotplug_slot); +} + +static int eeepc_setup_pci_hotplug(void) +{ + int ret = -ENOMEM; + struct pci_bus *bus = pci_find_bus(0, 1); + + if (!bus) { + printk(EEEPC_ERR "Unable to find wifi PCI bus\n"); + return -ENODEV; + } + + ehotk->hotplug_slot = kzalloc(sizeof(struct hotplug_slot), GFP_KERNEL); + if (!ehotk->hotplug_slot) + goto error_slot; + + ehotk->hotplug_slot->info = kzalloc(sizeof(struct hotplug_slot_info), + GFP_KERNEL); + if (!ehotk->hotplug_slot->info) + goto error_info; + + ehotk->hotplug_slot->private = ehotk; + ehotk->hotplug_slot->release = &eeepc_cleanup_pci_hotplug; + ehotk->hotplug_slot->ops = &eeepc_hotplug_slot_ops; + eeepc_get_adapter_status(ehotk->hotplug_slot, + &ehotk->hotplug_slot->info->adapter_status); + + ret = pci_hp_register(ehotk->hotplug_slot, bus, 0, "eeepc-wifi"); + if (ret) { + printk(EEEPC_ERR "Unable to register hotplug slot - %d\n", ret); + goto error_register; + } + + return 0; + +error_register: + kfree(ehotk->hotplug_slot->info); +error_info: + kfree(ehotk->hotplug_slot); + ehotk->hotplug_slot = NULL; +error_slot: + return ret; +} + static int eeepc_hotk_add(struct acpi_device *device) { acpi_status status = AE_OK; @@ -738,8 +810,21 @@ static int eeepc_hotk_add(struct acpi_device *device) goto bluetooth_fail; } + result = eeepc_setup_pci_hotplug(); + /* + * If we get -EBUSY then something else is handling the PCI hotplug - + * don't fail in this case + */ + if (result == -EBUSY) + return 0; + else if (result) + goto pci_fail; + return 0; + pci_fail: + if (ehotk->eeepc_bluetooth_rfkill) + rfkill_unregister(ehotk->eeepc_bluetooth_rfkill); bluetooth_fail: if (ehotk->eeepc_bluetooth_rfkill) rfkill_free(ehotk->eeepc_bluetooth_rfkill); @@ -770,6 +855,8 @@ static int eeepc_hotk_remove(struct acpi_device *device, int type) eeepc_unregister_rfkill_notifier("\\_SB.PCI0.P0P6"); eeepc_unregister_rfkill_notifier("\\_SB.PCI0.P0P7"); + if (ehotk->hotplug_slot) + pci_hp_deregister(ehotk->hotplug_slot); kfree(ehotk); return 0;