diff options
Diffstat (limited to 'drivers/acpi')
39 files changed, 1016 insertions, 178 deletions
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig index 290c767dd77..56c5ba87462 100644 --- a/drivers/acpi/Kconfig +++ b/drivers/acpi/Kconfig @@ -107,7 +107,6 @@ config ACPI_BUTTON config ACPI_VIDEO tristate "Video" depends on X86 - default y help This driver implement the ACPI Extensions For Display Adapters for integrated graphics devices on motherboard, as specified in @@ -133,6 +132,12 @@ config ACPI_FAN This driver adds support for ACPI fan devices, allowing user-mode applications to perform basic fan control (on, off, status). +config ACPI_DOCK + tristate "Dock" + depends on EXPERIMENTAL + help + This driver adds support for ACPI controlled docking stations + config ACPI_PROCESSOR tristate "Processor" default y @@ -207,6 +212,7 @@ config ACPI_IBM config ACPI_IBM_DOCK bool "Legacy Docking Station Support" depends on ACPI_IBM + depends on ACPI_DOCK=n default n ---help--- Allows the ibm_acpi driver to handle docking station events. @@ -350,7 +356,6 @@ config ACPI_SBS tristate "Smart Battery System (EXPERIMENTAL)" depends on X86 && I2C depends on EXPERIMENTAL - default y help This driver adds support for the Smart Battery System. Depends on I2C (Device Drivers ---> I2C support) diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile index bb5b80a80b1..bce7ca27b42 100644 --- a/drivers/acpi/Makefile +++ b/drivers/acpi/Makefile @@ -42,6 +42,7 @@ obj-$(CONFIG_ACPI_BATTERY) += battery.o obj-$(CONFIG_ACPI_BUTTON) += button.o obj-$(CONFIG_ACPI_EC) += ec.o obj-$(CONFIG_ACPI_FAN) += fan.o +obj-$(CONFIG_ACPI_DOCK) += dock.o obj-$(CONFIG_ACPI_VIDEO) += video.o obj-$(CONFIG_ACPI_HOTKEY) += hotkey.o obj-y += pci_root.o pci_link.o pci_irq.o pci_bind.o diff --git a/drivers/acpi/ac.c b/drivers/acpi/ac.c index 24ccf81d135..96309b9660d 100644 --- a/drivers/acpi/ac.c +++ b/drivers/acpi/ac.c @@ -72,7 +72,7 @@ struct acpi_ac { unsigned long state; }; -static struct file_operations acpi_ac_fops = { +static const struct file_operations acpi_ac_fops = { .open = acpi_ac_open_fs, .read = seq_read, .llseek = seq_lseek, diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c index 24bf4dca88c..6e5221707d9 100644 --- a/drivers/acpi/battery.c +++ b/drivers/acpi/battery.c @@ -557,7 +557,7 @@ static int acpi_battery_alarm_open_fs(struct inode *inode, struct file *file) return single_open(file, acpi_battery_read_alarm, PDE(inode)->data); } -static struct file_operations acpi_battery_info_ops = { +static const struct file_operations acpi_battery_info_ops = { .open = acpi_battery_info_open_fs, .read = seq_read, .llseek = seq_lseek, @@ -565,7 +565,7 @@ static struct file_operations acpi_battery_info_ops = { .owner = THIS_MODULE, }; -static struct file_operations acpi_battery_state_ops = { +static const struct file_operations acpi_battery_state_ops = { .open = acpi_battery_state_open_fs, .read = seq_read, .llseek = seq_lseek, @@ -573,7 +573,7 @@ static struct file_operations acpi_battery_state_ops = { .owner = THIS_MODULE, }; -static struct file_operations acpi_battery_alarm_ops = { +static const struct file_operations acpi_battery_alarm_ops = { .open = acpi_battery_alarm_open_fs, .read = seq_read, .write = acpi_battery_write_alarm, diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index ea5a0496a4f..b2977695e12 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -192,8 +192,8 @@ int acpi_bus_set_power(acpi_handle handle, int state) /* Make sure this is a valid target state */ if (!device->flags.power_manageable) { - printk(KERN_DEBUG "Device `[%s]' is not power manageable", - device->kobj.name); + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device `[%s]' is not power manageable", + device->kobj.name)); return -ENODEV; } /* diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c index fd1ba05eab6..5ef885e82c7 100644 --- a/drivers/acpi/button.c +++ b/drivers/acpi/button.c @@ -87,14 +87,14 @@ struct acpi_button { unsigned long pushed; }; -static struct file_operations acpi_button_info_fops = { +static const struct file_operations acpi_button_info_fops = { .open = acpi_button_info_open_fs, .read = seq_read, .llseek = seq_lseek, .release = single_release, }; -static struct file_operations acpi_button_state_fops = { +static const struct file_operations acpi_button_state_fops = { .open = acpi_button_state_open_fs, .read = seq_read, .llseek = seq_lseek, diff --git a/drivers/acpi/cm_sbs.c b/drivers/acpi/cm_sbs.c index 574a75a166c..a01ce6700bf 100644 --- a/drivers/acpi/cm_sbs.c +++ b/drivers/acpi/cm_sbs.c @@ -39,50 +39,43 @@ ACPI_MODULE_NAME("cm_sbs") static struct proc_dir_entry *acpi_ac_dir; static struct proc_dir_entry *acpi_battery_dir; -static struct semaphore cm_sbs_sem; +static DEFINE_MUTEX(cm_sbs_mutex); -static int lock_ac_dir_cnt = 0; -static int lock_battery_dir_cnt = 0; +static int lock_ac_dir_cnt; +static int lock_battery_dir_cnt; struct proc_dir_entry *acpi_lock_ac_dir(void) { - - down(&cm_sbs_sem); - if (!acpi_ac_dir) { + mutex_lock(&cm_sbs_mutex); + if (!acpi_ac_dir) acpi_ac_dir = proc_mkdir(ACPI_AC_CLASS, acpi_root_dir); - } if (acpi_ac_dir) { lock_ac_dir_cnt++; } else { ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Cannot create %s\n", ACPI_AC_CLASS)); } - up(&cm_sbs_sem); + mutex_unlock(&cm_sbs_mutex); return acpi_ac_dir; } - EXPORT_SYMBOL(acpi_lock_ac_dir); void acpi_unlock_ac_dir(struct proc_dir_entry *acpi_ac_dir_param) { - - down(&cm_sbs_sem); - if (acpi_ac_dir_param) { + mutex_lock(&cm_sbs_mutex); + if (acpi_ac_dir_param) lock_ac_dir_cnt--; - } if (lock_ac_dir_cnt == 0 && acpi_ac_dir_param && acpi_ac_dir) { remove_proc_entry(ACPI_AC_CLASS, acpi_root_dir); acpi_ac_dir = 0; } - up(&cm_sbs_sem); + mutex_unlock(&cm_sbs_mutex); } - EXPORT_SYMBOL(acpi_unlock_ac_dir); struct proc_dir_entry *acpi_lock_battery_dir(void) { - - down(&cm_sbs_sem); + mutex_lock(&cm_sbs_mutex); if (!acpi_battery_dir) { acpi_battery_dir = proc_mkdir(ACPI_BATTERY_CLASS, acpi_root_dir); @@ -93,39 +86,28 @@ struct proc_dir_entry *acpi_lock_battery_dir(void) ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Cannot create %s\n", ACPI_BATTERY_CLASS)); } - up(&cm_sbs_sem); + mutex_unlock(&cm_sbs_mutex); return acpi_battery_dir; } - EXPORT_SYMBOL(acpi_lock_battery_dir); void acpi_unlock_battery_dir(struct proc_dir_entry *acpi_battery_dir_param) { - - down(&cm_sbs_sem); - if (acpi_battery_dir_param) { + mutex_lock(&cm_sbs_mutex); + if (acpi_battery_dir_param) lock_battery_dir_cnt--; - } if (lock_battery_dir_cnt == 0 && acpi_battery_dir_param && acpi_battery_dir) { remove_proc_entry(ACPI_BATTERY_CLASS, acpi_root_dir); acpi_battery_dir = 0; } - up(&cm_sbs_sem); + mutex_unlock(&cm_sbs_mutex); return; } - EXPORT_SYMBOL(acpi_unlock_battery_dir); static int __init acpi_cm_sbs_init(void) { - - if (acpi_disabled) - return 0; - - init_MUTEX(&cm_sbs_sem); - return 0; } - subsys_initcall(acpi_cm_sbs_init); diff --git a/drivers/acpi/dispatcher/dsinit.c b/drivers/acpi/dispatcher/dsinit.c index daf51b5b587..1888c055d10 100644 --- a/drivers/acpi/dispatcher/dsinit.c +++ b/drivers/acpi/dispatcher/dsinit.c @@ -116,16 +116,6 @@ acpi_ds_init_one_object(acpi_handle obj_handle, case ACPI_TYPE_METHOD: - /* - * Set the execution data width (32 or 64) based upon the - * revision number of the parent ACPI table. - * TBD: This is really for possible future support of integer width - * on a per-table basis. Currently, we just use a global for the width. - */ - if (info->table_desc->pointer->revision == 1) { - node->flags |= ANOBJ_DATA_WIDTH_32; - } - info->method_count++; break; diff --git a/drivers/acpi/dispatcher/dsmethod.c b/drivers/acpi/dispatcher/dsmethod.c index a39a33f4847..cf888add319 100644 --- a/drivers/acpi/dispatcher/dsmethod.c +++ b/drivers/acpi/dispatcher/dsmethod.c @@ -134,7 +134,7 @@ acpi_ds_create_method_mutex(union acpi_operand_object *method_desc) union acpi_operand_object *mutex_desc; acpi_status status; - ACPI_FUNCTION_NAME(ds_create_method_mutex); + ACPI_FUNCTION_TRACE(ds_create_method_mutex); /* Create the new mutex object */ @@ -493,7 +493,7 @@ acpi_ds_restart_control_method(struct acpi_walk_state *walk_state, ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, "****Restart [%4.4s] Op %p ReturnValueFromCallee %p\n", - (char *)&walk_state->method_node->name, + acpi_ut_get_node_name(walk_state->method_node), walk_state->method_call_op, return_desc)); ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, @@ -610,6 +610,7 @@ acpi_ds_terminate_control_method(union acpi_operand_object *method_desc, acpi_os_release_mutex(method_desc->method.mutex->mutex. os_mutex); + method_desc->method.mutex->mutex.owner_thread = NULL; } } @@ -620,27 +621,11 @@ acpi_ds_terminate_control_method(union acpi_operand_object *method_desc, */ method_node = walk_state->method_node; - /* Lock namespace for possible update */ - - status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); - if (ACPI_FAILURE(status)) { - return_VOID; - } - - /* - * Delete any namespace entries created immediately underneath - * the method - */ - if (method_node && method_node->child) { - acpi_ns_delete_namespace_subtree(method_node); - } - /* - * Delete any namespace entries created anywhere else within + * Delete any namespace objects created anywhere within * the namespace by the execution of this method */ acpi_ns_delete_namespace_by_owner(method_desc->method.owner_id); - status = acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); } /* Decrement the thread count on the method */ diff --git a/drivers/acpi/dispatcher/dswexec.c b/drivers/acpi/dispatcher/dswexec.c index b1ded62d0df..d7a616c3104 100644 --- a/drivers/acpi/dispatcher/dswexec.c +++ b/drivers/acpi/dispatcher/dswexec.c @@ -313,10 +313,10 @@ acpi_ds_exec_begin_op(struct acpi_walk_state *walk_state, case AML_CLASS_EXECUTE: case AML_CLASS_CREATE: /* - * Most operators with arguments. + * Most operators with arguments (except create_xxx_field operators) * Start a new result/operand state */ - if (walk_state->opcode != AML_CREATE_FIELD_OP) { + if (walk_state->op_info->object_type != ACPI_TYPE_BUFFER_FIELD) { status = acpi_ds_result_stack_push(walk_state); } break; diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c new file mode 100644 index 00000000000..510a9452429 --- /dev/null +++ b/drivers/acpi/dock.c @@ -0,0 +1,739 @@ +/* + * dock.c - ACPI dock station driver + * + * Copyright (C) 2006 Kristen Carlson Accardi <kristen.c.accardi@intel.com> + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/types.h> +#include <linux/notifier.h> +#include <acpi/acpi_bus.h> +#include <acpi/acpi_drivers.h> + +#define ACPI_DOCK_DRIVER_NAME "ACPI Dock Station Driver" + +ACPI_MODULE_NAME("dock") +MODULE_AUTHOR("Kristen Carlson Accardi"); +MODULE_DESCRIPTION(ACPI_DOCK_DRIVER_NAME); +MODULE_LICENSE("GPL"); + +static struct atomic_notifier_head dock_notifier_list; + +struct dock_station { + acpi_handle handle; + unsigned long last_dock_time; + u32 flags; + spinlock_t dd_lock; + spinlock_t hp_lock; + struct list_head dependent_devices; + struct list_head hotplug_devices; +}; + +struct dock_dependent_device { + struct list_head list; + struct list_head hotplug_list; + acpi_handle handle; + acpi_notify_handler handler; + void *context; +}; + +#define DOCK_DOCKING 0x00000001 +#define DOCK_EVENT KOBJ_DOCK +#define UNDOCK_EVENT KOBJ_UNDOCK + +static struct dock_station *dock_station; + +/***************************************************************************** + * Dock Dependent device functions * + *****************************************************************************/ +/** + * alloc_dock_dependent_device - allocate and init a dependent device + * @handle: the acpi_handle of the dependent device + * + * Allocate memory for a dependent device structure for a device referenced + * by the acpi handle + */ +static struct dock_dependent_device * +alloc_dock_dependent_device(acpi_handle handle) +{ + struct dock_dependent_device *dd; + + dd = kzalloc(sizeof(*dd), GFP_KERNEL); + if (dd) { + dd->handle = handle; + INIT_LIST_HEAD(&dd->list); + INIT_LIST_HEAD(&dd->hotplug_list); + } + return dd; +} + +/** + * add_dock_dependent_device - associate a device with the dock station + * @ds: The dock station + * @dd: The dependent device + * + * Add the dependent device to the dock's dependent device list. + */ +static void +add_dock_dependent_device(struct dock_station *ds, + struct dock_dependent_device *dd) +{ + spin_lock(&ds->dd_lock); + list_add_tail(&dd->list, &ds->dependent_devices); + spin_unlock(&ds->dd_lock); +} + +/** + * dock_add_hotplug_device - associate a hotplug handler with the dock station + * @ds: The dock station + * @dd: The dependent device struct + * + * Add the dependent device to the dock's hotplug device list + */ +static void +dock_add_hotplug_device(struct dock_station *ds, + struct dock_dependent_device *dd) +{ + spin_lock(&ds->hp_lock); + list_add_tail(&dd->hotplug_list, &ds->hotplug_devices); + spin_unlock(&ds->hp_lock); +} + +/** + * dock_del_hotplug_device - remove a hotplug handler from the dock station + * @ds: The dock station + * @dd: the dependent device struct + * + * Delete the dependent device from the dock's hotplug device list + */ +static void +dock_del_hotplug_device(struct dock_station *ds, + struct dock_dependent_device *dd) +{ + spin_lock(&ds->hp_lock); + list_del(&dd->hotplug_list); + spin_unlock(&ds->hp_lock); +} + +/** + * find_dock_dependent_device - get a device dependent on this dock + * @ds: the dock station + * @handle: the acpi_handle of the device we want + * + * iterate over the dependent device list for this dock. If the + * dependent device matches the handle, return. + */ +static struct dock_dependent_device * +find_dock_dependent_device(struct dock_station *ds, acpi_handle handle) +{ + struct dock_dependent_device *dd; + + spin_lock(&ds->dd_lock); + list_for_each_entry(dd, &ds->dependent_devices, list) { + if (handle == dd->handle) { + spin_unlock(&ds->dd_lock); + return dd; + } + } + spin_unlock(&ds->dd_lock); + return NULL; +} + +/***************************************************************************** + * Dock functions * + *****************************************************************************/ +/** + * is_dock - see if a device is a dock station + * @handle: acpi handle of the device + * + * If an acpi object has a _DCK method, then it is by definition a dock + * station, so return true. + */ +static int is_dock(acpi_handle handle) +{ + acpi_status status; + acpi_handle tmp; + + status = acpi_get_handle(handle, "_DCK", &tmp); + if (ACPI_FAILURE(status)) + return 0; + return 1; +} + +/** + * is_dock_device - see if a device is on a dock station + * @handle: acpi handle of the device + * + * If this device is either the dock station itself, + * or is a device dependent on the dock station, then it + * is a dock device + */ +int is_dock_device(acpi_handle handle) +{ + if (!dock_station) + return 0; + + if (is_dock(handle) || find_dock_dependent_device(dock_station, handle)) + return 1; + + return 0; +} + +EXPORT_SYMBOL_GPL(is_dock_device); + +/** + * dock_present - see if the dock station is present. + * @ds: the dock station + * + * execute the _STA method. note that present does not + * imply that we are docked. + */ +static int dock_present(struct dock_station *ds) +{ + unsigned long sta; + acpi_status status; + + if (ds) { + status = acpi_evaluate_integer(ds->handle, "_STA", NULL, &sta); + if (ACPI_SUCCESS(status) && sta) + return 1; + } + return 0; +} + + + +/** + * dock_create_acpi_device - add new devices to acpi + * @handle - handle of the device to add + * + * This function will create a new acpi_device for the given + * handle if one does not exist already. This should cause + * acpi to scan for drivers for the given devices, and call + * matching driver's add routine. + * + * Returns a pointer to the acpi_device corresponding to the handle. + */ +static struct acpi_device * dock_create_acpi_device(acpi_handle handle) +{ + struct acpi_device *device = NULL; + struct acpi_device *parent_device; + acpi_handle parent; + int ret; + + if (acpi_bus_get_device(handle, &device)) { + /* + * no device created for this object, + * so we should create one. + */ + acpi_get_parent(handle, &parent); + if (acpi_bus_get_device(parent, &parent_device)) + parent_device = NULL; + + ret = acpi_bus_add(&device, parent_device, handle, + ACPI_BUS_TYPE_DEVICE); + if (ret) { + pr_debug("error adding bus, %x\n", + -ret); + return NULL; + } + } + return device; +} + +/** + * dock_remove_acpi_device - remove the acpi_device struct from acpi + * @handle - the handle of the device to remove + * + * Tell acpi to remove the acpi_device. This should cause any loaded + * driver to have it's remove routine called. + */ +static void dock_remove_acpi_device(acpi_handle handle) +{ + struct acpi_device *device; + int ret; + + if (!acpi_bus_get_device(handle, &device)) { + ret = acpi_bus_trim(device, 1); + if (ret) + pr_debug("error removing bus, %x\n", -ret); + } +} + + +/** + * hotplug_dock_devices - insert or remove devices on the dock station + * @ds: the dock station + * @event: either bus check or eject request + * + * Some devices on the dock station need to have drivers called + * to perform hotplug operations after a dock event has occurred. + * Traverse the list of dock devices that have registered a + * hotplug handler, and call the handler. + */ +static void hotplug_dock_devices(struct dock_station *ds, u32 event) +{ + struct dock_dependent_device *dd; + + spin_lock(&ds->hp_lock); + + /* + * First call driver specific hotplug functions + */ + list_for_each_entry(dd, &ds->hotplug_devices, hotplug_list) { + if (dd->handler) + dd->handler(dd->handle, event, dd->context); + } + + /* + * Now make sure that an acpi_device is created for each + * dependent device, or removed if this is an eject request. + * This will cause acpi_drivers to be stopped/started if they + * exist + */ + list_for_each_entry(dd, &ds->dependent_devices, list) { + if (event == ACPI_NOTIFY_EJECT_REQUEST) + dock_remove_acpi_device(dd->handle); + else + dock_create_acpi_device(dd->handle); + } + spin_unlock(&ds->hp_lock); +} + +static void dock_event(struct dock_station *ds, u32 event, int num) +{ + struct acpi_device *device; + + device = dock_create_acpi_device(ds->handle); + if (device) + kobject_uevent(&device->kobj, num); +} + +/** + * eject_dock - respond to a dock eject request + * @ds: the dock station + * + * This is called after _DCK is called, to execute the dock station's + * _EJ0 method. + */ +static void eject_dock(struct dock_station *ds) +{ + struct acpi_object_list arg_list; + union acpi_object arg; + acpi_status status; + acpi_handle tmp; + + /* all dock devices should have _EJ0, but check anyway */ + status = acpi_get_handle(ds->handle, "_EJ0", &tmp); + if (ACPI_FAILURE(status)) { + pr_debug("No _EJ0 support for dock device\n"); + return; + } + + arg_list.count = 1; + arg_list.pointer = &arg; + arg.type = ACPI_TYPE_INTEGER; + arg.integer.value = 1; + + if (ACPI_FAILURE(acpi_evaluate_object(ds->handle, "_EJ0", + &arg_list, NULL))) + pr_debug("Failed to evaluate _EJ0!\n"); +} + +/** + * handle_dock - handle a dock event + * @ds: the dock station + * @dock: to dock, or undock - that is the question + * + * Execute the _DCK method in response to an acpi event + */ +static void handle_dock(struct dock_station *ds, int dock) +{ + acpi_status status; + struct acpi_object_list arg_list; + union acpi_object arg; + struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; + struct acpi_buffer name_buffer = { ACPI_ALLOCATE_BUFFER, NULL }; + union acpi_object *obj; + + acpi_get_name(ds->handle, ACPI_FULL_PATHNAME, &name_buffer); + obj = name_buffer.pointer; + + printk(KERN_INFO PREFIX "%s\n", dock ? "docking" : "undocking"); + + /* _DCK method has one argument */ + arg_list.count = 1; + arg_list.pointer = &arg; + arg.type = ACPI_TYPE_INTEGER; + arg.integer.value = dock; + status = acpi_evaluate_object(ds->handle, "_DCK", &arg_list, &buffer); + if (ACPI_FAILURE(status)) + pr_debug("%s: failed to execute _DCK\n", obj->string.pointer); + kfree(buffer.pointer); + kfree(name_buffer.pointer); +} + +static inline void dock(struct dock_station *ds) +{ + handle_dock(ds, 1); +} + +static inline void undock(struct dock_station *ds) +{ + handle_dock(ds, 0); +} + +static inline void begin_dock(struct dock_station *ds) +{ + ds->flags |= DOCK_DOCKING; +} + +static inline void complete_dock(struct dock_station *ds) +{ + ds->flags &= ~(DOCK_DOCKING); + ds->last_dock_time = jiffies; +} + +/** + * dock_in_progress - see if we are in the middle of handling a dock event + * @ds: the dock station + * + * Sometimes while docking, false dock events can be sent to the driver + * because good connections aren't made or some other reason. Ignore these + * if we are in the middle of doing something. + */ +static int dock_in_progress(struct dock_station *ds) +{ + if ((ds->flags & DOCK_DOCKING) || + time_before(jiffies, (ds->last_dock_time + HZ))) + return 1; + return 0; +} + +/** + * register_dock_notifier - add yourself to the dock notifier list + * @nb: the callers notifier block + * + * If a driver wishes to be notified about dock events, they can + * use this function to put a notifier block on the dock notifier list. + * this notifier call chain will be called after a dock event, but + * before hotplugging any new devices. + */ +int register_dock_notifier(struct notifier_block *nb) +{ + return atomic_notifier_chain_register(&dock_notifier_list, nb); +} + +EXPORT_SYMBOL_GPL(register_dock_notifier); + +/** + * unregister_dock_notifier - remove yourself from the dock notifier list + * @nb: the callers notifier block + */ +void unregister_dock_notifier(struct notifier_block *nb) +{ + atomic_notifier_chain_unregister(&dock_notifier_list, nb); +} + +EXPORT_SYMBOL_GPL(unregister_dock_notifier); + +/** + * register_hotplug_dock_device - register a hotplug function + * @handle: the handle of the device + * @handler: the acpi_notifier_handler to call after docking + * @context: device specific data + * + * If a driver would like to perform a hotplug operation after a dock + * event, they can register an acpi_notifiy_handler to be called by + * the dock driver after _DCK is executed. + */ +int +register_hotplug_dock_device(acpi_handle handle, acpi_notify_handler handler, + void *context) +{ + struct dock_dependent_device *dd; + + if (!dock_station) + return -ENODEV; + + /* + * make sure this handle is for a device dependent on the dock, + * this would include the dock station itself + */ + dd = find_dock_dependent_device(dock_station, handle); + if (dd) { + dd->handler = handler; + dd->context = context; + dock_add_hotplug_device(dock_station, dd); + return 0; + } + + return -EINVAL; +} + +EXPORT_SYMBOL_GPL(register_hotplug_dock_device); + +/** + * unregister_hotplug_dock_device - remove yourself from the hotplug list + * @handle: the acpi handle of the device + */ +void unregister_hotplug_dock_device(acpi_handle handle) +{ + struct dock_dependent_device *dd; + + if (!dock_station) + return; + + dd = find_dock_dependent_device(dock_station, handle); + if (dd) + dock_del_hotplug_device(dock_station, dd); +} + +EXPORT_SYMBOL_GPL(unregister_hotplug_dock_device); + +/** + * dock_notify - act upon an acpi dock notification + * @handle: the dock station handle + * @event: the acpi event + * @data: our driver data struct + * + * If we are notified to dock, then check to see if the dock is + * present and then dock. Notify all drivers of the dock event, + * and then hotplug and devices that may need hotplugging. For undock + * check to make sure the dock device is still present, then undock + * and hotremove all the devices that may need removing. + */ +static void dock_notify(acpi_handle handle, u32 event, void *data) +{ + struct dock_station *ds = (struct dock_station *)data; + + switch (event) { + case ACPI_NOTIFY_BUS_CHECK: + if (!dock_in_progress(ds) && dock_present(ds)) { + begin_dock(ds); + dock(ds); + if (!dock_present(ds)) { + printk(KERN_ERR PREFIX "Unable to dock!\n"); + break; + } + atomic_notifier_call_chain(&dock_notifier_list, + event, NULL); + hotplug_dock_devices(ds, event); + complete_dock(ds); + dock_event(ds, event, DOCK_EVENT); + } + break; + case ACPI_NOTIFY_DEVICE_CHECK: + /* + * According to acpi spec 3.0a, if a DEVICE_CHECK notification + * is sent and _DCK is present, it is assumed to mean an + * undock request. This notify routine will only be called + * for objects defining _DCK, so we will fall through to eject + * request here. However, we will pass an eject request through + * to the driver who wish to hotplug. + */ + case ACPI_NOTIFY_EJECT_REQUEST: + if (!dock_in_progress(ds) && dock_present(ds)) { + /* + * here we need to generate the undock + * event prior to actually doing the undock + * so that the device struct still exists. + */ + dock_event(ds, event, UNDOCK_EVENT); + hotplug_dock_devices(ds, ACPI_NOTIFY_EJECT_REQUEST); + undock(ds); + eject_dock(ds); + if (dock_present(ds)) + printk(KERN_ERR PREFIX "Unable to undock!\n"); + } + break; + default: + printk(KERN_ERR PREFIX "Unknown dock event %d\n", event); + } +} + +/** + * find_dock_devices - find devices on the dock station + * @handle: the handle of the device we are examining + * @lvl: unused + * @context: the dock station private data + * @rv: unused + * + * This function is called by acpi_walk_namespace. It will + * check to see if an object has an _EJD method. If it does, then it + * will see if it is dependent on the dock station. + */ +static acpi_status +find_dock_devices(acpi_handle handle, u32 lvl, void *context, void **rv) +{ + acpi_status status; + acpi_handle tmp; + struct dock_station *ds = (struct dock_station *)context; + struct dock_dependent_device *dd; + + status = acpi_bus_get_ejd(handle, &tmp); + if (ACPI_FAILURE(status)) + return AE_OK; + + if (tmp == ds->handle) { + dd = alloc_dock_dependent_device(handle); + if (dd) + add_dock_dependent_device(ds, dd); + } + + return AE_OK; +} + +/** + * dock_add - add a new dock station + * @handle: the dock station handle + * + * allocated and initialize a new dock station device. Find all devices + * that are on the dock station, and register for dock event notifications. + */ +static int dock_add(acpi_handle handle) +{ + int ret; + acpi_status status; + struct dock_dependent_device *dd; + + /* allocate & initialize the dock_station private data */ + dock_station = kzalloc(sizeof(*dock_station), GFP_KERNEL); + if (!dock_station) + return -ENOMEM; + dock_station->handle = handle; + dock_station->last_dock_time = jiffies - HZ; + INIT_LIST_HEAD(&dock_station->dependent_devices); + INIT_LIST_HEAD(&dock_station->hotplug_devices); + spin_lock_init(&dock_station->dd_lock); + spin_lock_init(&dock_station->hp_lock); + + /* Find dependent devices */ + acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, + ACPI_UINT32_MAX, find_dock_devices, dock_station, + NULL); + + /* add the dock station as a device dependent on itself */ + dd = alloc_dock_dependent_device(handle); + if (!dd) { + kfree(dock_station); + return -ENOMEM; + } + add_dock_dependent_device(dock_station, dd); + + /* register for dock events */ + status = acpi_install_notify_handler(dock_station->handle, + ACPI_SYSTEM_NOTIFY, + dock_notify, dock_station); + + if (ACPI_FAILURE(status)) { + printk(KERN_ERR PREFIX "Error installing notify handler\n"); + ret = -ENODEV; + goto dock_add_err; + } + + printk(KERN_INFO PREFIX "%s \n", ACPI_DOCK_DRIVER_NAME); + + return 0; + +dock_add_err: + kfree(dock_station); + kfree(dd); + return ret; +} + +/** + * dock_remove - free up resources related to the dock station + */ +static int dock_remove(void) +{ + struct dock_dependent_device *dd, *tmp; + acpi_status status; + + if (!dock_station) + return 0; + + /* remove dependent devices */ + list_for_each_entry_safe(dd, tmp, &dock_station->dependent_devices, + list) + kfree(dd); + + /* remove dock notify handler */ + status = acpi_remove_notify_handler(dock_station->handle, + ACPI_SYSTEM_NOTIFY, + dock_notify); + if (ACPI_FAILURE(status)) + printk(KERN_ERR "Error removing notify handler\n"); + + /* free dock station memory */ + kfree(dock_station); + return 0; +} + +/** + * find_dock - look for a dock station + * @handle: acpi handle of a device + * @lvl: unused + * @context: counter of dock stations found + * @rv: unused + * + * This is called by acpi_walk_namespace to look for dock stations. + */ +static acpi_status +find_dock(acpi_handle handle, u32 lvl, void *context, void **rv) +{ + int *count = (int *)context; + acpi_status status = AE_OK; + + if (is_dock(handle)) { + if (dock_add(handle) >= 0) { + (*count)++; + status = AE_CTRL_TERMINATE; + } + } + return status; +} + +static int __init dock_init(void) +{ + int num = 0; + + dock_station = NULL; + + /* look for a dock station */ + acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, + ACPI_UINT32_MAX, find_dock, &num, NULL); + + if (!num) + return -ENODEV; + + return 0; +} + +static void __exit dock_exit(void) +{ + dock_remove(); +} + +postcore_initcall(dock_init); +module_exit(dock_exit); diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index 8c5d7df7d34..e5d79636285 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -929,7 +929,7 @@ 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 = { +static const struct file_operations acpi_ec_info_ops = { .open = acpi_ec_info_open_fs, .read = seq_read, .llseek = seq_lseek, diff --git a/drivers/acpi/event.c b/drivers/acpi/event.c index a901b23e95e..959a893c8d1 100644 --- a/drivers/acpi/event.c +++ b/drivers/acpi/event.c @@ -99,7 +99,7 @@ static unsigned int acpi_system_poll_event(struct file *file, poll_table * wait) return 0; } -static struct file_operations acpi_system_event_ops = { +static const struct file_operations acpi_system_event_ops = { .open = acpi_system_open_event, .read = acpi_system_read_event, .release = acpi_system_close_event, diff --git a/drivers/acpi/events/evregion.c b/drivers/acpi/events/evregion.c index 094a17e4c86..21caae04fe8 100644 --- a/drivers/acpi/events/evregion.c +++ b/drivers/acpi/events/evregion.c @@ -528,34 +528,40 @@ acpi_ev_detach_region(union acpi_operand_object *region_obj, } } - /* Call the setup handler with the deactivate notification */ + /* + * If the region has been activated, call the setup handler + * with the deactivate notification + */ + if (region_obj->region.flags & AOPOBJ_SETUP_COMPLETE) { + region_setup = handler_obj->address_space.setup; + status = + region_setup(region_obj, + ACPI_REGION_DEACTIVATE, + handler_obj->address_space. + context, region_context); - region_setup = handler_obj->address_space.setup; - status = - region_setup(region_obj, ACPI_REGION_DEACTIVATE, - handler_obj->address_space.context, - region_context); + /* Init routine may fail, Just ignore errors */ - /* Init routine may fail, Just ignore errors */ + if (ACPI_FAILURE(status)) { + ACPI_EXCEPTION((AE_INFO, status, + "from region handler - deactivate, [%s]", + acpi_ut_get_region_name + (region_obj->region. + space_id))); + } - if (ACPI_FAILURE(status)) { - ACPI_EXCEPTION((AE_INFO, status, - "from region init, [%s]", - acpi_ut_get_region_name - (region_obj->region.space_id))); + region_obj->region.flags &= + ~(AOPOBJ_SETUP_COMPLETE); } - region_obj->region.flags &= ~(AOPOBJ_SETUP_COMPLETE); - /* * Remove handler reference in the region * - * NOTE: this doesn't mean that the region goes away - * The region is just inaccessible as indicated to - * the _REG method + * NOTE: this doesn't mean that the region goes away, the region + * is just inaccessible as indicated to the _REG method * - * If the region is on the handler's list - * this better be the region's handler + * If the region is on the handler's list, this must be the + * region's handler */ region_obj->region.handler = NULL; acpi_ut_remove_reference(handler_obj); diff --git a/drivers/acpi/events/evxface.c b/drivers/acpi/events/evxface.c index 4f948df17ab..923fd2b4695 100644 --- a/drivers/acpi/events/evxface.c +++ b/drivers/acpi/events/evxface.c @@ -428,7 +428,7 @@ acpi_remove_notify_handler(acpi_handle device, node = acpi_ns_map_handle_to_node(device); if (!node) { status = AE_BAD_PARAMETER; - goto unlock; + goto unlock_and_exit; } /* Root Object */ @@ -442,7 +442,7 @@ acpi_remove_notify_handler(acpi_handle device, ((handler_type & ACPI_DEVICE_NOTIFY) && !acpi_gbl_device_notify.handler)) { status = AE_NOT_EXIST; - goto unlock; + goto unlock_and_exit; } /* Make sure all deferred tasks are completed */ @@ -474,7 +474,7 @@ acpi_remove_notify_handler(acpi_handle device, if (!acpi_ev_is_notify_object(node)) { status = AE_TYPE; - goto unlock; + goto unlock_and_exit; } /* Check for an existing internal object */ @@ -482,17 +482,21 @@ acpi_remove_notify_handler(acpi_handle device, obj_desc = acpi_ns_get_attached_object(node); if (!obj_desc) { status = AE_NOT_EXIST; - goto unlock; + goto unlock_and_exit; } /* Object exists - make sure there's an existing handler */ if (handler_type & ACPI_SYSTEM_NOTIFY) { notify_obj = obj_desc->common_notify.system_notify; - if ((!notify_obj) || - (notify_obj->notify.handler != handler)) { + if (!notify_obj) { + status = AE_NOT_EXIST; + goto unlock_and_exit; + } + + if (notify_obj->notify.handler != handler) { status = AE_BAD_PARAMETER; - goto unlock; + goto unlock_and_exit; } /* Make sure all deferred tasks are completed */ @@ -510,10 +514,14 @@ acpi_remove_notify_handler(acpi_handle device, if (handler_type & ACPI_DEVICE_NOTIFY) { notify_obj = obj_desc->common_notify.device_notify; - if ((!notify_obj) || - (notify_obj->notify.handler != handler)) { + if (!notify_obj) { + status = AE_NOT_EXIST; + goto unlock_and_exit; + } + + if (notify_obj->notify.handler != handler) { status = AE_BAD_PARAMETER; - goto unlock; + goto unlock_and_exit; } /* Make sure all deferred tasks are completed */ @@ -530,9 +538,9 @@ acpi_remove_notify_handler(acpi_handle device, } } -unlock: + unlock_and_exit: (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); -exit: + exit: if (ACPI_FAILURE(status)) ACPI_EXCEPTION((AE_INFO, status, "Removing notify handler")); return_ACPI_STATUS(status); @@ -586,7 +594,7 @@ acpi_install_gpe_handler(acpi_handle gpe_device, gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number); if (!gpe_event_info) { status = AE_BAD_PARAMETER; - goto unlock; + goto unlock_and_exit; } /* Make sure that there isn't a handler there already */ @@ -594,7 +602,7 @@ acpi_install_gpe_handler(acpi_handle gpe_device, if ((gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) == ACPI_GPE_DISPATCH_HANDLER) { status = AE_ALREADY_EXISTS; - goto unlock; + goto unlock_and_exit; } /* Allocate and init handler object */ @@ -602,7 +610,7 @@ acpi_install_gpe_handler(acpi_handle gpe_device, handler = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_handler_info)); if (!handler) { status = AE_NO_MEMORY; - goto unlock; + goto unlock_and_exit; } handler->address = address; @@ -613,7 +621,7 @@ acpi_install_gpe_handler(acpi_handle gpe_device, status = acpi_ev_disable_gpe(gpe_event_info); if (ACPI_FAILURE(status)) { - goto unlock; + goto unlock_and_exit; } /* Install the handler */ @@ -628,9 +636,9 @@ acpi_install_gpe_handler(acpi_handle gpe_device, acpi_os_release_lock(acpi_gbl_gpe_lock, flags); -unlock: + unlock_and_exit: (void)acpi_ut_release_mutex(ACPI_MTX_EVENTS); -exit: + exit: if (ACPI_FAILURE(status)) ACPI_EXCEPTION((AE_INFO, status, "Installing notify handler failed")); diff --git a/drivers/acpi/events/evxfregn.c b/drivers/acpi/events/evxfregn.c index e8b86a0baad..83b12a9afa3 100644 --- a/drivers/acpi/events/evxfregn.c +++ b/drivers/acpi/events/evxfregn.c @@ -155,7 +155,11 @@ acpi_remove_address_space_handler(acpi_handle device, /* Convert and validate the device handle */ node = acpi_ns_map_handle_to_node(device); - if (!node) { + if (!node || + ((node->type != ACPI_TYPE_DEVICE) && + (node->type != ACPI_TYPE_PROCESSOR) && + (node->type != ACPI_TYPE_THERMAL) && + (node != acpi_gbl_root_node))) { status = AE_BAD_PARAMETER; goto unlock_and_exit; } @@ -178,6 +182,13 @@ acpi_remove_address_space_handler(acpi_handle device, if (handler_obj->address_space.space_id == space_id) { + /* Handler must be the same as the installed handler */ + + if (handler_obj->address_space.handler != handler) { + status = AE_BAD_PARAMETER; + goto unlock_and_exit; + } + /* Matched space_id, first dereference this in the Regions */ ACPI_DEBUG_PRINT((ACPI_DB_OPREGION, diff --git a/drivers/acpi/executer/exconfig.c b/drivers/acpi/executer/exconfig.c index 83fed079a27..c8341fa5fe0 100644 --- a/drivers/acpi/executer/exconfig.c +++ b/drivers/acpi/executer/exconfig.c @@ -502,7 +502,6 @@ acpi_status acpi_ex_unload_table(union acpi_operand_object *ddb_handle) * (Offset contains the table_id) */ acpi_ns_delete_namespace_by_owner(table_info->owner_id); - acpi_ut_release_owner_id(&table_info->owner_id); /* Delete the table itself */ diff --git a/drivers/acpi/executer/exconvrt.c b/drivers/acpi/executer/exconvrt.c index b732e399b1e..544e81a6a43 100644 --- a/drivers/acpi/executer/exconvrt.c +++ b/drivers/acpi/executer/exconvrt.c @@ -170,6 +170,9 @@ acpi_ex_convert_to_integer(union acpi_operand_object *obj_desc, return_ACPI_STATUS(AE_NO_MEMORY); } + ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Converted value: %8.8X%8.8X\n", + ACPI_FORMAT_UINT64(result))); + /* Save the Result */ return_desc->integer.value = result; diff --git a/drivers/acpi/executer/exmutex.c b/drivers/acpi/executer/exmutex.c index d8ac2877cf0..3a39c2e8e10 100644 --- a/drivers/acpi/executer/exmutex.c +++ b/drivers/acpi/executer/exmutex.c @@ -267,9 +267,9 @@ acpi_ex_release_mutex(union acpi_operand_object *obj_desc, && (obj_desc->mutex.os_mutex != ACPI_GLOBAL_LOCK)) { ACPI_ERROR((AE_INFO, "Thread %X cannot release Mutex [%4.4s] acquired by thread %X", - walk_state->thread->thread_id, + (u32) walk_state->thread->thread_id, acpi_ut_get_node_name(obj_desc->mutex.node), - obj_desc->mutex.owner_thread->thread_id)); + (u32) obj_desc->mutex.owner_thread->thread_id)); return_ACPI_STATUS(AE_AML_NOT_OWNER); } diff --git a/drivers/acpi/executer/exsystem.c b/drivers/acpi/executer/exsystem.c index 6b5d1e6ce94..28aef3e69ec 100644 --- a/drivers/acpi/executer/exsystem.c +++ b/drivers/acpi/executer/exsystem.c @@ -60,7 +60,7 @@ ACPI_MODULE_NAME("exsystem") * * DESCRIPTION: Implements a semaphore wait with a check to see if the * semaphore is available immediately. If it is not, the - * interpreter is released. + * interpreter is released before waiting. * ******************************************************************************/ acpi_status acpi_ex_system_wait_semaphore(acpi_semaphore semaphore, u16 timeout) @@ -110,9 +110,9 @@ acpi_status acpi_ex_system_wait_semaphore(acpi_semaphore semaphore, u16 timeout) * * RETURN: Status * - * DESCRIPTION: Implements a semaphore wait with a check to see if the - * semaphore is available immediately. If it is not, the - * interpreter is released. + * DESCRIPTION: Implements a mutex wait with a check to see if the + * mutex is available immediately. If it is not, the + * interpreter is released before waiting. * ******************************************************************************/ diff --git a/drivers/acpi/fan.c b/drivers/acpi/fan.c index daed2460924..045c89477e5 100644 --- a/drivers/acpi/fan.c +++ b/drivers/acpi/fan.c @@ -120,7 +120,7 @@ acpi_fan_write_state(struct file *file, const char __user * buffer, return count; } -static struct file_operations acpi_fan_state_ops = { +static const struct file_operations acpi_fan_state_ops = { .open = acpi_fan_state_open_fs, .read = seq_read, .write = acpi_fan_write_state, diff --git a/drivers/acpi/hotkey.c b/drivers/acpi/hotkey.c index fd81a0f5222..32c9d88fd19 100644 --- a/drivers/acpi/hotkey.c +++ b/drivers/acpi/hotkey.c @@ -184,7 +184,7 @@ static union acpi_hotkey *get_hotkey_by_event(struct *hotkey_list, int event); /* event based config */ -static struct file_operations hotkey_config_fops = { +static const struct file_operations hotkey_config_fops = { .open = hotkey_open_config, .read = seq_read, .write = hotkey_write_config, @@ -193,7 +193,7 @@ static struct file_operations hotkey_config_fops = { }; /* polling based config */ -static struct file_operations hotkey_poll_config_fops = { +static const struct file_operations hotkey_poll_config_fops = { .open = hotkey_poll_open_config, .read = seq_read, .write = hotkey_write_config, @@ -202,7 +202,7 @@ static struct file_operations hotkey_poll_config_fops = { }; /* hotkey driver info */ -static struct file_operations hotkey_info_fops = { +static const struct file_operations hotkey_info_fops = { .open = hotkey_info_open_fs, .read = seq_read, .llseek = seq_lseek, @@ -210,7 +210,7 @@ static struct file_operations hotkey_info_fops = { }; /* action */ -static struct file_operations hotkey_action_fops = { +static const struct file_operations hotkey_action_fops = { .open = hotkey_action_open_fs, .read = seq_read, .write = hotkey_execute_aml_method, @@ -219,7 +219,7 @@ static struct file_operations hotkey_action_fops = { }; /* polling results */ -static struct file_operations hotkey_polling_fops = { +static const struct file_operations hotkey_polling_fops = { .open = hotkey_polling_open_fs, .read = seq_read, .llseek = seq_lseek, diff --git a/drivers/acpi/namespace/nsalloc.c b/drivers/acpi/namespace/nsalloc.c index dc3f0739a46..55b407aae26 100644 --- a/drivers/acpi/namespace/nsalloc.c +++ b/drivers/acpi/namespace/nsalloc.c @@ -386,14 +386,17 @@ void acpi_ns_delete_namespace_subtree(struct acpi_namespace_node *parent_node) * specific ID. Used to delete entire ACPI tables. All * reference counts are updated. * + * MUTEX: Locks namespace during deletion walk. + * ******************************************************************************/ void acpi_ns_delete_namespace_by_owner(acpi_owner_id owner_id) { struct acpi_namespace_node *child_node; struct acpi_namespace_node *deletion_node; - u32 level; struct acpi_namespace_node *parent_node; + u32 level; + acpi_status status; ACPI_FUNCTION_TRACE_U32(ns_delete_namespace_by_owner, owner_id); @@ -401,6 +404,13 @@ void acpi_ns_delete_namespace_by_owner(acpi_owner_id owner_id) return_VOID; } + /* Lock namespace for possible update */ + + status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE(status)) { + return_VOID; + } + deletion_node = NULL; parent_node = acpi_gbl_root_node; child_node = NULL; @@ -469,5 +479,6 @@ void acpi_ns_delete_namespace_by_owner(acpi_owner_id owner_id) } } + (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); return_VOID; } diff --git a/drivers/acpi/power.c b/drivers/acpi/power.c index 5d3447f4582..fec225d1b6b 100644 --- a/drivers/acpi/power.c +++ b/drivers/acpi/power.c @@ -80,7 +80,7 @@ struct acpi_power_resource { static struct list_head acpi_power_resource_list; -static struct file_operations acpi_power_fops = { +static const struct file_operations acpi_power_fops = { .open = acpi_power_open_fs, .read = seq_read, .llseek = seq_lseek, diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c index 52674323b14..b13d64415b7 100644 --- a/drivers/acpi/processor_core.c +++ b/drivers/acpi/processor_core.c @@ -102,7 +102,7 @@ static struct acpi_driver acpi_processor_driver = { #define INSTALL_NOTIFY_HANDLER 1 #define UNINSTALL_NOTIFY_HANDLER 2 -static struct file_operations acpi_processor_info_fops = { +static const struct file_operations acpi_processor_info_fops = { .open = acpi_processor_info_open_fs, .read = seq_read, .llseek = seq_lseek, diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index 8e9c26aae8f..71066066d62 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c @@ -1070,7 +1070,7 @@ static int acpi_processor_power_open_fs(struct inode *inode, struct file *file) PDE(inode)->data); } -static struct file_operations acpi_processor_power_fops = { +static const struct file_operations acpi_processor_power_fops = { .open = acpi_processor_power_open_fs, .read = seq_read, .llseek = seq_lseek, diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index cac4fcdcfc8..5fcb50c7b77 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -663,6 +663,29 @@ static int acpi_bus_find_driver(struct acpi_device *device) 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; diff --git a/drivers/acpi/sleep/proc.c b/drivers/acpi/sleep/proc.c index 4696a85a98b..34962578039 100644 --- a/drivers/acpi/sleep/proc.c +++ b/drivers/acpi/sleep/proc.c @@ -434,7 +434,7 @@ acpi_system_wakeup_device_open_fs(struct inode *inode, struct file *file) PDE(inode)->data); } -static struct file_operations acpi_system_wakeup_device_fops = { +static const struct file_operations acpi_system_wakeup_device_fops = { .open = acpi_system_wakeup_device_open_fs, .read = seq_read, .write = acpi_system_write_wakeup_device, @@ -443,7 +443,7 @@ static struct file_operations acpi_system_wakeup_device_fops = { }; #ifdef CONFIG_ACPI_SLEEP_PROC_SLEEP -static struct file_operations acpi_system_sleep_fops = { +static const struct file_operations acpi_system_sleep_fops = { .open = acpi_system_sleep_open_fs, .read = seq_read, .write = acpi_system_write_sleep, @@ -452,7 +452,7 @@ static struct file_operations acpi_system_sleep_fops = { }; #endif /* CONFIG_ACPI_SLEEP_PROC_SLEEP */ -static struct file_operations acpi_system_alarm_fops = { +static const struct file_operations acpi_system_alarm_fops = { .open = acpi_system_alarm_open_fs, .read = seq_read, .write = acpi_system_write_alarm, diff --git a/drivers/acpi/system.c b/drivers/acpi/system.c index c3bb7faad75..d86dcb3c236 100644 --- a/drivers/acpi/system.c +++ b/drivers/acpi/system.c @@ -57,7 +57,7 @@ static int acpi_system_info_open_fs(struct inode *inode, struct file *file) return single_open(file, acpi_system_read_info, PDE(inode)->data); } -static struct file_operations acpi_system_info_ops = { +static const struct file_operations acpi_system_info_ops = { .open = acpi_system_info_open_fs, .read = seq_read, .llseek = seq_lseek, @@ -67,7 +67,7 @@ static struct file_operations acpi_system_info_ops = { static ssize_t acpi_system_read_dsdt(struct file *, char __user *, size_t, loff_t *); -static struct file_operations acpi_system_dsdt_ops = { +static const struct file_operations acpi_system_dsdt_ops = { .read = acpi_system_read_dsdt, }; @@ -94,7 +94,7 @@ acpi_system_read_dsdt(struct file *file, static ssize_t acpi_system_read_fadt(struct file *, char __user *, size_t, loff_t *); -static struct file_operations acpi_system_fadt_ops = { +static const struct file_operations acpi_system_fadt_ops = { .read = acpi_system_read_fadt, }; diff --git a/drivers/acpi/tables/tbget.c b/drivers/acpi/tables/tbget.c index 99eacceff56..7856db759af 100644 --- a/drivers/acpi/tables/tbget.c +++ b/drivers/acpi/tables/tbget.c @@ -320,6 +320,16 @@ acpi_tb_get_this_table(struct acpi_pointer *address, ACPI_FUNCTION_TRACE(tb_get_this_table); + /* Validate minimum length */ + + if (header->length < sizeof(struct acpi_table_header)) { + ACPI_ERROR((AE_INFO, + "Table length (%X) is smaller than minimum (%X)", + header->length, sizeof(struct acpi_table_header))); + + return_ACPI_STATUS(AE_INVALID_TABLE_LENGTH); + } + /* * Flags contains the current processor mode (Virtual or Physical * addressing) The pointer_type is either Logical or Physical @@ -356,7 +366,7 @@ acpi_tb_get_this_table(struct acpi_pointer *address, */ status = acpi_os_map_memory(address->pointer.physical, (acpi_size) header->length, - (void *)&full_table); + ACPI_CAST_PTR(void, &full_table)); if (ACPI_FAILURE(status)) { ACPI_ERROR((AE_INFO, "Could not map memory for table [%4.4s] at %8.8X%8.8X for length %X", diff --git a/drivers/acpi/tables/tbinstal.c b/drivers/acpi/tables/tbinstal.c index 7ca2df75bb1..1668a232fb6 100644 --- a/drivers/acpi/tables/tbinstal.c +++ b/drivers/acpi/tables/tbinstal.c @@ -256,7 +256,7 @@ acpi_tb_init_table_descriptor(acpi_table_type table_type, status = acpi_ut_allocate_owner_id(&table_desc->owner_id); if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); + goto error_exit1; } /* Install the table into the global data structure */ @@ -274,8 +274,8 @@ acpi_tb_init_table_descriptor(acpi_table_type table_type, * at this location, so return an error. */ if (list_head->next) { - ACPI_FREE(table_desc); - return_ACPI_STATUS(AE_ALREADY_EXISTS); + status = AE_ALREADY_EXISTS; + goto error_exit2; } table_desc->next = list_head->next; @@ -335,6 +335,17 @@ acpi_tb_init_table_descriptor(acpi_table_type table_type, table_info->owner_id = table_desc->owner_id; table_info->installed_desc = table_desc; return_ACPI_STATUS(AE_OK); + + /* Error exit with cleanup */ + + error_exit2: + + acpi_ut_release_owner_id(&table_desc->owner_id); + + error_exit1: + + ACPI_FREE(table_desc); + return_ACPI_STATUS(status); } /******************************************************************************* @@ -525,6 +536,10 @@ struct acpi_table_desc *acpi_tb_uninstall_table(struct acpi_table_desc acpi_tb_delete_single_table(table_desc); + /* Free the owner ID associated with this table */ + + acpi_ut_release_owner_id(&table_desc->owner_id); + /* Free the table descriptor */ next_desc = table_desc->next; diff --git a/drivers/acpi/tables/tbrsdt.c b/drivers/acpi/tables/tbrsdt.c index abcb08c2592..0ad3dbb9ebc 100644 --- a/drivers/acpi/tables/tbrsdt.c +++ b/drivers/acpi/tables/tbrsdt.c @@ -183,6 +183,17 @@ acpi_status acpi_tb_validate_rsdt(struct acpi_table_header *table_ptr) ACPI_FUNCTION_ENTRY(); + /* Validate minimum length */ + + if (table_ptr->length < sizeof(struct acpi_table_header)) { + ACPI_ERROR((AE_INFO, + "RSDT/XSDT length (%X) is smaller than minimum (%X)", + table_ptr->length, + sizeof(struct acpi_table_header))); + + return (AE_INVALID_TABLE_LENGTH); + } + /* Search for appropriate signature, RSDT or XSDT */ if (acpi_gbl_root_table_type == ACPI_TABLE_TYPE_RSDT) { @@ -210,7 +221,7 @@ acpi_status acpi_tb_validate_rsdt(struct acpi_table_header *table_ptr) ACPI_ERROR((AE_INFO, "Looking for XSDT")); } - ACPI_DUMP_BUFFER((char *)table_ptr, 48); + ACPI_DUMP_BUFFER(ACPI_CAST_PTR(char, table_ptr), 48); return (AE_BAD_SIGNATURE); } @@ -258,7 +269,7 @@ acpi_status acpi_tb_get_table_rsdt(void) status = acpi_tb_validate_rsdt(table_info.pointer); if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); + goto error_cleanup; } /* Get the number of tables defined in the RSDT or XSDT */ @@ -270,14 +281,14 @@ acpi_status acpi_tb_get_table_rsdt(void) status = acpi_tb_convert_to_xsdt(&table_info); if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); + goto error_cleanup; } /* Save the table pointers and allocation info */ status = acpi_tb_init_table_descriptor(ACPI_TABLE_ID_XSDT, &table_info); if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); + goto error_cleanup; } acpi_gbl_XSDT = @@ -285,4 +296,12 @@ acpi_status acpi_tb_get_table_rsdt(void) ACPI_DEBUG_PRINT((ACPI_DB_INFO, "XSDT located at %p\n", acpi_gbl_XSDT)); return_ACPI_STATUS(status); + + error_cleanup: + + /* Free table allocated by acpi_tb_get_table */ + + acpi_tb_delete_single_table(&table_info); + + return_ACPI_STATUS(status); } diff --git a/drivers/acpi/tables/tbxface.c b/drivers/acpi/tables/tbxface.c index 4e91f298481..7767987be15 100644 --- a/drivers/acpi/tables/tbxface.c +++ b/drivers/acpi/tables/tbxface.c @@ -134,8 +134,8 @@ ACPI_EXPORT_SYMBOL(acpi_load_tables) * RETURN: Status * * DESCRIPTION: This function is called to load a table from the caller's - * buffer. The buffer must contain an entire ACPI Table including - * a valid header. The header fields will be verified, and if it + * buffer. The buffer must contain an entire ACPI Table including + * a valid header. The header fields will be verified, and if it * is determined that the table is invalid, the call will fail. * ******************************************************************************/ @@ -245,15 +245,18 @@ acpi_status acpi_unload_table(acpi_table_type table_type) /* Find all tables of the requested type */ table_desc = acpi_gbl_table_lists[table_type].next; + if (!table_desc) { + return_ACPI_STATUS(AE_NOT_EXIST); + } + while (table_desc) { /* - * Delete all namespace entries owned by this table. Note that these - * entries can appear anywhere in the namespace by virtue of the AML - * "Scope" operator. Thus, we need to track ownership by an ID, not + * Delete all namespace objects owned by this table. Note that these + * objects can appear anywhere in the namespace by virtue of the AML + * "Scope" operator. Thus, we need to track ownership by an ID, not * simply a position within the hierarchy */ acpi_ns_delete_namespace_by_owner(table_desc->owner_id); - acpi_ut_release_owner_id(&table_desc->owner_id); table_desc = table_desc->next; } @@ -275,12 +278,12 @@ ACPI_EXPORT_SYMBOL(acpi_unload_table) * see acpi_gbl_acpi_table_flag * out_table_header - pointer to the struct acpi_table_header if successful * - * DESCRIPTION: This function is called to get an ACPI table header. The caller + * DESCRIPTION: This function is called to get an ACPI table header. The caller * supplies an pointer to a data area sufficient to contain an ACPI * struct acpi_table_header structure. * * The header contains a length field that can be used to determine - * the size of the buffer needed to contain the entire table. This + * the size of the buffer needed to contain the entire table. This * function is not valid for the RSD PTR table since it does not * have a standard header and is fixed length. * @@ -322,7 +325,8 @@ acpi_get_table_header(acpi_table_type table_type, /* Copy the header to the caller's buffer */ - ACPI_MEMCPY((void *)out_table_header, (void *)tbl_ptr, + ACPI_MEMCPY(ACPI_CAST_PTR(void, out_table_header), + ACPI_CAST_PTR(void, tbl_ptr), sizeof(struct acpi_table_header)); return_ACPI_STATUS(status); @@ -344,10 +348,10 @@ ACPI_EXPORT_SYMBOL(acpi_get_table_header) * * RETURN: Status * - * DESCRIPTION: This function is called to get an ACPI table. The caller + * DESCRIPTION: This function is called to get an ACPI table. The caller * supplies an out_buffer large enough to contain the entire ACPI - * table. The caller should call the acpi_get_table_header function - * first to determine the buffer size needed. Upon completion + * table. The caller should call the acpi_get_table_header function + * first to determine the buffer size needed. Upon completion * the out_buffer->Length field will indicate the number of bytes * copied into the out_buffer->buf_ptr buffer. This table will be * a complete table including the header. @@ -417,7 +421,9 @@ acpi_get_table(acpi_table_type table_type, /* Copy the table to the buffer */ - ACPI_MEMCPY((void *)ret_buffer->pointer, (void *)tbl_ptr, table_length); + ACPI_MEMCPY(ACPI_CAST_PTR(void, ret_buffer->pointer), + ACPI_CAST_PTR(void, tbl_ptr), table_length); + return_ACPI_STATUS(AE_OK); } diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c index 503c0b99db1..480a3179688 100644 --- a/drivers/acpi/thermal.c +++ b/drivers/acpi/thermal.c @@ -176,21 +176,21 @@ struct acpi_thermal { struct timer_list timer; }; -static struct file_operations acpi_thermal_state_fops = { +static const struct file_operations acpi_thermal_state_fops = { .open = acpi_thermal_state_open_fs, .read = seq_read, .llseek = seq_lseek, .release = single_release, }; -static struct file_operations acpi_thermal_temp_fops = { +static const struct file_operations acpi_thermal_temp_fops = { .open = acpi_thermal_temp_open_fs, .read = seq_read, .llseek = seq_lseek, .release = single_release, }; -static struct file_operations acpi_thermal_trip_fops = { +static const struct file_operations acpi_thermal_trip_fops = { .open = acpi_thermal_trip_open_fs, .read = seq_read, .write = acpi_thermal_write_trip_points, @@ -198,7 +198,7 @@ static struct file_operations acpi_thermal_trip_fops = { .release = single_release, }; -static struct file_operations acpi_thermal_cooling_fops = { +static const struct file_operations acpi_thermal_cooling_fops = { .open = acpi_thermal_cooling_open_fs, .read = seq_read, .write = acpi_thermal_write_cooling_mode, @@ -206,7 +206,7 @@ static struct file_operations acpi_thermal_cooling_fops = { .release = single_release, }; -static struct file_operations acpi_thermal_polling_fops = { +static const struct file_operations acpi_thermal_polling_fops = { .open = acpi_thermal_polling_open_fs, .read = seq_read, .write = acpi_thermal_write_polling, diff --git a/drivers/acpi/utilities/utdebug.c b/drivers/acpi/utilities/utdebug.c index 5ec1cfcc611..bb1eaf9aa65 100644 --- a/drivers/acpi/utilities/utdebug.c +++ b/drivers/acpi/utilities/utdebug.c @@ -47,7 +47,7 @@ ACPI_MODULE_NAME("utdebug") #ifdef ACPI_DEBUG_OUTPUT -static u32 acpi_gbl_prev_thread_id = 0xFFFFFFFF; +static acpi_thread_id acpi_gbl_prev_thread_id; static char *acpi_gbl_fn_entry_str = "----Entry"; static char *acpi_gbl_fn_exit_str = "----Exit-"; @@ -181,7 +181,7 @@ acpi_ut_debug_print(u32 requested_debug_level, if (ACPI_LV_THREADS & acpi_dbg_level) { acpi_os_printf ("\n**** Context Switch from TID %X to TID %X ****\n\n", - acpi_gbl_prev_thread_id, thread_id); + (u32) acpi_gbl_prev_thread_id, (u32) thread_id); } acpi_gbl_prev_thread_id = thread_id; diff --git a/drivers/acpi/utilities/utdelete.c b/drivers/acpi/utilities/utdelete.c index 38ebe1c5433..9d3f1149ba2 100644 --- a/drivers/acpi/utilities/utdelete.c +++ b/drivers/acpi/utilities/utdelete.c @@ -447,11 +447,16 @@ acpi_ut_update_object_reference(union acpi_operand_object *object, u16 action) */ switch (ACPI_GET_OBJECT_TYPE(object)) { case ACPI_TYPE_DEVICE: + case ACPI_TYPE_PROCESSOR: + case ACPI_TYPE_POWER: + case ACPI_TYPE_THERMAL: - acpi_ut_update_ref_count(object->device.system_notify, - action); - acpi_ut_update_ref_count(object->device.device_notify, - action); + /* Update the notify objects for these types (if present) */ + + acpi_ut_update_ref_count(object->common_notify. + system_notify, action); + acpi_ut_update_ref_count(object->common_notify. + device_notify, action); break; case ACPI_TYPE_PACKAGE: diff --git a/drivers/acpi/utilities/utmisc.c b/drivers/acpi/utilities/utmisc.c index 33268310c73..6d8a8211be9 100644 --- a/drivers/acpi/utilities/utmisc.c +++ b/drivers/acpi/utilities/utmisc.c @@ -65,7 +65,7 @@ ACPI_MODULE_NAME("utmisc") u8 acpi_ut_is_aml_table(struct acpi_table_header *table) { - /* Ignore tables that contain AML */ + /* These are the only tables that contain executable AML */ if (ACPI_COMPARE_NAME(table->signature, DSDT_SIG) || ACPI_COMPARE_NAME(table->signature, PSDT_SIG) || @@ -419,10 +419,15 @@ void acpi_ut_set_integer_width(u8 revision) { if (revision <= 1) { + + /* 32-bit case */ + acpi_gbl_integer_bit_width = 32; acpi_gbl_integer_nybble_width = 8; acpi_gbl_integer_byte_width = 4; } else { + /* 64-bit case (ACPI 2.0+) */ + acpi_gbl_integer_bit_width = 64; acpi_gbl_integer_nybble_width = 16; acpi_gbl_integer_byte_width = 8; @@ -502,6 +507,7 @@ acpi_ut_display_init_pathname(u8 type, * FUNCTION: acpi_ut_valid_acpi_char * * PARAMETERS: Char - The character to be examined + * Position - Byte position (0-3) * * RETURN: TRUE if the character is valid, FALSE otherwise * @@ -609,7 +615,9 @@ acpi_name acpi_ut_repair_name(acpi_name name) * * RETURN: Status and Converted value * - * DESCRIPTION: Convert a string into an unsigned value. + * DESCRIPTION: Convert a string into an unsigned value. Performs either a + * 32-bit or 64-bit conversion, depending on the current mode + * of the interpreter. * NOTE: Does not support Octal strings, not needed. * ******************************************************************************/ @@ -627,7 +635,7 @@ acpi_ut_strtoul64(char *string, u32 base, acpi_integer * ret_integer) u8 sign_of0x = 0; u8 term = 0; - ACPI_FUNCTION_TRACE(ut_stroul64); + ACPI_FUNCTION_TRACE_STR(ut_stroul64, string); switch (base) { case ACPI_ANY_BASE: @@ -675,11 +683,13 @@ acpi_ut_strtoul64(char *string, u32 base, acpi_integer * ret_integer) } } + /* + * Perform a 32-bit or 64-bit conversion, depending upon the current + * execution mode of the interpreter + */ dividend = (mode32) ? ACPI_UINT32_MAX : ACPI_UINT64_MAX; - /* At least one character in the string here */ - - /* Main loop: convert the string to a 64-bit integer */ + /* Main loop: convert the string to a 32- or 64-bit integer */ while (*string) { if (ACPI_IS_DIGIT(*string)) { @@ -754,6 +764,9 @@ acpi_ut_strtoul64(char *string, u32 base, acpi_integer * ret_integer) all_done: + ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Converted value: %8.8X%8.8X\n", + ACPI_FORMAT_UINT64(return_value))); + *ret_integer = return_value; return_ACPI_STATUS(AE_OK); diff --git a/drivers/acpi/utilities/utmutex.c b/drivers/acpi/utilities/utmutex.c index dfc8f30ca89..c39062a047c 100644 --- a/drivers/acpi/utilities/utmutex.c +++ b/drivers/acpi/utilities/utmutex.c @@ -244,14 +244,14 @@ acpi_status acpi_ut_acquire_mutex(acpi_mutex_handle mutex_id) ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "Thread %X attempting to acquire Mutex [%s]\n", - this_thread_id, acpi_ut_get_mutex_name(mutex_id))); + (u32) this_thread_id, acpi_ut_get_mutex_name(mutex_id))); status = acpi_os_acquire_mutex(acpi_gbl_mutex_info[mutex_id].mutex, ACPI_WAIT_FOREVER); if (ACPI_SUCCESS(status)) { ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "Thread %X acquired Mutex [%s]\n", - this_thread_id, + (u32) this_thread_id, acpi_ut_get_mutex_name(mutex_id))); acpi_gbl_mutex_info[mutex_id].use_count++; @@ -259,7 +259,7 @@ acpi_status acpi_ut_acquire_mutex(acpi_mutex_handle mutex_id) } else { ACPI_EXCEPTION((AE_INFO, status, "Thread %X could not acquire Mutex [%X]", - this_thread_id, mutex_id)); + (u32) this_thread_id, mutex_id)); } return (status); @@ -285,7 +285,7 @@ acpi_status acpi_ut_release_mutex(acpi_mutex_handle mutex_id) this_thread_id = acpi_os_get_thread_id(); ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, - "Thread %X releasing Mutex [%s]\n", this_thread_id, + "Thread %X releasing Mutex [%s]\n", (u32) this_thread_id, acpi_ut_get_mutex_name(mutex_id))); if (mutex_id > ACPI_MAX_MUTEX) { diff --git a/drivers/acpi/utilities/utstate.c b/drivers/acpi/utilities/utstate.c index 0f5c5bb5def..eaa13d05c85 100644 --- a/drivers/acpi/utilities/utstate.c +++ b/drivers/acpi/utilities/utstate.c @@ -199,6 +199,13 @@ struct acpi_thread_state *acpi_ut_create_thread_state(void) state->common.descriptor_type = ACPI_DESC_TYPE_STATE_THREAD; state->thread.thread_id = acpi_os_get_thread_id(); + /* Check for invalid thread ID - zero is very bad, it will break things */ + + if (!state->thread.thread_id) { + ACPI_ERROR((AE_INFO, "Invalid zero ID from AcpiOsGetThreadId")); + state->thread.thread_id = (acpi_thread_id) 1; + } + return_PTR((struct acpi_thread_state *)state); } |