diff options
Diffstat (limited to 'drivers/platform/x86/wmi.c')
-rw-r--r-- | drivers/platform/x86/wmi.c | 143 |
1 files changed, 34 insertions, 109 deletions
diff --git a/drivers/platform/x86/wmi.c b/drivers/platform/x86/wmi.c index 1d0b2d6040d1..3cbe180c3fc0 100644 --- a/drivers/platform/x86/wmi.c +++ b/drivers/platform/x86/wmi.c @@ -166,22 +166,6 @@ static inline acpi_object_type get_param_acpi_type(const struct wmi_block *wbloc return ACPI_TYPE_BUFFER; } -static acpi_status get_event_data(const struct wmi_block *wblock, struct acpi_buffer *out) -{ - union acpi_object param = { - .integer = { - .type = ACPI_TYPE_INTEGER, - .value = wblock->gblock.notify_id, - } - }; - struct acpi_object_list input = { - .count = 1, - .pointer = ¶m, - }; - - return acpi_evaluate_object(wblock->acpi_device->handle, "_WED", &input, out); -} - static int wmidev_match_guid(struct device *dev, const void *data) { struct wmi_block *wblock = dev_to_wblock(dev); @@ -199,23 +183,6 @@ static int wmidev_match_guid(struct device *dev, const void *data) return 0; } -static int wmidev_match_notify_id(struct device *dev, const void *data) -{ - struct wmi_block *wblock = dev_to_wblock(dev); - const u32 *notify_id = data; - - /* Legacy GUID-based functions are restricted to only see - * a single WMI device for each GUID. - */ - if (test_bit(WMI_GUID_DUPLICATED, &wblock->flags)) - return 0; - - if (wblock->gblock.flags & ACPI_WMI_EVENT && wblock->gblock.notify_id == *notify_id) - return 1; - - return 0; -} - static const struct bus_type wmi_bus_type; static struct wmi_device *wmi_find_device_by_guid(const char *guid_string) @@ -235,17 +202,6 @@ static struct wmi_device *wmi_find_device_by_guid(const char *guid_string) return dev_to_wdev(dev); } -static struct wmi_device *wmi_find_event_by_notify_id(const u32 notify_id) -{ - struct device *dev; - - dev = bus_find_device(&wmi_bus_type, NULL, ¬ify_id, wmidev_match_notify_id); - if (!dev) - return ERR_PTR(-ENODEV); - - return to_wmi_device(dev); -} - static void wmi_device_put(struct wmi_device *wdev) { put_device(&wdev->dev); @@ -650,35 +606,6 @@ acpi_status wmi_remove_notify_handler(const char *guid) EXPORT_SYMBOL_GPL(wmi_remove_notify_handler); /** - * wmi_get_event_data - Get WMI data associated with an event (deprecated) - * - * @event: Event to find - * @out: Buffer to hold event data - * - * Get extra data associated with an WMI event, the caller needs to free @out. - * - * Return: acpi_status signaling success or error. - */ -acpi_status wmi_get_event_data(u32 event, struct acpi_buffer *out) -{ - struct wmi_block *wblock; - struct wmi_device *wdev; - acpi_status status; - - wdev = wmi_find_event_by_notify_id(event); - if (IS_ERR(wdev)) - return AE_NOT_FOUND; - - wblock = container_of(wdev, struct wmi_block, dev); - status = get_event_data(wblock, out); - - wmi_device_put(wdev); - - return status; -} -EXPORT_SYMBOL_GPL(wmi_get_event_data); - -/** * wmi_has_guid - Check if a GUID is available * @guid_string: 36 char string of the form fa50ff2b-f2e8-45de-83fa-65417f2f49ba * @@ -1186,14 +1113,19 @@ static int parse_wdg(struct device *wmi_bus_dev, struct platform_device *pdev) static int wmi_get_notify_data(struct wmi_block *wblock, union acpi_object **obj) { struct acpi_buffer data = { ACPI_ALLOCATE_BUFFER, NULL }; + union acpi_object param = { + .integer = { + .type = ACPI_TYPE_INTEGER, + .value = wblock->gblock.notify_id, + } + }; + struct acpi_object_list input = { + .count = 1, + .pointer = ¶m, + }; acpi_status status; - if (test_bit(WMI_NO_EVENT_DATA, &wblock->flags)) { - *obj = NULL; - return 0; - } - - status = get_event_data(wblock, &data); + status = acpi_evaluate_object(wblock->acpi_device->handle, "_WED", &input, &data); if (ACPI_FAILURE(status)) { dev_warn(&wblock->dev.dev, "Failed to get event data\n"); return -EIO; @@ -1220,47 +1152,40 @@ static void wmi_notify_driver(struct wmi_block *wblock, union acpi_object *obj) static int wmi_notify_device(struct device *dev, void *data) { struct wmi_block *wblock = dev_to_wblock(dev); - union acpi_object *obj; + union acpi_object *obj = NULL; u32 *event = data; int ret; if (!(wblock->gblock.flags & ACPI_WMI_EVENT && wblock->gblock.notify_id == *event)) return 0; - down_read(&wblock->notify_lock); - /* The WMI driver notify handler conflicts with the legacy WMI handler. - * Because of this the WMI driver notify handler takes precedence. + /* The ACPI WMI specification says that _WED should be + * evaluated every time an notification is received, even + * if no consumers are present. + * + * Some firmware implementations actually depend on this + * by using a queue for events which will fill up if the + * WMI driver core stops evaluating _WED due to missing + * WMI event consumers. */ - if (wblock->dev.dev.driver && wblock->driver_ready) { + if (!test_bit(WMI_NO_EVENT_DATA, &wblock->flags)) { ret = wmi_get_notify_data(wblock, &obj); - if (ret >= 0) { - wmi_notify_driver(wblock, obj); - kfree(obj); - } - } else { - if (wblock->handler) { - wblock->handler(*event, wblock->handler_data); - } else { - /* The ACPI WMI specification says that _WED should be - * evaluated every time an notification is received, even - * if no consumers are present. - * - * Some firmware implementations actually depend on this - * by using a queue for events which will fill up if the - * WMI driver core stops evaluating _WED due to missing - * WMI event consumers. - * - * Because of this we need this seemingly useless call to - * wmi_get_notify_data() which in turn evaluates _WED. - */ - ret = wmi_get_notify_data(wblock, &obj); - if (ret >= 0) - kfree(obj); - } - + if (ret < 0) + return -EIO; } + + down_read(&wblock->notify_lock); + + if (wblock->dev.dev.driver && wblock->driver_ready) + wmi_notify_driver(wblock, obj); + + if (wblock->handler) + wblock->handler(obj, wblock->handler_data); + up_read(&wblock->notify_lock); + kfree(obj); + acpi_bus_generate_netlink_event("wmi", acpi_dev_name(wblock->acpi_device), *event, 0); return -EBUSY; |