diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index 55ca39d..6b84907 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -331,7 +331,6 @@ config EEEPC_LAPTOP depends on INPUT depends on EXPERIMENTAL depends on RFKILL || RFKILL = n - depends on HOTPLUG_PCI select BACKLIGHT_CLASS_DEVICE select HWMON ---help--- diff --git a/drivers/platform/x86/eeepc-laptop.c b/drivers/platform/x86/eeepc-laptop.c index 4226e53..294b7ae 100644 --- a/drivers/platform/x86/eeepc-laptop.c +++ b/drivers/platform/x86/eeepc-laptop.c @@ -32,8 +32,6 @@ #include #include #include -#include -#include #define EEEPC_LAPTOP_VERSION "0.1" @@ -66,7 +64,7 @@ enum { DISABLE_ASL_HWCF = 0x0800 }; -enum { +enum eeepc_cm { CM_ASL_WLAN = 0, CM_ASL_BLUETOOTH, CM_ASL_IRDA, @@ -139,18 +137,11 @@ struct eeepc_hotk { u16 event_count[128]; /* count for each event */ struct input_dev *inputdev; u16 *keycode_map; - 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; }; /* The actual device the driver binds to */ static struct eeepc_hotk *ehotk; -/* Platform device/driver */ static int eeepc_hotk_thaw(struct device *device); static int eeepc_hotk_restore(struct device *device); @@ -222,15 +213,6 @@ 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; @@ -247,6 +229,46 @@ static struct backlight_ops eeepcbl_ops = { .update_status = update_bl_status, }; + +/* + * Rfkill + */ + +struct eeepc_rfkill_t { + const char *name; + enum rfkill_type type; + enum eeepc_cm cm; + struct rfkill *rf; +}; + +static struct eeepc_rfkill_t eeepc_rfkill[] = { + { + .name = "eeepc-wlan", + .type = RFKILL_TYPE_WLAN, + .cm = CM_ASL_WLAN, + }, + { + .name = "eeepc-bluetooth", + .type = RFKILL_TYPE_BLUETOOTH, + .cm = CM_ASL_BLUETOOTH, + }, + { + .name = "eeepc-wwan3g", + .type = RFKILL_TYPE_WWAN, + .cm = CM_ASL_3G, + }, + { + .name = "eeepc-wimax", + .type = RFKILL_TYPE_WIMAX, + .cm = CM_ASL_WIMAX, + }, +}; + +static int eeepc_rfkill_set(void *data, bool blocked); +static struct rfkill_ops eeepc_rfkill_ops = { + .set_block = eeepc_rfkill_set, +}; + MODULE_AUTHOR("Corentin Chary, Eric Cooper"); MODULE_DESCRIPTION(EEEPC_HOTK_NAME); MODULE_LICENSE("GPL"); @@ -329,35 +351,13 @@ static int update_bl_status(struct backlight_device *bd) return set_brightness(bd, bd->props.brightness); } -/* - * Rfkill helpers - */ - -static bool eeepc_wlan_rfkill_blocked(void) -{ - if (get_acpi(CM_ASL_WLAN) == 1) - return false; - return true; -} - -static int eeepc_rfkill_set(void *data, bool blocked) -{ - unsigned long asl = (unsigned long)data; - return set_acpi(asl, !blocked); -} - -static const struct rfkill_ops eeepc_rfkill_ops = { - .set_block = eeepc_rfkill_set, -}; - static void __devinit eeepc_enable_camera(void) { /* * If the following call to set_acpi() fails, it's because there's no * camera so we can ignore the error. */ - if (get_acpi(CM_ASL_CAMERA) == 0) - set_acpi(CM_ASL_CAMERA, 1); + set_acpi(CM_ASL_CAMERA, 1); } /* @@ -631,71 +631,6 @@ 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_hotplug(void) -{ - struct pci_dev *dev; - struct pci_bus *bus; - bool blocked = eeepc_wlan_rfkill_blocked(); - - if (ehotk->wlan_rfkill) - rfkill_set_sw_state(ehotk->wlan_rfkill, blocked); - - mutex_lock(&ehotk->hotplug_lock); - - if (ehotk->hotplug_slot) { - 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); - 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); - } - } - } - -out_unlock: - mutex_unlock(&ehotk->hotplug_lock); -} - -static void eeepc_rfkill_notify(acpi_handle handle, u32 event, void *data) -{ - if (event != ACPI_NOTIFY_BUS_CHECK) - return; - - eeepc_rfkill_hotplug(); -} - static void eeepc_hotk_notify(struct acpi_device *device, u32 event) { static struct key_entry *key; @@ -745,127 +680,6 @@ static void eeepc_hotk_notify(struct acpi_device *device, u32 event) } } -static int eeepc_register_rfkill_notifier(char *node) -{ - acpi_status status = AE_OK; - acpi_handle handle; - - status = acpi_get_handle(NULL, node, &handle); - - if (ACPI_SUCCESS(status)) { - status = acpi_install_notify_handler(handle, - ACPI_SYSTEM_NOTIFY, - eeepc_rfkill_notify, - NULL); - if (ACPI_FAILURE(status)) - pr_warning("Failed to register notify on %s\n", node); - } else - return -ENODEV; - - return 0; -} - -static void eeepc_unregister_rfkill_notifier(char *node) -{ - acpi_status status = AE_OK; - acpi_handle handle; - - status = acpi_get_handle(NULL, node, &handle); - - if (ACPI_SUCCESS(status)) { - status = acpi_remove_notify_handler(handle, - ACPI_SYSTEM_NOTIFY, - eeepc_rfkill_notify); - if (ACPI_FAILURE(status)) - pr_err("Error removing rfkill notify handler %s\n", - 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) { - pr_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) { - pr_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_thaw(struct device *device) -{ - if (ehotk->wlan_rfkill) { - bool wlan; - - /* - * 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 hibernation is aborted. - */ - wlan = get_acpi(CM_ASL_WLAN); - set_acpi(CM_ASL_WLAN, wlan); - } - - return 0; -} - -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, - get_acpi(CM_ASL_BLUETOOTH) != 1); - 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; -} - /* * Hwmon */ @@ -971,48 +785,50 @@ static struct attribute_group hwmon_attribute_group = { }; /* - * exit/init + * Rfkill */ -static void eeepc_backlight_exit(void) +static int eeepc_rfkill_set(void *data, bool blocked) { - if (eeepc_backlight_device) - backlight_device_unregister(eeepc_backlight_device); - eeepc_backlight_device = NULL; + enum eeepc_cm cm = (enum eeepc_cm)data; + return set_acpi(cm, !blocked); } -static void eeepc_rfkill_exit(void) +static int eeepc_hotk_restore(struct device *device) { - 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) { - rfkill_unregister(ehotk->wlan_rfkill); - rfkill_destroy(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); - rfkill_destroy(ehotk->bluetooth_rfkill); - ehotk->bluetooth_rfkill = NULL; - } - if (ehotk->wwan3g_rfkill) { - rfkill_unregister(ehotk->wwan3g_rfkill); - rfkill_destroy(ehotk->wwan3g_rfkill); - ehotk->wwan3g_rfkill = NULL; + struct eeepc_rfkill_t *i; + for(i = &(eeepc_rfkill[0]); + i < &(eeepc_rfkill[sizeof(eeepc_rfkill)/sizeof(struct eeepc_rfkill_t)]); + ++i) + { + if ( i->rf ) + rfkill_set_sw_state(i->rf, get_acpi(i->cm) != 1); } - if (ehotk->wimax_rfkill) { - rfkill_unregister(ehotk->wimax_rfkill); - rfkill_destroy(ehotk->wimax_rfkill); - ehotk->wimax_rfkill = NULL; + return 0; +} + +static int eeepc_hotk_thaw(struct device *device) +{ + if (eeepc_rfkill[0].rf) { + /* + * 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 hibernation is aborted. + */ + set_acpi(CM_ASL_WLAN, get_acpi(CM_ASL_WLAN)); } + + return 0; +} + + +/* + * exit/init + */ +static void eeepc_backlight_exit(void) +{ + if (eeepc_backlight_device) + backlight_device_unregister(eeepc_backlight_device); + eeepc_backlight_device = NULL; } static void eeepc_input_exit(void) @@ -1034,88 +850,20 @@ static void eeepc_hwmon_exit(void) eeepc_hwmon_device = NULL; } -static int eeepc_new_rfkill(struct rfkill **rfkill, - const char *name, struct device *dev, - enum rfkill_type type, int cm) +static void eeepc_rfkill_exit(void) { - int result; - - result = get_acpi(cm); - if (result < 0) - return result; - - *rfkill = rfkill_alloc(name, dev, type, - &eeepc_rfkill_ops, (void *)(unsigned long)cm); - - if (!*rfkill) - return -EINVAL; - - rfkill_init_sw_state(*rfkill, get_acpi(cm) != 1); - result = rfkill_register(*rfkill); - if (result) { - rfkill_destroy(*rfkill); - *rfkill = NULL; - return result; + struct eeepc_rfkill_t *i; + for(i = &(eeepc_rfkill[0]); + i < &(eeepc_rfkill[sizeof(eeepc_rfkill)/sizeof(struct eeepc_rfkill_t)]); + ++i) + { + if ( i->rf ) + { + rfkill_unregister(i->rf); + rfkill_destroy(i->rf); + i->rf = NULL; + } } - return 0; -} - - -static int eeepc_rfkill_init(struct device *dev) -{ - int result = 0; - - mutex_init(&ehotk->hotplug_lock); - - result = eeepc_new_rfkill(&ehotk->wlan_rfkill, - "eeepc-wlan", dev, - RFKILL_TYPE_WLAN, CM_ASL_WLAN); - - if (result && result != -ENODEV) - goto exit; - - result = eeepc_new_rfkill(&ehotk->bluetooth_rfkill, - "eeepc-bluetooth", dev, - RFKILL_TYPE_BLUETOOTH, CM_ASL_BLUETOOTH); - - if (result && result != -ENODEV) - goto exit; - - result = eeepc_new_rfkill(&ehotk->wwan3g_rfkill, - "eeepc-wwan3g", dev, - RFKILL_TYPE_WWAN, CM_ASL_3G); - - 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 - - * don't fail in this case - */ - 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"); - /* - * Refresh pci hotplug in case the rfkill state was changed during - * setup. - */ - eeepc_rfkill_hotplug(); - -exit: - if (result && result != -ENODEV) - eeepc_rfkill_exit(); - return result; } static int eeepc_backlight_init(struct device *dev) @@ -1190,13 +938,68 @@ static int eeepc_input_init(struct device *dev) return 0; } +static int eeepc_rfkill_new(struct eeepc_rfkill_t *rfk, + struct device *dev) +{ + int ret = 0; + if ( get_acpi(rfk->cm) < 0 ) + { + ret = -ENODEV; + goto eeepc_rfkill_new_end; + } + + rfk->rf = rfkill_alloc(rfk->name, + dev, + rfk->type, + &eeepc_rfkill_ops, + (void *)rfk->cm); + if ( unlikely(!(rfk->rf)) ) + { + pr_notice("can't alloc rfkill for %s", rfk->name); + ret = -EINVAL; + goto eeepc_rfkill_new_end; + } + + rfkill_init_sw_state(rfk->rf, get_acpi(rfk->cm) != 1); + ret = rfkill_register(rfk->rf); + if ( unlikely(ret) ) + { + pr_notice("can't register rfkill for %s", rfk->name); + rfkill_destroy(rfk->rf); + rfk->rf = NULL; + } + +eeepc_rfkill_new_end: + return ret; +} + +static int eeepc_rfkill_init(struct device *dev) +{ + int ret = 0; + struct eeepc_rfkill_t *i; + for(i = &(eeepc_rfkill[0]); + i < &(eeepc_rfkill[sizeof(eeepc_rfkill)/sizeof(struct eeepc_rfkill_t)]); + ++i) + { + ret = eeepc_rfkill_new(i, dev); + if ( ret ) + { + if (unlikely(ret != -ENODEV)) + break; + else + ret = 0; + } + } + return ret; +} + static int __devinit eeepc_hotk_add(struct acpi_device *device) { struct device *dev; int result; if (!device) - return -EINVAL; + return -EINVAL; pr_notice(EEEPC_HOTK_NAME "\n"); ehotk = kzalloc(sizeof(struct eeepc_hotk), GFP_KERNEL); if (!ehotk) @@ -1249,7 +1052,7 @@ static int __devinit eeepc_hotk_add(struct acpi_device *device) goto fail_hwmon; result = eeepc_rfkill_init(dev); - if (result) + if (unlikely(result)) goto fail_rfkill; return 0; @@ -1278,10 +1081,10 @@ 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(); + eeepc_backlight_exit(); eeepc_input_exit(); eeepc_hwmon_exit(); sysfs_remove_group(&platform_device->dev.kobj,