From 15b8dd53f5ffaf8e2d9095c423f713423f576c0f Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Mon, 29 Jun 2009 13:39:29 +0800 Subject: ACPICA: Major update for acpi_get_object_info external interface Completed a major update for the acpi_get_object_info external interface. Changes include: - Support for variable, unlimited length HID, UID, and CID strings - Support Processor objects the same as Devices (HID,UID,CID,ADR,STA, etc.) - Call the _SxW power methods on behalf of a device object - Determine if a device is a PCI root bridge - Change the ACPI_BUFFER parameter to ACPI_DEVICE_INFO. These changes will require an update to all callers of this interface. See the ACPICA Programmer Reference for details. Also, update all invocations of acpi_get_object_info interface Signed-off-by: Bob Moore Signed-off-by: Lin Ming Signed-off-by: Len Brown --- drivers/acpi/scan.c | 153 +++++++++++++++++++++++++++++++++------------------- 1 file changed, 99 insertions(+), 54 deletions(-) (limited to 'drivers/acpi/scan.c') diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 781435d7e369..0ab526de7c55 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -60,13 +60,13 @@ static int create_modalias(struct acpi_device *acpi_dev, char *modalias, } if (acpi_dev->flags.compatible_ids) { - struct acpi_compatible_id_list *cid_list; + 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->id[i].value); + 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); @@ -287,14 +287,14 @@ int acpi_match_device_ids(struct acpi_device *device, } if (device->flags.compatible_ids) { - struct acpi_compatible_id_list *cid_list = device->pnp.cid_list; + 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->id[i].value)) + cid_list->ids[i].string)) return 0; } } @@ -999,33 +999,89 @@ 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) +{ + 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; + + ACPI_MEMCPY(next_id_string, info->compatible_id_list.ids[i].string, + cid_length); + + next_id_string += cid_length; + } + + /* Append the new CID */ + + if (new_cid) { + cid->ids[i].string = next_id_string; + cid->ids[i].length = new_cid->length; + + ACPI_MEMCPY(next_id_string, new_cid->string, new_cid->length); + } + + return cid; +} + static void acpi_device_set_id(struct acpi_device *device, struct acpi_device *parent, acpi_handle handle, int type) { - struct acpi_device_info *info; - struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; + struct acpi_device_info *info = NULL; char *hid = NULL; char *uid = NULL; - struct acpi_compatible_id_list *cid_list = NULL; - const char *cid_add = NULL; + struct acpica_device_id_list *cid_list = NULL; + char *cid_add = NULL; acpi_status status; switch (type) { case ACPI_BUS_TYPE_DEVICE: - status = acpi_get_object_info(handle, &buffer); + status = acpi_get_object_info(handle, &info); if (ACPI_FAILURE(status)) { printk(KERN_ERR PREFIX "%s: Error reading device info\n", __func__); return; } - info = buffer.pointer; if (info->valid & ACPI_VALID_HID) - hid = info->hardware_id.value; + hid = info->hardware_id.string; if (info->valid & ACPI_VALID_UID) - uid = info->unique_id.value; + uid = info->unique_id.string; if (info->valid & ACPI_VALID_CID) - cid_list = &info->compatibility_id; + cid_list = &info->compatible_id_list; if (info->valid & ACPI_VALID_ADR) { device->pnp.bus_address = info->address; device->flags.bus_address = 1; @@ -1076,55 +1132,44 @@ static void acpi_device_set_id(struct acpi_device *device, } if (hid) { - strcpy(device->pnp.hardware_id, hid); - device->flags.hardware_id = 1; - } + 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; + } + } else + device->pnp.hardware_id = NULL; + if (uid) { - strcpy(device->pnp.unique_id, uid); - device->flags.unique_id = 1; - } + 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; + } + } else + device->pnp.unique_id = NULL; + if (cid_list || cid_add) { - struct acpi_compatible_id_list *list; - int size = 0; - int count = 0; - - if (cid_list) { - size = cid_list->size; - } else if (cid_add) { - size = sizeof(struct acpi_compatible_id_list); - cid_list = ACPI_ALLOCATE_ZEROED((acpi_size) size); - if (!cid_list) { - printk(KERN_ERR "Memory allocation error\n"); - kfree(buffer.pointer); - return; - } else { - cid_list->count = 0; - cid_list->size = size; - } + 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 (cid_add) - size += sizeof(struct acpi_compatible_id); - list = kmalloc(size, GFP_KERNEL); if (list) { - if (cid_list) { - memcpy(list, cid_list, cid_list->size); - count = cid_list->count; - } - if (cid_add) { - strncpy(list->id[count].value, cid_add, - ACPI_MAX_CID_LENGTH); - count++; - device->flags.compatible_ids = 1; - } - list->size = size; - list->count = count; device->pnp.cid_list = list; - } else - printk(KERN_ERR PREFIX "Memory allocation error\n"); + if (cid_add) + device->flags.compatible_ids = 1; + } } - kfree(buffer.pointer); + kfree(info); } static int acpi_device_set_context(struct acpi_device *device, int type) -- cgit v1.2.3 From 8e4319c425077c4cc540696a5bb6c4d12f017dcd Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Mon, 29 Jun 2009 13:43:27 +0800 Subject: ACPICA: Fix several acpi_attach_data problems Handler was never invoked. Now invoked if/when host node is deleted. Data object was not automatically deleted when host node was deleted. Interface to handler had an unused parameter, removed it. ACPICA BZ 778. http://acpica.org/bugzilla/show_bug.cgi?id=778 Signed-off-by: Bob Moore Signed-off-by: Lin Ming Signed-off-by: Len Brown --- drivers/acpi/acpica/acnamesp.h | 2 + drivers/acpi/acpica/nsalloc.c | 88 +++++++++++++++++++++++++++++------------- drivers/acpi/acpica/nsload.c | 3 +- drivers/acpi/bus.c | 2 +- drivers/acpi/glue.c | 2 +- drivers/acpi/scan.c | 2 +- include/acpi/acpi_bus.h | 4 +- include/acpi/actypes.h | 2 +- 8 files changed, 70 insertions(+), 35 deletions(-) (limited to 'drivers/acpi/scan.c') diff --git a/drivers/acpi/acpica/acnamesp.h b/drivers/acpi/acpica/acnamesp.h index 94cdc2b8cb93..a78e02f62d5e 100644 --- a/drivers/acpi/acpica/acnamesp.h +++ b/drivers/acpi/acpica/acnamesp.h @@ -144,6 +144,8 @@ struct acpi_namespace_node *acpi_ns_create_node(u32 name); void acpi_ns_delete_node(struct acpi_namespace_node *node); +void acpi_ns_remove_node(struct acpi_namespace_node *node); + void acpi_ns_delete_namespace_subtree(struct acpi_namespace_node *parent_handle); diff --git a/drivers/acpi/acpica/nsalloc.c b/drivers/acpi/acpica/nsalloc.c index efc971ab7d65..8a58a1b85aa0 100644 --- a/drivers/acpi/acpica/nsalloc.c +++ b/drivers/acpi/acpica/nsalloc.c @@ -96,17 +96,68 @@ struct acpi_namespace_node *acpi_ns_create_node(u32 name) * * RETURN: None * - * DESCRIPTION: Delete a namespace node + * DESCRIPTION: Delete a namespace node. All node deletions must come through + * here. Detaches any attached objects, including any attached + * data. If a handler is associated with attached data, it is + * invoked before the node is deleted. * ******************************************************************************/ void acpi_ns_delete_node(struct acpi_namespace_node *node) +{ + union acpi_operand_object *obj_desc; + + ACPI_FUNCTION_NAME(ns_delete_node); + + /* Detach an object if there is one */ + + acpi_ns_detach_object(node); + + /* + * Delete an attached data object if present (an object that was created + * and attached via acpi_attach_data). Note: After any normal object is + * detached above, the only possible remaining object is a data object. + */ + obj_desc = node->object; + if (obj_desc && (obj_desc->common.type == ACPI_TYPE_LOCAL_DATA)) { + + /* Invoke the attached data deletion handler if present */ + + if (obj_desc->data.handler) { + obj_desc->data.handler(node, obj_desc->data.pointer); + } + + acpi_ut_remove_reference(obj_desc); + } + + /* Now we can delete the node */ + + (void)acpi_os_release_object(acpi_gbl_namespace_cache, node); + + ACPI_MEM_TRACKING(acpi_gbl_ns_node_list->total_freed++); + ACPI_DEBUG_PRINT((ACPI_DB_ALLOCATIONS, "Node %p, Remaining %X\n", + node, acpi_gbl_current_node_count)); +} + +/******************************************************************************* + * + * FUNCTION: acpi_ns_remove_node + * + * PARAMETERS: Node - Node to be removed/deleted + * + * RETURN: None + * + * DESCRIPTION: Remove (unlink) and delete a namespace node + * + ******************************************************************************/ + +void acpi_ns_remove_node(struct acpi_namespace_node *node) { struct acpi_namespace_node *parent_node; struct acpi_namespace_node *prev_node; struct acpi_namespace_node *next_node; - ACPI_FUNCTION_TRACE_PTR(ns_delete_node, node); + ACPI_FUNCTION_TRACE_PTR(ns_remove_node, node); parent_node = acpi_ns_get_parent_node(node); @@ -142,12 +193,9 @@ void acpi_ns_delete_node(struct acpi_namespace_node *node) } } - ACPI_MEM_TRACKING(acpi_gbl_ns_node_list->total_freed++); - - /* Detach an object if there is one, then delete the node */ + /* Delete the node and any attached objects */ - acpi_ns_detach_object(node); - (void)acpi_os_release_object(acpi_gbl_namespace_cache, node); + acpi_ns_delete_node(node); return_VOID; } @@ -273,25 +321,11 @@ void acpi_ns_delete_children(struct acpi_namespace_node *parent_node) parent_node, child_node)); } - /* Now we can free this child object */ - - ACPI_MEM_TRACKING(acpi_gbl_ns_node_list->total_freed++); - - ACPI_DEBUG_PRINT((ACPI_DB_ALLOCATIONS, - "Object %p, Remaining %X\n", child_node, - acpi_gbl_current_node_count)); - - /* Detach an object if there is one, then free the child node */ - - acpi_ns_detach_object(child_node); - - /* Now we can delete the node */ - - (void)acpi_os_release_object(acpi_gbl_namespace_cache, - child_node); - - /* And move on to the next child in the list */ - + /* + * Delete this child node and move on to the next child in the list. + * No need to unlink the node since we are deleting the entire branch. + */ + acpi_ns_delete_node(child_node); child_node = next_node; } while (!(flags & ANOBJ_END_OF_PEER_LIST)); @@ -433,7 +467,7 @@ void acpi_ns_delete_namespace_by_owner(acpi_owner_id owner_id) if (deletion_node) { acpi_ns_delete_children(deletion_node); - acpi_ns_delete_node(deletion_node); + acpi_ns_remove_node(deletion_node); deletion_node = NULL; } diff --git a/drivers/acpi/acpica/nsload.c b/drivers/acpi/acpica/nsload.c index dcd7a6adbbbc..a7234e60e985 100644 --- a/drivers/acpi/acpica/nsload.c +++ b/drivers/acpi/acpica/nsload.c @@ -270,8 +270,7 @@ static acpi_status acpi_ns_delete_subtree(acpi_handle start_handle) /* Now delete the starting object, and we are done */ - acpi_ns_delete_node(child_handle); - + acpi_ns_remove_node(child_handle); return_ACPI_STATUS(AE_OK); } diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index 2876fc70c3a9..620183f13e5e 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -141,7 +141,7 @@ int acpi_bus_get_status(struct acpi_device *device) EXPORT_SYMBOL(acpi_bus_get_status); void acpi_bus_private_data_handler(acpi_handle handle, - u32 function, void *context) + void *context) { return; } diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c index 27a7072347ea..9a4ce33f137e 100644 --- a/drivers/acpi/glue.c +++ b/drivers/acpi/glue.c @@ -119,7 +119,7 @@ EXPORT_SYMBOL(acpi_get_child); /* Link ACPI devices with physical devices */ static void acpi_glue_data_handler(acpi_handle handle, - u32 function, void *context) + void *context) { /* we provide an empty handler */ } diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 0ab526de7c55..9606af13d3b8 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -687,7 +687,7 @@ acpi_bus_get_ejd(acpi_handle handle, acpi_handle *ejd) } EXPORT_SYMBOL_GPL(acpi_bus_get_ejd); -void acpi_bus_data_handler(acpi_handle handle, u32 function, void *context) +void acpi_bus_data_handler(acpi_handle handle, void *context) { /* TBD */ diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index b91420b52c6f..6e83a68fbd7b 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -312,7 +312,7 @@ struct acpi_bus_event { extern struct kobject *acpi_kobj; extern int acpi_bus_generate_netlink_event(const char*, const char*, u8, int); -void acpi_bus_private_data_handler(acpi_handle, u32, void *); +void acpi_bus_private_data_handler(acpi_handle, void *); int acpi_bus_get_private_data(acpi_handle, void **); extern int acpi_notifier_call_chain(struct acpi_device *, u32, u32); extern int register_acpi_notifier(struct notifier_block *); @@ -325,7 +325,7 @@ 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, u32 function, void *context); +void acpi_bus_data_handler(acpi_handle handle, void *context); 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); diff --git a/include/acpi/actypes.h b/include/acpi/actypes.h index 4371805d2def..ef4601149f49 100644 --- a/include/acpi/actypes.h +++ b/include/acpi/actypes.h @@ -922,7 +922,7 @@ typedef void (*acpi_notify_handler) (acpi_handle device, u32 value, void *context); typedef -void (*acpi_object_handler) (acpi_handle object, u32 function, void *data); +void (*acpi_object_handler) (acpi_handle object, void *data); typedef acpi_status(*acpi_init_handler) (acpi_handle object, u32 function); -- cgit v1.2.3 From 718fb0de8ff88f71b3b91a8ee8e42e60c88e5128 Mon Sep 17 00:00:00 2001 From: Hugh Dickins Date: Thu, 6 Aug 2009 23:18:12 +0000 Subject: ACPI: fix NULL bug for HID/UID string acpi_device->pnp.hardware_id and unique_id are now allocated pointers, replacing the previous arrays. acpi_device_install_notify_handler() oopsed on the NULL hid when probing the video device, and perhaps other uses are vulnerable too. So initialize those pointers to empty strings when there is no hid or uid. Also, free hardware_id and unique_id when when acpi_device is going to be freed. http://bugzilla.kernel.org/show_bug.cgi?id=14096 Signed-off-by: Hugh Dickins Signed-off-by: Lin Ming Signed-off-by: Len Brown --- drivers/acpi/scan.c | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) (limited to 'drivers/acpi/scan.c') diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 9606af13d3b8..dc14421b93f1 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -309,6 +309,10 @@ 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); kfree(acpi_dev); } @@ -1137,8 +1141,9 @@ static void acpi_device_set_id(struct acpi_device *device, strcpy(device->pnp.hardware_id, hid); device->flags.hardware_id = 1; } - } else - device->pnp.hardware_id = NULL; + } + if (!device->flags.hardware_id) + device->pnp.hardware_id = ""; if (uid) { device->pnp.unique_id = ACPI_ALLOCATE_ZEROED(strlen (uid) + 1); @@ -1146,8 +1151,9 @@ static void acpi_device_set_id(struct acpi_device *device, strcpy(device->pnp.unique_id, uid); device->flags.unique_id = 1; } - } else - device->pnp.unique_id = NULL; + } + if (!device->flags.unique_id) + device->pnp.unique_id = ""; if (cid_list || cid_add) { struct acpica_device_id_list *list; @@ -1362,10 +1368,8 @@ acpi_add_single_object(struct acpi_device **child, end: if (!result) *child = device; - else { - kfree(device->pnp.cid_list); - kfree(device); - } + else + acpi_device_release(&device->dev); return result; } -- cgit v1.2.3