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 + -
显示快捷键?