|
@@ -105,6 +105,7 @@ struct acpi_ec_query_handler {
|
|
|
acpi_handle handle;
|
|
|
void *data;
|
|
|
u8 query_bit;
|
|
|
+ struct kref kref;
|
|
|
};
|
|
|
|
|
|
struct transaction {
|
|
@@ -580,6 +581,27 @@ static int acpi_ec_query_unlocked(struct acpi_ec *ec, u8 *data)
|
|
|
/* --------------------------------------------------------------------------
|
|
|
Event Management
|
|
|
-------------------------------------------------------------------------- */
|
|
|
+static struct acpi_ec_query_handler *
|
|
|
+acpi_ec_get_query_handler(struct acpi_ec_query_handler *handler)
|
|
|
+{
|
|
|
+ if (handler)
|
|
|
+ kref_get(&handler->kref);
|
|
|
+ return handler;
|
|
|
+}
|
|
|
+
|
|
|
+static void acpi_ec_query_handler_release(struct kref *kref)
|
|
|
+{
|
|
|
+ struct acpi_ec_query_handler *handler =
|
|
|
+ container_of(kref, struct acpi_ec_query_handler, kref);
|
|
|
+
|
|
|
+ kfree(handler);
|
|
|
+}
|
|
|
+
|
|
|
+static void acpi_ec_put_query_handler(struct acpi_ec_query_handler *handler)
|
|
|
+{
|
|
|
+ kref_put(&handler->kref, acpi_ec_query_handler_release);
|
|
|
+}
|
|
|
+
|
|
|
int acpi_ec_add_query_handler(struct acpi_ec *ec, u8 query_bit,
|
|
|
acpi_handle handle, acpi_ec_query_func func,
|
|
|
void *data)
|
|
@@ -595,6 +617,7 @@ int acpi_ec_add_query_handler(struct acpi_ec *ec, u8 query_bit,
|
|
|
handler->func = func;
|
|
|
handler->data = data;
|
|
|
mutex_lock(&ec->mutex);
|
|
|
+ kref_init(&handler->kref);
|
|
|
list_add(&handler->node, &ec->list);
|
|
|
mutex_unlock(&ec->mutex);
|
|
|
return 0;
|
|
@@ -604,15 +627,18 @@ EXPORT_SYMBOL_GPL(acpi_ec_add_query_handler);
|
|
|
void acpi_ec_remove_query_handler(struct acpi_ec *ec, u8 query_bit)
|
|
|
{
|
|
|
struct acpi_ec_query_handler *handler, *tmp;
|
|
|
+ LIST_HEAD(free_list);
|
|
|
|
|
|
mutex_lock(&ec->mutex);
|
|
|
list_for_each_entry_safe(handler, tmp, &ec->list, node) {
|
|
|
if (query_bit == handler->query_bit) {
|
|
|
- list_del(&handler->node);
|
|
|
- kfree(handler);
|
|
|
+ list_del_init(&handler->node);
|
|
|
+ list_add(&handler->node, &free_list);
|
|
|
}
|
|
|
}
|
|
|
mutex_unlock(&ec->mutex);
|
|
|
+ list_for_each_entry(handler, &free_list, node)
|
|
|
+ acpi_ec_put_query_handler(handler);
|
|
|
}
|
|
|
EXPORT_SYMBOL_GPL(acpi_ec_remove_query_handler);
|
|
|
|
|
@@ -628,14 +654,14 @@ static void acpi_ec_run(void *cxt)
|
|
|
else if (handler->handle)
|
|
|
acpi_evaluate_object(handler->handle, NULL, NULL, NULL);
|
|
|
pr_debug("##### Query(0x%02x) stopped #####\n", handler->query_bit);
|
|
|
- kfree(handler);
|
|
|
+ acpi_ec_put_query_handler(handler);
|
|
|
}
|
|
|
|
|
|
static int acpi_ec_sync_query(struct acpi_ec *ec, u8 *data)
|
|
|
{
|
|
|
u8 value = 0;
|
|
|
int status;
|
|
|
- struct acpi_ec_query_handler *handler, *copy;
|
|
|
+ struct acpi_ec_query_handler *handler;
|
|
|
|
|
|
status = acpi_ec_query_unlocked(ec, &value);
|
|
|
if (data)
|
|
@@ -646,15 +672,12 @@ static int acpi_ec_sync_query(struct acpi_ec *ec, u8 *data)
|
|
|
list_for_each_entry(handler, &ec->list, node) {
|
|
|
if (value == handler->query_bit) {
|
|
|
/* have custom handler for this bit */
|
|
|
- copy = kmalloc(sizeof(*handler), GFP_KERNEL);
|
|
|
- if (!copy)
|
|
|
- return -ENOMEM;
|
|
|
- memcpy(copy, handler, sizeof(*copy));
|
|
|
+ handler = acpi_ec_get_query_handler(handler);
|
|
|
pr_debug("##### Query(0x%02x) scheduled #####\n",
|
|
|
handler->query_bit);
|
|
|
- return acpi_os_execute((copy->func) ?
|
|
|
+ return acpi_os_execute((handler->func) ?
|
|
|
OSL_NOTIFY_HANDLER : OSL_GPE_HANDLER,
|
|
|
- acpi_ec_run, copy);
|
|
|
+ acpi_ec_run, handler);
|
|
|
}
|
|
|
}
|
|
|
return 0;
|