diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2008-07-17 01:52:12 +0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2008-07-17 01:52:12 +0400 |
commit | 4314652bb41df08ad65bd25176ba1dfd24b14a51 (patch) | |
tree | 1632ae5936422bb36f2c43948bf079b7ca17e76f /drivers/acpi/scan.c | |
parent | d442cc44c0db56e84ef6aa244a88427d2efe06cd (diff) | |
parent | 01a5bba576b9364b33f61f0cd9fa70c2cf5535e2 (diff) | |
download | linux-4314652bb41df08ad65bd25176ba1dfd24b14a51.tar.xz |
Merge branch 'release-2.6.27' of git://git.kernel.org/pub/scm/linux/kernel/git/ak/linux-acpi-merge-2.6
* 'release-2.6.27' of git://git.kernel.org/pub/scm/linux/kernel/git/ak/linux-acpi-merge-2.6: (87 commits)
Fix FADT parsing
Add the ability to reset the machine using the RESET_REG in ACPI's FADT table.
ACPI: use dev_printk when possible
PNPACPI: add support for HP vendor-specific CCSR descriptors
PNP: avoid legacy IDE IRQs
PNP: convert resource options to single linked list
ISAPNP: handle independent options following dependent ones
PNP: remove extra 0x100 bit from option priority
PNP: support optional IRQ resources
PNP: rename pnp_register_*_resource() local variables
PNPACPI: ignore _PRS interrupt numbers larger than PNP_IRQ_NR
PNP: centralize resource option allocations
PNP: remove redundant pnp_can_configure() check
PNP: make resource assignment functions return 0 (success) or -EBUSY (failure)
PNP: in debug resource dump, make empty list obvious
PNP: improve resource assignment debug
PNP: increase I/O port & memory option address sizes
PNP: introduce pnp_irq_mask_t typedef
PNP: make resource option structures private to PNP subsystem
PNP: define PNP-specific IORESOURCE_IO_* flags alongside IRQ, DMA, MEM
...
Diffstat (limited to 'drivers/acpi/scan.c')
-rw-r--r-- | drivers/acpi/scan.c | 62 |
1 files changed, 37 insertions, 25 deletions
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 6d85289f1c12..5b049cd79553 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -6,6 +6,8 @@ #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() */ @@ -92,17 +94,37 @@ acpi_device_modalias_show(struct device *dev, struct device_attribute *attr, cha } 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 (lockable) { + if (!device) + return 0; + + ACPI_DEBUG_PRINT((ACPI_DB_INFO, + "Hot-removing device %s...\n", device->dev.bus_id)); + + + if (acpi_bus_trim(device, 1)) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "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) + ACPI_DEBUG_PRINT((ACPI_DB_WARN, + "Power-off device failed\n")); + + if (device->flags.lockable) { arg_list.count = 1; arg_list.pointer = &arg; arg.type = ACPI_TYPE_INTEGER; @@ -118,26 +140,22 @@ static int acpi_eject_operation(acpi_handle handle, int lockable) /* * 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; @@ -154,18 +172,12 @@ acpi_eject_store(struct device *d, struct device_attribute *attr, 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; } |