⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ec.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
static void acpi_ec_gpe_query(void *ec_cxt){	struct acpi_ec *ec = ec_cxt;	u8 value = 0;	struct acpi_ec_query_handler *handler, copy;	if (!ec || acpi_ec_query(ec, &value))		return;	mutex_lock(&ec->lock);	list_for_each_entry(handler, &ec->list, node) {		if (value == handler->query_bit) {			/* have custom handler for this bit */			memcpy(&copy, 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);}static u32 acpi_ec_gpe_handler(void *data){	acpi_status status = AE_OK;	struct acpi_ec *ec = data;	pr_debug(PREFIX "~~~> interrupt\n");	clear_bit(EC_FLAGS_WAIT_GPE, &ec->flags);	if (test_bit(EC_FLAGS_GPE_MODE, &ec->flags))		wake_up(&ec->wait);	if (acpi_ec_read_status(ec) & ACPI_EC_FLAG_SCI) {		if (!test_and_set_bit(EC_FLAGS_QUERY_PENDING, &ec->flags))			status = acpi_os_execute(OSL_EC_BURST_HANDLER,				acpi_ec_gpe_query, ec);	} else if (unlikely(!test_bit(EC_FLAGS_GPE_MODE, &ec->flags))) {		/* this is non-query, must be confirmation */		if (printk_ratelimit())			pr_info(PREFIX "non-query interrupt received,"				" switching to interrupt mode\n");		set_bit(EC_FLAGS_GPE_MODE, &ec->flags);	}	return ACPI_SUCCESS(status) ?	    ACPI_INTERRUPT_HANDLED : ACPI_INTERRUPT_NOT_HANDLED;}/* --------------------------------------------------------------------------                             Address Space Management   -------------------------------------------------------------------------- */static acpi_statusacpi_ec_space_setup(acpi_handle region_handle,		    u32 function, void *handler_context, void **return_context){	/*	 * The EC object is in the handler context and is needed	 * when calling the acpi_ec_space_handler.	 */	*return_context = (function != ACPI_REGION_DEACTIVATE) ?	    handler_context : NULL;	return AE_OK;}static acpi_statusacpi_ec_space_handler(u32 function, acpi_physical_address address,		      u32 bits, acpi_integer *value,		      void *handler_context, void *region_context){	struct acpi_ec *ec = handler_context;	int result = 0, i = 0;	u8 temp = 0;	if ((address > 0xFF) || !value || !handler_context)		return AE_BAD_PARAMETER;	if (function != ACPI_READ && function != ACPI_WRITE)		return AE_BAD_PARAMETER;	if (bits != 8 && acpi_strict)		return AE_BAD_PARAMETER;	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;	}	switch (result) {	case -EINVAL:		return AE_BAD_PARAMETER;		break;	case -ENODEV:		return AE_NOT_FOUND;		break;	case -ETIME:		return AE_TIME;		break;	default:		return AE_OK;	}}/* --------------------------------------------------------------------------                              FS Interface (/proc)   -------------------------------------------------------------------------- */static struct proc_dir_entry *acpi_ec_dir;static int acpi_ec_read_info(struct seq_file *seq, void *offset){	struct acpi_ec *ec = seq->private;	if (!ec)		goto end;	seq_printf(seq, "gpe:\t\t\t0x%02x\n", (u32) ec->gpe);	seq_printf(seq, "ports:\t\t\t0x%02x, 0x%02x\n",		   (unsigned)ec->command_addr, (unsigned)ec->data_addr);	seq_printf(seq, "use global lock:\t%s\n",		   ec->global_lock ? "yes" : "no");      end:	return 0;}static int acpi_ec_info_open_fs(struct inode *inode, struct file *file){	return single_open(file, acpi_ec_read_info, PDE(inode)->data);}static struct file_operations acpi_ec_info_ops = {	.open = acpi_ec_info_open_fs,	.read = seq_read,	.llseek = seq_lseek,	.release = single_release,	.owner = THIS_MODULE,};static int acpi_ec_add_fs(struct acpi_device *device){	struct proc_dir_entry *entry = NULL;	if (!acpi_device_dir(device)) {		acpi_device_dir(device) = proc_mkdir(acpi_device_bid(device),						     acpi_ec_dir);		if (!acpi_device_dir(device))			return -ENODEV;	}	entry = create_proc_entry(ACPI_EC_FILE_INFO, S_IRUGO,				  acpi_device_dir(device));	if (!entry)		return -ENODEV;	else {		entry->proc_fops = &acpi_ec_info_ops;		entry->data = acpi_driver_data(device);		entry->owner = THIS_MODULE;	}	return 0;}static int acpi_ec_remove_fs(struct acpi_device *device){	if (acpi_device_dir(device)) {		remove_proc_entry(ACPI_EC_FILE_INFO, acpi_device_dir(device));		remove_proc_entry(acpi_device_bid(device), acpi_ec_dir);		acpi_device_dir(device) = NULL;	}	return 0;}/* --------------------------------------------------------------------------                               Driver Interface   -------------------------------------------------------------------------- */static acpi_statusec_parse_io_ports(struct acpi_resource *resource, void *context);static struct acpi_ec *make_acpi_ec(void){	struct acpi_ec *ec = kzalloc(sizeof(struct acpi_ec), GFP_KERNEL);	if (!ec)		return NULL;	ec->flags = 1 << EC_FLAGS_QUERY_PENDING;	mutex_init(&ec->lock);	init_waitqueue_head(&ec->wait);	INIT_LIST_HEAD(&ec->list);	return ec;}static acpi_statusacpi_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 acpi_statusec_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;	/* 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;	return AE_CTRL_TERMINATE;}static void ec_remove_handlers(struct acpi_ec *ec){	if (ACPI_FAILURE(acpi_remove_address_space_handler(ec->handle,				ACPI_ADR_SPACE_EC, &acpi_ec_space_handler)))		pr_err(PREFIX "failed to remove space handler\n");	if (ACPI_FAILURE(acpi_remove_gpe_handler(NULL, ec->gpe,				&acpi_ec_gpe_handler)))		pr_err(PREFIX "failed to remove gpe handler\n");	ec->handlers_installed = 0;}static int acpi_ec_add(struct acpi_device *device){	struct acpi_ec *ec = NULL;	if (!device)		return -EINVAL;	strcpy(acpi_device_name(device), ACPI_EC_DEVICE_NAME);	strcpy(acpi_device_class(device), ACPI_EC_CLASS);	/* Check for boot EC */	if (boot_ec) {		if (boot_ec->handle == device->handle) {			/* Pre-loaded EC from DSDT, just move pointer */			ec = boot_ec;			boot_ec = NULL;			goto end;		} else if (boot_ec->handle == ACPI_ROOT_OBJECT) {			/* ECDT-based EC, time to shut it down */			ec_remove_handlers(boot_ec);			kfree(boot_ec);			first_ec = boot_ec = NULL;		}	}	ec = make_acpi_ec();	if (!ec)		return -ENOMEM;	if (ec_parse_device(device->handle, 0, ec, NULL) !=	    AE_CTRL_TERMINATE) {		kfree(ec);		return -EINVAL;	}	ec->handle = device->handle;      end:	if (!first_ec)		first_ec = ec;	acpi_driver_data(device) = ec;	acpi_ec_add_fs(device);	pr_info(PREFIX "GPE = 0x%lx, I/O: command/status = 0x%lx, data = 0x%lx\n",			  ec->gpe, ec->command_addr, ec->data_addr);	pr_info(PREFIX "driver started in %s mode\n",		(test_bit(EC_FLAGS_GPE_MODE, &ec->flags))?"interrupt":"poll");	return 0;}static int acpi_ec_remove(struct acpi_device *device, int type){	struct acpi_ec *ec;	struct acpi_ec_query_handler *handler, *tmp;	if (!device)		return -EINVAL;	ec = acpi_driver_data(device);	mutex_lock(&ec->lock);	list_for_each_entry_safe(handler, tmp, &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)		first_ec = NULL;	kfree(ec);	return 0;}static acpi_statusec_parse_io_ports(struct acpi_resource *resource, void *context){	struct acpi_ec *ec = context;	if (resource->type != ACPI_RESOURCE_TYPE_IO)		return AE_OK;	/*	 * The first address region returned is the data port, and	 * the second address region returned is the status/command	 * port.	 */	if (ec->data_addr == 0)		ec->data_addr = resource->data.io.minimum;	else if (ec->command_addr == 0)		ec->command_addr = resource->data.io.minimum;	else		return AE_CTRL_TERMINATE;	return AE_OK;}static int ec_install_handlers(struct acpi_ec *ec){	acpi_status status;	if (ec->handlers_installed)		return 0;	status = acpi_install_gpe_handler(NULL, ec->gpe,					  ACPI_GPE_EDGE_TRIGGERED,					  &acpi_ec_gpe_handler, ec);	if (ACPI_FAILURE(status))		return -ENODEV;	acpi_set_gpe_type(NULL, ec->gpe, ACPI_GPE_TYPE_RUNTIME);	acpi_enable_gpe(NULL, ec->gpe, ACPI_NOT_ISR);	status = acpi_install_address_space_handler(ec->handle,						    ACPI_ADR_SPACE_EC,						    &acpi_ec_space_handler,						    &acpi_ec_space_setup, ec);	if (ACPI_FAILURE(status)) {		acpi_remove_gpe_handler(NULL, ec->gpe, &acpi_ec_gpe_handler);		return -ENODEV;	}	ec->handlers_installed = 1;	return 0;}static int acpi_ec_start(struct acpi_device *device){	struct acpi_ec *ec;	int ret = 0;	if (!device)		return -EINVAL;	ec = acpi_driver_data(device);	if (!ec)		return -EINVAL;	ret = ec_install_handlers(ec);	/* EC is fully operational, allow queries */	clear_bit(EC_FLAGS_QUERY_PENDING, &ec->flags);	return ret;}static int acpi_ec_stop(struct acpi_device *device, int type){	struct acpi_ec *ec;	if (!device)		return -EINVAL;	ec = acpi_driver_data(device);	if (!ec)		return -EINVAL;	ec_remove_handlers(ec);	return 0;}int __init acpi_boot_ec_enable(void){	if (!boot_ec || boot_ec->handlers_installed)		return 0;	if (!ec_install_handlers(boot_ec)) {		first_ec = boot_ec;		return 0;	}	return -EFAULT;}int __init acpi_ec_ecdt_probe(void){	int ret;	acpi_status status;	struct acpi_table_ecdt *ecdt_ptr;	boot_ec = make_acpi_ec();	if (!boot_ec)		return -ENOMEM;	/*	 * Generate a boot ec context	 */	status = acpi_get_table(ACPI_SIG_ECDT, 1,				(struct acpi_table_header **)&ecdt_ptr);	if (ACPI_SUCCESS(status)) {		pr_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;	} else {		/* This workaround is needed only on some broken machines,		 * which require early EC, but fail to provide ECDT */		acpi_handle x;		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);		/* Check that acpi_get_devices actually find something */		if (ACPI_FAILURE(status) || !boot_ec->handle)			goto error;		/* We really need to limit this workaround, the only ASUS,		 * which needs it, has fake EC._INI method, so use it as flag.		 * Keep boot_ec struct as it will be needed soon.		 */		if (ACPI_FAILURE(acpi_get_handle(boot_ec->handle, "_INI", &x)))			return -ENODEV;	}	ret = ec_install_handlers(boot_ec);	if (!ret) {		first_ec = boot_ec;		return 0;	}      error:	kfree(boot_ec);	boot_ec = NULL;	return -ENODEV;}static int __init acpi_ec_init(void){	int result = 0;	if (acpi_disabled)		return 0;	acpi_ec_dir = proc_mkdir(ACPI_EC_CLASS, acpi_root_dir);	if (!acpi_ec_dir)		return -ENODEV;	/* Now register the driver for the EC */	result = acpi_bus_register_driver(&acpi_ec_driver);	if (result < 0) {		remove_proc_entry(ACPI_EC_CLASS, acpi_root_dir);		return -ENODEV;	}	return result;}subsys_initcall(acpi_ec_init);/* EC driver currently not unloadable */#if 0static void __exit acpi_ec_exit(void){	acpi_bus_unregister_driver(&acpi_ec_driver);	remove_proc_entry(ACPI_EC_CLASS, acpi_root_dir);	return;}#endif	/* 0 */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -