Commit ea261051 authored by Len Brown's avatar Len Brown

Merge branch 'bjorn-HID' into release

parents 6d7f18f6 57f3674f
......@@ -94,36 +94,33 @@ int acpi_bus_get_device(acpi_handle handle, struct acpi_device **device)
EXPORT_SYMBOL(acpi_bus_get_device);
int acpi_bus_get_status(struct acpi_device *device)
acpi_status acpi_bus_get_status_handle(acpi_handle handle,
unsigned long long *sta)
{
acpi_status status = AE_OK;
unsigned long long sta = 0;
acpi_status status;
if (!device)
return -EINVAL;
status = acpi_evaluate_integer(handle, "_STA", NULL, sta);
if (ACPI_SUCCESS(status))
return AE_OK;
/*
* Evaluate _STA if present.
*/
if (device->flags.dynamic_status) {
status =
acpi_evaluate_integer(device->handle, "_STA", NULL, &sta);
if (ACPI_FAILURE(status))
return -ENODEV;
STRUCT_TO_INT(device->status) = (int)sta;
if (status == AE_NOT_FOUND) {
*sta = ACPI_STA_DEVICE_PRESENT | ACPI_STA_DEVICE_ENABLED |
ACPI_STA_DEVICE_UI | ACPI_STA_DEVICE_FUNCTIONING;
return AE_OK;
}
return status;
}
/*
* According to ACPI spec some device can be present and functional
* even if the parent is not present but functional.
* In such conditions the child device should not inherit the status
* from the parent.
*/
else
STRUCT_TO_INT(device->status) =
ACPI_STA_DEVICE_PRESENT | ACPI_STA_DEVICE_ENABLED |
ACPI_STA_DEVICE_UI | ACPI_STA_DEVICE_FUNCTIONING;
int acpi_bus_get_status(struct acpi_device *device)
{
acpi_status status;
unsigned long long sta;
status = acpi_bus_get_status_handle(device->handle, &sta);
if (ACPI_FAILURE(status))
return -ENODEV;
STRUCT_TO_INT(device->status) = (int) sta;
if (device->status.functional && !device->status.present) {
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device [%s] status [%08x]: "
......@@ -135,10 +132,8 @@ int acpi_bus_get_status(struct acpi_device *device)
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device [%s] status [%08x]\n",
device->pnp.bus_id,
(u32) STRUCT_TO_INT(device->status)));
return 0;
}
EXPORT_SYMBOL(acpi_bus_get_status);
void acpi_bus_private_data_handler(acpi_handle handle,
......
......@@ -22,6 +22,8 @@ extern struct acpi_device *acpi_root;
#define ACPI_BUS_HID "LNXSYBUS"
#define ACPI_BUS_DEVICE_NAME "System Bus"
#define ACPI_IS_ROOT_DEVICE(device) (!(device)->parent)
static LIST_HEAD(acpi_device_list);
static LIST_HEAD(acpi_bus_id_list);
DEFINE_MUTEX(acpi_device_lock);
......@@ -43,40 +45,19 @@ static int create_modalias(struct acpi_device *acpi_dev, char *modalias,
{
int len;
int count;
if (!acpi_dev->flags.hardware_id && !acpi_dev->flags.compatible_ids)
return -ENODEV;
struct acpi_hardware_id *id;
len = snprintf(modalias, size, "acpi:");
size -= len;
if (acpi_dev->flags.hardware_id) {
count = snprintf(&modalias[len], size, "%s:",
acpi_dev->pnp.hardware_id);
list_for_each_entry(id, &acpi_dev->pnp.ids, list) {
count = snprintf(&modalias[len], size, "%s:", id->id);
if (count < 0 || count >= size)
return -EINVAL;
len += count;
size -= count;
}
if (acpi_dev->flags.compatible_ids) {
struct acpica_device_id_list *cid_list;
int i;
cid_list = acpi_dev->pnp.cid_list;
for (i = 0; i < cid_list->count; i++) {
count = snprintf(&modalias[len], size, "%s:",
cid_list->ids[i].string);
if (count < 0 || count >= size) {
printk(KERN_ERR PREFIX "%s cid[%i] exceeds event buffer size",
acpi_dev->pnp.device_name, i);
break;
}
len += count;
size -= count;
}
}
modalias[len] = '\0';
return len;
}
......@@ -183,7 +164,7 @@ static ssize_t
acpi_device_hid_show(struct device *dev, struct device_attribute *attr, char *buf) {
struct acpi_device *acpi_dev = to_acpi_device(dev);
return sprintf(buf, "%s\n", acpi_dev->pnp.hardware_id);
return sprintf(buf, "%s\n", acpi_device_hid(acpi_dev));
}
static DEVICE_ATTR(hid, 0444, acpi_device_hid_show, NULL);
......@@ -219,17 +200,13 @@ static int acpi_device_setup_files(struct acpi_device *dev)
goto end;
}
if (dev->flags.hardware_id) {
result = device_create_file(&dev->dev, &dev_attr_hid);
if (result)
goto end;
}
result = device_create_file(&dev->dev, &dev_attr_hid);
if (result)
goto end;
if (dev->flags.hardware_id || dev->flags.compatible_ids) {
result = device_create_file(&dev->dev, &dev_attr_modalias);
if (result)
goto end;
}
result = device_create_file(&dev->dev, &dev_attr_modalias);
if (result)
goto end;
/*
* If device has _EJ0, 'eject' file is created that is used to trigger
......@@ -255,11 +232,8 @@ static void acpi_device_remove_files(struct acpi_device *dev)
if (ACPI_SUCCESS(status))
device_remove_file(&dev->dev, &dev_attr_eject);
if (dev->flags.hardware_id || dev->flags.compatible_ids)
device_remove_file(&dev->dev, &dev_attr_modalias);
if (dev->flags.hardware_id)
device_remove_file(&dev->dev, &dev_attr_hid);
device_remove_file(&dev->dev, &dev_attr_modalias);
device_remove_file(&dev->dev, &dev_attr_hid);
if (dev->handle)
device_remove_file(&dev->dev, &dev_attr_path);
}
......@@ -271,6 +245,7 @@ int acpi_match_device_ids(struct acpi_device *device,
const struct acpi_device_id *ids)
{
const struct acpi_device_id *id;
struct acpi_hardware_id *hwid;
/*
* If the device is not present, it is unnecessary to load device
......@@ -279,40 +254,30 @@ int acpi_match_device_ids(struct acpi_device *device,
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))
for (id = ids; id->id[0]; id++)
list_for_each_entry(hwid, &device->pnp.ids, list)
if (!strcmp((char *) id->id, hwid->id))
return 0;
}
}
if (device->flags.compatible_ids) {
struct acpica_device_id_list *cid_list = device->pnp.cid_list;
int i;
for (id = ids; id->id[0]; id++) {
/* compare multiple _CID entries against driver ids */
for (i = 0; i < cid_list->count; i++) {
if (!strcmp((char*)id->id,
cid_list->ids[i].string))
return 0;
}
}
}
return -ENOENT;
}
EXPORT_SYMBOL(acpi_match_device_ids);
static 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);
}
}
static void acpi_device_release(struct device *dev)
{
struct acpi_device *acpi_dev = to_acpi_device(dev);
kfree(acpi_dev->pnp.cid_list);
if (acpi_dev->flags.hardware_id)
kfree(acpi_dev->pnp.hardware_id);
if (acpi_dev->flags.unique_id)
kfree(acpi_dev->pnp.unique_id);
acpi_free_ids(acpi_dev);
kfree(acpi_dev);
}
......@@ -378,15 +343,13 @@ static acpi_status acpi_device_notify_fixed(void *data)
static int acpi_device_install_notify_handler(struct acpi_device *device)
{
acpi_status status;
char *hid;
hid = acpi_device_hid(device);
if (!strcmp(hid, ACPI_BUTTON_HID_POWERF))
if (device->device_type == ACPI_BUS_TYPE_POWER_BUTTON)
status =
acpi_install_fixed_event_handler(ACPI_EVENT_POWER_BUTTON,
acpi_device_notify_fixed,
device);
else if (!strcmp(hid, ACPI_BUTTON_HID_SLEEPF))
else if (device->device_type == ACPI_BUS_TYPE_SLEEP_BUTTON)
status =
acpi_install_fixed_event_handler(ACPI_EVENT_SLEEP_BUTTON,
acpi_device_notify_fixed,
......@@ -404,10 +367,10 @@ static int acpi_device_install_notify_handler(struct acpi_device *device)
static void acpi_device_remove_notify_handler(struct acpi_device *device)
{
if (!strcmp(acpi_device_hid(device), ACPI_BUTTON_HID_POWERF))
if (device->device_type == ACPI_BUS_TYPE_POWER_BUTTON)
acpi_remove_fixed_event_handler(ACPI_EVENT_POWER_BUTTON,
acpi_device_notify_fixed);
else if (!strcmp(acpi_device_hid(device), ACPI_BUTTON_HID_SLEEPF))
else if (device->device_type == ACPI_BUS_TYPE_SLEEP_BUTTON)
acpi_remove_fixed_event_handler(ACPI_EVENT_SLEEP_BUTTON,
acpi_device_notify_fixed);
else
......@@ -474,12 +437,12 @@ struct bus_type acpi_bus_type = {
.uevent = acpi_device_uevent,
};
static int acpi_device_register(struct acpi_device *device,
struct acpi_device *parent)
static int acpi_device_register(struct acpi_device *device)
{
int result;
struct acpi_device_bus_id *acpi_device_bus_id, *new_bus_id;
int found = 0;
/*
* Linkage
* -------
......@@ -501,8 +464,9 @@ static int acpi_device_register(struct acpi_device *device,
* If failed, create one and link it into acpi_bus_id_list
*/
list_for_each_entry(acpi_device_bus_id, &acpi_bus_id_list, node) {
if(!strcmp(acpi_device_bus_id->bus_id, device->flags.hardware_id? device->pnp.hardware_id : "device")) {
acpi_device_bus_id->instance_no ++;
if (!strcmp(acpi_device_bus_id->bus_id,
acpi_device_hid(device))) {
acpi_device_bus_id->instance_no++;
found = 1;
kfree(new_bus_id);
break;
......@@ -510,7 +474,7 @@ static int acpi_device_register(struct acpi_device *device,
}
if (!found) {
acpi_device_bus_id = new_bus_id;
strcpy(acpi_device_bus_id->bus_id, device->flags.hardware_id ? device->pnp.hardware_id : "device");
strcpy(acpi_device_bus_id->bus_id, acpi_device_hid(device));
acpi_device_bus_id->instance_no = 0;
list_add_tail(&acpi_device_bus_id->node, &acpi_bus_id_list);
}
......@@ -524,7 +488,7 @@ static int acpi_device_register(struct acpi_device *device,
mutex_unlock(&acpi_device_lock);
if (device->parent)
device->dev.parent = &parent->dev;
device->dev.parent = &device->parent->dev;
device->dev.bus = &acpi_bus_type;
device->dev.release = &acpi_device_release;
result = device_register(&device->dev);
......@@ -664,6 +628,33 @@ EXPORT_SYMBOL(acpi_bus_unregister_driver);
/* --------------------------------------------------------------------------
Device Enumeration
-------------------------------------------------------------------------- */
static struct acpi_device *acpi_bus_get_parent(acpi_handle handle)
{
acpi_status status;
int ret;
struct acpi_device *device;
/*
* Fixed hardware devices do not appear in the namespace and do not
* have handles, but we fabricate acpi_devices for them, so we have
* to deal with them specially.
*/
if (handle == NULL)
return acpi_root;
do {
status = acpi_get_parent(handle, &handle);
if (status == AE_NULL_ENTRY)
return NULL;
if (ACPI_FAILURE(status))
return acpi_root;
ret = acpi_bus_get_device(handle, &device);
if (ret == 0)
return device;
} while (1);
}
acpi_status
acpi_bus_get_ejd(acpi_handle handle, acpi_handle *ejd)
{
......@@ -876,11 +867,6 @@ static int acpi_bus_get_flags(struct acpi_device *device)
if (ACPI_SUCCESS(status))
device->flags.dynamic_status = 1;
/* Presence of _CID indicates 'compatible_ids' */
status = acpi_get_handle(device->handle, "_CID", &temp);
if (ACPI_SUCCESS(status))
device->flags.compatible_ids = 1;
/* Presence of _RMV indicates 'removable' */
status = acpi_get_handle(device->handle, "_RMV", &temp);
if (ACPI_SUCCESS(status))
......@@ -918,8 +904,7 @@ static int acpi_bus_get_flags(struct acpi_device *device)
return 0;
}
static void acpi_device_get_busid(struct acpi_device *device,
acpi_handle handle, int type)
static void acpi_device_get_busid(struct acpi_device *device)
{
char bus_id[5] = { '?', 0 };
struct acpi_buffer buffer = { sizeof(bus_id), bus_id };
......@@ -931,10 +916,12 @@ static void acpi_device_get_busid(struct acpi_device *device,
* The device's Bus ID is simply the object name.
* TBD: Shouldn't this value be unique (within the ACPI namespace)?
*/
switch (type) {
case ACPI_BUS_TYPE_SYSTEM:
if (ACPI_IS_ROOT_DEVICE(device)) {
strcpy(device->pnp.bus_id, "ACPI");
break;
return;
}
switch (device->device_type) {
case ACPI_BUS_TYPE_POWER_BUTTON:
strcpy(device->pnp.bus_id, "PWRF");
break;
......@@ -942,7 +929,7 @@ static void acpi_device_get_busid(struct acpi_device *device,
strcpy(device->pnp.bus_id, "SLPF");
break;
default:
acpi_get_name(handle, ACPI_SINGLE_NAME, &buffer);
acpi_get_name(device->handle, ACPI_SINGLE_NAME, &buffer);
/* Clean up trailing underscores (if any) */
for (i = 3; i > 1; i--) {
if (bus_id[i] == '_')
......@@ -1000,204 +987,132 @@ static int acpi_dock_match(struct acpi_device *device)
return acpi_get_handle(device->handle, "_DCK", &tmp);
}
static struct acpica_device_id_list*
acpi_add_cid(
struct acpi_device_info *info,
struct acpica_device_id *new_cid)
char *acpi_device_hid(struct acpi_device *device)
{
struct acpica_device_id_list *cid;
char *next_id_string;
acpi_size cid_length;
acpi_size new_cid_length;
u32 i;
/* Allocate new CID list with room for the new CID */
if (!new_cid)
new_cid_length = info->compatible_id_list.list_size;
else if (info->compatible_id_list.list_size)
new_cid_length = info->compatible_id_list.list_size +
new_cid->length + sizeof(struct acpica_device_id);
else
new_cid_length = sizeof(struct acpica_device_id_list) + new_cid->length;
cid = ACPI_ALLOCATE_ZEROED(new_cid_length);
if (!cid) {
return NULL;
}
cid->list_size = new_cid_length;
cid->count = info->compatible_id_list.count;
if (new_cid)
cid->count++;
next_id_string = (char *) cid->ids + (cid->count * sizeof(struct acpica_device_id));
/* Copy all existing CIDs */
for (i = 0; i < info->compatible_id_list.count; i++) {
cid_length = info->compatible_id_list.ids[i].length;
cid->ids[i].string = next_id_string;
cid->ids[i].length = cid_length;
struct acpi_hardware_id *hid;
ACPI_MEMCPY(next_id_string, info->compatible_id_list.ids[i].string,
cid_length);
next_id_string += cid_length;
}
hid = list_first_entry(&device->pnp.ids, struct acpi_hardware_id, list);
return hid->id;
}
EXPORT_SYMBOL(acpi_device_hid);
/* Append the new CID */
static void acpi_add_id(struct acpi_device *device, const char *dev_id)
{
struct acpi_hardware_id *id;
if (new_cid) {
cid->ids[i].string = next_id_string;
cid->ids[i].length = new_cid->length;
id = kmalloc(sizeof(*id), GFP_KERNEL);
if (!id)
return;
ACPI_MEMCPY(next_id_string, new_cid->string, new_cid->length);
id->id = kmalloc(strlen(dev_id) + 1, GFP_KERNEL);
if (!id->id) {
kfree(id);
return;
}
return cid;
strcpy(id->id, dev_id);
list_add_tail(&id->list, &device->pnp.ids);
}
static void acpi_device_set_id(struct acpi_device *device,
struct acpi_device *parent, acpi_handle handle,
int type)
static void acpi_device_set_id(struct acpi_device *device)
{
struct acpi_device_info *info = NULL;
char *hid = NULL;
char *uid = NULL;
struct acpica_device_id_list *cid_list = NULL;
char *cid_add = NULL;
acpi_status status;
struct acpi_device_info *info;
struct acpica_device_id_list *cid_list;
int i;
switch (type) {
switch (device->device_type) {
case ACPI_BUS_TYPE_DEVICE:
status = acpi_get_object_info(handle, &info);
if (ACPI_IS_ROOT_DEVICE(device)) {
acpi_add_id(device, ACPI_SYSTEM_HID);
break;
} else if (ACPI_IS_ROOT_DEVICE(device->parent)) {
/* \_SB_, the only root-level namespace device */
acpi_add_id(device, ACPI_BUS_HID);
strcpy(device->pnp.device_name, ACPI_BUS_DEVICE_NAME);
strcpy(device->pnp.device_class, ACPI_BUS_CLASS);
break;
}
status = acpi_get_object_info(device->handle, &info);
if (ACPI_FAILURE(status)) {
printk(KERN_ERR PREFIX "%s: Error reading device info\n", __func__);
return;
}
if (info->valid & ACPI_VALID_HID)
hid = info->hardware_id.string;
if (info->valid & ACPI_VALID_UID)
uid = info->unique_id.string;
if (info->valid & ACPI_VALID_CID)
acpi_add_id(device, 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);
}
if (info->valid & ACPI_VALID_ADR) {
device->pnp.bus_address = info->address;
device->flags.bus_address = 1;
}
/* If we have a video/bay/dock device, add our selfdefined
HID to the CID list. Like that the video/bay/dock drivers
will get autoloaded and the device might still match
against another driver.
*/
/*
* 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))
cid_add = ACPI_VIDEO_HID;
acpi_add_id(device, ACPI_VIDEO_HID);
else if (ACPI_SUCCESS(acpi_bay_match(device)))
cid_add = ACPI_BAY_HID;
acpi_add_id(device, ACPI_BAY_HID);
else if (ACPI_SUCCESS(acpi_dock_match(device)))
cid_add = ACPI_DOCK_HID;
acpi_add_id(device, ACPI_DOCK_HID);
break;
case ACPI_BUS_TYPE_POWER:
hid = ACPI_POWER_HID;
acpi_add_id(device, ACPI_POWER_HID);
break;
case ACPI_BUS_TYPE_PROCESSOR:
hid = ACPI_PROCESSOR_OBJECT_HID;
break;
case ACPI_BUS_TYPE_SYSTEM:
hid = ACPI_SYSTEM_HID;
acpi_add_id(device, ACPI_PROCESSOR_OBJECT_HID);
break;
case ACPI_BUS_TYPE_THERMAL:
hid = ACPI_THERMAL_HID;
acpi_add_id(device, ACPI_THERMAL_HID);
break;
case ACPI_BUS_TYPE_POWER_BUTTON:
hid = ACPI_BUTTON_HID_POWERF;
acpi_add_id(device, ACPI_BUTTON_HID_POWERF);
break;
case ACPI_BUS_TYPE_SLEEP_BUTTON:
hid = ACPI_BUTTON_HID_SLEEPF;
acpi_add_id(device, ACPI_BUTTON_HID_SLEEPF);
break;
}
/*
* \_SB
* ----
* Fix for the system root bus device -- the only root-level device.
* We build acpi_devices for some objects that don't have _HID or _CID,
* e.g., PCI bridges and slots. Drivers can't bind to these objects,
* but we do use them indirectly by traversing the acpi_device tree.
* This generic ID isn't useful for driver binding, but it provides
* the useful property that "every acpi_device has an ID."
*/
if (((acpi_handle)parent == ACPI_ROOT_OBJECT) && (type == ACPI_BUS_TYPE_DEVICE)) {
hid = ACPI_BUS_HID;
strcpy(device->pnp.device_name, ACPI_BUS_DEVICE_NAME);
strcpy(device->pnp.device_class, ACPI_BUS_CLASS);
}
if (hid) {
device->pnp.hardware_id = ACPI_ALLOCATE_ZEROED(strlen (hid) + 1);
if (device->pnp.hardware_id) {
strcpy(device->pnp.hardware_id, hid);
device->flags.hardware_id = 1;
}
}
if (!device->flags.hardware_id)
device->pnp.hardware_id = "";
if (uid) {
device->pnp.unique_id = ACPI_ALLOCATE_ZEROED(strlen (uid) + 1);
if (device->pnp.unique_id) {
strcpy(device->pnp.unique_id, uid);
device->flags.unique_id = 1;
}
}
if (!device->flags.unique_id)
device->pnp.unique_id = "";
if (cid_list || cid_add) {
struct acpica_device_id_list *list;
if (cid_add) {
struct acpica_device_id cid;
cid.length = strlen (cid_add) + 1;
cid.string = cid_add;
list = acpi_add_cid(info, &cid);
} else {
list = acpi_add_cid(info, NULL);
}
if (list) {
device->pnp.cid_list = list;
if (cid_add)
device->flags.compatible_ids = 1;
}
}
kfree(info);
if (list_empty(&device->pnp.ids))
acpi_add_id(device, "device");
}
static int acpi_device_set_context(struct acpi_device *device, int type)
static int acpi_device_set_context(struct acpi_device *device)
{
acpi_status status = AE_OK;
int result = 0;
acpi_status status;
/*
* Context
* -------
* Attach this 'struct acpi_device' to the ACPI object. This makes
* resolutions from handle->device very efficient. Note that we need
* to be careful with fixed-feature devices as they all attach to the
* root object.
* resolutions from handle->device very efficient. Fixed hardware
* devices have no handles, so we skip them.
*/
if (type != ACPI_BUS_TYPE_POWER_BUTTON &&
type != ACPI_BUS_TYPE_SLEEP_BUTTON) {
status = acpi_attach_data(device->handle,
acpi_bus_data_handler, device);
if (!device->handle)
return 0;
if (ACPI_FAILURE(status)) {
printk(KERN_ERR PREFIX "Error attaching device data\n");
result = -ENODEV;
}
}
return result;
status = acpi_attach_data(device->handle,
acpi_bus_data_handler, device);
if (ACPI_SUCCESS(status))
return 0;
printk(KERN_ERR PREFIX "Error attaching device data\n");
return -ENODEV;
}
static int acpi_bus_remove(struct acpi_device *dev, int rmdevice)
......@@ -1223,17 +1138,14 @@ static int acpi_bus_remove(struct acpi_device *dev, int rmdevice)
return 0;
}
static int
acpi_add_single_object(struct acpi_device **child,
struct acpi_device *parent, acpi_handle handle, int type,
struct acpi_bus_ops *ops)
static int acpi_add_single_object(struct acpi_device **child,
acpi_handle handle, int type,
unsigned long long sta,
struct acpi_bus_ops *ops)
{
int result = 0;
struct acpi_device *device = NULL;
if (!child)
return -EINVAL;
int result;
struct acpi_device *device;
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
device = kzalloc(sizeof(struct acpi_device), GFP_KERNEL);
if (!device) {
......@@ -1241,75 +1153,31 @@ acpi_add_single_object(struct acpi_device **child,
return -ENOMEM;
}
INIT_LIST_HEAD(&device->pnp.ids);
device->device_type = type;
device->handle = handle;
device->parent = parent;
device->parent = acpi_bus_get_parent(handle);
device->bus_ops = *ops; /* workround for not call .start */
STRUCT_TO_INT(device->status) = sta;
acpi_device_get_busid(device, handle, type);
acpi_device_get_busid(device);
/*
* Flags
* -----
* Get prior to calling acpi_bus_get_status() so we know whether
* or not _STA is present. Note that we only look for object
* handles -- cannot evaluate objects until we know the device is
* present and properly initialized.
* Note that we only look for object handles -- cannot evaluate objects
* until we know the device is present and properly initialized.
*/
result = acpi_bus_get_flags(device);
if (result)
goto end;
/*
* Status
* ------
* See if the device is present. We always assume that non-Device
* and non-Processor objects (e.g. thermal zones, power resources,
* etc.) are present, functioning, etc. (at least when parent object
* is present). Note that _STA has a different meaning for some
* objects (e.g. power resources) so we need to be careful how we use
* it.
*/
switch (type) {
case ACPI_BUS_TYPE_PROCESSOR:
case ACPI_BUS_TYPE_DEVICE:
result = acpi_bus_get_status(device);
if (ACPI_FAILURE(result)) {
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:
STRUCT_TO_INT(device->status) =
ACPI_STA_DEVICE_PRESENT | ACPI_STA_DEVICE_ENABLED |
ACPI_STA_DEVICE_UI | ACPI_STA_DEVICE_FUNCTIONING;
break;
}
/*
* Initialize Device
* -----------------
* TBD: Synch with Core's enumeration/initialization process.
*/
/*
* Hardware ID, Unique ID, & Bus Address
* -------------------------------------
*/
acpi_device_set_id(device, parent, handle, type);
acpi_device_set_id(device);
/*
* Power Management
......@@ -1341,10 +1209,10 @@ acpi_add_single_object(struct acpi_device **child,
goto end;
}
if ((result = acpi_device_set_context(device, type)))
if ((result = acpi_device_set_context(device)))
goto end;
result = acpi_device_register(device, parent);
result = acpi_device_register(device);
/*
* Bind _ADR-Based Devices when hot add
......@@ -1355,128 +1223,122 @@ acpi_add_single_object(struct acpi_device **child,
}
end:
if (!result)
if (!result) {
acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"Adding %s [%s] parent %s\n", dev_name(&device->dev),
(char *) buffer.pointer,
device->parent ? dev_name(&device->parent->dev) :
"(null)"));
kfree(buffer.pointer);
*child = device;
else
} else
acpi_device_release(&device->dev);
return result;
}
static int acpi_bus_scan(struct acpi_device *start, struct acpi_bus_ops *ops)
#define ACPI_STA_DEFAULT (ACPI_STA_DEVICE_PRESENT | ACPI_STA_DEVICE_ENABLED | \
ACPI_STA_DEVICE_UI | ACPI_STA_DEVICE_FUNCTIONING)
static int acpi_bus_type_and_status(acpi_handle handle, int *type,
unsigned long long *sta)
{
acpi_status status = AE_OK;
struct acpi_device *parent = NULL;
struct acpi_device *child = NULL;
acpi_handle phandle = NULL;
acpi_handle chandle = NULL;
acpi_object_type type = 0;
u32 level = 1;
acpi_status status;
acpi_object_type acpi_type;
status = acpi_get_type(handle, &acpi_type);
if (ACPI_FAILURE(status))
return -ENODEV;
if (!start)
return -EINVAL;
switch (acpi_type) {
case ACPI_TYPE_ANY: /* for ACPI_ROOT_OBJECT */
case ACPI_TYPE_DEVICE:
*type = ACPI_BUS_TYPE_DEVICE;
status = acpi_bus_get_status_handle(handle, sta);
if (ACPI_FAILURE(status))
return -ENODEV;
break;
case ACPI_TYPE_PROCESSOR:
*type = ACPI_BUS_TYPE_PROCESSOR;
status = acpi_bus_get_status_handle(handle, sta);
if (ACPI_FAILURE(status))
return -ENODEV;
break;
case ACPI_TYPE_THERMAL:
*type = ACPI_BUS_TYPE_THERMAL;
*sta = ACPI_STA_DEFAULT;
break;
case ACPI_TYPE_POWER:
*type = ACPI_BUS_TYPE_POWER;
*sta = ACPI_STA_DEFAULT;
break;
default:
return -ENODEV;
}
parent = start;
phandle = start->handle;
return 0;
}
/*
* Parse through the ACPI namespace, identify all 'devices', and
* create a new 'struct acpi_device' for each.
*/
while ((level > 0) && parent) {
static acpi_status acpi_bus_check_add(acpi_handle handle, u32 lvl,
void *context, void **return_value)
{
struct acpi_bus_ops *ops = context;
int type;
unsigned long long sta;
struct acpi_device *device;
acpi_status status;
int result;
status = acpi_get_next_object(ACPI_TYPE_ANY, phandle,
chandle, &chandle);
result = acpi_bus_type_and_status(handle, &type, &sta);
if (result)
return AE_OK;
/*
* If this scope is exhausted then move our way back up.
*/
if (ACPI_FAILURE(status)) {
level--;
chandle = phandle;
acpi_get_parent(phandle, &phandle);
if (parent->parent)
parent = parent->parent;
continue;
}
if (!(sta & ACPI_STA_DEVICE_PRESENT) &&
!(sta & ACPI_STA_DEVICE_FUNCTIONING))
return AE_CTRL_DEPTH;
status = acpi_get_type(chandle, &type);
if (ACPI_FAILURE(status))
continue;
/*
* We may already have an acpi_device from a previous enumeration. If
* so, we needn't add it again, but we may still have to start it.
*/
device = NULL;
acpi_bus_get_device(handle, &device);
if (ops->acpi_op_add && !device)
acpi_add_single_object(&device, handle, type, sta, ops);
/*
* If this is a scope object then parse it (depth-first).
*/
if (type == ACPI_TYPE_LOCAL_SCOPE) {
level++;
phandle = chandle;
chandle = NULL;
continue;
}
if (!device)
return AE_CTRL_DEPTH;
/*
* We're only interested in objects that we consider 'devices'.
*/
switch (type) {
case ACPI_TYPE_DEVICE:
type = ACPI_BUS_TYPE_DEVICE;
break;
case ACPI_TYPE_PROCESSOR:
type = ACPI_BUS_TYPE_PROCESSOR;
break;
case ACPI_TYPE_THERMAL:
type = ACPI_BUS_TYPE_THERMAL;
break;
case ACPI_TYPE_POWER:
type = ACPI_BUS_TYPE_POWER;
break;
default:
continue;
}
if (ops->acpi_op_start && !(ops->acpi_op_add)) {
status = acpi_start_single_object(device);
if (ACPI_FAILURE(status))
return AE_CTRL_DEPTH;
}
if (ops->acpi_op_add)
status = acpi_add_single_object(&child, parent,
chandle, type, ops);
else
status = acpi_bus_get_device(chandle, &child);
if (!*return_value)
*return_value = device;
return AE_OK;
}
if (ACPI_FAILURE(status))
continue;
static int acpi_bus_scan(acpi_handle handle, struct acpi_bus_ops *ops,
struct acpi_device **child)
{
acpi_status status;
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
void *device = NULL;
if (ops->acpi_op_start && !(ops->acpi_op_add)) {
status = acpi_start_single_object(child);
if (ACPI_FAILURE(status))
continue;
}
acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
printk(KERN_INFO PREFIX "Enumerating devices from [%s]\n",
(char *) buffer.pointer);
/*
* If the device is present, enabled, and functioning then
* parse its scope (depth-first). Note that we need to
* represent absent devices to facilitate PnP notifications
* -- but only the subtree head (not all of its children,
* which will be enumerated when the parent is inserted).
*
* TBD: Need notifications and other detection mechanisms
* in place before we can fully implement this.
*/
/*
* 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)) {
level++;
phandle = chandle;
chandle = NULL;
parent = child;
}
}
}
status = acpi_bus_check_add(handle, 0, ops, &device);
if (ACPI_SUCCESS(status))
acpi_walk_namespace(ACPI_TYPE_ANY, handle, ACPI_UINT32_MAX,
acpi_bus_check_add, ops, &device);
if (child)
*child = device;
return 0;
}
......@@ -1484,36 +1346,25 @@ int
acpi_bus_add(struct acpi_device **child,
struct acpi_device *parent, acpi_handle handle, int type)
{
int result;
struct acpi_bus_ops ops;
memset(&ops, 0, sizeof(ops));
ops.acpi_op_add = 1;
result = acpi_add_single_object(child, parent, handle, type, &ops);
if (!result)
result = acpi_bus_scan(*child, &ops);
return result;
acpi_bus_scan(handle, &ops, child);
return 0;
}
EXPORT_SYMBOL(acpi_bus_add);
int acpi_bus_start(struct acpi_device *device)
{
int result;
struct acpi_bus_ops ops;
memset(&ops, 0, sizeof(ops));
ops.acpi_op_start = 1;
if (!device)
return -EINVAL;
result = acpi_start_single_object(device);
if (!result) {
memset(&ops, 0, sizeof(ops));
ops.acpi_op_start = 1;
result = acpi_bus_scan(device, &ops);
}
return result;
acpi_bus_scan(device->handle, &ops, NULL);
return 0;
}
EXPORT_SYMBOL(acpi_bus_start);
......@@ -1572,15 +1423,12 @@ int acpi_bus_trim(struct acpi_device *start, int rmdevice)
}
EXPORT_SYMBOL_GPL(acpi_bus_trim);
static int acpi_bus_scan_fixed(struct acpi_device *root)
static int acpi_bus_scan_fixed(void)
{
int result = 0;
struct acpi_device *device = NULL;
struct acpi_bus_ops ops;
if (!root)
return -ENODEV;
memset(&ops, 0, sizeof(ops));
ops.acpi_op_add = 1;
ops.acpi_op_start = 1;
......@@ -1589,16 +1437,16 @@ static int acpi_bus_scan_fixed(struct acpi_device *root)
* Enumerate all fixed-feature devices.
*/
if ((acpi_gbl_FADT.flags & ACPI_FADT_POWER_BUTTON) == 0) {
result = acpi_add_single_object(&device, acpi_root,
NULL,
result = acpi_add_single_object(&device, NULL,
ACPI_BUS_TYPE_POWER_BUTTON,
ACPI_STA_DEFAULT,
&ops);
}
if ((acpi_gbl_FADT.flags & ACPI_FADT_SLEEP_BUTTON) == 0) {
result = acpi_add_single_object(&device, acpi_root,
NULL,
result = acpi_add_single_object(&device, NULL,
ACPI_BUS_TYPE_SLEEP_BUTTON,
ACPI_STA_DEFAULT,
&ops);
}
......@@ -1620,25 +1468,16 @@ int __init acpi_scan_init(void)
printk(KERN_ERR PREFIX "Could not register bus type\n");
}
/*
* Create the root device in the bus's device tree
*/
result = acpi_add_single_object(&acpi_root, NULL, ACPI_ROOT_OBJECT,
ACPI_BUS_TYPE_SYSTEM, &ops);
if (result)
goto Done;
/*
* Enumerate devices in the ACPI namespace.
*/
result = acpi_bus_scan_fixed(acpi_root);
result = acpi_bus_scan(ACPI_ROOT_OBJECT, &ops, &acpi_root);
if (!result)
result = acpi_bus_scan(acpi_root, &ops);
result = acpi_bus_scan_fixed();
if (result)
acpi_device_unregister(acpi_root, ACPI_BUS_REMOVAL_NORMAL);
Done:
return result;
}
......@@ -406,7 +406,6 @@ static acpi_status __init ibm_find_acpi_device(acpi_handle handle,
__func__, status);
return retval;
}
info->hardware_id.string[sizeof(info->hardware_id.length) - 1] = '\0';
if (info->current_status && (info->valid & ACPI_VALID_HID) &&
(!strcmp(info->hardware_id.string, IBM_HARDWARE_ID1) ||
......
......@@ -153,6 +153,7 @@ static int __init pnpacpi_add_device(struct acpi_device *device)
acpi_handle temp = NULL;
acpi_status status;
struct pnp_dev *dev;
struct acpi_hardware_id *id;
/*
* If a PnPacpi device is not present , the device
......@@ -193,15 +194,12 @@ static int __init pnpacpi_add_device(struct acpi_device *device)
if (dev->capabilities & PNP_CONFIGURABLE)
pnpacpi_parse_resource_option_data(dev);
if (device->flags.compatible_ids) {
struct acpica_device_id_list *cid_list = device->pnp.cid_list;
int i;
for (i = 0; i < cid_list->count; i++) {
if (!ispnpidacpi(cid_list->ids[i].string))
continue;
pnp_add_id(dev, cid_list->ids[i].string);
}
list_for_each_entry(id, &device->pnp.ids, list) {
if (!strcmp(id->id, acpi_device_hid(device)))
continue;
if (!ispnpidacpi(id->id))
continue;
pnp_add_id(dev, id->id);
}
/* clear out the damaged flags */
......@@ -232,9 +230,8 @@ static int __init acpi_pnp_match(struct device *dev, void *_pnp)
struct pnp_dev *pnp = _pnp;
/* true means it matched */
return acpi->flags.hardware_id
&& !acpi_get_physical_device(acpi->handle)
&& compare_pnp_id(pnp->id, acpi->pnp.hardware_id);
return !acpi_get_physical_device(acpi->handle)
&& compare_pnp_id(pnp->id, acpi_device_hid(acpi));
}
static int __init acpi_pnp_find_device(struct device *dev, acpi_handle * handle)
......
......@@ -70,7 +70,6 @@ enum acpi_bus_device_type {
ACPI_BUS_TYPE_POWER,
ACPI_BUS_TYPE_PROCESSOR,
ACPI_BUS_TYPE_THERMAL,
ACPI_BUS_TYPE_SYSTEM,
ACPI_BUS_TYPE_POWER_BUTTON,
ACPI_BUS_TYPE_SLEEP_BUTTON,
ACPI_BUS_DEVICE_TYPE_COUNT
......@@ -142,10 +141,7 @@ struct acpi_device_status {
struct acpi_device_flags {
u32 dynamic_status:1;
u32 hardware_id:1;
u32 compatible_ids:1;
u32 bus_address:1;
u32 unique_id:1;
u32 removable:1;
u32 ejectable:1;
u32 lockable:1;
......@@ -154,7 +150,7 @@ struct acpi_device_flags {
u32 performance_manageable:1;
u32 wake_capable:1; /* Wakeup(_PRW) supported? */
u32 force_power_state:1;
u32 reserved:19;
u32 reserved:22;
};
/* File System */
......@@ -172,20 +168,23 @@ typedef unsigned long acpi_bus_address;
typedef char acpi_device_name[40];
typedef char acpi_device_class[20];
struct acpi_hardware_id {
struct list_head list;
char *id;
};
struct acpi_device_pnp {
acpi_bus_id bus_id; /* Object name */
acpi_bus_address bus_address; /* _ADR */
char *hardware_id; /* _HID */
struct acpica_device_id_list *cid_list; /* _CIDs */
char *unique_id; /* _UID */
struct list_head ids; /* _HID and _CIDs */
acpi_device_name device_name; /* Driver-determined */
acpi_device_class device_class; /* " */
};
#define acpi_device_bid(d) ((d)->pnp.bus_id)
#define acpi_device_adr(d) ((d)->pnp.bus_address)
#define acpi_device_hid(d) ((d)->pnp.hardware_id)
#define acpi_device_uid(d) ((d)->pnp.unique_id)
char *acpi_device_hid(struct acpi_device *device);
#define acpi_device_name(d) ((d)->pnp.device_name)
#define acpi_device_class(d) ((d)->pnp.device_class)
......@@ -262,7 +261,8 @@ struct acpi_device_wakeup {
/* Device */
struct acpi_device {
acpi_handle handle;
int device_type;
acpi_handle handle; /* no handle for fixed hardware */
struct acpi_device *parent;
struct list_head children;
struct list_head node;
......@@ -322,6 +322,8 @@ extern void unregister_acpi_bus_notifier(struct notifier_block *nb);
int acpi_bus_get_device(acpi_handle handle, struct acpi_device **device);
void acpi_bus_data_handler(acpi_handle handle, void *context);
acpi_status acpi_bus_get_status_handle(acpi_handle handle,
unsigned long long *sta);
int acpi_bus_get_status(struct acpi_device *device);
int acpi_bus_get_power(acpi_handle handle, int *state);
int acpi_bus_set_power(acpi_handle handle, int state);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment