diff options
Diffstat (limited to 'drivers/acpi/ec.c')
| -rw-r--r-- | drivers/acpi/ec.c | 106 | 
1 files changed, 50 insertions, 56 deletions
diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index 469f3f57f88..56bee9e065c 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -471,7 +471,6 @@ static void acpi_ec_gpe_query(void *ec_cxt)  		}  	}  	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) @@ -665,30 +664,44 @@ acpi_ec_register_query_methods(acpi_handle handle, u32 level,  	return AE_OK;  } -static int ec_parse_device(struct acpi_ec *ec, acpi_handle handle) +static acpi_status +ec_parse_device(acpi_handle handle, u32 Level, void *context, void **retval)  { -	if (ACPI_FAILURE(acpi_walk_resources(handle, METHOD_NAME__CRS, -				     ec_parse_io_ports, ec))) -		return -EINVAL; +	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 */ -	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); +	status = acpi_evaluate_integer(handle, "_GPE", NULL, &ec->gpe); +	if (ACPI_FAILURE(status)) +		return status;  	/* Find and register all query methods */  	acpi_walk_namespace(ACPI_TYPE_METHOD, handle, 1,  			    acpi_ec_register_query_methods, ec, NULL); +	/* 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", +	printk(KERN_INFO PREFIX "GPE = 0x%lx, I/O: command/status = 0x%lx, data = 0x%lx\n",  			  ec->gpe, ec->command_addr, ec->data_addr); -	return 0; +	return AE_CTRL_TERMINATE; +} + +static void ec_remove_handlers(struct acpi_ec *ec) +{ +	acpi_remove_address_space_handler(ec->handle, +					  ACPI_ADR_SPACE_EC, +					  &acpi_ec_space_handler); +	acpi_remove_gpe_handler(NULL, ec->gpe, &acpi_ec_gpe_handler);  }  static int acpi_ec_add(struct acpi_device *device) @@ -705,7 +718,8 @@ static int acpi_ec_add(struct acpi_device *device)  	if (!ec)  		return -ENOMEM; -	if (ec_parse_device(ec, device->handle)) { +	if (ec_parse_device(device->handle, 0, ec, NULL) != +	    AE_CTRL_TERMINATE) {  		kfree(ec);  		return -EINVAL;  	} @@ -713,16 +727,13 @@ static int acpi_ec_add(struct acpi_device *device)  	/* Check if we found the boot EC */  	if (boot_ec) {  		if (boot_ec->gpe == ec->gpe) { -			/* 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; +			ec_remove_handlers(boot_ec); +			mutex_destroy(&boot_ec->lock); +			kfree(boot_ec); +			first_ec = boot_ec = NULL;  		} -	} else +	} +	if (!first_ec)  		first_ec = ec;  	ec->handle = device->handle;  	acpi_driver_data(device) = ec; @@ -734,14 +745,14 @@ static int acpi_ec_add(struct acpi_device *device)  static int acpi_ec_remove(struct acpi_device *device, int type)  {  	struct acpi_ec *ec; -	struct acpi_ec_query_handler *handler; +	struct acpi_ec_query_handler *handler, *tmp;  	if (!device)  		return -EINVAL;  	ec = acpi_driver_data(device);  	mutex_lock(&ec->lock); -	list_for_each_entry(handler, &ec->list, node) { +	list_for_each_entry_safe(handler, tmp, &ec->list, node) {  		list_del(&handler->node);  		kfree(handler);  	} @@ -751,9 +762,6 @@ static int acpi_ec_remove(struct acpi_device *device, int type)  	if (ec == first_ec)  		first_ec = NULL; -	/* Don't touch boot EC */ -	if (boot_ec != ec) -		kfree(ec);  	return 0;  } @@ -817,9 +825,7 @@ static int acpi_ec_start(struct acpi_device *device)  	if (!ec)  		return -EINVAL; -	/* Boot EC is already working */ -	if (ec != boot_ec) -		ret = ec_install_handlers(ec); +	ret = ec_install_handlers(ec);  	/* EC is fully operational, allow queries */  	atomic_set(&ec->query_pending, 0); @@ -829,7 +835,6 @@ static int acpi_ec_start(struct acpi_device *device)  static int acpi_ec_stop(struct acpi_device *device, int type)  { -	acpi_status status;  	struct acpi_ec *ec;  	if (!device) @@ -838,21 +843,7 @@ static int acpi_ec_stop(struct acpi_device *device, int type)  	ec = acpi_driver_data(device);  	if (!ec)  		return -EINVAL; - -	/* Don't touch boot EC */ -	if (ec == boot_ec) -		return 0; - -	status = acpi_remove_address_space_handler(ec->handle, -						   ACPI_ADR_SPACE_EC, -						   &acpi_ec_space_handler); -	if (ACPI_FAILURE(status)) -		return -ENODEV; - -	status = acpi_remove_gpe_handler(NULL, ec->gpe, &acpi_ec_gpe_handler); -	if (ACPI_FAILURE(status)) -		return -ENODEV; - +	ec_remove_handlers(ec);  	return 0;  } @@ -868,18 +859,21 @@ int __init acpi_ec_ecdt_probe(void)  	/*  	 * Generate a boot ec context  	 */ -  	status = acpi_get_table(ACPI_SIG_ECDT, 1,  				(struct acpi_table_header **)&ecdt_ptr); -	if (ACPI_FAILURE(status)) -		goto error; - -	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; -	boot_ec->gpe = ecdt_ptr->gpe; -	boot_ec->handle = ACPI_ROOT_OBJECT; +	if (ACPI_SUCCESS(status)) { +		printk(KERN_INFO PREFIX "EC description table is found, configuring boot EC\n\n"); +		boot_ec->command_addr = ecdt_ptr->control.address; +		boot_ec->data_addr = ecdt_ptr->data.address; +		boot_ec->gpe = ecdt_ptr->gpe; +		boot_ec->handle = ACPI_ROOT_OBJECT; +	} else { +		printk(KERN_DEBUG PREFIX "Look up EC in DSDT\n"); +		status = acpi_get_devices(ec_device_ids[0].id, ec_parse_device, +						boot_ec, NULL); +		if (ACPI_FAILURE(status)) +			goto error; +	}  	ret = ec_install_handlers(boot_ec);  	if (!ret) {  | 
