Merge branch 'acpi-hotplug' into linux-next
* acpi-hotplug: ACPI / memhotplug: Remove info->failed bit ACPI / memhotplug: set info->enabled for memory present at boot time ACPI: Verify device status after eject acpi: remove reference to ACPI_HOTPLUG_IO ACPI: Update _OST handling for notify ACPI: Update PNPID match handling for notify ACPI: Update PNPID set/free interfaces ACPI: Remove acpi_device dependency in acpi_device_set_id() ACPI / hotplug: Make acpi_hotplug_profile_ktype static ACPI / scan: Make memory hotplug driver use struct acpi_scan_handler ACPI / container: Use hotplug profile user space interface ACPI / hotplug: Introduce user space interface for hotplug profiles ACPI / scan: Introduce acpi_scan_handler_matching() ACPI / container: Use common hotplug code ACPI / scan: Introduce common code for ACPI-based device hotplug ACPI / scan: Introduce acpi_scan_match_handler()
This commit is contained in:
Коммит
408fb7f37b
|
@ -18,6 +18,32 @@ Description:
|
|||
yoffset: The number of pixels between the top of the screen
|
||||
and the top edge of the image.
|
||||
|
||||
What: /sys/firmware/acpi/hotplug/
|
||||
Date: February 2013
|
||||
Contact: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
|
||||
Description:
|
||||
There are separate hotplug profiles for different classes of
|
||||
devices supported by ACPI, such as containers, memory modules,
|
||||
processors, PCI root bridges etc. A hotplug profile for a given
|
||||
class of devices is a collection of settings defining the way
|
||||
that class of devices will be handled by the ACPI core hotplug
|
||||
code. Those profiles are represented in sysfs as subdirectories
|
||||
of /sys/firmware/acpi/hotplug/.
|
||||
|
||||
The following setting is available to user space for each
|
||||
hotplug profile:
|
||||
|
||||
enabled: If set, the ACPI core will handle notifications of
|
||||
hotplug events associated with the given class of
|
||||
devices and will allow those devices to be ejected with
|
||||
the help of the _EJ0 control method. Unsetting it
|
||||
effectively disables hotplug for the correspoinding
|
||||
class of devices.
|
||||
|
||||
The value of the above attribute is an integer number: 1 (set)
|
||||
or 0 (unset). Attempts to write any other values to it will
|
||||
cause -EINVAL to be returned.
|
||||
|
||||
What: /sys/firmware/acpi/interrupts/
|
||||
Date: February 2008
|
||||
Contact: Len Brown <lenb@kernel.org>
|
||||
|
|
|
@ -334,7 +334,7 @@ config X86_PM_TIMER
|
|||
|
||||
config ACPI_CONTAINER
|
||||
bool "Container and Module Devices"
|
||||
default (ACPI_HOTPLUG_MEMORY || ACPI_HOTPLUG_CPU || ACPI_HOTPLUG_IO)
|
||||
default (ACPI_HOTPLUG_MEMORY || ACPI_HOTPLUG_CPU)
|
||||
help
|
||||
This driver supports ACPI Container and Module devices (IDs
|
||||
ACPI0004, PNP0A05, and PNP0A06).
|
||||
|
@ -345,9 +345,8 @@ config ACPI_CONTAINER
|
|||
the module will be called container.
|
||||
|
||||
config ACPI_HOTPLUG_MEMORY
|
||||
tristate "Memory Hotplug"
|
||||
bool "Memory Hotplug"
|
||||
depends on MEMORY_HOTPLUG
|
||||
default n
|
||||
help
|
||||
This driver supports ACPI memory hotplug. The driver
|
||||
fields notifications on ACPI memory devices (PNP0C80),
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
/*
|
||||
* Copyright (C) 2004 Intel Corporation <naveen.b.s@intel.com>
|
||||
* Copyright (C) 2004, 2013 Intel Corporation
|
||||
* Author: Naveen B S <naveen.b.s@intel.com>
|
||||
* Author: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
|
@ -25,14 +27,10 @@
|
|||
* ranges.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/memory_hotplug.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/acpi.h>
|
||||
#include <acpi/acpi_drivers.h>
|
||||
#include <linux/memory_hotplug.h>
|
||||
|
||||
#include "internal.h"
|
||||
|
||||
#define ACPI_MEMORY_DEVICE_CLASS "memory"
|
||||
#define ACPI_MEMORY_DEVICE_HID "PNP0C80"
|
||||
|
@ -44,32 +42,28 @@
|
|||
#define PREFIX "ACPI:memory_hp:"
|
||||
|
||||
ACPI_MODULE_NAME("acpi_memhotplug");
|
||||
MODULE_AUTHOR("Naveen B S <naveen.b.s@intel.com>");
|
||||
MODULE_DESCRIPTION("Hotplug Mem Driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
/* Memory Device States */
|
||||
#define MEMORY_INVALID_STATE 0
|
||||
#define MEMORY_POWER_ON_STATE 1
|
||||
#define MEMORY_POWER_OFF_STATE 2
|
||||
|
||||
static int acpi_memory_device_add(struct acpi_device *device);
|
||||
static int acpi_memory_device_remove(struct acpi_device *device);
|
||||
static int acpi_memory_device_add(struct acpi_device *device,
|
||||
const struct acpi_device_id *not_used);
|
||||
static void acpi_memory_device_remove(struct acpi_device *device);
|
||||
|
||||
static const struct acpi_device_id memory_device_ids[] = {
|
||||
{ACPI_MEMORY_DEVICE_HID, 0},
|
||||
{"", 0},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(acpi, memory_device_ids);
|
||||
|
||||
static struct acpi_driver acpi_memory_device_driver = {
|
||||
.name = "acpi_memhotplug",
|
||||
.class = ACPI_MEMORY_DEVICE_CLASS,
|
||||
static struct acpi_scan_handler memory_device_handler = {
|
||||
.ids = memory_device_ids,
|
||||
.ops = {
|
||||
.add = acpi_memory_device_add,
|
||||
.remove = acpi_memory_device_remove,
|
||||
},
|
||||
.attach = acpi_memory_device_add,
|
||||
.detach = acpi_memory_device_remove,
|
||||
.hotplug = {
|
||||
.enabled = true,
|
||||
},
|
||||
};
|
||||
|
||||
struct acpi_memory_info {
|
||||
|
@ -79,7 +73,6 @@ struct acpi_memory_info {
|
|||
unsigned short caching; /* memory cache attribute */
|
||||
unsigned short write_protect; /* memory read/write attribute */
|
||||
unsigned int enabled:1;
|
||||
unsigned int failed:1;
|
||||
};
|
||||
|
||||
struct acpi_memory_device {
|
||||
|
@ -153,48 +146,6 @@ acpi_memory_get_device_resources(struct acpi_memory_device *mem_device)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int acpi_memory_get_device(acpi_handle handle,
|
||||
struct acpi_memory_device **mem_device)
|
||||
{
|
||||
struct acpi_device *device = NULL;
|
||||
int result = 0;
|
||||
|
||||
acpi_scan_lock_acquire();
|
||||
|
||||
acpi_bus_get_device(handle, &device);
|
||||
if (device)
|
||||
goto end;
|
||||
|
||||
/*
|
||||
* Now add the notified device. This creates the acpi_device
|
||||
* and invokes .add function
|
||||
*/
|
||||
result = acpi_bus_scan(handle);
|
||||
if (result) {
|
||||
acpi_handle_warn(handle, "ACPI namespace scan failed\n");
|
||||
result = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
result = acpi_bus_get_device(handle, &device);
|
||||
if (result) {
|
||||
acpi_handle_warn(handle, "Missing device object\n");
|
||||
result = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
end:
|
||||
*mem_device = acpi_driver_data(device);
|
||||
if (!(*mem_device)) {
|
||||
dev_err(&device->dev, "driver data not found\n");
|
||||
result = -ENODEV;
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
acpi_scan_lock_release();
|
||||
return result;
|
||||
}
|
||||
|
||||
static int acpi_memory_check_device(struct acpi_memory_device *mem_device)
|
||||
{
|
||||
unsigned long long current_status;
|
||||
|
@ -249,13 +200,11 @@ static int acpi_memory_enable_device(struct acpi_memory_device *mem_device)
|
|||
* returns -EEXIST. If add_memory() returns the other error, it
|
||||
* means that this memory block is not used by the kernel.
|
||||
*/
|
||||
if (result && result != -EEXIST) {
|
||||
info->failed = 1;
|
||||
if (result && result != -EEXIST)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!result)
|
||||
info->enabled = 1;
|
||||
info->enabled = 1;
|
||||
|
||||
/*
|
||||
* Add num_enable even if add_memory() returns -EEXIST, so the
|
||||
* device is bound to this driver.
|
||||
|
@ -286,16 +235,8 @@ static int acpi_memory_remove_memory(struct acpi_memory_device *mem_device)
|
|||
nid = acpi_get_node(mem_device->device->handle);
|
||||
|
||||
list_for_each_entry_safe(info, n, &mem_device->res_list, list) {
|
||||
if (info->failed)
|
||||
/* The kernel does not use this memory block */
|
||||
continue;
|
||||
|
||||
if (!info->enabled)
|
||||
/*
|
||||
* The kernel uses this memory block, but it may be not
|
||||
* managed by us.
|
||||
*/
|
||||
return -EBUSY;
|
||||
continue;
|
||||
|
||||
if (nid < 0)
|
||||
nid = memory_add_physaddr_to_nid(info->start_addr);
|
||||
|
@ -310,95 +251,21 @@ static int acpi_memory_remove_memory(struct acpi_memory_device *mem_device)
|
|||
return result;
|
||||
}
|
||||
|
||||
static void acpi_memory_device_notify(acpi_handle handle, u32 event, void *data)
|
||||
{
|
||||
struct acpi_memory_device *mem_device;
|
||||
struct acpi_device *device;
|
||||
struct acpi_eject_event *ej_event = NULL;
|
||||
u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; /* default */
|
||||
acpi_status status;
|
||||
|
||||
switch (event) {
|
||||
case ACPI_NOTIFY_BUS_CHECK:
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
|
||||
"\nReceived BUS CHECK notification for device\n"));
|
||||
/* Fall Through */
|
||||
case ACPI_NOTIFY_DEVICE_CHECK:
|
||||
if (event == ACPI_NOTIFY_DEVICE_CHECK)
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
|
||||
"\nReceived DEVICE CHECK notification for device\n"));
|
||||
if (acpi_memory_get_device(handle, &mem_device)) {
|
||||
acpi_handle_err(handle, "Cannot find driver data\n");
|
||||
break;
|
||||
}
|
||||
|
||||
ost_code = ACPI_OST_SC_SUCCESS;
|
||||
break;
|
||||
|
||||
case ACPI_NOTIFY_EJECT_REQUEST:
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
|
||||
"\nReceived EJECT REQUEST notification for device\n"));
|
||||
|
||||
status = AE_ERROR;
|
||||
acpi_scan_lock_acquire();
|
||||
|
||||
if (acpi_bus_get_device(handle, &device)) {
|
||||
acpi_handle_err(handle, "Device doesn't exist\n");
|
||||
goto unlock;
|
||||
}
|
||||
mem_device = acpi_driver_data(device);
|
||||
if (!mem_device) {
|
||||
acpi_handle_err(handle, "Driver Data is NULL\n");
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
ej_event = kmalloc(sizeof(*ej_event), GFP_KERNEL);
|
||||
if (!ej_event) {
|
||||
pr_err(PREFIX "No memory, dropping EJECT\n");
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
get_device(&device->dev);
|
||||
ej_event->device = device;
|
||||
ej_event->event = ACPI_NOTIFY_EJECT_REQUEST;
|
||||
/* The eject is carried out asynchronously. */
|
||||
status = acpi_os_hotplug_execute(acpi_bus_hot_remove_device,
|
||||
ej_event);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
put_device(&device->dev);
|
||||
kfree(ej_event);
|
||||
}
|
||||
|
||||
unlock:
|
||||
acpi_scan_lock_release();
|
||||
if (ACPI_SUCCESS(status))
|
||||
return;
|
||||
default:
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
|
||||
"Unsupported event [0x%x]\n", event));
|
||||
|
||||
/* non-hotplug event; possibly handled by other handler */
|
||||
return;
|
||||
}
|
||||
|
||||
/* Inform firmware that the hotplug operation has completed */
|
||||
(void) acpi_evaluate_hotplug_ost(handle, event, ost_code, NULL);
|
||||
}
|
||||
|
||||
static void acpi_memory_device_free(struct acpi_memory_device *mem_device)
|
||||
{
|
||||
if (!mem_device)
|
||||
return;
|
||||
|
||||
acpi_memory_free_device_resources(mem_device);
|
||||
mem_device->device->driver_data = NULL;
|
||||
kfree(mem_device);
|
||||
}
|
||||
|
||||
static int acpi_memory_device_add(struct acpi_device *device)
|
||||
static int acpi_memory_device_add(struct acpi_device *device,
|
||||
const struct acpi_device_id *not_used)
|
||||
{
|
||||
struct acpi_memory_device *mem_device;
|
||||
int result;
|
||||
struct acpi_memory_device *mem_device = NULL;
|
||||
|
||||
|
||||
if (!device)
|
||||
return -EINVAL;
|
||||
|
@ -423,147 +290,36 @@ static int acpi_memory_device_add(struct acpi_device *device)
|
|||
/* Set the device state */
|
||||
mem_device->state = MEMORY_POWER_ON_STATE;
|
||||
|
||||
pr_debug("%s\n", acpi_device_name(device));
|
||||
|
||||
if (!acpi_memory_check_device(mem_device)) {
|
||||
/* call add_memory func */
|
||||
result = acpi_memory_enable_device(mem_device);
|
||||
if (result) {
|
||||
dev_err(&device->dev,
|
||||
"Error in acpi_memory_enable_device\n");
|
||||
acpi_memory_device_free(mem_device);
|
||||
}
|
||||
result = acpi_memory_check_device(mem_device);
|
||||
if (result) {
|
||||
acpi_memory_device_free(mem_device);
|
||||
return 0;
|
||||
}
|
||||
return result;
|
||||
|
||||
result = acpi_memory_enable_device(mem_device);
|
||||
if (result) {
|
||||
dev_err(&device->dev, "acpi_memory_enable_device() error\n");
|
||||
acpi_memory_device_free(mem_device);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
dev_dbg(&device->dev, "Memory device configured by ACPI\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int acpi_memory_device_remove(struct acpi_device *device)
|
||||
static void acpi_memory_device_remove(struct acpi_device *device)
|
||||
{
|
||||
struct acpi_memory_device *mem_device = NULL;
|
||||
int result;
|
||||
struct acpi_memory_device *mem_device;
|
||||
|
||||
if (!device || !acpi_driver_data(device))
|
||||
return -EINVAL;
|
||||
return;
|
||||
|
||||
mem_device = acpi_driver_data(device);
|
||||
|
||||
result = acpi_memory_remove_memory(mem_device);
|
||||
if (result)
|
||||
return result;
|
||||
|
||||
acpi_memory_remove_memory(mem_device);
|
||||
acpi_memory_device_free(mem_device);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Helper function to check for memory device
|
||||
*/
|
||||
static acpi_status is_memory_device(acpi_handle handle)
|
||||
void __init acpi_memory_hotplug_init(void)
|
||||
{
|
||||
char *hardware_id;
|
||||
acpi_status status;
|
||||
struct acpi_device_info *info;
|
||||
|
||||
status = acpi_get_object_info(handle, &info);
|
||||
if (ACPI_FAILURE(status))
|
||||
return status;
|
||||
|
||||
if (!(info->valid & ACPI_VALID_HID)) {
|
||||
kfree(info);
|
||||
return AE_ERROR;
|
||||
}
|
||||
|
||||
hardware_id = info->hardware_id.string;
|
||||
if ((hardware_id == NULL) ||
|
||||
(strcmp(hardware_id, ACPI_MEMORY_DEVICE_HID)))
|
||||
status = AE_ERROR;
|
||||
|
||||
kfree(info);
|
||||
return status;
|
||||
acpi_scan_add_handler_with_hotplug(&memory_device_handler, "memory");
|
||||
}
|
||||
|
||||
static acpi_status
|
||||
acpi_memory_register_notify_handler(acpi_handle handle,
|
||||
u32 level, void *ctxt, void **retv)
|
||||
{
|
||||
acpi_status status;
|
||||
|
||||
|
||||
status = is_memory_device(handle);
|
||||
if (ACPI_FAILURE(status))
|
||||
return AE_OK; /* continue */
|
||||
|
||||
status = acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY,
|
||||
acpi_memory_device_notify, NULL);
|
||||
/* continue */
|
||||
return AE_OK;
|
||||
}
|
||||
|
||||
static acpi_status
|
||||
acpi_memory_deregister_notify_handler(acpi_handle handle,
|
||||
u32 level, void *ctxt, void **retv)
|
||||
{
|
||||
acpi_status status;
|
||||
|
||||
|
||||
status = is_memory_device(handle);
|
||||
if (ACPI_FAILURE(status))
|
||||
return AE_OK; /* continue */
|
||||
|
||||
status = acpi_remove_notify_handler(handle,
|
||||
ACPI_SYSTEM_NOTIFY,
|
||||
acpi_memory_device_notify);
|
||||
|
||||
return AE_OK; /* continue */
|
||||
}
|
||||
|
||||
static int __init acpi_memory_device_init(void)
|
||||
{
|
||||
int result;
|
||||
acpi_status status;
|
||||
|
||||
|
||||
result = acpi_bus_register_driver(&acpi_memory_device_driver);
|
||||
|
||||
if (result < 0)
|
||||
return -ENODEV;
|
||||
|
||||
status = acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
|
||||
ACPI_UINT32_MAX,
|
||||
acpi_memory_register_notify_handler, NULL,
|
||||
NULL, NULL);
|
||||
|
||||
if (ACPI_FAILURE(status)) {
|
||||
ACPI_EXCEPTION((AE_INFO, status, "walk_namespace failed"));
|
||||
acpi_bus_unregister_driver(&acpi_memory_device_driver);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit acpi_memory_device_exit(void)
|
||||
{
|
||||
acpi_status status;
|
||||
|
||||
|
||||
/*
|
||||
* Adding this to un-install notification handlers for all the device
|
||||
* handles.
|
||||
*/
|
||||
status = acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
|
||||
ACPI_UINT32_MAX,
|
||||
acpi_memory_deregister_notify_handler, NULL,
|
||||
NULL, NULL);
|
||||
|
||||
if (ACPI_FAILURE(status))
|
||||
ACPI_EXCEPTION((AE_INFO, status, "walk_namespace failed"));
|
||||
|
||||
acpi_bus_unregister_driver(&acpi_memory_device_driver);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
module_init(acpi_memory_device_init);
|
||||
module_exit(acpi_memory_device_exit);
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
/*
|
||||
* acpi_container.c - ACPI Generic Container Driver
|
||||
* ($Revision: )
|
||||
* container.c - ACPI Generic Container Driver
|
||||
*
|
||||
* Copyright (C) 2004 Anil S Keshavamurthy (anil.s.keshavamurthy@intel.com)
|
||||
* Copyright (C) 2004 Keiichiro Tokunaga (tokunaga.keiich@jp.fujitsu.com)
|
||||
* Copyright (C) 2004 Motoyuki Ito (motoyuki@soft.fujitsu.com)
|
||||
* Copyright (C) 2004 Intel Corp.
|
||||
* Copyright (C) 2004 FUJITSU LIMITED
|
||||
* Copyright (C) 2004, 2013 Intel Corp.
|
||||
* Author: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
|
||||
*
|
||||
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
*
|
||||
|
@ -26,14 +26,9 @@
|
|||
*
|
||||
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
*/
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/acpi.h>
|
||||
#include <acpi/acpi_bus.h>
|
||||
#include <acpi/acpi_drivers.h>
|
||||
|
||||
#include "internal.h"
|
||||
|
||||
#define PREFIX "ACPI: "
|
||||
|
||||
|
@ -50,141 +45,20 @@ static const struct acpi_device_id container_device_ids[] = {
|
|||
static int container_device_attach(struct acpi_device *device,
|
||||
const struct acpi_device_id *not_used)
|
||||
{
|
||||
/*
|
||||
* FIXME: This is necessary, so that acpi_eject_store() doesn't return
|
||||
* -ENODEV for containers.
|
||||
*/
|
||||
/* This is necessary for container hotplug to work. */
|
||||
return 1;
|
||||
}
|
||||
|
||||
static struct acpi_scan_handler container_device_handler = {
|
||||
static struct acpi_scan_handler container_handler = {
|
||||
.ids = container_device_ids,
|
||||
.attach = container_device_attach,
|
||||
.hotplug = {
|
||||
.enabled = true,
|
||||
.mode = AHM_CONTAINER,
|
||||
},
|
||||
};
|
||||
|
||||
static int is_device_present(acpi_handle handle)
|
||||
{
|
||||
acpi_handle temp;
|
||||
acpi_status status;
|
||||
unsigned long long sta;
|
||||
|
||||
|
||||
status = acpi_get_handle(handle, "_STA", &temp);
|
||||
if (ACPI_FAILURE(status))
|
||||
return 1; /* _STA not found, assume device present */
|
||||
|
||||
status = acpi_evaluate_integer(handle, "_STA", NULL, &sta);
|
||||
if (ACPI_FAILURE(status))
|
||||
return 0; /* Firmware error */
|
||||
|
||||
return ((sta & ACPI_STA_DEVICE_PRESENT) == ACPI_STA_DEVICE_PRESENT);
|
||||
}
|
||||
|
||||
static void container_notify_cb(acpi_handle handle, u32 type, void *context)
|
||||
{
|
||||
struct acpi_device *device = NULL;
|
||||
int result;
|
||||
int present;
|
||||
acpi_status status;
|
||||
u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; /* default */
|
||||
|
||||
acpi_scan_lock_acquire();
|
||||
|
||||
switch (type) {
|
||||
case ACPI_NOTIFY_BUS_CHECK:
|
||||
/* Fall through */
|
||||
case ACPI_NOTIFY_DEVICE_CHECK:
|
||||
pr_debug("Container driver received %s event\n",
|
||||
(type == ACPI_NOTIFY_BUS_CHECK) ?
|
||||
"ACPI_NOTIFY_BUS_CHECK" : "ACPI_NOTIFY_DEVICE_CHECK");
|
||||
|
||||
present = is_device_present(handle);
|
||||
status = acpi_bus_get_device(handle, &device);
|
||||
if (!present) {
|
||||
if (ACPI_SUCCESS(status)) {
|
||||
/* device exist and this is a remove request */
|
||||
device->flags.eject_pending = 1;
|
||||
kobject_uevent(&device->dev.kobj, KOBJ_OFFLINE);
|
||||
goto out;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (!ACPI_FAILURE(status) || device)
|
||||
break;
|
||||
|
||||
result = acpi_bus_scan(handle);
|
||||
if (result) {
|
||||
acpi_handle_warn(handle, "Failed to add container\n");
|
||||
break;
|
||||
}
|
||||
result = acpi_bus_get_device(handle, &device);
|
||||
if (result) {
|
||||
acpi_handle_warn(handle, "Missing device object\n");
|
||||
break;
|
||||
}
|
||||
|
||||
kobject_uevent(&device->dev.kobj, KOBJ_ONLINE);
|
||||
ost_code = ACPI_OST_SC_SUCCESS;
|
||||
break;
|
||||
|
||||
case ACPI_NOTIFY_EJECT_REQUEST:
|
||||
if (!acpi_bus_get_device(handle, &device) && device) {
|
||||
device->flags.eject_pending = 1;
|
||||
kobject_uevent(&device->dev.kobj, KOBJ_OFFLINE);
|
||||
goto out;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
/* non-hotplug event; possibly handled by other handler */
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Inform firmware that the hotplug operation has completed */
|
||||
(void) acpi_evaluate_hotplug_ost(handle, type, ost_code, NULL);
|
||||
|
||||
out:
|
||||
acpi_scan_lock_release();
|
||||
}
|
||||
|
||||
static bool is_container(acpi_handle handle)
|
||||
{
|
||||
struct acpi_device_info *info;
|
||||
bool ret = false;
|
||||
|
||||
if (ACPI_FAILURE(acpi_get_object_info(handle, &info)))
|
||||
return false;
|
||||
|
||||
if (info->valid & ACPI_VALID_HID) {
|
||||
const struct acpi_device_id *id;
|
||||
|
||||
for (id = container_device_ids; id->id[0]; id++) {
|
||||
ret = !strcmp((char *)id->id, info->hardware_id.string);
|
||||
if (ret)
|
||||
break;
|
||||
}
|
||||
}
|
||||
kfree(info);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static acpi_status acpi_container_register_notify_handler(acpi_handle handle,
|
||||
u32 lvl, void *ctxt,
|
||||
void **retv)
|
||||
{
|
||||
if (is_container(handle))
|
||||
acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY,
|
||||
container_notify_cb, NULL);
|
||||
|
||||
return AE_OK;
|
||||
}
|
||||
|
||||
void __init acpi_container_init(void)
|
||||
{
|
||||
acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, ACPI_UINT32_MAX,
|
||||
acpi_container_register_notify_handler, NULL,
|
||||
NULL, NULL);
|
||||
|
||||
acpi_scan_add_handler(&container_device_handler);
|
||||
acpi_scan_add_handler_with_hotplug(&container_handler, "container");
|
||||
}
|
||||
|
|
|
@ -41,6 +41,17 @@ void acpi_container_init(void);
|
|||
#else
|
||||
static inline void acpi_container_init(void) {}
|
||||
#endif
|
||||
#ifdef CONFIG_ACPI_HOTPLUG_MEMORY
|
||||
void acpi_memory_hotplug_init(void);
|
||||
#else
|
||||
static inline void acpi_memory_hotplug_init(void) {}
|
||||
#endif
|
||||
|
||||
void acpi_sysfs_add_hotplug_profile(struct acpi_hotplug_profile *hotplug,
|
||||
const char *name);
|
||||
int acpi_scan_add_handler_with_hotplug(struct acpi_scan_handler *handler,
|
||||
const char *hotplug_profile_name);
|
||||
void acpi_scan_hotplug_enabled(struct acpi_hotplug_profile *hotplug, bool val);
|
||||
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
extern struct dentry *acpi_debugfs_dir;
|
||||
|
@ -60,7 +71,7 @@ int acpi_device_add(struct acpi_device *device,
|
|||
void acpi_init_device_object(struct acpi_device *device, acpi_handle handle,
|
||||
int type, unsigned long long sta);
|
||||
void acpi_device_add_finalize(struct acpi_device *device);
|
||||
void acpi_free_ids(struct acpi_device *device);
|
||||
void acpi_free_pnp_ids(struct acpi_device_pnp *pnp);
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
Power Resource
|
||||
|
|
|
@ -824,7 +824,7 @@ static void acpi_release_power_resource(struct device *dev)
|
|||
list_del(&resource->list_node);
|
||||
mutex_unlock(&power_resource_list_lock);
|
||||
|
||||
acpi_free_ids(device);
|
||||
acpi_free_pnp_ids(&device->pnp);
|
||||
kfree(resource);
|
||||
}
|
||||
|
||||
|
|
|
@ -63,6 +63,19 @@ int acpi_scan_add_handler(struct acpi_scan_handler *handler)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int acpi_scan_add_handler_with_hotplug(struct acpi_scan_handler *handler,
|
||||
const char *hotplug_profile_name)
|
||||
{
|
||||
int error;
|
||||
|
||||
error = acpi_scan_add_handler(handler);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
acpi_sysfs_add_hotplug_profile(&handler->hotplug, hotplug_profile_name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Creates hid/cid(s) string needed for modalias and uevent
|
||||
* e.g. on a device with hid:IBM0001 and cid:ACPI0001 you get:
|
||||
|
@ -107,32 +120,20 @@ acpi_device_modalias_show(struct device *dev, struct device_attribute *attr, cha
|
|||
}
|
||||
static DEVICE_ATTR(modalias, 0444, acpi_device_modalias_show, NULL);
|
||||
|
||||
/**
|
||||
* acpi_bus_hot_remove_device: hot-remove a device and its children
|
||||
* @context: struct acpi_eject_event pointer (freed in this func)
|
||||
*
|
||||
* Hot-remove a device and its children. This function frees up the
|
||||
* memory space passed by arg context, so that the caller may call
|
||||
* this function asynchronously through acpi_os_hotplug_execute().
|
||||
*/
|
||||
void acpi_bus_hot_remove_device(void *context)
|
||||
static int acpi_scan_hot_remove(struct acpi_device *device)
|
||||
{
|
||||
struct acpi_eject_event *ej_event = context;
|
||||
struct acpi_device *device = ej_event->device;
|
||||
acpi_handle handle = device->handle;
|
||||
acpi_handle temp;
|
||||
acpi_handle not_used;
|
||||
struct acpi_object_list arg_list;
|
||||
union acpi_object arg;
|
||||
acpi_status status = AE_OK;
|
||||
u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; /* default */
|
||||
|
||||
mutex_lock(&acpi_scan_lock);
|
||||
acpi_status status;
|
||||
unsigned long long sta;
|
||||
|
||||
/* If there is no handle, the device node has been unregistered. */
|
||||
if (!device->handle) {
|
||||
if (!handle) {
|
||||
dev_dbg(&device->dev, "ACPI handle missing\n");
|
||||
put_device(&device->dev);
|
||||
goto out;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
|
||||
|
@ -143,7 +144,7 @@ void acpi_bus_hot_remove_device(void *context)
|
|||
put_device(&device->dev);
|
||||
device = NULL;
|
||||
|
||||
if (ACPI_SUCCESS(acpi_get_handle(handle, "_LCK", &temp))) {
|
||||
if (ACPI_SUCCESS(acpi_get_handle(handle, "_LCK", ¬_used))) {
|
||||
arg_list.count = 1;
|
||||
arg_list.pointer = &arg;
|
||||
arg.type = ACPI_TYPE_INTEGER;
|
||||
|
@ -161,18 +162,205 @@ void acpi_bus_hot_remove_device(void *context)
|
|||
*/
|
||||
status = acpi_evaluate_object(handle, "_EJ0", &arg_list, NULL);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
if (status != AE_NOT_FOUND)
|
||||
acpi_handle_warn(handle, "Eject failed\n");
|
||||
if (status == AE_NOT_FOUND) {
|
||||
return -ENODEV;
|
||||
} else {
|
||||
acpi_handle_warn(handle, "Eject failed (0x%x)\n",
|
||||
status);
|
||||
return -EIO;
|
||||
}
|
||||
}
|
||||
|
||||
/* Tell the firmware the hot-remove operation has failed. */
|
||||
acpi_evaluate_hotplug_ost(handle, ej_event->event,
|
||||
ost_code, NULL);
|
||||
/*
|
||||
* Verify if eject was indeed successful. If not, log an error
|
||||
* message. No need to call _OST since _EJ0 call was made OK.
|
||||
*/
|
||||
status = acpi_evaluate_integer(handle, "_STA", NULL, &sta);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
acpi_handle_warn(handle,
|
||||
"Status check after eject failed (0x%x)\n", status);
|
||||
} else if (sta & ACPI_STA_DEVICE_ENABLED) {
|
||||
acpi_handle_warn(handle,
|
||||
"Eject incomplete - status 0x%llx\n", sta);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void acpi_bus_device_eject(void *context)
|
||||
{
|
||||
acpi_handle handle = context;
|
||||
struct acpi_device *device = NULL;
|
||||
struct acpi_scan_handler *handler;
|
||||
u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE;
|
||||
|
||||
mutex_lock(&acpi_scan_lock);
|
||||
|
||||
acpi_bus_get_device(handle, &device);
|
||||
if (!device)
|
||||
goto err_out;
|
||||
|
||||
handler = device->handler;
|
||||
if (!handler || !handler->hotplug.enabled) {
|
||||
ost_code = ACPI_OST_SC_EJECT_NOT_SUPPORTED;
|
||||
goto err_out;
|
||||
}
|
||||
acpi_evaluate_hotplug_ost(handle, ACPI_NOTIFY_EJECT_REQUEST,
|
||||
ACPI_OST_SC_EJECT_IN_PROGRESS, NULL);
|
||||
if (handler->hotplug.mode == AHM_CONTAINER) {
|
||||
device->flags.eject_pending = true;
|
||||
kobject_uevent(&device->dev.kobj, KOBJ_OFFLINE);
|
||||
} else {
|
||||
int error;
|
||||
|
||||
get_device(&device->dev);
|
||||
error = acpi_scan_hot_remove(device);
|
||||
if (error)
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
out:
|
||||
mutex_unlock(&acpi_scan_lock);
|
||||
kfree(context);
|
||||
return;
|
||||
|
||||
err_out:
|
||||
acpi_evaluate_hotplug_ost(handle, ACPI_NOTIFY_EJECT_REQUEST, ost_code,
|
||||
NULL);
|
||||
goto out;
|
||||
}
|
||||
|
||||
static void acpi_scan_bus_device_check(acpi_handle handle, u32 ost_source)
|
||||
{
|
||||
struct acpi_device *device = NULL;
|
||||
u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE;
|
||||
int error;
|
||||
|
||||
mutex_lock(&acpi_scan_lock);
|
||||
|
||||
acpi_bus_get_device(handle, &device);
|
||||
if (device) {
|
||||
dev_warn(&device->dev, "Attempt to re-insert\n");
|
||||
goto out;
|
||||
}
|
||||
acpi_evaluate_hotplug_ost(handle, ost_source,
|
||||
ACPI_OST_SC_INSERT_IN_PROGRESS, NULL);
|
||||
error = acpi_bus_scan(handle);
|
||||
if (error) {
|
||||
acpi_handle_warn(handle, "Namespace scan failure\n");
|
||||
goto out;
|
||||
}
|
||||
error = acpi_bus_get_device(handle, &device);
|
||||
if (error) {
|
||||
acpi_handle_warn(handle, "Missing device node object\n");
|
||||
goto out;
|
||||
}
|
||||
ost_code = ACPI_OST_SC_SUCCESS;
|
||||
if (device->handler && device->handler->hotplug.mode == AHM_CONTAINER)
|
||||
kobject_uevent(&device->dev.kobj, KOBJ_ONLINE);
|
||||
|
||||
out:
|
||||
acpi_evaluate_hotplug_ost(handle, ost_source, ost_code, NULL);
|
||||
mutex_unlock(&acpi_scan_lock);
|
||||
}
|
||||
|
||||
static void acpi_scan_bus_check(void *context)
|
||||
{
|
||||
acpi_scan_bus_device_check((acpi_handle)context,
|
||||
ACPI_NOTIFY_BUS_CHECK);
|
||||
}
|
||||
|
||||
static void acpi_scan_device_check(void *context)
|
||||
{
|
||||
acpi_scan_bus_device_check((acpi_handle)context,
|
||||
ACPI_NOTIFY_DEVICE_CHECK);
|
||||
}
|
||||
|
||||
static void acpi_hotplug_unsupported(acpi_handle handle, u32 type)
|
||||
{
|
||||
u32 ost_status;
|
||||
|
||||
switch (type) {
|
||||
case ACPI_NOTIFY_BUS_CHECK:
|
||||
acpi_handle_debug(handle,
|
||||
"ACPI_NOTIFY_BUS_CHECK event: unsupported\n");
|
||||
ost_status = ACPI_OST_SC_INSERT_NOT_SUPPORTED;
|
||||
break;
|
||||
case ACPI_NOTIFY_DEVICE_CHECK:
|
||||
acpi_handle_debug(handle,
|
||||
"ACPI_NOTIFY_DEVICE_CHECK event: unsupported\n");
|
||||
ost_status = ACPI_OST_SC_INSERT_NOT_SUPPORTED;
|
||||
break;
|
||||
case ACPI_NOTIFY_EJECT_REQUEST:
|
||||
acpi_handle_debug(handle,
|
||||
"ACPI_NOTIFY_EJECT_REQUEST event: unsupported\n");
|
||||
ost_status = ACPI_OST_SC_EJECT_NOT_SUPPORTED;
|
||||
break;
|
||||
default:
|
||||
/* non-hotplug event; possibly handled by other handler */
|
||||
return;
|
||||
}
|
||||
|
||||
acpi_evaluate_hotplug_ost(handle, type, ost_status, NULL);
|
||||
}
|
||||
|
||||
static void acpi_hotplug_notify_cb(acpi_handle handle, u32 type, void *data)
|
||||
{
|
||||
acpi_osd_exec_callback callback;
|
||||
struct acpi_scan_handler *handler = data;
|
||||
acpi_status status;
|
||||
|
||||
if (!handler->hotplug.enabled)
|
||||
return acpi_hotplug_unsupported(handle, type);
|
||||
|
||||
switch (type) {
|
||||
case ACPI_NOTIFY_BUS_CHECK:
|
||||
acpi_handle_debug(handle, "ACPI_NOTIFY_BUS_CHECK event\n");
|
||||
callback = acpi_scan_bus_check;
|
||||
break;
|
||||
case ACPI_NOTIFY_DEVICE_CHECK:
|
||||
acpi_handle_debug(handle, "ACPI_NOTIFY_DEVICE_CHECK event\n");
|
||||
callback = acpi_scan_device_check;
|
||||
break;
|
||||
case ACPI_NOTIFY_EJECT_REQUEST:
|
||||
acpi_handle_debug(handle, "ACPI_NOTIFY_EJECT_REQUEST event\n");
|
||||
callback = acpi_bus_device_eject;
|
||||
break;
|
||||
default:
|
||||
/* non-hotplug event; possibly handled by other handler */
|
||||
return;
|
||||
}
|
||||
status = acpi_os_hotplug_execute(callback, handle);
|
||||
if (ACPI_FAILURE(status))
|
||||
acpi_evaluate_hotplug_ost(handle, type,
|
||||
ACPI_OST_SC_NON_SPECIFIC_FAILURE,
|
||||
NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* acpi_bus_hot_remove_device: hot-remove a device and its children
|
||||
* @context: struct acpi_eject_event pointer (freed in this func)
|
||||
*
|
||||
* Hot-remove a device and its children. This function frees up the
|
||||
* memory space passed by arg context, so that the caller may call
|
||||
* this function asynchronously through acpi_os_hotplug_execute().
|
||||
*/
|
||||
void acpi_bus_hot_remove_device(void *context)
|
||||
{
|
||||
struct acpi_eject_event *ej_event = context;
|
||||
struct acpi_device *device = ej_event->device;
|
||||
acpi_handle handle = device->handle;
|
||||
int error;
|
||||
|
||||
mutex_lock(&acpi_scan_lock);
|
||||
|
||||
error = acpi_scan_hot_remove(device);
|
||||
if (error && handle)
|
||||
acpi_evaluate_hotplug_ost(handle, ej_event->event,
|
||||
ACPI_OST_SC_NON_SPECIFIC_FAILURE,
|
||||
NULL);
|
||||
|
||||
mutex_unlock(&acpi_scan_lock);
|
||||
kfree(context);
|
||||
}
|
||||
EXPORT_SYMBOL(acpi_bus_hot_remove_device);
|
||||
|
||||
|
@ -206,51 +394,61 @@ static ssize_t
|
|||
acpi_eject_store(struct device *d, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
int ret = count;
|
||||
acpi_status status;
|
||||
acpi_object_type type = 0;
|
||||
struct acpi_device *acpi_device = to_acpi_device(d);
|
||||
struct acpi_eject_event *ej_event;
|
||||
acpi_object_type not_used;
|
||||
acpi_status status;
|
||||
u32 ost_source;
|
||||
int ret;
|
||||
|
||||
if ((!count) || (buf[0] != '1')) {
|
||||
if (!count || buf[0] != '1')
|
||||
return -EINVAL;
|
||||
}
|
||||
if (!acpi_device->driver && !acpi_device->handler) {
|
||||
ret = -ENODEV;
|
||||
goto err;
|
||||
}
|
||||
status = acpi_get_type(acpi_device->handle, &type);
|
||||
if (ACPI_FAILURE(status) || (!acpi_device->flags.ejectable)) {
|
||||
ret = -ENODEV;
|
||||
goto err;
|
||||
}
|
||||
|
||||
if ((!acpi_device->handler || !acpi_device->handler->hotplug.enabled)
|
||||
&& !acpi_device->driver)
|
||||
return -ENODEV;
|
||||
|
||||
status = acpi_get_type(acpi_device->handle, ¬_used);
|
||||
if (ACPI_FAILURE(status) || !acpi_device->flags.ejectable)
|
||||
return -ENODEV;
|
||||
|
||||
mutex_lock(&acpi_scan_lock);
|
||||
|
||||
if (acpi_device->flags.eject_pending) {
|
||||
/* ACPI eject notification event. */
|
||||
ost_source = ACPI_NOTIFY_EJECT_REQUEST;
|
||||
acpi_device->flags.eject_pending = 0;
|
||||
} else {
|
||||
/* Eject initiated by user space. */
|
||||
ost_source = ACPI_OST_EC_OSPM_EJECT;
|
||||
}
|
||||
ej_event = kmalloc(sizeof(*ej_event), GFP_KERNEL);
|
||||
if (!ej_event) {
|
||||
ret = -ENOMEM;
|
||||
goto err;
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
get_device(&acpi_device->dev);
|
||||
acpi_evaluate_hotplug_ost(acpi_device->handle, ost_source,
|
||||
ACPI_OST_SC_EJECT_IN_PROGRESS, NULL);
|
||||
ej_event->device = acpi_device;
|
||||
if (acpi_device->flags.eject_pending) {
|
||||
/* event originated from ACPI eject notification */
|
||||
ej_event->event = ACPI_NOTIFY_EJECT_REQUEST;
|
||||
acpi_device->flags.eject_pending = 0;
|
||||
} else {
|
||||
/* event originated from user */
|
||||
ej_event->event = ACPI_OST_EC_OSPM_EJECT;
|
||||
(void) acpi_evaluate_hotplug_ost(acpi_device->handle,
|
||||
ej_event->event, ACPI_OST_SC_EJECT_IN_PROGRESS, NULL);
|
||||
}
|
||||
|
||||
ej_event->event = ost_source;
|
||||
get_device(&acpi_device->dev);
|
||||
status = acpi_os_hotplug_execute(acpi_bus_hot_remove_device, ej_event);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
put_device(&acpi_device->dev);
|
||||
kfree(ej_event);
|
||||
ret = status == AE_NO_MEMORY ? -ENOMEM : -EAGAIN;
|
||||
goto err_out;
|
||||
}
|
||||
err:
|
||||
ret = count;
|
||||
|
||||
out:
|
||||
mutex_unlock(&acpi_scan_lock);
|
||||
return ret;
|
||||
|
||||
err_out:
|
||||
acpi_evaluate_hotplug_ost(acpi_device->handle, ost_source,
|
||||
ACPI_OST_SC_NON_SPECIFIC_FAILURE, NULL);
|
||||
goto out;
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(eject, 0200, NULL, acpi_eject_store);
|
||||
|
@ -376,7 +574,7 @@ static int acpi_device_setup_files(struct acpi_device *dev)
|
|||
goto end;
|
||||
}
|
||||
|
||||
if (dev->flags.bus_address)
|
||||
if (dev->pnp.type.bus_address)
|
||||
result = device_create_file(&dev->dev, &dev_attr_adr);
|
||||
if (dev->pnp.unique_id)
|
||||
result = device_create_file(&dev->dev, &dev_attr_uid);
|
||||
|
@ -449,7 +647,7 @@ static void acpi_device_remove_files(struct acpi_device *dev)
|
|||
|
||||
if (dev->pnp.unique_id)
|
||||
device_remove_file(&dev->dev, &dev_attr_uid);
|
||||
if (dev->flags.bus_address)
|
||||
if (dev->pnp.type.bus_address)
|
||||
device_remove_file(&dev->dev, &dev_attr_adr);
|
||||
device_remove_file(&dev->dev, &dev_attr_modalias);
|
||||
device_remove_file(&dev->dev, &dev_attr_hid);
|
||||
|
@ -512,17 +710,6 @@ int acpi_match_device_ids(struct acpi_device *device,
|
|||
}
|
||||
EXPORT_SYMBOL(acpi_match_device_ids);
|
||||
|
||||
void acpi_free_ids(struct acpi_device *device)
|
||||
{
|
||||
struct acpi_hardware_id *id, *tmp;
|
||||
|
||||
list_for_each_entry_safe(id, tmp, &device->pnp.ids, list) {
|
||||
kfree(id->id);
|
||||
kfree(id);
|
||||
}
|
||||
kfree(device->pnp.unique_id);
|
||||
}
|
||||
|
||||
static void acpi_free_power_resources_lists(struct acpi_device *device)
|
||||
{
|
||||
int i;
|
||||
|
@ -543,7 +730,7 @@ static void acpi_device_release(struct device *dev)
|
|||
{
|
||||
struct acpi_device *acpi_dev = to_acpi_device(dev);
|
||||
|
||||
acpi_free_ids(acpi_dev);
|
||||
acpi_free_pnp_ids(&acpi_dev->pnp);
|
||||
acpi_free_power_resources_lists(acpi_dev);
|
||||
kfree(acpi_dev);
|
||||
}
|
||||
|
@ -1256,19 +1443,17 @@ static void acpi_device_get_busid(struct acpi_device *device)
|
|||
}
|
||||
|
||||
/*
|
||||
* acpi_bay_match - see if a device is an ejectable driver bay
|
||||
* acpi_bay_match - see if an acpi object is an ejectable driver bay
|
||||
*
|
||||
* If an acpi object is ejectable and has one of the ACPI ATA methods defined,
|
||||
* then we can safely call it an ejectable drive bay
|
||||
*/
|
||||
static int acpi_bay_match(struct acpi_device *device){
|
||||
static int acpi_bay_match(acpi_handle handle)
|
||||
{
|
||||
acpi_status status;
|
||||
acpi_handle handle;
|
||||
acpi_handle tmp;
|
||||
acpi_handle phandle;
|
||||
|
||||
handle = device->handle;
|
||||
|
||||
status = acpi_get_handle(handle, "_EJ0", &tmp);
|
||||
if (ACPI_FAILURE(status))
|
||||
return -ENODEV;
|
||||
|
@ -1292,12 +1477,12 @@ static int acpi_bay_match(struct acpi_device *device){
|
|||
}
|
||||
|
||||
/*
|
||||
* acpi_dock_match - see if a device has a _DCK method
|
||||
* acpi_dock_match - see if an acpi object has a _DCK method
|
||||
*/
|
||||
static int acpi_dock_match(struct acpi_device *device)
|
||||
static int acpi_dock_match(acpi_handle handle)
|
||||
{
|
||||
acpi_handle tmp;
|
||||
return acpi_get_handle(device->handle, "_DCK", &tmp);
|
||||
return acpi_get_handle(handle, "_DCK", &tmp);
|
||||
}
|
||||
|
||||
const char *acpi_device_hid(struct acpi_device *device)
|
||||
|
@ -1312,7 +1497,7 @@ const char *acpi_device_hid(struct acpi_device *device)
|
|||
}
|
||||
EXPORT_SYMBOL(acpi_device_hid);
|
||||
|
||||
static void acpi_add_id(struct acpi_device *device, const char *dev_id)
|
||||
static void acpi_add_id(struct acpi_device_pnp *pnp, const char *dev_id)
|
||||
{
|
||||
struct acpi_hardware_id *id;
|
||||
|
||||
|
@ -1326,7 +1511,8 @@ static void acpi_add_id(struct acpi_device *device, const char *dev_id)
|
|||
return;
|
||||
}
|
||||
|
||||
list_add_tail(&id->list, &device->pnp.ids);
|
||||
list_add_tail(&id->list, &pnp->ids);
|
||||
pnp->type.hardware_id = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1334,7 +1520,7 @@ static void acpi_add_id(struct acpi_device *device, const char *dev_id)
|
|||
* lacks the SMBUS01 HID and the methods do not have the necessary "_"
|
||||
* prefix. Work around this.
|
||||
*/
|
||||
static int acpi_ibm_smbus_match(struct acpi_device *device)
|
||||
static int acpi_ibm_smbus_match(acpi_handle handle)
|
||||
{
|
||||
acpi_handle h_dummy;
|
||||
struct acpi_buffer path = {ACPI_ALLOCATE_BUFFER, NULL};
|
||||
|
@ -1344,7 +1530,7 @@ static int acpi_ibm_smbus_match(struct acpi_device *device)
|
|||
return -ENODEV;
|
||||
|
||||
/* Look for SMBS object */
|
||||
result = acpi_get_name(device->handle, ACPI_SINGLE_NAME, &path);
|
||||
result = acpi_get_name(handle, ACPI_SINGLE_NAME, &path);
|
||||
if (result)
|
||||
return result;
|
||||
|
||||
|
@ -1355,48 +1541,50 @@ static int acpi_ibm_smbus_match(struct acpi_device *device)
|
|||
|
||||
/* Does it have the necessary (but misnamed) methods? */
|
||||
result = -ENODEV;
|
||||
if (ACPI_SUCCESS(acpi_get_handle(device->handle, "SBI", &h_dummy)) &&
|
||||
ACPI_SUCCESS(acpi_get_handle(device->handle, "SBR", &h_dummy)) &&
|
||||
ACPI_SUCCESS(acpi_get_handle(device->handle, "SBW", &h_dummy)))
|
||||
if (ACPI_SUCCESS(acpi_get_handle(handle, "SBI", &h_dummy)) &&
|
||||
ACPI_SUCCESS(acpi_get_handle(handle, "SBR", &h_dummy)) &&
|
||||
ACPI_SUCCESS(acpi_get_handle(handle, "SBW", &h_dummy)))
|
||||
result = 0;
|
||||
out:
|
||||
kfree(path.pointer);
|
||||
return result;
|
||||
}
|
||||
|
||||
static void acpi_device_set_id(struct acpi_device *device)
|
||||
static void acpi_set_pnp_ids(acpi_handle handle, struct acpi_device_pnp *pnp,
|
||||
int device_type)
|
||||
{
|
||||
acpi_status status;
|
||||
struct acpi_device_info *info;
|
||||
struct acpi_pnp_device_id_list *cid_list;
|
||||
int i;
|
||||
|
||||
switch (device->device_type) {
|
||||
switch (device_type) {
|
||||
case ACPI_BUS_TYPE_DEVICE:
|
||||
if (ACPI_IS_ROOT_DEVICE(device)) {
|
||||
acpi_add_id(device, ACPI_SYSTEM_HID);
|
||||
if (handle == ACPI_ROOT_OBJECT) {
|
||||
acpi_add_id(pnp, ACPI_SYSTEM_HID);
|
||||
break;
|
||||
}
|
||||
|
||||
status = acpi_get_object_info(device->handle, &info);
|
||||
status = acpi_get_object_info(handle, &info);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
printk(KERN_ERR PREFIX "%s: Error reading device info\n", __func__);
|
||||
pr_err(PREFIX "%s: Error reading device info\n",
|
||||
__func__);
|
||||
return;
|
||||
}
|
||||
|
||||
if (info->valid & ACPI_VALID_HID)
|
||||
acpi_add_id(device, info->hardware_id.string);
|
||||
acpi_add_id(pnp, info->hardware_id.string);
|
||||
if (info->valid & ACPI_VALID_CID) {
|
||||
cid_list = &info->compatible_id_list;
|
||||
for (i = 0; i < cid_list->count; i++)
|
||||
acpi_add_id(device, cid_list->ids[i].string);
|
||||
acpi_add_id(pnp, cid_list->ids[i].string);
|
||||
}
|
||||
if (info->valid & ACPI_VALID_ADR) {
|
||||
device->pnp.bus_address = info->address;
|
||||
device->flags.bus_address = 1;
|
||||
pnp->bus_address = info->address;
|
||||
pnp->type.bus_address = 1;
|
||||
}
|
||||
if (info->valid & ACPI_VALID_UID)
|
||||
device->pnp.unique_id = kstrdup(info->unique_id.string,
|
||||
pnp->unique_id = kstrdup(info->unique_id.string,
|
||||
GFP_KERNEL);
|
||||
|
||||
kfree(info);
|
||||
|
@ -1405,40 +1593,50 @@ static void acpi_device_set_id(struct acpi_device *device)
|
|||
* Some devices don't reliably have _HIDs & _CIDs, so add
|
||||
* synthetic HIDs to make sure drivers can find them.
|
||||
*/
|
||||
if (acpi_is_video_device(device))
|
||||
acpi_add_id(device, ACPI_VIDEO_HID);
|
||||
else if (ACPI_SUCCESS(acpi_bay_match(device)))
|
||||
acpi_add_id(device, ACPI_BAY_HID);
|
||||
else if (ACPI_SUCCESS(acpi_dock_match(device)))
|
||||
acpi_add_id(device, ACPI_DOCK_HID);
|
||||
else if (!acpi_ibm_smbus_match(device))
|
||||
acpi_add_id(device, ACPI_SMBUS_IBM_HID);
|
||||
else if (list_empty(&device->pnp.ids) &&
|
||||
ACPI_IS_ROOT_DEVICE(device->parent)) {
|
||||
acpi_add_id(device, ACPI_BUS_HID); /* \_SB, LNXSYBUS */
|
||||
strcpy(device->pnp.device_name, ACPI_BUS_DEVICE_NAME);
|
||||
strcpy(device->pnp.device_class, ACPI_BUS_CLASS);
|
||||
if (acpi_is_video_device(handle))
|
||||
acpi_add_id(pnp, ACPI_VIDEO_HID);
|
||||
else if (ACPI_SUCCESS(acpi_bay_match(handle)))
|
||||
acpi_add_id(pnp, ACPI_BAY_HID);
|
||||
else if (ACPI_SUCCESS(acpi_dock_match(handle)))
|
||||
acpi_add_id(pnp, ACPI_DOCK_HID);
|
||||
else if (!acpi_ibm_smbus_match(handle))
|
||||
acpi_add_id(pnp, ACPI_SMBUS_IBM_HID);
|
||||
else if (list_empty(&pnp->ids) && handle == ACPI_ROOT_OBJECT) {
|
||||
acpi_add_id(pnp, ACPI_BUS_HID); /* \_SB, LNXSYBUS */
|
||||
strcpy(pnp->device_name, ACPI_BUS_DEVICE_NAME);
|
||||
strcpy(pnp->device_class, ACPI_BUS_CLASS);
|
||||
}
|
||||
|
||||
break;
|
||||
case ACPI_BUS_TYPE_POWER:
|
||||
acpi_add_id(device, ACPI_POWER_HID);
|
||||
acpi_add_id(pnp, ACPI_POWER_HID);
|
||||
break;
|
||||
case ACPI_BUS_TYPE_PROCESSOR:
|
||||
acpi_add_id(device, ACPI_PROCESSOR_OBJECT_HID);
|
||||
acpi_add_id(pnp, ACPI_PROCESSOR_OBJECT_HID);
|
||||
break;
|
||||
case ACPI_BUS_TYPE_THERMAL:
|
||||
acpi_add_id(device, ACPI_THERMAL_HID);
|
||||
acpi_add_id(pnp, ACPI_THERMAL_HID);
|
||||
break;
|
||||
case ACPI_BUS_TYPE_POWER_BUTTON:
|
||||
acpi_add_id(device, ACPI_BUTTON_HID_POWERF);
|
||||
acpi_add_id(pnp, ACPI_BUTTON_HID_POWERF);
|
||||
break;
|
||||
case ACPI_BUS_TYPE_SLEEP_BUTTON:
|
||||
acpi_add_id(device, ACPI_BUTTON_HID_SLEEPF);
|
||||
acpi_add_id(pnp, ACPI_BUTTON_HID_SLEEPF);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void acpi_free_pnp_ids(struct acpi_device_pnp *pnp)
|
||||
{
|
||||
struct acpi_hardware_id *id, *tmp;
|
||||
|
||||
list_for_each_entry_safe(id, tmp, &pnp->ids, list) {
|
||||
kfree(id->id);
|
||||
kfree(id);
|
||||
}
|
||||
kfree(pnp->unique_id);
|
||||
}
|
||||
|
||||
void acpi_init_device_object(struct acpi_device *device, acpi_handle handle,
|
||||
int type, unsigned long long sta)
|
||||
{
|
||||
|
@ -1448,7 +1646,7 @@ void acpi_init_device_object(struct acpi_device *device, acpi_handle handle,
|
|||
device->parent = acpi_bus_get_parent(handle);
|
||||
STRUCT_TO_INT(device->status) = sta;
|
||||
acpi_device_get_busid(device);
|
||||
acpi_device_set_id(device);
|
||||
acpi_set_pnp_ids(handle, &device->pnp, type);
|
||||
acpi_bus_get_flags(device);
|
||||
device->flags.match_driver = false;
|
||||
device_initialize(&device->dev);
|
||||
|
@ -1536,6 +1734,75 @@ static int acpi_bus_type_and_status(acpi_handle handle, int *type,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static bool acpi_scan_handler_matching(struct acpi_scan_handler *handler,
|
||||
char *idstr,
|
||||
const struct acpi_device_id **matchid)
|
||||
{
|
||||
const struct acpi_device_id *devid;
|
||||
|
||||
for (devid = handler->ids; devid->id[0]; devid++)
|
||||
if (!strcmp((char *)devid->id, idstr)) {
|
||||
if (matchid)
|
||||
*matchid = devid;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static struct acpi_scan_handler *acpi_scan_match_handler(char *idstr,
|
||||
const struct acpi_device_id **matchid)
|
||||
{
|
||||
struct acpi_scan_handler *handler;
|
||||
|
||||
list_for_each_entry(handler, &acpi_scan_handlers_list, list_node)
|
||||
if (acpi_scan_handler_matching(handler, idstr, matchid))
|
||||
return handler;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void acpi_scan_hotplug_enabled(struct acpi_hotplug_profile *hotplug, bool val)
|
||||
{
|
||||
if (!!hotplug->enabled == !!val)
|
||||
return;
|
||||
|
||||
mutex_lock(&acpi_scan_lock);
|
||||
|
||||
hotplug->enabled = val;
|
||||
|
||||
mutex_unlock(&acpi_scan_lock);
|
||||
}
|
||||
|
||||
static void acpi_scan_init_hotplug(acpi_handle handle, int type)
|
||||
{
|
||||
struct acpi_device_pnp pnp = {};
|
||||
struct acpi_hardware_id *hwid;
|
||||
struct acpi_scan_handler *handler;
|
||||
|
||||
INIT_LIST_HEAD(&pnp.ids);
|
||||
acpi_set_pnp_ids(handle, &pnp, type);
|
||||
|
||||
if (!pnp.type.hardware_id)
|
||||
return;
|
||||
|
||||
/*
|
||||
* This relies on the fact that acpi_install_notify_handler() will not
|
||||
* install the same notify handler routine twice for the same handle.
|
||||
*/
|
||||
list_for_each_entry(hwid, &pnp.ids, list) {
|
||||
handler = acpi_scan_match_handler(hwid->id, NULL);
|
||||
if (handler) {
|
||||
acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY,
|
||||
acpi_hotplug_notify_cb, handler);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
acpi_free_pnp_ids(&pnp);
|
||||
}
|
||||
|
||||
static acpi_status acpi_bus_check_add(acpi_handle handle, u32 lvl_not_used,
|
||||
void *not_used, void **return_value)
|
||||
{
|
||||
|
@ -1558,6 +1825,8 @@ static acpi_status acpi_bus_check_add(acpi_handle handle, u32 lvl_not_used,
|
|||
return AE_OK;
|
||||
}
|
||||
|
||||
acpi_scan_init_hotplug(handle, type);
|
||||
|
||||
if (!(sta & ACPI_STA_DEVICE_PRESENT) &&
|
||||
!(sta & ACPI_STA_DEVICE_FUNCTIONING)) {
|
||||
struct acpi_device_wakeup wakeup;
|
||||
|
@ -1583,41 +1852,25 @@ static acpi_status acpi_bus_check_add(acpi_handle handle, u32 lvl_not_used,
|
|||
return AE_OK;
|
||||
}
|
||||
|
||||
static int acpi_scan_do_attach_handler(struct acpi_device *device, char *id)
|
||||
{
|
||||
struct acpi_scan_handler *handler;
|
||||
|
||||
list_for_each_entry(handler, &acpi_scan_handlers_list, list_node) {
|
||||
const struct acpi_device_id *devid;
|
||||
|
||||
for (devid = handler->ids; devid->id[0]; devid++) {
|
||||
int ret;
|
||||
|
||||
if (strcmp((char *)devid->id, id))
|
||||
continue;
|
||||
|
||||
ret = handler->attach(device, devid);
|
||||
if (ret > 0) {
|
||||
device->handler = handler;
|
||||
return ret;
|
||||
} else if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int acpi_scan_attach_handler(struct acpi_device *device)
|
||||
{
|
||||
struct acpi_hardware_id *hwid;
|
||||
int ret = 0;
|
||||
|
||||
list_for_each_entry(hwid, &device->pnp.ids, list) {
|
||||
ret = acpi_scan_do_attach_handler(device, hwid->id);
|
||||
if (ret)
|
||||
break;
|
||||
const struct acpi_device_id *devid;
|
||||
struct acpi_scan_handler *handler;
|
||||
|
||||
handler = acpi_scan_match_handler(hwid->id, &devid);
|
||||
if (handler) {
|
||||
ret = handler->attach(device, devid);
|
||||
if (ret > 0) {
|
||||
device->handler = handler;
|
||||
break;
|
||||
} else if (ret < 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
@ -1791,6 +2044,7 @@ int __init acpi_scan_init(void)
|
|||
acpi_csrt_init();
|
||||
acpi_container_init();
|
||||
acpi_pci_slot_init();
|
||||
acpi_memory_hotplug_init();
|
||||
|
||||
mutex_lock(&acpi_scan_lock);
|
||||
/*
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
#include <linux/moduleparam.h>
|
||||
#include <acpi/acpi_drivers.h>
|
||||
|
||||
#include "internal.h"
|
||||
|
||||
#define _COMPONENT ACPI_SYSTEM_COMPONENT
|
||||
ACPI_MODULE_NAME("sysfs");
|
||||
|
||||
|
@ -249,6 +251,7 @@ module_param_call(acpica_version, NULL, param_get_acpica_version, NULL, 0444);
|
|||
static LIST_HEAD(acpi_table_attr_list);
|
||||
static struct kobject *tables_kobj;
|
||||
static struct kobject *dynamic_tables_kobj;
|
||||
static struct kobject *hotplug_kobj;
|
||||
|
||||
struct acpi_table_attr {
|
||||
struct bin_attribute attr;
|
||||
|
@ -716,6 +719,67 @@ acpi_show_profile(struct device *dev, struct device_attribute *attr,
|
|||
static const struct device_attribute pm_profile_attr =
|
||||
__ATTR(pm_profile, S_IRUGO, acpi_show_profile, NULL);
|
||||
|
||||
static ssize_t hotplug_enabled_show(struct kobject *kobj,
|
||||
struct kobj_attribute *attr, char *buf)
|
||||
{
|
||||
struct acpi_hotplug_profile *hotplug = to_acpi_hotplug_profile(kobj);
|
||||
|
||||
return sprintf(buf, "%d\n", hotplug->enabled);
|
||||
}
|
||||
|
||||
static ssize_t hotplug_enabled_store(struct kobject *kobj,
|
||||
struct kobj_attribute *attr,
|
||||
const char *buf, size_t size)
|
||||
{
|
||||
struct acpi_hotplug_profile *hotplug = to_acpi_hotplug_profile(kobj);
|
||||
unsigned int val;
|
||||
|
||||
if (kstrtouint(buf, 10, &val) || val > 1)
|
||||
return -EINVAL;
|
||||
|
||||
acpi_scan_hotplug_enabled(hotplug, val);
|
||||
return size;
|
||||
}
|
||||
|
||||
static struct kobj_attribute hotplug_enabled_attr =
|
||||
__ATTR(enabled, S_IRUGO | S_IWUSR, hotplug_enabled_show,
|
||||
hotplug_enabled_store);
|
||||
|
||||
static struct attribute *hotplug_profile_attrs[] = {
|
||||
&hotplug_enabled_attr.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static struct kobj_type acpi_hotplug_profile_ktype = {
|
||||
.sysfs_ops = &kobj_sysfs_ops,
|
||||
.default_attrs = hotplug_profile_attrs,
|
||||
};
|
||||
|
||||
void acpi_sysfs_add_hotplug_profile(struct acpi_hotplug_profile *hotplug,
|
||||
const char *name)
|
||||
{
|
||||
int error;
|
||||
|
||||
if (!hotplug_kobj)
|
||||
goto err_out;
|
||||
|
||||
kobject_init(&hotplug->kobj, &acpi_hotplug_profile_ktype);
|
||||
error = kobject_set_name(&hotplug->kobj, "%s", name);
|
||||
if (error)
|
||||
goto err_out;
|
||||
|
||||
hotplug->kobj.parent = hotplug_kobj;
|
||||
error = kobject_add(&hotplug->kobj, hotplug_kobj, NULL);
|
||||
if (error)
|
||||
goto err_out;
|
||||
|
||||
kobject_uevent(&hotplug->kobj, KOBJ_ADD);
|
||||
return;
|
||||
|
||||
err_out:
|
||||
pr_err(PREFIX "Unable to add hotplug profile '%s'\n", name);
|
||||
}
|
||||
|
||||
int __init acpi_sysfs_init(void)
|
||||
{
|
||||
int result;
|
||||
|
@ -723,6 +787,8 @@ int __init acpi_sysfs_init(void)
|
|||
result = acpi_tables_sysfs_init();
|
||||
if (result)
|
||||
return result;
|
||||
|
||||
hotplug_kobj = kobject_create_and_add("hotplug", acpi_kobj);
|
||||
result = sysfs_create_file(acpi_kobj, &pm_profile_attr.attr);
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -67,40 +67,37 @@ acpi_backlight_cap_match(acpi_handle handle, u32 level, void *context,
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* Returns true if the device is a video device which can be handled by
|
||||
* video.ko.
|
||||
/* Returns true if the ACPI object is a video device which can be
|
||||
* handled by video.ko.
|
||||
* The device will get a Linux specific CID added in scan.c to
|
||||
* identify the device as an ACPI graphics device
|
||||
* Be aware that the graphics device may not be physically present
|
||||
* Use acpi_video_get_capabilities() to detect general ACPI video
|
||||
* capabilities of present cards
|
||||
*/
|
||||
long acpi_is_video_device(struct acpi_device *device)
|
||||
long acpi_is_video_device(acpi_handle handle)
|
||||
{
|
||||
acpi_handle h_dummy;
|
||||
long video_caps = 0;
|
||||
|
||||
if (!device)
|
||||
return 0;
|
||||
|
||||
/* Is this device able to support video switching ? */
|
||||
if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_DOD", &h_dummy)) ||
|
||||
ACPI_SUCCESS(acpi_get_handle(device->handle, "_DOS", &h_dummy)))
|
||||
if (ACPI_SUCCESS(acpi_get_handle(handle, "_DOD", &h_dummy)) ||
|
||||
ACPI_SUCCESS(acpi_get_handle(handle, "_DOS", &h_dummy)))
|
||||
video_caps |= ACPI_VIDEO_OUTPUT_SWITCHING;
|
||||
|
||||
/* Is this device able to retrieve a video ROM ? */
|
||||
if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_ROM", &h_dummy)))
|
||||
if (ACPI_SUCCESS(acpi_get_handle(handle, "_ROM", &h_dummy)))
|
||||
video_caps |= ACPI_VIDEO_ROM_AVAILABLE;
|
||||
|
||||
/* Is this device able to configure which video head to be POSTed ? */
|
||||
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)))
|
||||
if (ACPI_SUCCESS(acpi_get_handle(handle, "_VPO", &h_dummy)) &&
|
||||
ACPI_SUCCESS(acpi_get_handle(handle, "_GPD", &h_dummy)) &&
|
||||
ACPI_SUCCESS(acpi_get_handle(handle, "_SPD", &h_dummy)))
|
||||
video_caps |= ACPI_VIDEO_DEVICE_POSTING;
|
||||
|
||||
/* Only check for backlight functionality if one of the above hit. */
|
||||
if (video_caps)
|
||||
acpi_walk_namespace(ACPI_TYPE_DEVICE, device->handle,
|
||||
acpi_walk_namespace(ACPI_TYPE_DEVICE, handle,
|
||||
ACPI_UINT32_MAX, acpi_backlight_cap_match, NULL,
|
||||
&video_caps, NULL);
|
||||
|
||||
|
@ -127,7 +124,7 @@ find_video(acpi_handle handle, u32 lvl, void *context, void **rv)
|
|||
if (!dev)
|
||||
return AE_OK;
|
||||
pci_dev_put(dev);
|
||||
*cap |= acpi_is_video_device(acpi_dev);
|
||||
*cap |= acpi_is_video_device(handle);
|
||||
}
|
||||
return AE_OK;
|
||||
}
|
||||
|
|
|
@ -350,11 +350,11 @@ static void intel_didl_outputs(struct drm_device *dev)
|
|||
if (!handle || acpi_bus_get_device(handle, &acpi_dev))
|
||||
return;
|
||||
|
||||
if (acpi_is_video_device(acpi_dev))
|
||||
if (acpi_is_video_device(handle))
|
||||
acpi_video_bus = acpi_dev;
|
||||
else {
|
||||
list_for_each_entry(acpi_cdev, &acpi_dev->children, node) {
|
||||
if (acpi_is_video_device(acpi_cdev)) {
|
||||
if (acpi_is_video_device(acpi_cdev->handle)) {
|
||||
acpi_video_bus = acpi_cdev;
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -88,11 +88,30 @@ struct acpi_device;
|
|||
* -----------------
|
||||
*/
|
||||
|
||||
enum acpi_hotplug_mode {
|
||||
AHM_GENERIC = 0,
|
||||
AHM_CONTAINER,
|
||||
AHM_COUNT
|
||||
};
|
||||
|
||||
struct acpi_hotplug_profile {
|
||||
struct kobject kobj;
|
||||
bool enabled:1;
|
||||
enum acpi_hotplug_mode mode;
|
||||
};
|
||||
|
||||
static inline struct acpi_hotplug_profile *to_acpi_hotplug_profile(
|
||||
struct kobject *kobj)
|
||||
{
|
||||
return container_of(kobj, struct acpi_hotplug_profile, kobj);
|
||||
}
|
||||
|
||||
struct acpi_scan_handler {
|
||||
const struct acpi_device_id *ids;
|
||||
struct list_head list_node;
|
||||
int (*attach)(struct acpi_device *dev, const struct acpi_device_id *id);
|
||||
void (*detach)(struct acpi_device *dev);
|
||||
struct acpi_hotplug_profile hotplug;
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -142,7 +161,6 @@ struct acpi_device_status {
|
|||
|
||||
struct acpi_device_flags {
|
||||
u32 dynamic_status:1;
|
||||
u32 bus_address:1;
|
||||
u32 removable:1;
|
||||
u32 ejectable:1;
|
||||
u32 suprise_removal_ok:1;
|
||||
|
@ -150,7 +168,7 @@ struct acpi_device_flags {
|
|||
u32 performance_manageable:1;
|
||||
u32 eject_pending:1;
|
||||
u32 match_driver:1;
|
||||
u32 reserved:23;
|
||||
u32 reserved:24;
|
||||
};
|
||||
|
||||
/* File System */
|
||||
|
@ -173,10 +191,17 @@ struct acpi_hardware_id {
|
|||
char *id;
|
||||
};
|
||||
|
||||
struct acpi_pnp_type {
|
||||
u32 hardware_id:1;
|
||||
u32 bus_address:1;
|
||||
u32 reserved:30;
|
||||
};
|
||||
|
||||
struct acpi_device_pnp {
|
||||
acpi_bus_id bus_id; /* Object name */
|
||||
acpi_bus_id bus_id; /* Object name */
|
||||
struct acpi_pnp_type type; /* ID type */
|
||||
acpi_bus_address bus_address; /* _ADR */
|
||||
char *unique_id; /* _UID */
|
||||
char *unique_id; /* _UID */
|
||||
struct list_head ids; /* _HID and _CIDs */
|
||||
acpi_device_name device_name; /* Driver-determined */
|
||||
acpi_device_class device_class; /* " */
|
||||
|
|
|
@ -204,7 +204,7 @@ extern bool wmi_has_guid(const char *guid);
|
|||
#if defined(CONFIG_ACPI_VIDEO) || defined(CONFIG_ACPI_VIDEO_MODULE)
|
||||
|
||||
extern long acpi_video_get_capabilities(acpi_handle graphics_dev_handle);
|
||||
extern long acpi_is_video_device(struct acpi_device *device);
|
||||
extern long acpi_is_video_device(acpi_handle handle);
|
||||
extern void acpi_video_dmi_promote_vendor(void);
|
||||
extern void acpi_video_dmi_demote_vendor(void);
|
||||
extern int acpi_video_backlight_support(void);
|
||||
|
@ -217,7 +217,7 @@ static inline long acpi_video_get_capabilities(acpi_handle graphics_dev_handle)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static inline long acpi_is_video_device(struct acpi_device *device)
|
||||
static inline long acpi_is_video_device(acpi_handle handle)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче