* e.g. on a device with hid:IBM0001 and cid:ACPI0001 you get:
* char *modalias: "acpi:IBM0001:ACPI0001"
*/
-int create_modalias(struct acpi_device *acpi_dev, char *modalias, int size){
-
+static int create_modalias(struct acpi_device *acpi_dev, char *modalias,
+ int size)
+{
int len;
+ int count;
- if (!acpi_dev->flags.hardware_id)
+ if (!acpi_dev->flags.hardware_id && !acpi_dev->flags.compatible_ids)
return -ENODEV;
- len = snprintf(modalias, size, "acpi:%s:",
- acpi_dev->pnp.hardware_id);
- if (len < 0 || len >= size)
- return -EINVAL;
+ len = snprintf(modalias, size, "acpi:");
size -= len;
+ if (acpi_dev->flags.hardware_id) {
+ count = snprintf(&modalias[len], size, "%s:",
+ acpi_dev->pnp.hardware_id);
+ if (count < 0 || count >= size)
+ return -EINVAL;
+ len += count;
+ size -= count;
+ }
+
if (acpi_dev->flags.compatible_ids) {
struct acpi_compatible_id_list *cid_list;
int i;
- int count;
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);
if (count < 0 || count >= size) {
- printk(KERN_ERR "acpi: %s cid[%i] exceeds event buffer size",
+ printk(KERN_ERR PREFIX "%s cid[%i] exceeds event buffer size",
acpi_dev->pnp.device_name, i);
break;
}
return !acpi_match_device_ids(acpi_dev, acpi_drv->ids);
}
-static int acpi_device_uevent(struct device *dev, char **envp, int num_envp,
- char *buffer, int buffer_size)
+static int acpi_device_uevent(struct device *dev, struct kobj_uevent_env *env)
{
struct acpi_device *acpi_dev = to_acpi_device(dev);
+ int len;
- strcpy(buffer, "MODALIAS=");
- if (create_modalias(acpi_dev, buffer + 9, buffer_size - 9) > 0) {
- envp[0] = buffer;
- envp[1] = NULL;
- }
+ if (add_uevent_var(env, "MODALIAS="))
+ return -ENOMEM;
+ len = create_modalias(acpi_dev, &env->buf[env->buflen - 1],
+ sizeof(env->buf) - env->buflen);
+ if (len >= (sizeof(env->buf) - env->buflen))
+ return -ENOMEM;
+ env->buflen += len;
return 0;
}
device->dev.release = &acpi_device_release;
result = device_add(&device->dev);
if(result) {
- printk("Error adding device %s", device->dev.bus_id);
+ printk(KERN_ERR PREFIX "Error adding device %s", device->dev.bus_id);
goto end;
}
status = acpi_evaluate_object(handle, "_EJD", NULL, &buffer);
if (ACPI_SUCCESS(status)) {
obj = buffer.pointer;
- status = acpi_get_handle(NULL, obj->string.pointer, ejd);
+ status = acpi_get_handle(ACPI_ROOT_OBJECT, obj->string.pointer,
+ ejd);
kfree(buffer.pointer);
}
return status;
device->wakeup.resources.count = package->package.count - 2;
for (i = 0; i < device->wakeup.resources.count; i++) {
element = &(package->package.elements[i + 2]);
- if (element->type != ACPI_TYPE_ANY) {
+ if (element->type != ACPI_TYPE_LOCAL_REFERENCE)
return AE_BAD_DATA;
- }
device->wakeup.resources.handles[i] = element->reference.handle;
}
acpi_status status = 0;
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
union acpi_object *package = NULL;
+ union acpi_object in_arg[3];
+ struct acpi_object_list arg_list = { 3, in_arg };
+ acpi_status psw_status = AE_OK;
struct acpi_device_id button_device_ids[] = {
{"PNP0C0D", 0},
{"", 0},
};
-
/* _PRW */
status = acpi_evaluate_object(device->handle, "_PRW", NULL, &buffer);
if (ACPI_FAILURE(status)) {
kfree(buffer.pointer);
device->wakeup.flags.valid = 1;
+ /* Call _PSW/_DSW object to disable its ability to wake the sleeping
+ * system for the ACPI device with the _PRW object.
+ * The _PSW object is depreciated in ACPI 3.0 and is replaced by _DSW.
+ * So it is necessary to call _DSW object first. Only when it is not
+ * present will the _PSW object used.
+ */
+ /*
+ * Three agruments are needed for the _DSW object.
+ * Argument 0: enable/disable the wake capabilities
+ * When _DSW object is called to disable the wake capabilities, maybe
+ * the first argument is filled. The value of the other two agruments
+ * is meaningless.
+ */
+ in_arg[0].type = ACPI_TYPE_INTEGER;
+ in_arg[0].integer.value = 0;
+ in_arg[1].type = ACPI_TYPE_INTEGER;
+ in_arg[1].integer.value = 0;
+ in_arg[2].type = ACPI_TYPE_INTEGER;
+ in_arg[2].integer.value = 0;
+ psw_status = acpi_evaluate_object(device->handle, "_DSW",
+ &arg_list, NULL);
+ if (ACPI_FAILURE(psw_status) && (psw_status != AE_NOT_FOUND))
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "error in evaluate _DSW\n"));
+ /*
+ * When the _DSW object is not present, OSPM will call _PSW object.
+ */
+ if (psw_status == AE_NOT_FOUND) {
+ /*
+ * Only one agruments is required for the _PSW object.
+ * agrument 0: enable/disable the wake capabilities
+ */
+ arg_list.count = 1;
+ in_arg[0].integer.value = 0;
+ psw_status = acpi_evaluate_object(device->handle, "_PSW",
+ &arg_list, NULL);
+ if (ACPI_FAILURE(psw_status) && (psw_status != AE_NOT_FOUND))
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "error in "
+ "evaluate _PSW\n"));
+ }
/* Power button, Lid switch always enable wakeup */
if (!acpi_match_device_ids(device, button_device_ids))
device->wakeup.flags.run_wake = 1;
if (ACPI_SUCCESS(status))
device->flags.wake_capable = 1;
- /* TBD: Peformance management */
+ /* TBD: Performance management */
return 0;
}
static int
acpi_video_bus_match(struct acpi_device *device)
{
- acpi_handle h_dummy1;
- acpi_handle h_dummy2;
- acpi_handle h_dummy3;
-
+ acpi_handle h_dummy;
if (!device)
return -EINVAL;
*/
/* Does this device able to support video switching ? */
- if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_DOD", &h_dummy1)) &&
- ACPI_SUCCESS(acpi_get_handle(device->handle, "_DOS", &h_dummy2)))
+ if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_DOD", &h_dummy)) &&
+ ACPI_SUCCESS(acpi_get_handle(device->handle, "_DOS", &h_dummy)))
return 0;
/* Does this device able to retrieve a video ROM ? */
- if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_ROM", &h_dummy1)))
+ if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_ROM", &h_dummy)))
return 0;
/* Does this device able to configure which video head to be POSTed ? */
- if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_VPO", &h_dummy1)) &&
- ACPI_SUCCESS(acpi_get_handle(device->handle, "_GPD", &h_dummy2)) &&
- ACPI_SUCCESS(acpi_get_handle(device->handle, "_SPD", &h_dummy3)))
+ if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_VPO", &h_dummy)) &&
+ ACPI_SUCCESS(acpi_get_handle(device->handle, "_GPD", &h_dummy)) &&
+ ACPI_SUCCESS(acpi_get_handle(device->handle, "_SPD", &h_dummy)))
return 0;
return -ENODEV;
return -ENODEV;
}
+/*
+ * acpi_dock_match - see if a device has a _DCK method
+ */
+static int acpi_dock_match(struct acpi_device *device)
+{
+ acpi_handle tmp;
+ return acpi_get_handle(device->handle, "_DCK", &tmp);
+}
+
static void acpi_device_set_id(struct acpi_device *device,
struct acpi_device *parent, acpi_handle handle,
int type)
char *hid = NULL;
char *uid = NULL;
struct acpi_compatible_id_list *cid_list = NULL;
+ const char *cid_add = NULL;
acpi_status status;
switch (type) {
case ACPI_BUS_TYPE_DEVICE:
status = acpi_get_object_info(handle, &buffer);
if (ACPI_FAILURE(status)) {
- printk("%s: Error reading device info\n", __FUNCTION__);
+ printk(KERN_ERR PREFIX "%s: Error reading device info\n", __func__);
return;
}
device->flags.bus_address = 1;
}
- if(!(info->valid & (ACPI_VALID_HID | ACPI_VALID_CID))){
- status = acpi_video_bus_match(device);
- if(ACPI_SUCCESS(status))
- hid = ACPI_VIDEO_HID;
+ /* 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.
+ */
+ if (ACPI_SUCCESS(acpi_video_bus_match(device)))
+ cid_add = ACPI_VIDEO_HID;
+ else if (ACPI_SUCCESS(acpi_bay_match(device)))
+ cid_add = ACPI_BAY_HID;
+ else if (ACPI_SUCCESS(acpi_dock_match(device)))
+ cid_add = ACPI_DOCK_HID;
- status = acpi_bay_match(device);
- if (ACPI_SUCCESS(status))
- hid = ACPI_BAY_HID;
- }
break;
case ACPI_BUS_TYPE_POWER:
hid = ACPI_POWER_HID;
strcpy(device->pnp.unique_id, uid);
device->flags.unique_id = 1;
}
- if (cid_list) {
- device->pnp.cid_list = kmalloc(cid_list->size, GFP_KERNEL);
- if (device->pnp.cid_list)
- memcpy(device->pnp.cid_list, cid_list, cid_list->size);
- else
- printk(KERN_ERR "Memory allocation error\n");
+ 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;
+ }
+ }
+ 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");
}
kfree(buffer.pointer);
acpi_bus_data_handler, device);
if (ACPI_FAILURE(status)) {
- printk("Error attaching device data\n");
+ printk(KERN_ERR PREFIX "Error attaching device data\n");
result = -ENODEV;
}
}
}
static int
+acpi_is_child_device(struct acpi_device *device,
+ int (*matcher)(struct acpi_device *))
+{
+ int result = -ENODEV;
+
+ do {
+ if (ACPI_SUCCESS(matcher(device)))
+ return AE_OK;
+ } while ((device = device->parent));
+
+ return result;
+}
+
+static int
acpi_add_single_object(struct acpi_device **child,
struct acpi_device *parent, acpi_handle handle, int type,
struct acpi_bus_ops *ops)
case ACPI_BUS_TYPE_PROCESSOR:
case ACPI_BUS_TYPE_DEVICE:
result = acpi_bus_get_status(device);
- if (ACPI_FAILURE(result) || !device->status.present) {
- result = -ENOENT;
+ if (ACPI_FAILURE(result)) {
+ result = -ENODEV;
goto end;
}
+ if (!device->status.present) {
+ /* Bay and dock should be handled even if absent */
+ if (!ACPI_SUCCESS(
+ acpi_is_child_device(device, acpi_bay_match)) &&
+ !ACPI_SUCCESS(
+ acpi_is_child_device(device, acpi_dock_match))) {
+ result = -ENODEV;
+ goto end;
+ }
+ }
break;
default:
STRUCT_TO_INT(device->status) =
return result;
}
+int __init acpi_boot_ec_enable(void);
+
static int __init acpi_scan_init(void)
{
int result;
* Enumerate devices in the ACPI namespace.
*/
result = acpi_bus_scan_fixed(acpi_root);
+
+ /* EC region might be needed at bus_scan, so enable it now */
+ acpi_boot_ec_enable();
+
if (!result)
result = acpi_bus_scan(acpi_root, &ops);