#include <linux/module.h>
#include <linux/init.h>
-#include <linux/kernel.h>
#include <linux/acpi.h>
#include <acpi/acpi_drivers.h>
DEFINE_SPINLOCK(acpi_device_lock);
LIST_HEAD(acpi_wakeup_device_list);
+static int acpi_bus_trim(struct acpi_device *start, int rmdevice);
static void acpi_device_release(struct kobject *kobj)
{
static void acpi_device_register(struct acpi_device *device,
struct acpi_device *parent)
{
- int err;
-
/*
* Linkage
* -------
device->kobj.parent = &parent->kobj;
device->kobj.ktype = &ktype_acpi_ns;
device->kobj.kset = &acpi_namespace_kset;
- err = kobject_register(&device->kobj);
- if (err < 0)
- printk(KERN_WARNING "%s: kobject_register error: %d\n",
- __FUNCTION__, err);
+ kobject_register(&device->kobj);
create_sysfs_device_files(device);
}
-static void acpi_device_unregister(struct acpi_device *device, int type)
+static int acpi_device_unregister(struct acpi_device *device, int type)
{
spin_lock(&acpi_device_lock);
if (device->parent) {
acpi_detach_data(device->handle, acpi_bus_data_handler);
remove_sysfs_device_files(device);
kobject_unregister(&device->kobj);
+ return 0;
}
void acpi_bus_data_handler(acpi_handle handle, u32 function, void *context)
{
+ ACPI_FUNCTION_TRACE("acpi_bus_data_handler");
/* TBD */
- return;
+ return_VOID;
}
static int acpi_bus_get_power_flags(struct acpi_device *device)
acpi_handle handle = NULL;
u32 i = 0;
+ ACPI_FUNCTION_TRACE("acpi_bus_get_power_flags");
/*
* Power Management Flags
device->power.state = ACPI_STATE_UNKNOWN;
- return 0;
+ return_VALUE(0);
}
int acpi_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))
- return 0;
+ goto Done;
if (device->flags.compatible_ids) {
struct acpi_compatible_id_list *cid_list = device->pnp.cid_list;
/* compare multiple _CID entries against driver ids */
for (i = 0; i < cid_list->count; i++) {
if (strstr(ids, cid_list->id[i].value))
- return 0;
+ goto Done;
}
}
- return -ENOENT;
+ error = -ENOENT;
+
+ Done:
+ if (buffer.pointer)
+ acpi_os_free(buffer.pointer);
+ return error;
}
static acpi_status
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_EXCEPTION((AE_INFO, status, "Evaluating _PRW"));
+ 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_EXCEPTION((AE_INFO, status, "Extracting _PRW package"));
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "Error extracting _PRW package\n"));
goto end;
}
- kfree(buffer.pointer);
+ acpi_os_free(buffer.pointer);
device->wakeup.flags.valid = 1;
/* Power button, Lid switch always enable wakeup */
end:
if (ACPI_FAILURE(status))
device->flags.wake_capable = 0;
- return 0;
+ return_VALUE(0);
}
/* --------------------------------------------------------------------------
islockable = device->flags.lockable;
handle = device->handle;
- result = acpi_bus_trim(device, 1);
+ if (type == ACPI_TYPE_PROCESSOR)
+ result = acpi_bus_trim(device, 0);
+ else
+ result = acpi_bus_trim(device, 1);
if (!result)
result = acpi_eject_operation(handle, islockable);
-------------------------------------------------------------------------- */
static LIST_HEAD(acpi_bus_drivers);
+static DECLARE_MUTEX(acpi_bus_drivers_lock);
/**
* acpi_bus_match - match device IDs to driver's supported IDs
{
int result = 0;
+ ACPI_FUNCTION_TRACE("acpi_bus_driver_init");
if (!device || !driver)
- return -EINVAL;
+ return_VALUE(-EINVAL);
if (!driver->ops.add)
- return -ENOSYS;
+ return_VALUE(-ENOSYS);
result = driver->ops.add(device);
if (result) {
device->driver = NULL;
acpi_driver_data(device) = NULL;
- return result;
+ return_VALUE(result);
}
device->driver = driver;
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"Driver successfully bound to device\n"));
- return 0;
+ return_VALUE(0);
}
static int acpi_start_single_object(struct acpi_device *device)
int result = 0;
struct acpi_driver *driver;
+ ACPI_FUNCTION_TRACE("acpi_start_single_object");
if (!(driver = device->driver))
- return 0;
+ return_VALUE(0);
if (driver->ops.start) {
result = driver->ops.start(device);
driver->ops.remove(device, ACPI_BUS_REMOVAL_NORMAL);
}
- return result;
+ return_VALUE(result);
}
-static void acpi_driver_attach(struct acpi_driver *drv)
+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) {
if (!acpi_bus_driver_init(dev, drv)) {
acpi_start_single_object(dev);
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 void acpi_driver_detach(struct acpi_driver *drv)
+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) {
}
}
spin_unlock(&acpi_device_lock);
+ return_VALUE(0);
}
/**
* @driver: driver being registered
*
* Registers a driver with the ACPI bus. Searches the namespace for all
- * devices that match the driver's criteria and binds. Returns zero for
- * success or a negative error status for failure.
+ * 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.
*/
int acpi_bus_register_driver(struct acpi_driver *driver)
{
+ int count;
+
+ ACPI_FUNCTION_TRACE("acpi_bus_register_driver");
if (acpi_disabled)
- return -ENODEV;
+ 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);
- acpi_driver_attach(driver);
+ count = acpi_driver_attach(driver);
- return 0;
+ return_VALUE(count);
}
EXPORT_SYMBOL(acpi_bus_register_driver);
* Unregisters a driver with the ACPI bus. Searches the namespace for all
* devices that match the driver's criteria and unbinds.
*/
-void acpi_bus_unregister_driver(struct acpi_driver *driver)
+int acpi_bus_unregister_driver(struct acpi_driver *driver)
{
- acpi_driver_detach(driver);
+ int error = 0;
- if (!atomic_read(&driver->references)) {
- spin_lock(&acpi_device_lock);
- list_del_init(&driver->node);
- spin_unlock(&acpi_device_lock);
- }
- return;
+ 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);
}
EXPORT_SYMBOL(acpi_bus_unregister_driver);
int result = 0;
struct list_head *node, *next;
+ ACPI_FUNCTION_TRACE("acpi_bus_find_driver");
spin_lock(&acpi_device_lock);
list_for_each_safe(node, next, &acpi_bus_drivers) {
spin_unlock(&acpi_device_lock);
Done:
- return result;
+ return_VALUE(result);
}
/* --------------------------------------------------------------------------
Device Enumeration
-------------------------------------------------------------------------- */
-acpi_status
-acpi_bus_get_ejd(acpi_handle handle, acpi_handle *ejd)
-{
- acpi_status status;
- acpi_handle tmp;
- struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
- union acpi_object *obj;
-
- status = acpi_get_handle(handle, "_EJD", &tmp);
- if (ACPI_FAILURE(status))
- return status;
-
- status = acpi_evaluate_object(handle, "_EJD", NULL, &buffer);
- if (ACPI_SUCCESS(status)) {
- obj = buffer.pointer;
- status = acpi_get_handle(NULL, obj->string.pointer, ejd);
- kfree(buffer.pointer);
- }
- return status;
-}
-EXPORT_SYMBOL_GPL(acpi_bus_get_ejd);
-
-
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);
/* TBD: Peformance management */
- return 0;
+ return_VALUE(0);
}
static void acpi_device_get_busid(struct acpi_device *device,
printk(KERN_ERR "Memory allocation error\n");
}
- kfree(buffer.pointer);
+ acpi_os_free(buffer.pointer);
}
static int acpi_device_set_context(struct acpi_device *device, int type)
int result = 0;
struct acpi_driver *driver;
+ ACPI_FUNCTION_TRACE("acpi_bus_remove");
if (!dev)
- return -EINVAL;
+ return_VALUE(-EINVAL);
driver = dev->driver;
if (driver->ops.stop) {
result = driver->ops.stop(dev, ACPI_BUS_REMOVAL_EJECT);
if (result)
- return result;
+ return_VALUE(result);
}
result = dev->driver->ops.remove(dev, ACPI_BUS_REMOVAL_EJECT);
if (result) {
- return result;
+ return_VALUE(result);
}
atomic_dec(&dev->driver->references);
}
if (!rmdevice)
- return 0;
+ return_VALUE(0);
if (dev->flags.bus_address) {
if ((dev->parent) && (dev->parent->ops.unbind))
acpi_device_unregister(dev, ACPI_BUS_REMOVAL_EJECT);
- return 0;
+ return_VALUE(0);
}
static int
int result = 0;
struct acpi_device *device = NULL;
+ ACPI_FUNCTION_TRACE("acpi_add_single_object");
if (!child)
- return -EINVAL;
+ return_VALUE(-EINVAL);
device = kmalloc(sizeof(struct acpi_device), GFP_KERNEL);
if (!device) {
- printk(KERN_ERR PREFIX "Memory allocation error\n");
- return -ENOMEM;
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Memory allocation error\n"));
+ return_VALUE(-ENOMEM);
}
memset(device, 0, sizeof(struct acpi_device));
kfree(device);
}
- return result;
+ return_VALUE(result);
}
static int acpi_bus_scan(struct acpi_device *start, struct acpi_bus_ops *ops)
acpi_object_type type = 0;
u32 level = 1;
+ ACPI_FUNCTION_TRACE("acpi_bus_scan");
if (!start)
- return -EINVAL;
+ return_VALUE(-EINVAL);
parent = start;
phandle = start->handle;
}
}
- return 0;
+ return_VALUE(0);
}
int
int result;
struct acpi_bus_ops ops;
+ ACPI_FUNCTION_TRACE("acpi_bus_add");
result = acpi_add_single_object(child, parent, handle, type);
if (!result) {
ops.acpi_op_add = 1;
result = acpi_bus_scan(*child, &ops);
}
- return result;
+ return_VALUE(result);
}
EXPORT_SYMBOL(acpi_bus_add);
int result;
struct acpi_bus_ops ops;
+ ACPI_FUNCTION_TRACE("acpi_bus_start");
if (!device)
- return -EINVAL;
+ return_VALUE(-EINVAL);
result = acpi_start_single_object(device);
if (!result) {
ops.acpi_op_start = 1;
result = acpi_bus_scan(device, &ops);
}
- return result;
+ return_VALUE(result);
}
EXPORT_SYMBOL(acpi_bus_start);
-int acpi_bus_trim(struct acpi_device *start, int rmdevice)
+static int acpi_bus_trim(struct acpi_device *start, int rmdevice)
{
acpi_status status;
struct acpi_device *parent, *child;
}
return err;
}
-EXPORT_SYMBOL_GPL(acpi_bus_trim);
-
static int acpi_bus_scan_fixed(struct acpi_device *root)
{
int result = 0;
struct acpi_device *device = NULL;
+ ACPI_FUNCTION_TRACE("acpi_bus_scan_fixed");
if (!root)
- return -ENODEV;
+ return_VALUE(-ENODEV);
/*
* Enumerate all fixed-feature devices.
result = acpi_start_single_object(device);
}
- return result;
-}
-
-
-static inline struct acpi_device * to_acpi_dev(struct device * dev)
-{
- return container_of(dev, struct acpi_device, dev);
+ return_VALUE(result);
}
-
-static int root_suspend(struct acpi_device * acpi_dev, pm_message_t state)
-{
- struct acpi_device * dev, * next;
- int result;
-
- spin_lock(&acpi_device_lock);
- list_for_each_entry_safe_reverse(dev, next, &acpi_device_list, g_list) {
- if (dev->driver && dev->driver->ops.suspend) {
- spin_unlock(&acpi_device_lock);
- result = dev->driver->ops.suspend(dev, 0);
- if (result) {
- printk(KERN_ERR PREFIX "[%s - %s] Suspend failed: %d\n",
- acpi_device_name(dev),
- acpi_device_bid(dev), result);
- }
- spin_lock(&acpi_device_lock);
- }
- }
- spin_unlock(&acpi_device_lock);
- return 0;
-}
-
-
-static int acpi_device_suspend(struct device * dev, pm_message_t state)
-{
- struct acpi_device * acpi_dev = to_acpi_dev(dev);
-
- /*
- * For now, we should only register 1 generic device -
- * the ACPI root device - and from there, we walk the
- * tree of ACPI devices to suspend each one using the
- * ACPI driver methods.
- */
- if (acpi_dev->handle == ACPI_ROOT_OBJECT)
- root_suspend(acpi_dev, state);
- return 0;
-}
-
-
-
-static int root_resume(struct acpi_device * acpi_dev)
-{
- struct acpi_device * dev, * next;
- int result;
-
- spin_lock(&acpi_device_lock);
- list_for_each_entry_safe(dev, next, &acpi_device_list, g_list) {
- if (dev->driver && dev->driver->ops.resume) {
- spin_unlock(&acpi_device_lock);
- result = dev->driver->ops.resume(dev, 0);
- if (result) {
- printk(KERN_ERR PREFIX "[%s - %s] resume failed: %d\n",
- acpi_device_name(dev),
- acpi_device_bid(dev), result);
- }
- spin_lock(&acpi_device_lock);
- }
- }
- spin_unlock(&acpi_device_lock);
- return 0;
-}
-
-
-static int acpi_device_resume(struct device * dev)
-{
- struct acpi_device * acpi_dev = to_acpi_dev(dev);
-
- /*
- * For now, we should only register 1 generic device -
- * the ACPI root device - and from there, we walk the
- * tree of ACPI devices to resume each one using the
- * ACPI driver methods.
- */
- if (acpi_dev->handle == ACPI_ROOT_OBJECT)
- root_resume(acpi_dev);
- return 0;
-}
-
-
-static struct bus_type acpi_bus_type = {
- .name = "acpi",
- .suspend = acpi_device_suspend,
- .resume = acpi_device_resume,
-};
-
-
-
static int __init acpi_scan_init(void)
{
int result;
struct acpi_bus_ops ops;
+ ACPI_FUNCTION_TRACE("acpi_scan_init");
if (acpi_disabled)
- return 0;
-
- result = kset_register(&acpi_namespace_kset);
- if (result < 0)
- printk(KERN_ERR PREFIX "kset_register error: %d\n", result);
+ return_VALUE(0);
- result = bus_register(&acpi_bus_type);
- if (result) {
- /* We don't want to quit even if we failed to add suspend/resume */
- printk(KERN_ERR PREFIX "Could not register bus type\n");
- }
+ kset_register(&acpi_namespace_kset);
/*
* Create the root device in the bus's device tree
goto Done;
result = acpi_start_single_object(acpi_root);
- if (result)
- goto Done;
-
- acpi_root->dev.bus = &acpi_bus_type;
- snprintf(acpi_root->dev.bus_id, BUS_ID_SIZE, "%s", acpi_bus_type.name);
- result = device_register(&acpi_root->dev);
- if (result) {
- /* We don't want to quit even if we failed to add suspend/resume */
- printk(KERN_ERR PREFIX "Could not register device\n");
- }
/*
* Enumerate devices in the ACPI namespace.
acpi_device_unregister(acpi_root, ACPI_BUS_REMOVAL_NORMAL);
Done:
- return result;
+ return_VALUE(result);
}
subsys_initcall(acpi_scan_init);