scan.c

来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 1,076 行 · 第 1/2 页

C
1,076
字号
/* * scan.c - support for transforming the ACPI namespace into individual objects */#include <linux/init.h>#include <linux/acpi.h>#include <acpi/acpi_drivers.h>#include <acpi/acinterp.h>	/* for acpi_ex_eisa_id_to_string() */#define _COMPONENT		ACPI_BUS_COMPONENTACPI_MODULE_NAME		("scan")#define STRUCT_TO_INT(s)	(*((int*)&s))extern struct acpi_device		*acpi_root;#define ACPI_BUS_CLASS			"system_bus"#define ACPI_BUS_HID			"ACPI_BUS"#define ACPI_BUS_DRIVER_NAME		"ACPI Bus Driver"#define ACPI_BUS_DEVICE_NAME		"System Bus"static LIST_HEAD(acpi_device_list);spinlock_t acpi_device_lock = SPIN_LOCK_UNLOCKED;LIST_HEAD(acpi_wakeup_device_list);static void acpi_device_release(struct kobject * kobj){	struct acpi_device * dev = container_of(kobj,struct acpi_device,kobj);	if (dev->pnp.cid_list)		kfree(dev->pnp.cid_list);	kfree(dev);}static struct kobj_type ktype_acpi_ns = {	.release	= acpi_device_release,};static struct kset acpi_namespace_kset = {	.kobj		= { 		.name = "namespace",	},	.subsys = &acpi_subsys,	.ktype	= &ktype_acpi_ns,};static void acpi_device_register(struct acpi_device * device, struct acpi_device * parent){	/*	 * Linkage	 * -------	 * Link this device to its parent and siblings.	 */	INIT_LIST_HEAD(&device->children);	INIT_LIST_HEAD(&device->node);	INIT_LIST_HEAD(&device->g_list);	spin_lock(&acpi_device_lock);	if (device->parent) {		list_add_tail(&device->node, &device->parent->children);		list_add_tail(&device->g_list,&device->parent->g_list);	} else		list_add_tail(&device->g_list,&acpi_device_list);	spin_unlock(&acpi_device_lock);	kobject_init(&device->kobj);	strlcpy(device->kobj.name,device->pnp.bus_id,KOBJ_NAME_LEN);	if (parent)		device->kobj.parent = &parent->kobj;	device->kobj.ktype = &ktype_acpi_ns;	device->kobj.kset = &acpi_namespace_kset;	kobject_add(&device->kobj);}static intacpi_device_unregister (	struct acpi_device	*device, 	int			type){	kobject_unregister(&device->kobj);	return 0;}voidacpi_bus_data_handler (	acpi_handle		handle,	u32			function,	void			*context){	ACPI_FUNCTION_TRACE("acpi_bus_data_handler");	/* TBD */	return_VOID;}static intacpi_bus_get_power_flags (	struct acpi_device	*device){	acpi_status             status = 0;	acpi_handle		handle = NULL;	u32                     i = 0;	ACPI_FUNCTION_TRACE("acpi_bus_get_power_flags");	/*	 * Power Management Flags	 */	status = acpi_get_handle(device->handle, "_PSC", &handle);	if (ACPI_SUCCESS(status))		device->power.flags.explicit_get = 1;	status = acpi_get_handle(device->handle, "_IRC", &handle);	if (ACPI_SUCCESS(status))		device->power.flags.inrush_current = 1;	/*	 * Enumerate supported power management states	 */	for (i = ACPI_STATE_D0; i <= ACPI_STATE_D3; i++) {		struct acpi_device_power_state *ps = &device->power.states[i];		char		object_name[5] = {'_','P','R','0'+i,'\0'};		/* Evaluate "_PRx" to se if power resources are referenced */		acpi_evaluate_reference(device->handle, object_name, NULL,			&ps->resources);		if (ps->resources.count) {			device->power.flags.power_resources = 1;			ps->flags.valid = 1;		}		/* Evaluate "_PSx" to see if we can do explicit sets */		object_name[2] = 'S';		status = acpi_get_handle(device->handle, object_name, &handle);		if (ACPI_SUCCESS(status)) {			ps->flags.explicit_set = 1;			ps->flags.valid = 1;		}		/* State is valid if we have some power control */		if (ps->resources.count || ps->flags.explicit_set)			ps->flags.valid = 1;		ps->power = -1;		/* Unknown - driver assigned */		ps->latency = -1;	/* Unknown - driver assigned */	}	/* Set defaults for D0 and D3 states (always valid) */	device->power.states[ACPI_STATE_D0].flags.valid = 1;	device->power.states[ACPI_STATE_D0].power = 100;	device->power.states[ACPI_STATE_D3].flags.valid = 1;	device->power.states[ACPI_STATE_D3].power = 0;	/* TBD: System wake support and resource requirements. */	device->power.state = ACPI_STATE_UNKNOWN;	return 0;}static intacpi_match_ids (	struct acpi_device	*device,	char			*ids){	int error = 0;	struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};	if (device->flags.hardware_id)		if (strstr(ids, device->pnp.hardware_id))			goto Done;	if (device->flags.compatible_ids) {		struct acpi_compatible_id_list *cid_list = device->pnp.cid_list;		int i;		/* compare multiple _CID entries against driver ids */		for (i = 0; i < cid_list->count; i++)		{			if (strstr(ids, cid_list->id[i].value))				goto Done;		}	}	error = -ENOENT; Done:	if (buffer.pointer)		acpi_os_free(buffer.pointer);	return error;}static acpi_statusacpi_bus_extract_wakeup_device_power_package (	struct acpi_device	*device,	union acpi_object	*package){	int 	 i = 0;	union acpi_object	*element = NULL;	if (!device || !package || (package->package.count < 2))		return AE_BAD_PARAMETER;	element = &(package->package.elements[0]);	if (!element)		return AE_BAD_PARAMETER;	if (element->type == ACPI_TYPE_PACKAGE) {		if ((element->package.count < 2) ||			(element->package.elements[0].type != ACPI_TYPE_LOCAL_REFERENCE) ||			(element->package.elements[1].type != ACPI_TYPE_INTEGER))			return AE_BAD_DATA;		device->wakeup.gpe_device = element->package.elements[0].reference.handle;		device->wakeup.gpe_number = (u32)element->package.elements[1].integer.value;	}else if (element->type == ACPI_TYPE_INTEGER) {		device->wakeup.gpe_number = element->integer.value;	}else		return AE_BAD_DATA;	element = &(package->package.elements[1]);	if (element->type != ACPI_TYPE_INTEGER) {		return AE_BAD_DATA;	}	device->wakeup.sleep_state = element->integer.value;	if ((package->package.count - 2) > ACPI_MAX_HANDLES) {		return AE_NO_MEMORY;	}	device->wakeup.resources.count = package->package.count - 2;	for (i=0; i < device->wakeup.resources.count; i++) {		element = &(package->package.elements[i + 2]);		if (element->type != ACPI_TYPE_ANY ) {			return AE_BAD_DATA;		}		device->wakeup.resources.handles[i] = element->reference.handle;	}	return AE_OK;}static intacpi_bus_get_wakeup_device_flags (	struct acpi_device	*device){	acpi_status	status = 0;	struct acpi_buffer	buffer = {ACPI_ALLOCATE_BUFFER, NULL};	union acpi_object	*package = NULL;	ACPI_FUNCTION_TRACE("acpi_bus_get_wakeup_flags");	/* _PRW */	status = acpi_evaluate_object(device->handle, "_PRW", NULL, &buffer);	if (ACPI_FAILURE(status)) {		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error evaluating _PRW\n"));		goto end;	}	package = (union acpi_object *) buffer.pointer;	status = acpi_bus_extract_wakeup_device_power_package(device, package);	if (ACPI_FAILURE(status)) {		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error extracting _PRW package\n"));		goto end;	}	acpi_os_free(buffer.pointer);	device->wakeup.flags.valid = 1;	/* Power button, Lid switch always enable wakeup*/	if (!acpi_match_ids(device, "PNP0C0D,PNP0C0C,PNP0C0E"))		device->wakeup.flags.run_wake = 1;	/* TBD: lock */	INIT_LIST_HEAD(&device->wakeup_list);	spin_lock(&acpi_device_lock);	list_add_tail(&device->wakeup_list, &acpi_wakeup_device_list);	spin_unlock(&acpi_device_lock);end:	if (ACPI_FAILURE(status))		device->flags.wake_capable = 0;	return 0;}/* --------------------------------------------------------------------------                              Performance Management   -------------------------------------------------------------------------- */static intacpi_bus_get_perf_flags (	struct acpi_device	*device){	device->performance.state = ACPI_STATE_UNKNOWN;	return 0;}/* --------------------------------------------------------------------------                                 Driver Management   -------------------------------------------------------------------------- */static LIST_HEAD(acpi_bus_drivers);static DECLARE_MUTEX(acpi_bus_drivers_lock);/** * acpi_bus_match  * -------------- * Checks the device's hardware (_HID) or compatible (_CID) ids to see if it * matches the specified driver's criteria. */static intacpi_bus_match (	struct acpi_device	*device,	struct acpi_driver	*driver){	return acpi_match_ids(device, driver->ids);}/** * acpi_bus_driver_init  * -------------------- * Used to initialize a device via its device driver.  Called whenever a  * driver is bound to a device.  Invokes the driver's add() and start() ops. */static intacpi_bus_driver_init (	struct acpi_device	*device, 	struct acpi_driver	*driver){	int			result = 0;	ACPI_FUNCTION_TRACE("acpi_bus_driver_init");	if (!device || !driver)		return_VALUE(-EINVAL);	if (!driver->ops.add)		return_VALUE(-ENOSYS);	result = driver->ops.add(device);	if (result) {		device->driver = NULL;		acpi_driver_data(device) = NULL;		return_VALUE(result);	}	device->driver = driver;	/*	 * TBD - Configuration Management: Assign resources to device based	 * upon possible configuration and currently allocated resources.	 */	if (driver->ops.start) {		result = driver->ops.start(device);		if (result && driver->ops.remove)			driver->ops.remove(device, ACPI_BUS_REMOVAL_NORMAL);		return_VALUE(result);	}	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Driver successfully bound to device\n"));	if (driver->ops.scan) {		driver->ops.scan(device);	}	return_VALUE(0);}static int acpi_driver_attach(struct acpi_driver * drv){	struct list_head * node, * next;	int count = 0;	ACPI_FUNCTION_TRACE("acpi_driver_attach");	spin_lock(&acpi_device_lock);	list_for_each_safe(node, next, &acpi_device_list) {		struct acpi_device * dev = container_of(node, struct acpi_device, g_list);		if (dev->driver || !dev->status.present)			continue;		spin_unlock(&acpi_device_lock);		if (!acpi_bus_match(dev, drv)) {			if (!acpi_bus_driver_init(dev, drv)) {				atomic_inc(&drv->references);				count++;				ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found driver [%s] for device [%s]\n",						  drv->name, dev->pnp.bus_id));			}		}		spin_lock(&acpi_device_lock);	}	spin_unlock(&acpi_device_lock);	return_VALUE(count);}static int acpi_driver_detach(struct acpi_driver * drv){	struct list_head * node, * next;	ACPI_FUNCTION_TRACE("acpi_driver_detach");	spin_lock(&acpi_device_lock);	list_for_each_safe(node,next,&acpi_device_list) {		struct acpi_device * dev = container_of(node,struct acpi_device,g_list);		if (dev->driver == drv) {			spin_unlock(&acpi_device_lock);			if (drv->ops.remove)				drv->ops.remove(dev,ACPI_BUS_REMOVAL_NORMAL);			spin_lock(&acpi_device_lock);			dev->driver = NULL;			dev->driver_data = NULL;			atomic_dec(&drv->references);		}	}	spin_unlock(&acpi_device_lock);	return_VALUE(0);}/** * acpi_bus_register_driver  * ------------------------  * Registers a driver with the ACPI bus.  Searches the namespace for all * devices that match the driver's criteria and binds.  Returns the * number of devices that were claimed by the driver, or a negative * error status for failure. */intacpi_bus_register_driver (	struct acpi_driver	*driver){	int count;	ACPI_FUNCTION_TRACE("acpi_bus_register_driver");	if (acpi_disabled)		return_VALUE(-ENODEV);	if (!driver)		return_VALUE(-EINVAL);	spin_lock(&acpi_device_lock);	list_add_tail(&driver->node, &acpi_bus_drivers);	spin_unlock(&acpi_device_lock);	count = acpi_driver_attach(driver);	return_VALUE(count);}/** * acpi_bus_unregister_driver  * -------------------------- * Unregisters a driver with the ACPI bus.  Searches the namespace for all * devices that match the driver's criteria and unbinds. */intacpi_bus_unregister_driver (	struct acpi_driver	*driver){	int error = 0;	ACPI_FUNCTION_TRACE("acpi_bus_unregister_driver");	if (driver) {		acpi_driver_detach(driver);		if (!atomic_read(&driver->references)) {			spin_lock(&acpi_device_lock);			list_del_init(&driver->node);			spin_unlock(&acpi_device_lock);		} 	} else 		error = -EINVAL;	return_VALUE(error);}/** * acpi_bus_find_driver  * -------------------- * Parses the list of registered drivers looking for a driver applicable for * the specified device. */static intacpi_bus_find_driver (	struct acpi_device	*device){	int			result = 0;	struct list_head	* node, *next;	ACPI_FUNCTION_TRACE("acpi_bus_find_driver");	if (!device->flags.hardware_id && !device->flags.compatible_ids)		goto Done;	spin_lock(&acpi_device_lock);	list_for_each_safe(node,next,&acpi_bus_drivers) {		struct acpi_driver * driver = container_of(node,struct acpi_driver,node);		atomic_inc(&driver->references);		spin_unlock(&acpi_device_lock);		if (!acpi_bus_match(device, driver)) {			result = acpi_bus_driver_init(device, driver);			if (!result)				goto Done;		}		atomic_dec(&driver->references);		spin_lock(&acpi_device_lock);	}	spin_unlock(&acpi_device_lock); Done:	return_VALUE(result);}/* --------------------------------------------------------------------------                                 Device Enumeration   -------------------------------------------------------------------------- */static int acpi_bus_get_flags (	struct acpi_device	*device){	acpi_status		status = AE_OK;	acpi_handle		temp = NULL;	ACPI_FUNCTION_TRACE("acpi_bus_get_flags");	/* Presence of _STA indicates 'dynamic_status' */	status = acpi_get_handle(device->handle, "_STA", &temp);	if (ACPI_SUCCESS(status))		device->flags.dynamic_status = 1;

⌨️ 快捷键说明

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