summaryrefslogtreecommitdiff
path: root/drivers/platform/x86/wmi.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/platform/x86/wmi.c')
-rw-r--r--drivers/platform/x86/wmi.c464
1 files changed, 200 insertions, 264 deletions
diff --git a/drivers/platform/x86/wmi.c b/drivers/platform/x86/wmi.c
index 1920e115da89..e46453750d5f 100644
--- a/drivers/platform/x86/wmi.c
+++ b/drivers/platform/x86/wmi.c
@@ -22,7 +22,6 @@
#include <linux/device.h>
#include <linux/init.h>
#include <linux/kernel.h>
-#include <linux/list.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/rwsem.h>
@@ -37,8 +36,6 @@ MODULE_AUTHOR("Carlos Corbacho");
MODULE_DESCRIPTION("ACPI-WMI Mapping Driver");
MODULE_LICENSE("GPL");
-static LIST_HEAD(wmi_block_list);
-
struct guid_block {
guid_t guid;
union {
@@ -63,7 +60,6 @@ enum { /* wmi_block flags */
struct wmi_block {
struct wmi_device dev;
- struct list_head list;
struct guid_block gblock;
struct acpi_device *acpi_device;
struct rw_semaphore notify_lock; /* Protects notify callback add/remove */
@@ -73,6 +69,10 @@ struct wmi_block {
unsigned long flags;
};
+struct wmi_guid_count_context {
+ const guid_t *guid;
+ int count;
+};
/*
* If the GUID data block is marked as expensive, we must enable and
@@ -91,7 +91,6 @@ static const struct acpi_device_id wmi_device_ids[] = {
MODULE_DEVICE_TABLE(acpi, wmi_device_ids);
#define dev_to_wblock(__dev) container_of_const(__dev, struct wmi_block, dev.dev)
-#define dev_to_wdev(__dev) container_of_const(__dev, struct wmi_device, dev)
/*
* GUID parsing functions
@@ -124,24 +123,6 @@ static const void *find_guid_context(struct wmi_block *wblock,
return NULL;
}
-static acpi_status wmi_method_enable(struct wmi_block *wblock, bool enable)
-{
- struct guid_block *block;
- char method[5];
- acpi_status status;
- acpi_handle handle;
-
- block = &wblock->gblock;
- handle = wblock->acpi_device->handle;
-
- snprintf(method, 5, "WE%02X", block->notify_id);
- status = acpi_execute_simple_method(handle, method, enable);
- if (status == AE_NOT_FOUND)
- return AE_OK;
-
- return status;
-}
-
#define WMI_ACPI_METHOD_NAME_SIZE 5
static inline void get_acpi_method_name(const struct wmi_block *wblock,
@@ -166,22 +147,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 = &param,
- };
-
- 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,25 +164,46 @@ 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)
+static const struct bus_type wmi_bus_type;
+
+static const struct device_type wmi_type_event;
+
+static const struct device_type wmi_type_method;
+
+static int wmi_device_enable(struct wmi_device *wdev, bool enable)
{
- struct wmi_block *wblock = dev_to_wblock(dev);
- const u32 *notify_id = data;
+ struct wmi_block *wblock = container_of(wdev, struct wmi_block, dev);
+ char method[WMI_ACPI_METHOD_NAME_SIZE];
+ acpi_handle handle;
+ acpi_status status;
- /* Legacy GUID-based functions are restricted to only see
- * a single WMI device for each GUID.
+ if (!(wblock->gblock.flags & ACPI_WMI_EXPENSIVE))
+ return 0;
+
+ if (wblock->dev.dev.type == &wmi_type_method)
+ return 0;
+
+ if (wblock->dev.dev.type == &wmi_type_event)
+ snprintf(method, sizeof(method), "WE%02X", wblock->gblock.notify_id);
+ else
+ get_acpi_method_name(wblock, 'C', method);
+
+ /*
+ * Not all WMI devices marked as expensive actually implement the
+ * necessary ACPI method. Ignore this missing ACPI method to match
+ * the behaviour of the Windows driver.
*/
- if (test_bit(WMI_GUID_DUPLICATED, &wblock->flags))
+ status = acpi_get_handle(wblock->acpi_device->handle, method, &handle);
+ if (ACPI_FAILURE(status))
return 0;
- if (wblock->gblock.flags & ACPI_WMI_EVENT && wblock->gblock.notify_id == *notify_id)
- return 1;
+ status = acpi_execute_simple_method(handle, NULL, enable);
+ if (ACPI_FAILURE(status))
+ return -EIO;
return 0;
}
-static const struct bus_type wmi_bus_type;
-
static struct wmi_device *wmi_find_device_by_guid(const char *guid_string)
{
struct device *dev;
@@ -232,17 +218,6 @@ static struct wmi_device *wmi_find_device_by_guid(const char *guid_string)
if (!dev)
return ERR_PTR(-ENODEV);
- 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, &notify_id, wmidev_match_notify_id);
- if (!dev)
- return ERR_PTR(-ENODEV);
-
return to_wmi_device(dev);
}
@@ -382,10 +357,8 @@ static acpi_status __query_block(struct wmi_block *wblock, u8 instance,
{
struct guid_block *block;
acpi_handle handle;
- acpi_status status, wc_status = AE_ERROR;
struct acpi_object_list input;
union acpi_object wq_params[1];
- char wc_method[WMI_ACPI_METHOD_NAME_SIZE];
char method[WMI_ACPI_METHOD_NAME_SIZE];
if (!out)
@@ -409,40 +382,9 @@ static acpi_status __query_block(struct wmi_block *wblock, u8 instance,
if (instance == 0 && test_bit(WMI_READ_TAKES_NO_ARGS, &wblock->flags))
input.count = 0;
- /*
- * If ACPI_WMI_EXPENSIVE, call the relevant WCxx method first to
- * enable collection.
- */
- if (block->flags & ACPI_WMI_EXPENSIVE) {
- get_acpi_method_name(wblock, 'C', wc_method);
-
- /*
- * Some GUIDs break the specification by declaring themselves
- * expensive, but have no corresponding WCxx method. So we
- * should not fail if this happens.
- */
- wc_status = acpi_execute_simple_method(handle, wc_method, 1);
- }
-
get_acpi_method_name(wblock, 'Q', method);
- status = acpi_evaluate_object(handle, method, &input, out);
- /*
- * If ACPI_WMI_EXPENSIVE, call the relevant WCxx method, even if
- * the WQxx method failed - we should disable collection anyway.
- */
- if ((block->flags & ACPI_WMI_EXPENSIVE) && ACPI_SUCCESS(wc_status)) {
- /*
- * Ignore whether this WCxx call succeeds or not since
- * the previously executed WQxx method call might have
- * succeeded, and returning the failing status code
- * of this call would throw away the result of the WQxx
- * call, potentially leaking memory.
- */
- acpi_execute_simple_method(handle, wc_method, 0);
- }
-
- return status;
+ return acpi_evaluate_object(handle, method, &input, out);
}
/**
@@ -466,9 +408,15 @@ acpi_status wmi_query_block(const char *guid_string, u8 instance,
if (IS_ERR(wdev))
return AE_ERROR;
+ if (wmi_device_enable(wdev, true) < 0)
+ dev_warn(&wdev->dev, "Failed to enable device\n");
+
wblock = container_of(wdev, struct wmi_block, dev);
status = __query_block(wblock, instance, out);
+ if (wmi_device_enable(wdev, false) < 0)
+ dev_warn(&wdev->dev, "Failed to disable device\n");
+
wmi_device_put(wdev);
return status;
@@ -515,7 +463,14 @@ acpi_status wmi_set_block(const char *guid_string, u8 instance, const struct acp
if (IS_ERR(wdev))
return AE_ERROR;
+ if (wmi_device_enable(wdev, true) < 0)
+ dev_warn(&wdev->dev, "Failed to enable device\n");
+
status = wmidev_block_set(wdev, instance, in);
+
+ if (wmi_device_enable(wdev, false) < 0)
+ dev_warn(&wdev->dev, "Failed to disable device\n");
+
wmi_device_put(wdev);
return status;
@@ -596,7 +551,7 @@ acpi_status wmi_install_notify_handler(const char *guid,
wblock->handler = handler;
wblock->handler_data = data;
- if (ACPI_FAILURE(wmi_method_enable(wblock, true)))
+ if (wmi_device_enable(wdev, true) < 0)
dev_warn(&wblock->dev.dev, "Failed to enable device\n");
status = AE_OK;
@@ -633,7 +588,7 @@ acpi_status wmi_remove_notify_handler(const char *guid)
if (!wblock->handler) {
status = AE_NULL_ENTRY;
} else {
- if (ACPI_FAILURE(wmi_method_enable(wblock, false)))
+ if (wmi_device_enable(wdev, false) < 0)
dev_warn(&wblock->dev.dev, "Failed to disable device\n");
wblock->handler = NULL;
@@ -650,35 +605,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
*
@@ -727,11 +653,6 @@ char *wmi_get_acpi_device_uid(const char *guid_string)
}
EXPORT_SYMBOL_GPL(wmi_get_acpi_device_uid);
-static inline struct wmi_driver *drv_to_wdrv(struct device_driver *drv)
-{
- return container_of(drv, struct wmi_driver, driver);
-}
-
/*
* sysfs interface
*/
@@ -772,11 +693,39 @@ static ssize_t expensive_show(struct device *dev,
}
static DEVICE_ATTR_RO(expensive);
+static ssize_t driver_override_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct wmi_device *wdev = to_wmi_device(dev);
+ ssize_t ret;
+
+ device_lock(dev);
+ ret = sysfs_emit(buf, "%s\n", wdev->driver_override);
+ device_unlock(dev);
+
+ return ret;
+}
+
+static ssize_t driver_override_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct wmi_device *wdev = to_wmi_device(dev);
+ int ret;
+
+ ret = driver_set_override(dev, &wdev->driver_override, buf, count);
+ if (ret < 0)
+ return ret;
+
+ return count;
+}
+static DEVICE_ATTR_RW(driver_override);
+
static struct attribute *wmi_attrs[] = {
&dev_attr_modalias.attr,
&dev_attr_guid.attr,
&dev_attr_instance_count.attr,
&dev_attr_expensive.attr,
+ &dev_attr_driver_override.attr,
NULL
};
ATTRIBUTE_GROUPS(wmi);
@@ -809,7 +758,7 @@ static DEVICE_ATTR_RO(object_id);
static ssize_t setable_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
- struct wmi_device *wdev = dev_to_wdev(dev);
+ struct wmi_device *wdev = to_wmi_device(dev);
return sysfs_emit(buf, "%d\n", (int)wdev->setable);
}
@@ -845,15 +794,20 @@ static void wmi_dev_release(struct device *dev)
{
struct wmi_block *wblock = dev_to_wblock(dev);
+ kfree(wblock->dev.driver_override);
kfree(wblock);
}
-static int wmi_dev_match(struct device *dev, struct device_driver *driver)
+static int wmi_dev_match(struct device *dev, const struct device_driver *driver)
{
- struct wmi_driver *wmi_driver = drv_to_wdrv(driver);
+ const struct wmi_driver *wmi_driver = to_wmi_driver(driver);
struct wmi_block *wblock = dev_to_wblock(dev);
const struct wmi_device_id *id = wmi_driver->id_table;
+ /* When driver_override is set, only bind to the matching driver */
+ if (wblock->dev.driver_override)
+ return !strcmp(wblock->dev.driver_override, driver->name);
+
if (id == NULL)
return 0;
@@ -867,11 +821,19 @@ static int wmi_dev_match(struct device *dev, struct device_driver *driver)
return 0;
}
+static void wmi_dev_disable(void *data)
+{
+ struct device *dev = data;
+
+ if (wmi_device_enable(to_wmi_device(dev), false) < 0)
+ dev_warn(dev, "Failed to disable device\n");
+}
+
static int wmi_dev_probe(struct device *dev)
{
struct wmi_block *wblock = dev_to_wblock(dev);
- struct wmi_driver *wdriver = drv_to_wdrv(dev->driver);
- int ret = 0;
+ struct wmi_driver *wdriver = to_wmi_driver(dev->driver);
+ int ret;
/* Some older WMI drivers will break if instantiated multiple times,
* so they are blocked from probing WMI devices with a duplicated GUID.
@@ -890,18 +852,22 @@ static int wmi_dev_probe(struct device *dev)
return -ENODEV;
}
- if (ACPI_FAILURE(wmi_method_enable(wblock, true)))
+ if (wmi_device_enable(to_wmi_device(dev), true) < 0)
dev_warn(dev, "failed to enable device -- probing anyway\n");
+ /*
+ * We have to make sure that all devres-managed resources are released first because
+ * some might still want to access the underlying WMI device.
+ */
+ ret = devm_add_action_or_reset(dev, wmi_dev_disable, dev);
+ if (ret < 0)
+ return ret;
+
if (wdriver->probe) {
- ret = wdriver->probe(dev_to_wdev(dev),
+ ret = wdriver->probe(to_wmi_device(dev),
find_guid_context(wblock, wdriver));
- if (ret) {
- if (ACPI_FAILURE(wmi_method_enable(wblock, false)))
- dev_warn(dev, "Failed to disable device\n");
-
+ if (ret)
return ret;
- }
}
down_write(&wblock->notify_lock);
@@ -914,17 +880,44 @@ static int wmi_dev_probe(struct device *dev)
static void wmi_dev_remove(struct device *dev)
{
struct wmi_block *wblock = dev_to_wblock(dev);
- struct wmi_driver *wdriver = drv_to_wdrv(dev->driver);
+ struct wmi_driver *wdriver = to_wmi_driver(dev->driver);
down_write(&wblock->notify_lock);
wblock->driver_ready = false;
up_write(&wblock->notify_lock);
if (wdriver->remove)
- wdriver->remove(dev_to_wdev(dev));
+ wdriver->remove(to_wmi_device(dev));
+}
+
+static void wmi_dev_shutdown(struct device *dev)
+{
+ struct wmi_driver *wdriver;
+ struct wmi_block *wblock;
+
+ if (dev->driver) {
+ wdriver = to_wmi_driver(dev->driver);
+ wblock = dev_to_wblock(dev);
+
+ /*
+ * Some machines return bogus WMI event data when disabling
+ * the WMI event. Because of this we must prevent the associated
+ * WMI driver from receiving new WMI events before disabling it.
+ */
+ down_write(&wblock->notify_lock);
+ wblock->driver_ready = false;
+ up_write(&wblock->notify_lock);
- if (ACPI_FAILURE(wmi_method_enable(wblock, false)))
- dev_warn(dev, "failed to disable device\n");
+ if (wdriver->shutdown)
+ wdriver->shutdown(to_wmi_device(dev));
+
+ /*
+ * We still need to disable the WMI device here since devres-managed resources
+ * like wmi_dev_disable() will not be release during shutdown.
+ */
+ if (wmi_device_enable(to_wmi_device(dev), false) < 0)
+ dev_warn(dev, "Failed to disable device\n");
+ }
}
static struct class wmi_bus_class = {
@@ -938,6 +931,7 @@ static const struct bus_type wmi_bus_type = {
.uevent = wmi_dev_uevent,
.probe = wmi_dev_probe,
.remove = wmi_dev_remove,
+ .shutdown = wmi_dev_shutdown,
};
static const struct device_type wmi_type_event = {
@@ -958,21 +952,30 @@ static const struct device_type wmi_type_data = {
.release = wmi_dev_release,
};
-/*
- * _WDG is a static list that is only parsed at startup,
- * so it's safe to count entries without extra protection.
- */
+static int wmi_count_guids(struct device *dev, void *data)
+{
+ struct wmi_guid_count_context *context = data;
+ struct wmi_block *wblock = dev_to_wblock(dev);
+
+ if (guid_equal(&wblock->gblock.guid, context->guid))
+ context->count++;
+
+ return 0;
+}
+
static int guid_count(const guid_t *guid)
{
- struct wmi_block *wblock;
- int count = 0;
+ struct wmi_guid_count_context context = {
+ .guid = guid,
+ .count = 0,
+ };
+ int ret;
- list_for_each_entry(wblock, &wmi_block_list, list) {
- if (guid_equal(&wblock->gblock.guid, guid))
- count++;
- }
+ ret = bus_for_each_dev(&wmi_bus_type, NULL, &context, wmi_count_guids);
+ if (ret < 0)
+ return ret;
- return count;
+ return context.count;
}
static int wmi_create_device(struct device *wmi_bus_dev,
@@ -983,7 +986,7 @@ static int wmi_create_device(struct device *wmi_bus_dev,
struct acpi_device_info *info;
acpi_handle method_handle;
acpi_status status;
- uint count;
+ int count;
if (wblock->gblock.flags & ACPI_WMI_EVENT) {
wblock->dev.dev.type = &wmi_type_event;
@@ -1051,6 +1054,9 @@ static int wmi_create_device(struct device *wmi_bus_dev,
wblock->dev.dev.parent = wmi_bus_dev;
count = guid_count(&wblock->gblock.guid);
+ if (count < 0)
+ return count;
+
if (count) {
dev_set_name(&wblock->dev.dev, "%pUL-%d", &wblock->gblock.guid, count);
set_bit(WMI_GUID_DUPLICATED, &wblock->flags);
@@ -1136,14 +1142,11 @@ static int parse_wdg(struct device *wmi_bus_dev, struct platform_device *pdev)
continue;
}
- list_add_tail(&wblock->list, &wmi_block_list);
-
retval = wmi_add_device(pdev, &wblock->dev);
if (retval) {
dev_err(wmi_bus_dev, "failed to register %pUL\n",
&wblock->gblock.guid);
- list_del(&wblock->list);
put_device(&wblock->dev.dev);
}
}
@@ -1153,58 +1156,22 @@ static int parse_wdg(struct device *wmi_bus_dev, struct platform_device *pdev)
return 0;
}
-/*
- * WMI can have EmbeddedControl access regions. In which case, we just want to
- * hand these off to the EC driver.
- */
-static acpi_status
-acpi_wmi_ec_space_handler(u32 function, acpi_physical_address address,
- u32 bits, u64 *value,
- void *handler_context, void *region_context)
-{
- int result = 0;
- u8 temp = 0;
-
- if ((address > 0xFF) || !value)
- return AE_BAD_PARAMETER;
-
- if (function != ACPI_READ && function != ACPI_WRITE)
- return AE_BAD_PARAMETER;
-
- if (bits != 8)
- return AE_BAD_PARAMETER;
-
- if (function == ACPI_READ) {
- result = ec_read(address, &temp);
- *value = temp;
- } else {
- temp = 0xff & *value;
- result = ec_write(address, temp);
- }
-
- switch (result) {
- case -EINVAL:
- return AE_BAD_PARAMETER;
- case -ENODEV:
- return AE_NOT_FOUND;
- case -ETIME:
- return AE_TIME;
- default:
- return AE_OK;
- }
-}
-
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 = &param,
+ };
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;
@@ -1217,7 +1184,7 @@ static int wmi_get_notify_data(struct wmi_block *wblock, union acpi_object **obj
static void wmi_notify_driver(struct wmi_block *wblock, union acpi_object *obj)
{
- struct wmi_driver *driver = drv_to_wdrv(wblock->dev.dev.driver);
+ struct wmi_driver *driver = to_wmi_driver(wblock->dev.dev.driver);
if (!obj && !driver->no_notify_data) {
dev_warn(&wblock->dev.dev, "Event contains no event data\n");
@@ -1231,47 +1198,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;
@@ -1286,9 +1246,6 @@ static void acpi_wmi_notify_handler(acpi_handle handle, u32 event, void *context
static int wmi_remove_device(struct device *dev, void *data)
{
- struct wmi_block *wblock = dev_to_wblock(dev);
-
- list_del(&wblock->list);
device_unregister(dev);
return 0;
@@ -1308,14 +1265,6 @@ static void acpi_wmi_remove_notify_handler(void *data)
acpi_remove_notify_handler(acpi_device->handle, ACPI_ALL_NOTIFY, acpi_wmi_notify_handler);
}
-static void acpi_wmi_remove_address_space_handler(void *data)
-{
- struct acpi_device *acpi_device = data;
-
- acpi_remove_address_space_handler(acpi_device->handle, ACPI_ADR_SPACE_EC,
- &acpi_wmi_ec_space_handler);
-}
-
static void acpi_wmi_remove_bus_device(void *data)
{
struct device *wmi_bus_dev = data;
@@ -1347,19 +1296,6 @@ static int acpi_wmi_probe(struct platform_device *device)
dev_set_drvdata(&device->dev, wmi_bus_dev);
- status = acpi_install_address_space_handler(acpi_device->handle,
- ACPI_ADR_SPACE_EC,
- &acpi_wmi_ec_space_handler,
- NULL, NULL);
- if (ACPI_FAILURE(status)) {
- dev_err(&device->dev, "Error installing EC region handler\n");
- return -ENODEV;
- }
- error = devm_add_action_or_reset(&device->dev, acpi_wmi_remove_address_space_handler,
- acpi_device);
- if (error < 0)
- return error;
-
status = acpi_install_notify_handler(acpi_device->handle, ACPI_ALL_NOTIFY,
acpi_wmi_notify_handler, wmi_bus_dev);
if (ACPI_FAILURE(status)) {
@@ -1408,7 +1344,7 @@ static struct platform_driver acpi_wmi_driver = {
.acpi_match_table = wmi_device_ids,
},
.probe = acpi_wmi_probe,
- .remove_new = acpi_wmi_remove,
+ .remove = acpi_wmi_remove,
};
static int __init acpi_wmi_init(void)