#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/acpi.h>
+#include <linux/signal.h>
+#include <linux/kthread.h>
#include <acpi/acpi_drivers.h>
#include <acpi/acinterp.h> /* for acpi_ex_eisa_id_to_string() */
}
static DEVICE_ATTR(modalias, 0444, acpi_device_modalias_show, NULL);
-static int acpi_eject_operation(acpi_handle handle, int lockable)
+static int acpi_bus_hot_remove_device(void *context)
{
+ struct acpi_device *device;
+ acpi_handle handle = context;
struct acpi_object_list arg_list;
union acpi_object arg;
acpi_status status = AE_OK;
- /*
- * TBD: evaluate _PS3?
- */
+ if (acpi_bus_get_device(handle, &device))
+ return 0;
+
+ if (!device)
+ return 0;
+
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+ "Hot-removing device %s...\n", device->dev.bus_id));
- if (lockable) {
+
+ if (acpi_bus_trim(device, 1)) {
+ printk(KERN_ERR PREFIX
+ "Removing device failed\n");
+ return -1;
+ }
+
+ /* power off device */
+ status = acpi_evaluate_object(handle, "_PS3", NULL, NULL);
+ if (ACPI_FAILURE(status) && status != AE_NOT_FOUND)
+ printk(KERN_WARNING PREFIX
+ "Power-off device failed\n");
+
+ if (device->flags.lockable) {
arg_list.count = 1;
arg_list.pointer = &arg;
arg.type = ACPI_TYPE_INTEGER;
/*
* TBD: _EJD support.
*/
-
status = acpi_evaluate_object(handle, "_EJ0", &arg_list, NULL);
- if (ACPI_FAILURE(status)) {
- return (-ENODEV);
- }
+ if (ACPI_FAILURE(status))
+ return -ENODEV;
- return (0);
+ return 0;
}
static ssize_t
acpi_eject_store(struct device *d, struct device_attribute *attr,
const char *buf, size_t count)
{
- int result;
int ret = count;
- int islockable;
acpi_status status;
- acpi_handle handle;
acpi_object_type type = 0;
struct acpi_device *acpi_device = to_acpi_device(d);
+ struct task_struct *task;
if ((!count) || (buf[0] != '1')) {
return -EINVAL;
goto err;
}
- islockable = acpi_device->flags.lockable;
- handle = acpi_device->handle;
-
- result = acpi_bus_trim(acpi_device, 1);
-
- if (!result)
- result = acpi_eject_operation(handle, islockable);
-
- if (result) {
- ret = -EBUSY;
- }
- err:
+ /* remove the device in another thread to fix the deadlock issue */
+ task = kthread_run(acpi_bus_hot_remove_device,
+ acpi_device->handle, "acpi_hot_remove_device");
+ if (IS_ERR(task))
+ ret = PTR_ERR(task);
+err:
return ret;
}
{
const struct acpi_device_id *id;
+ /*
+ * If the device is not present, it is unnecessary to load device
+ * driver for it.
+ */
+ if (!device->status.present)
+ return -ENODEV;
+
if (device->flags.hardware_id) {
for (id = ids; id->id[0]; id++) {
if (!strcmp((char*)id->id, device->pnp.hardware_id))
acpi_drv->ops.remove(acpi_dev, acpi_dev->removal_type);
}
acpi_dev->driver = NULL;
- acpi_driver_data(dev) = NULL;
+ acpi_dev->driver_data = NULL;
put_device(dev);
return 0;
device->dev.release = &acpi_device_release;
result = device_add(&device->dev);
if(result) {
- printk(KERN_ERR PREFIX "Error adding device %s", device->dev.bus_id);
+ dev_err(&device->dev, "Error adding device\n");
goto end;
}
result = acpi_device_setup_files(device);
if(result)
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error creating sysfs interface for device %s\n", device->dev.bus_id));
+ printk(KERN_ERR PREFIX "Error creating sysfs interface for device %s\n", device->dev.bus_id);
device->removal_type = ACPI_BUS_REMOVAL_NORMAL;
return 0;
result = driver->ops.add(device);
if (result) {
device->driver = NULL;
- acpi_driver_data(device) = NULL;
+ device->driver_data = NULL;
return result;
}
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) {
+ if (element->type != ACPI_TYPE_LOCAL_REFERENCE)
return AE_BAD_DATA;
- }
device->wakeup.resources.handles[i] = element->reference.handle;
}
acpi_status status = 0;
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
union acpi_object *package = NULL;
+ int psw_error;
struct acpi_device_id button_device_ids[] = {
{"PNP0C0D", 0},
{"", 0},
};
-
/* _PRW */
status = acpi_evaluate_object(device->handle, "_PRW", NULL, &buffer);
if (ACPI_FAILURE(status)) {
kfree(buffer.pointer);
device->wakeup.flags.valid = 1;
+ /* Call _PSW/_DSW object to disable its ability to wake the sleeping
+ * system for the ACPI device with the _PRW object.
+ * The _PSW object is depreciated in ACPI 3.0 and is replaced by _DSW.
+ * So it is necessary to call _DSW object first. Only when it is not
+ * present will the _PSW object used.
+ */
+ psw_error = acpi_device_sleep_wake(device, 0, 0, 0);
+ if (psw_error)
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+ "error in _DSW or _PSW evaluation\n"));
+
/* Power button, Lid switch always enable wakeup */
if (!acpi_match_device_ids(device, button_device_ids))
device->wakeup.flags.run_wake = 1;
+ /*
+ * Don't set Power button GPE as run_wake
+ * if Fixed Power button is used
+ */
+ if (!strcmp(device->pnp.hardware_id, "PNP0C0C") &&
+ !(acpi_gbl_FADT.flags & ACPI_FADT_POWER_BUTTON)) {
+ device->wakeup.flags.run_wake = 0;
+ device->wakeup.flags.valid = 0;
+ }
+
end:
if (ACPI_FAILURE(status))
device->flags.wake_capable = 0;
/* TBD: System wake support and resource requirements. */
device->power.state = ACPI_STATE_UNKNOWN;
+ acpi_bus_get_power(device->handle, &(device->power.state));
return 0;
}
static int
acpi_video_bus_match(struct acpi_device *device)
{
- acpi_handle h_dummy1;
- acpi_handle h_dummy2;
- acpi_handle h_dummy3;
-
+ acpi_handle h_dummy;
if (!device)
return -EINVAL;
*/
/* Does this device able to support video switching ? */
- if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_DOD", &h_dummy1)) &&
- ACPI_SUCCESS(acpi_get_handle(device->handle, "_DOS", &h_dummy2)))
+ if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_DOD", &h_dummy)) &&
+ ACPI_SUCCESS(acpi_get_handle(device->handle, "_DOS", &h_dummy)))
return 0;
/* Does this device able to retrieve a video ROM ? */
- if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_ROM", &h_dummy1)))
+ if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_ROM", &h_dummy)))
return 0;
/* Does this device able to configure which video head to be POSTed ? */
- if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_VPO", &h_dummy1)) &&
- ACPI_SUCCESS(acpi_get_handle(device->handle, "_GPD", &h_dummy2)) &&
- ACPI_SUCCESS(acpi_get_handle(device->handle, "_SPD", &h_dummy3)))
+ if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_VPO", &h_dummy)) &&
+ ACPI_SUCCESS(acpi_get_handle(device->handle, "_GPD", &h_dummy)) &&
+ ACPI_SUCCESS(acpi_get_handle(device->handle, "_SPD", &h_dummy)))
return 0;
return -ENODEV;
return 0;
}
-static int
-acpi_is_child_device(struct acpi_device *device,
- int (*matcher)(struct acpi_device *))
-{
- int result = -ENODEV;
-
- do {
- if (ACPI_SUCCESS(matcher(device)))
- return AE_OK;
- } while ((device = device->parent));
-
- return result;
-}
-
static int
acpi_add_single_object(struct acpi_device **child,
struct acpi_device *parent, acpi_handle handle, int type,
result = -ENODEV;
goto end;
}
- if (!device->status.present) {
- /* Bay and dock should be handled even if absent */
- if (!ACPI_SUCCESS(
- acpi_is_child_device(device, acpi_bay_match)) &&
- !ACPI_SUCCESS(
- acpi_is_child_device(device, acpi_dock_match))) {
- result = -ENODEV;
- goto end;
- }
+ /*
+ * When the device is neither present nor functional, the
+ * device should not be added to Linux ACPI device tree.
+ * When the status of the device is not present but functinal,
+ * it should be added to Linux ACPI tree. For example : bay
+ * device , dock device.
+ * In such conditions it is unncessary to check whether it is
+ * bay device or dock device.
+ */
+ if (!device->status.present && !device->status.functional) {
+ result = -ENODEV;
+ goto end;
}
break;
default:
*/
acpi_device_set_id(device, parent, handle, type);
+ /*
+ * The ACPI device is attached to acpi handle before getting
+ * the power/wakeup/peformance flags. Otherwise OS can't get
+ * the corresponding ACPI device by the acpi handle in the course
+ * of getting the power/wakeup/performance flags.
+ */
+ result = acpi_device_set_context(device, type);
+ if (result)
+ goto end;
+
/*
* Power Management
* ----------------
goto end;
}
- if ((result = acpi_device_set_context(device, type)))
- goto end;
result = acpi_device_register(device, parent);
* TBD: Need notifications and other detection mechanisms
* in place before we can fully implement this.
*/
- if (child->status.present) {
+ /*
+ * When the device is not present but functional, it is also
+ * necessary to scan the children of this device.
+ */
+ if (child->status.present || (!child->status.present &&
+ child->status.functional)) {
status = acpi_get_next_object(ACPI_TYPE_ANY, chandle,
NULL, NULL);
if (ACPI_SUCCESS(status)) {
return result;
}
-int __init acpi_boot_ec_enable(void);
static int __init acpi_scan_init(void)
{
*/
result = acpi_bus_scan_fixed(acpi_root);
- /* EC region might be needed at bus_scan, so enable it now */
- acpi_boot_ec_enable();
-
if (!result)
result = acpi_bus_scan(acpi_root, &ops);