Series short description
cover Series short description
In order to get notifications from Smart Batteries there is a need to allow non-AML query handlers in EC driver.
AML query handlers are now found at init time, so there is no need to look them up in namespace at query time.
Signature · 2 lines
Regards, Alex.
PATCH 1/3 ACPI EC: Re-factor EC space handler to avoid using label/goto for cycle.
---
drivers/acpi/ec.c | 56 ++++++++++++++++------------------------------------- 1 files changed, 17 insertions(+), 39 deletions(-)
drivers/acpi/ec.c +17 -39
@@ -454,57 +454,35 @@ acpi_ec_space_setup(acpi_handle region_handle, }static acpi_status -acpi_ec_space_handler (u32 function, -acpi_physical_address address, -u32 bit_width, -acpi_integer * value, +acpi_ec_space_handler (u32 function,acpi_physical_address address, +u32 bits,acpi_integer *value,void *handler_context,void *region_context) { -int result =0 ;struct acpi_ec *ec = handler_context; -u64 temp = *value; -acpi_integer f_v =0 ; -int i =0 ; +int result =0 , i =0 ; +u8 temp =0 ;if ((address >0xFF ) || !value || !handler_context)return AE_BAD_PARAMETER ; -if (bit_width !=8 && acpi_strict) { +if (function !=ACPI_READ && function !=ACPI_WRITE )return AE_BAD_PARAMETER ; - } - - next_byte: -switch (function) { -case ACPI_READ : - temp =0 ; - result =acpi_ec_read (ec, (u8 ) address, (u8 *) & temp); -break ; -case ACPI_WRITE : - result =acpi_ec_write (ec, (u8 ) address, (u8 ) temp); -break ; -default : - result = -EINVAL ; - goto out; -break ; - } - bit_width -=8 ; -if (bit_width) { -if (function ==ACPI_READ ) - f_v |= temp <<8 * i; -if (function ==ACPI_WRITE ) - temp >>=8 ; - i++; - address++; - goto next_byte; - } +if (bits !=8 && acpi_strict) +return AE_BAD_PARAMETER ; -if (function ==ACPI_READ ) { - f_v |= temp <<8 * i; - *value = f_v; +while (bits - i >0 ) { +if (function ==ACPI_READ ) { + result =acpi_ec_read (ec, address, &temp); + (*value) |= ((acpi_integer )temp) << i; + }else { + temp =0xff & ((*value) >> i); + result =acpi_ec_write (ec, address, temp); + } + i +=8 ; + ++address; } - out:switch (result) {case -EINVAL :return AE_BAD_PARAMETER ;
Re: [PATCH 1/3] ACPI EC: Re-factor EC space handler to avoid using label/goto for cycle.
Applied.
thanks,
-Len
Quoted 92 lines · Alexey Starikovskiy
Signed-off-by Alexey Starikovskiy <[email protected]>---
drivers/acpi/ec.c | 56 ++++++++++++++++------------------------------------- 1 files changed, 17 insertions(+), 39 deletions(-)drivers/acpi/ec.c +17
-40@@ -454,57 +454,35 @@ acpi_ec_space_setup(acpi_handle region_handle, }static acpi_status -acpi_ec_space_handler (u32 function, -acpi_physical_address address, -u32 bit_width, -acpi_integer * value, +acpi_ec_space_handler (u32 function,acpi_physical_address address, +u32 bits,acpi_integer *value,void *handler_context,void *region_context) { -int result =0 ;struct acpi_ec *ec = handler_context; -u64 temp = *value; -acpi_integer f_v =0 ; -int i =0 ; +int result =0 , i =0 ; +u8 temp =0 ;if ((address >0xFF ) || !value || !handler_context)return AE_BAD_PARAMETER ; -if (bit_width !=8 && acpi_strict) { +if (function !=ACPI_READ && function !=ACPI_WRITE )return AE_BAD_PARAMETER ; - } - - next_byte: -switch (function) { -case ACPI_READ : - temp =0 ; - result =acpi_ec_read (ec, (u8 ) address, (u8 *) & temp); -break ; -case ACPI_WRITE : - result =acpi_ec_write (ec, (u8 ) address, (u8 ) temp); -break ; -default : - result = -EINVAL ; - goto out; -break ; - } - bit_width -=8 ; -if (bit_width) { -if (function ==ACPI_READ ) - f_v |= temp <<8 * i; -if (function ==ACPI_WRITE ) - temp >>=8 ; - i++; - address++; - goto next_byte; - } +if (bits !=8 && acpi_strict) +return AE_BAD_PARAMETER ; -if (function ==ACPI_READ ) { - f_v |= temp <<8 * i; - *value = f_v; +while (bits - i >0 ) { +if (function ==ACPI_READ ) { + result =acpi_ec_read (ec, address, &temp); + (*value) |= ((acpi_integer )temp) << i; + }else { + temp =0xff & ((*value) >> i); + result =acpi_ec_write (ec, address, temp); + } + i +=8 ; + ++address; } - out:switch (result) {case -EINVAL :return AE_BAD_PARAMETER ; -To unsubscribe from this list: send the line "unsubscribe linux-acpi" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
PATCH 2/3 ACPI EC: drop usage of ACPI_DEBUG_PRINT as too heavy weight
In reply to Alexey Starikovskiy---
drivers/acpi/ec.c | 20 ++++++-------------- 1 files changed, 6 insertions(+), 14 deletions(-)
drivers/acpi/ec.c +6 -14
@@ -39,20 +39,19 @@#include <acpi/acpi_drivers.h> #include <acpi/actypes.h> -#define _COMPONENT ACPI_EC_COMPONENT -ACPI_MODULE_NAME ("ec" ); -#define ACPI_EC_COMPONENT 0x00100000#define ACPI_EC_CLASS "embedded_controller"#define ACPI_EC_HID "PNP0C09"#define ACPI_EC_DEVICE_NAME "Embedded Controller"#define ACPI_EC_FILE_INFO "info"#undef PREFIX#define PREFIX "ACPI: EC: " +/* EC status register */ #define ACPI_EC_FLAG_OBF 0x01/* Output buffer full */ #define ACPI_EC_FLAG_IBF 0x02/* Input buffer full */ #define ACPI_EC_FLAG_BURST 0x10/* burst mode */ #define ACPI_EC_FLAG_SCI 0x20/* EC-SCI occurred */ +/* EC commands */ enum ec_command {ACPI_EC_COMMAND_READ =0x80 ,
@@ -245,7 +244,7 @@ static int acpi_ec_transaction(struct acpi_ec *ec, u8 command, status =acpi_ec_wait (ec,ACPI_EC_EVENT_IBF_0 ,0 ,0 );if (status) { - printk(KERN_DEBUG PREFIX + printk(KERN_ERR PREFIX "input buffer is not empty, aborting transaction\n"); goto end; }
@@ -630,10 +629,6 @@ static int acpi_ec_add(struct acpi_device *device)acpi_ec_add_fs (device); -ACPI_DEBUG_PRINT ((ACPI_DB_INFO ,"%s [%s] (gpe %d) interrupt mode." , -acpi_device_name (device),acpi_device_bid (device), - (u32 ) ec->gpe)); -return 0 ; }
@@ -718,9 +713,6 @@ static int acpi_ec_start(struct acpi_device *device)if (!ec)return -EINVAL ; -ACPI_DEBUG_PRINT ((ACPI_DB_INFO ,"gpe=0x%02lx, ports=0x%2lx,0x%2lx" , - ec->gpe, ec->command_addr, ec->data_addr)); -/* Boot EC is already working */ if (ec == boot_ec)return 0 ;
@@ -779,8 +771,8 @@ ec_parse_device(acpi_handle handle, u32 Level, void *context, void **retval) ec->handle = handle; -ACPI_DEBUG_PRINT ((ACPI_DB_INFO ,"GPE=0x%02lx, ports=0x%2lx, 0x%2lx" , - ec->gpe, ec->command_addr, ec->data_addr)); + printk(KERN_INFO PREFIX "GPE = 0x%lx, I/O: command/status = 0x%lx, data = 0x%lx", + ec->gpe, ec->command_addr, ec->data_addr);return AE_CTRL_TERMINATE ; }
@@ -803,7 +795,7 @@ int __init acpi_ec_ecdt_probe(void)if (ACPI_FAILURE (status)) goto error; -ACPI_DEBUG_PRINT ((ACPI_DB_INFO ,"Found ECDT" )); + printk(KERN_INFO PREFIX "EC description table is found, configuring boot EC\n"); boot_ec->command_addr = ecdt_ptr->control.address; boot_ec->data_addr = ecdt_ptr->data.address;
Re: [PATCH 2/3] ACPI EC: drop usage of ACPI_DEBUG_PRINT as too heavy weight
Applied.
thanks,
-Len
Quoted 90 lines · Alexey Starikovskiy
Signed-off-by Alexey Starikovskiy <[email protected]>---
drivers/acpi/ec.c | 20 ++++++-------------- 1 files changed, 6 insertions(+), 14 deletions(-)drivers/acpi/ec.c +6
-15@@ -39,20 +39,19 @@#include <acpi/acpi_drivers.h> #include <acpi/actypes.h> -#define _COMPONENT ACPI_EC_COMPONENT -ACPI_MODULE_NAME ("ec" ); -#define ACPI_EC_COMPONENT 0x00100000#define ACPI_EC_CLASS "embedded_controller"#define ACPI_EC_HID "PNP0C09"#define ACPI_EC_DEVICE_NAME "Embedded Controller"#define ACPI_EC_FILE_INFO "info"#undef PREFIX#define PREFIX "ACPI: EC: " +/* EC status register */ #define ACPI_EC_FLAG_OBF 0x01/* Output buffer full */ #define ACPI_EC_FLAG_IBF 0x02/* Input buffer full */ #define ACPI_EC_FLAG_BURST 0x10/* burst mode */ #define ACPI_EC_FLAG_SCI 0x20/* EC-SCI occurred */ +/* EC commands */ enum ec_command {ACPI_EC_COMMAND_READ =0x80 ,@@ -245,7 +244,7 @@ static int acpi_ec_transaction(struct acpi_ec *ec, u8 command, status =acpi_ec_wait (ec,ACPI_EC_EVENT_IBF_0 ,0 ,0 );if (status) { - printk(KERN_DEBUG PREFIX + printk(KERN_ERR PREFIX "input buffer is not empty, aborting transaction\n"); goto end; }@@ -630,10 +629,6 @@ static int acpi_ec_add(struct acpi_device *device)acpi_ec_add_fs (device); -ACPI_DEBUG_PRINT ((ACPI_DB_INFO ,"%s [%s] (gpe %d) interrupt mode." , -acpi_device_name (device),acpi_device_bid (device), - (u32 ) ec->gpe)); -return 0 ; }@@ -718,9 +713,6 @@ static int acpi_ec_start(struct acpi_device *device)if (!ec)return -EINVAL ; -ACPI_DEBUG_PRINT ((ACPI_DB_INFO ,"gpe=0x%02lx, ports=0x%2lx,0x%2lx" , - ec->gpe, ec->command_addr, ec->data_addr)); -/* Boot EC is already working */ if (ec == boot_ec)return 0 ;@@ -779,8 +771,8 @@ ec_parse_device(acpi_handle handle, u32 Level, void *context, void **retval) ec->handle = handle; -ACPI_DEBUG_PRINT ((ACPI_DB_INFO ,"GPE=0x%02lx, ports=0x%2lx, 0x%2lx" , - ec->gpe, ec->command_addr, ec->data_addr)); + printk(KERN_INFO PREFIX "GPE = 0x%lx, I/O: command/status = 0x%lx, data = 0x%lx", + ec->gpe, ec->command_addr, ec->data_addr);return AE_CTRL_TERMINATE ; }@@ -803,7 +795,7 @@ int __init acpi_ec_ecdt_probe(void)if (ACPI_FAILURE (status)) goto error; -ACPI_DEBUG_PRINT ((ACPI_DB_INFO ,"Found ECDT" )); + printk(KERN_INFO PREFIX "EC description table is found, configuring boot EC\n"); boot_ec->command_addr = ecdt_ptr->control.address; boot_ec->data_addr = ecdt_ptr->data.address; -To unsubscribe from this list: send the line "unsubscribe linux-acpi" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
PATCH 3/3 ACPI EC: Add support for non-AML EC query handlers
In reply to Alexey Starikovskiy---
drivers/acpi/ec.c | 175 ++++++++++++++++++++++++++++++++++++++--------------- 1 files changed, 125 insertions(+), 50 deletions(-)
drivers/acpi/ec.c +125 -50
@@ -34,6 +34,7 @@#include <linux/proc_fs.h> #include <linux/seq_file.h> #include <linux/interrupt.h> +#include <linux/list.h> #include <asm/io.h> #include <acpi/acpi_bus.h> #include <acpi/acpi_drivers.h>
@@ -43,6 +44,7 @@#define ACPI_EC_HID "PNP0C09"#define ACPI_EC_DEVICE_NAME "Embedded Controller"#define ACPI_EC_FILE_INFO "info" +#undef PREFIX#define PREFIX "ACPI: EC: "
@@ -60,6 +62,7 @@ enum ec_command {ACPI_EC_BURST_DISABLE =0x83 , ACPI_EC_COMMAND_QUERY = 0x84, }; +/* EC events */ enum ec_event { ACPI_EC_EVENT_OBF_1 = 1, /* Output buffer full */
@@ -93,6 +96,16 @@ static struct acpi_driver acpi_ec_driver = {/* If we find an EC via the ECDT, we need to keep a ptr to its context */ /* External interfaces use first EC only, so remember */ +typedef int (*acpi_ec_query_func ) (void *data); + +struct acpi_ec_query_handler { +struct list_head node; +acpi_ec_query_func func; +acpi_handle handle; +void *data; +u8 query_bit; +}; + static struct acpi_ec { acpi_handle handle; unsigned long gpe;
@@ -103,6 +116,7 @@ static struct acpi_ec {atomic_t query_pending;atomic_t event_count;wait_queue_head_t wait; +struct list_head list; } *boot_ec, *first_ec;/* --------------------------------------------------------------------------
@@ -393,21 +407,67 @@ static int acpi_ec_query(struct acpi_ec *ec, u8 * data)/* -------------------------------------------------------------------------- Event Management -------------------------------------------------------------------------- */ +int acpi_ec_add_query_handler (struct acpi_ec *ec,u8 query_bit, +acpi_handle handle,acpi_ec_query_func func, +void *data) +{ +struct acpi_ec_query_handler *handler = +kzalloc (sizeof (struct acpi_ec_query_handler ),GFP_KERNEL ); +if (!handler) +return -ENOMEM ; + + handler->query_bit = query_bit; + handler->handle = handle; + handler->func = func; + handler->data = data; +mutex_lock (&ec->lock); +list_add_tail (&handler->node, &ec->list); +mutex_unlock (&ec->lock); +return 0 ; +} + +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; +mutex_lock (&ec->lock); +list_for_each_entry (handler, &ec->list, node) { +if (query_bit == handler->query_bit) { +list_del (&handler->node); +kfree (handler); +break ; + } + } +mutex_unlock (&ec->lock); +} + +EXPORT_SYMBOL_GPL (acpi_ec_remove_query_handler);static void acpi_ec_gpe_query (void *ec_cxt) {struct acpi_ec *ec = ec_cxt;u8 value =0 ; -char object_name[8 ]; +struct acpi_ec_query_handler *handler, copy;if (!ec ||acpi_ec_query (ec, &value))return ; - -snprintf (object_name,8 ,"_Q%2.2X" , value); - -ACPI_DEBUG_PRINT ((ACPI_DB_INFO ,"Evaluating %s" , object_name)); - -acpi_evaluate_object (ec->handle, object_name,NULL ,NULL ); +mutex_lock (&ec->lock); +list_for_each_entry (handler, &ec->list, node) { +if (value == handler->query_bit) { +/* have custom handler for this bit */ +memcpy (©, handler,sizeof (copy)); +mutex_unlock (&ec->lock); +if (copy.func) { + copy.func (copy.data); + }else if (copy.handle) { +acpi_evaluate_object (copy.handle,NULL ,NULL ,NULL ); + } +return ; + } + } +mutex_unlock (&ec->lock); + printk(KERN_ERR PREFIX "Handler for query 0x%x is not found!\n", value); }static u32 acpi_ec_gpe_handler (void *data)
@@ -426,8 +486,7 @@ static u32 acpi_ec_gpe_handler(void *data)if ((value &ACPI_EC_FLAG_SCI ) && !atomic_read (&ec->query_pending)) {atomic_set (&ec->query_pending,1 ); status = -acpi_os_execute (OSL_EC_BURST_HANDLER , acpi_ec_gpe_query, - ec); +acpi_os_execute (OSL_EC_BURST_HANDLER , acpi_ec_gpe_query, ec); } return status == AE_OK ?
@@ -574,9 +633,6 @@ static int acpi_ec_remove_fs(struct acpi_device *device)static acpi_status ec_parse_io_ports (struct acpi_resource *resource,void *context); -static acpi_status -ec_parse_device (acpi_handle handle,u32 Level,void *context,void **retval); -static struct acpi_ec *make_acpi_ec (void ) {struct acpi_ec *ec =kzalloc (sizeof (struct acpi_ec ),GFP_KERNEL );
@@ -587,13 +643,52 @@ static struct acpi_ec *make_acpi_ec(void)atomic_set (&ec->event_count,1 );mutex_init (&ec->lock);init_waitqueue_head (&ec->wait); +INIT_LIST_HEAD (&ec->list);return ec; } +static acpi_status +acpi_ec_register_query_methods (acpi_handle handle,u32 level, +void *context,void **return_value) +{ +struct acpi_namespace_node *node = handle; +struct acpi_ec *ec = context; +int value =0 ; +if (sscanf (node->name.ascii,"_Q%x" , &value) ==1 ) { +acpi_ec_add_query_handler (ec, value, handle,NULL ,NULL ); + } +return AE_OK ; +} + +static int ec_parse_device (struct acpi_ec *ec,acpi_handle handle) +{ +if (ACPI_FAILURE (acpi_walk_resources (handle,METHOD_NAME__CRS , + ec_parse_io_ports, ec))) +return -EINVAL ; + +/* Get GPE bit assignment (EC events). */ +/* TODO: Add support for _GPE returning a package */ +if (ACPI_FAILURE (acpi_evaluate_integer (handle,"_GPE" ,NULL , &ec->gpe))) +return -EINVAL ; + +/* Use the global lock for all EC transactions? */ +acpi_evaluate_integer (handle,"_GLK" ,NULL , &ec->global_lock); + +/* Find and register all query methods */ +acpi_walk_namespace (ACPI_TYPE_METHOD , handle,1 , + acpi_ec_register_query_methods, ec,NULL ); + + ec->handle = handle; + + printk(KERN_INFO PREFIX "GPE = 0x%lx, I/O: command/status = 0x%lx, data = 0x%lx", + ec->gpe, ec->command_addr, ec->data_addr); + +return 0 ; +} +static int acpi_ec_add (struct acpi_device *device) { -acpi_status status =AE_OK ;struct acpi_ec *ec =NULL ;if (!device)
@@ -606,8 +701,7 @@ static int acpi_ec_add(struct acpi_device *device)if (!ec)return -ENOMEM ; - status =ec_parse_device (device->handle,0 , ec,NULL ); -if (status !=AE_CTRL_TERMINATE ) { +if (ec_parse_device (ec, device->handle)) {kfree (ec);return -EINVAL ; }
@@ -618,6 +712,8 @@ static int acpi_ec_add(struct acpi_device *device)/* We might have incorrect info for GL at boot time */ mutex_lock (&boot_ec->lock); boot_ec->global_lock = ec->global_lock; +/* Copy handlers from new ec into boot ec */ +list_splice (&ec->list, &boot_ec->list);mutex_unlock (&boot_ec->lock);kfree (ec); ec = boot_ec;
@@ -628,18 +724,24 @@ static int acpi_ec_add(struct acpi_device *device)acpi_driver_data (device) = ec;acpi_ec_add_fs (device); -return 0 ; }static int acpi_ec_remove (struct acpi_device *device,int type) {struct acpi_ec *ec; +struct acpi_ec_query_handler *handler;if (!device)return -EINVAL ; ec =acpi_driver_data (device); +mutex_lock (&ec->lock); +list_for_each_entry (handler, &ec->list, node) { +list_del (&handler->node); +kfree (handler); + } +mutex_unlock (&ec->lock);acpi_ec_remove_fs (device);acpi_driver_data (device) =NULL ;if (ec == first_ec)
@@ -695,15 +797,13 @@ static int ec_install_handlers(struct acpi_ec *ec)return -ENODEV ; } -/* EC is fully operational, allow queries */ -atomic_set (&ec->query_pending,0 ); -return 0 ; }static int acpi_ec_start (struct acpi_device *device) {struct acpi_ec *ec; +int ret =0 ;if (!device)return -EINVAL ;
@@ -714,10 +814,13 @@ static int acpi_ec_start(struct acpi_device *device)return -EINVAL ;/* Boot EC is already working */ -if (ec == boot_ec) -return 0 ; +if (ec != boot_ec) + ret =ec_install_handlers (ec); + +/* EC is fully operational, allow queries */ +atomic_set (&ec->query_pending,0 ); -return ec_install_handlers (ec); +return ret; }static int acpi_ec_stop (struct acpi_device *device,int type)
@@ -749,34 +852,6 @@ static int acpi_ec_stop(struct acpi_device *device, int type)return 0 ; } -static acpi_status -ec_parse_device (acpi_handle handle,u32 Level,void *context,void **retval) -{ -acpi_status status; - -struct acpi_ec *ec = context; - status =acpi_walk_resources (handle,METHOD_NAME__CRS , - ec_parse_io_ports, ec); -if (ACPI_FAILURE (status)) -return status; - -/* Get GPE bit assignment (EC events). */ -/* TODO: Add support for _GPE returning a package */ - status =acpi_evaluate_integer (handle,"_GPE" ,NULL , &ec->gpe); -if (ACPI_FAILURE (status)) -return status; - -/* Use the global lock for all EC transactions? */ -acpi_evaluate_integer (handle,"_GLK" ,NULL , &ec->global_lock); - - ec->handle = handle; - - printk(KERN_INFO PREFIX "GPE = 0x%lx, I/O: command/status = 0x%lx, data = 0x%lx", - ec->gpe, ec->command_addr, ec->data_addr); - -return AE_CTRL_TERMINATE ; -} -int __init acpi_ec_ecdt_probe (void ) {int ret;
Len Brown
reviewerRe: [PATCH 3/3] ACPI EC: Add support for non-AML EC query handlers
What is the benefit of this patch?
(it would be good to say in the check-in comments...hint hint)
Also, if you want your git commit author tag to be
"Alexey Starikovskiy <[email protected]>" as you mentioned earlier, then this would be a good time to cut over to sending patches From and signed-off-by that address.
thanks,
-Len
Quoted 328 lines · Alexey Starikovskiy
Signed-off-by Alexey Starikovskiy <[email protected]>---
drivers/acpi/ec.c | 175 ++++++++++++++++++++++++++++++++++++++--------------- 1 files changed, 125 insertions(+), 50 deletions(-)drivers/acpi/ec.c +125
-51@@ -34,6 +34,7 @@#include <linux/proc_fs.h> #include <linux/seq_file.h> #include <linux/interrupt.h> +#include <linux/list.h> #include <asm/io.h> #include <acpi/acpi_bus.h> #include <acpi/acpi_drivers.h> @@ -43,6 +44,7 @@#define ACPI_EC_HID "PNP0C09"#define ACPI_EC_DEVICE_NAME "Embedded Controller"#define ACPI_EC_FILE_INFO "info" +#undef PREFIX#define PREFIX "ACPI: EC: "@@ -60,6 +62,7 @@ enum ec_command {ACPI_EC_BURST_DISABLE =0x83 , ACPI_EC_COMMAND_QUERY = 0x84, }; +/* EC events */ enum ec_event { ACPI_EC_EVENT_OBF_1 = 1, /* Output buffer full */@@ -93,6 +96,16 @@ static struct acpi_driver acpi_ec_driver = {/* If we find an EC via the ECDT, we need to keep a ptr to its context */ /* External interfaces use first EC only, so remember */ +typedef int (*acpi_ec_query_func ) (void *data); + +struct acpi_ec_query_handler { +struct list_head node; +acpi_ec_query_func func; +acpi_handle handle; +void *data; +u8 query_bit; +}; + static struct acpi_ec { acpi_handle handle; unsigned long gpe;@@ -103,6 +116,7 @@ static struct acpi_ec {atomic_t query_pending;atomic_t event_count;wait_queue_head_t wait; +struct list_head list; } *boot_ec, *first_ec;/* -------------------------------------------------------------------------- @@ -393,21 +407,67 @@ static int acpi_ec_query(struct acpi_ec *ec, u8 * data)/* -------------------------------------------------------------------------- Event Management -------------------------------------------------------------------------- */ +int acpi_ec_add_query_handler (struct acpi_ec *ec,u8 query_bit, +acpi_handle handle,acpi_ec_query_func func, +void *data) +{ +struct acpi_ec_query_handler *handler = +kzalloc (sizeof (struct acpi_ec_query_handler ),GFP_KERNEL ); +if (!handler) +return -ENOMEM ; + + handler->query_bit = query_bit; + handler->handle = handle; + handler->func = func; + handler->data = data; +mutex_lock (&ec->lock); +list_add_tail (&handler->node, &ec->list); +mutex_unlock (&ec->lock); +return 0 ; +} + +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; +mutex_lock (&ec->lock); +list_for_each_entry (handler, &ec->list, node) { +if (query_bit == handler->query_bit) { +list_del (&handler->node); +kfree (handler); +break ; + } + } +mutex_unlock (&ec->lock); +} + +EXPORT_SYMBOL_GPL (acpi_ec_remove_query_handler);static void acpi_ec_gpe_query (void *ec_cxt) {struct acpi_ec *ec = ec_cxt;u8 value =0 ; -char object_name[8 ]; +struct acpi_ec_query_handler *handler, copy;if (!ec ||acpi_ec_query (ec, &value))return ; - -snprintf (object_name,8 ,"_Q%2.2X" , value); - -ACPI_DEBUG_PRINT ((ACPI_DB_INFO ,"Evaluating %s" , object_name)); - -acpi_evaluate_object (ec->handle, object_name,NULL ,NULL ); +mutex_lock (&ec->lock); +list_for_each_entry (handler, &ec->list, node) { +if (value == handler->query_bit) { +/* have custom handler for this bit */ +memcpy (©, handler,sizeof (copy)); +mutex_unlock (&ec->lock); +if (copy.func) { + copy.func (copy.data); + }else if (copy.handle) { +acpi_evaluate_object (copy.handle,NULL ,NULL ,NULL ); + } +return ; + } + } +mutex_unlock (&ec->lock); + printk(KERN_ERR PREFIX "Handler for query 0x%x is not found!\n", value); }static u32 acpi_ec_gpe_handler (void *data)@@ -426,8 +486,7 @@ static u32 acpi_ec_gpe_handler(void *data)if ((value &ACPI_EC_FLAG_SCI ) && !atomic_read (&ec->query_pending)) {atomic_set (&ec->query_pending,1 ); status = -acpi_os_execute (OSL_EC_BURST_HANDLER , acpi_ec_gpe_query, - ec); +acpi_os_execute (OSL_EC_BURST_HANDLER , acpi_ec_gpe_query, ec); } return status == AE_OK ?@@ -574,9 +633,6 @@ static int acpi_ec_remove_fs(struct acpi_device *device)static acpi_status ec_parse_io_ports (struct acpi_resource *resource,void *context); -static acpi_status -ec_parse_device (acpi_handle handle,u32 Level,void *context,void **retval); -static struct acpi_ec *make_acpi_ec (void ) {struct acpi_ec *ec =kzalloc (sizeof (struct acpi_ec ),GFP_KERNEL );@@ -587,13 +643,52 @@ static struct acpi_ec *make_acpi_ec(void)atomic_set (&ec->event_count,1 );mutex_init (&ec->lock);init_waitqueue_head (&ec->wait); +INIT_LIST_HEAD (&ec->list);return ec; } +static acpi_status +acpi_ec_register_query_methods (acpi_handle handle,u32 level, +void *context,void **return_value) +{ +struct acpi_namespace_node *node = handle; +struct acpi_ec *ec = context; +int value =0 ; +if (sscanf (node->name.ascii,"_Q%x" , &value) ==1 ) { +acpi_ec_add_query_handler (ec, value, handle,NULL ,NULL ); + } +return AE_OK ; +} + +static int ec_parse_device (struct acpi_ec *ec,acpi_handle handle) +{ +if (ACPI_FAILURE (acpi_walk_resources (handle,METHOD_NAME__CRS , + ec_parse_io_ports, ec))) +return -EINVAL ; + +/* Get GPE bit assignment (EC events). */ +/* TODO: Add support for _GPE returning a package */ +if (ACPI_FAILURE (acpi_evaluate_integer (handle,"_GPE" ,NULL , &ec->gpe))) +return -EINVAL ; + +/* Use the global lock for all EC transactions? */ +acpi_evaluate_integer (handle,"_GLK" ,NULL , &ec->global_lock); + +/* Find and register all query methods */ +acpi_walk_namespace (ACPI_TYPE_METHOD , handle,1 , + acpi_ec_register_query_methods, ec,NULL ); + + ec->handle = handle; + + printk(KERN_INFO PREFIX "GPE = 0x%lx, I/O: command/status = 0x%lx, data = 0x%lx", + ec->gpe, ec->command_addr, ec->data_addr); + +return 0 ; +} +static int acpi_ec_add (struct acpi_device *device) { -acpi_status status =AE_OK ;struct acpi_ec *ec =NULL ;if (!device)@@ -606,8 +701,7 @@ static int acpi_ec_add(struct acpi_device *device)if (!ec)return -ENOMEM ; - status =ec_parse_device (device->handle,0 , ec,NULL ); -if (status !=AE_CTRL_TERMINATE ) { +if (ec_parse_device (ec, device->handle)) {kfree (ec);return -EINVAL ; }@@ -618,6 +712,8 @@ static int acpi_ec_add(struct acpi_device *device)/* We might have incorrect info for GL at boot time */ mutex_lock (&boot_ec->lock); boot_ec->global_lock = ec->global_lock; +/* Copy handlers from new ec into boot ec */ +list_splice (&ec->list, &boot_ec->list);mutex_unlock (&boot_ec->lock);kfree (ec); ec = boot_ec;@@ -628,18 +724,24 @@ static int acpi_ec_add(struct acpi_device *device)acpi_driver_data (device) = ec;acpi_ec_add_fs (device); -return 0 ; }static int acpi_ec_remove (struct acpi_device *device,int type) {struct acpi_ec *ec; +struct acpi_ec_query_handler *handler;if (!device)return -EINVAL ; ec =acpi_driver_data (device); +mutex_lock (&ec->lock); +list_for_each_entry (handler, &ec->list, node) { +list_del (&handler->node); +kfree (handler); + } +mutex_unlock (&ec->lock);acpi_ec_remove_fs (device);acpi_driver_data (device) =NULL ;if (ec == first_ec)@@ -695,15 +797,13 @@ static int ec_install_handlers(struct acpi_ec *ec)return -ENODEV ; } -/* EC is fully operational, allow queries */ -atomic_set (&ec->query_pending,0 ); -return 0 ; }static int acpi_ec_start (struct acpi_device *device) {struct acpi_ec *ec; +int ret =0 ;if (!device)return -EINVAL ;@@ -714,10 +814,13 @@ static int acpi_ec_start(struct acpi_device *device)return -EINVAL ;/* Boot EC is already working */ -if (ec == boot_ec) -return 0 ; +if (ec != boot_ec) + ret =ec_install_handlers (ec); + +/* EC is fully operational, allow queries */ +atomic_set (&ec->query_pending,0 ); -return ec_install_handlers (ec); +return ret; }static int acpi_ec_stop (struct acpi_device *device,int type)@@ -749,34 +852,6 @@ static int acpi_ec_stop(struct acpi_device *device, int type)return 0 ; } -static acpi_status -ec_parse_device (acpi_handle handle,u32 Level,void *context,void **retval) -{ -acpi_status status; - -struct acpi_ec *ec = context; - status =acpi_walk_resources (handle,METHOD_NAME__CRS , - ec_parse_io_ports, ec); -if (ACPI_FAILURE (status)) -return status; - -/* Get GPE bit assignment (EC events). */ -/* TODO: Add support for _GPE returning a package */ - status =acpi_evaluate_integer (handle,"_GPE" ,NULL , &ec->gpe); -if (ACPI_FAILURE (status)) -return status; - -/* Use the global lock for all EC transactions? */ -acpi_evaluate_integer (handle,"_GLK" ,NULL , &ec->global_lock); - - ec->handle = handle; - - printk(KERN_INFO PREFIX "GPE = 0x%lx, I/O: command/status = 0x%lx, data = 0x%lx", - ec->gpe, ec->command_addr, ec->data_addr); - -return AE_CTRL_TERMINATE ; -} -int __init acpi_ec_ecdt_probe (void ) {int ret; -To unsubscribe from this list: send the line "unsubscribe linux-acpi" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html