diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2009-09-26 10:12:03 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-09-26 10:12:03 -0700 |
commit | 76e0134f4154aeadac833c2daea32102c64c0bb0 (patch) | |
tree | 0b0fe59fd655a7ca43b77629f3ba98e6cc876db2 /drivers | |
parent | bfebb1406329667f2cccb50fad1de87f573b2c1a (diff) | |
parent | e96c9284bdffa1f1d39a502c3d3b71fd8cce7014 (diff) |
Merge branch 'release' of git://git.kernel.org/pub/scm/linux/kernel/git/lenb/linux-acpi-2.6
* 'release' of git://git.kernel.org/pub/scm/linux/kernel/git/lenb/linux-acpi-2.6: (32 commits)
ACPI: i2c-scmi: don't use acpi_device_uid()
ACPI: simplify building device HID/CID list
ACPI: remove acpi_device_uid() and related stuff
ACPI: remove acpi_device.flags.hardware_id
ACPI: remove acpi_device.flags.compatible_ids
ACPI: maintain a single list of _HID and _CID IDs
ACPI: make sure every acpi_device has an ID
ACPI: use acpi_device_hid() when possible
ACPI: fix synthetic HID for \_SB_
ACPI: handle re-enumeration, when acpi_devices might already exist
ACPI: factor out device type and status checking
ACPI: add acpi_bus_get_status_handle()
ACPI: use acpi_walk_namespace() to enumerate devices
ACPI: identify device tree root by null parent pointer, not ACPI_BUS_TYPE
ACPI: enumerate namespace before adding functional fixed hardware devices
ACPI: convert acpi_bus_scan() to operate on an acpi_handle
ACPI: add acpi_bus_get_parent() and remove "parent" arguments
ACPI: remove unnecessary argument checking
ACPI: remove redundant "type" arguments
ACPI: remove acpi_device_set_context() "type" argument
...
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/acpi/bus.c | 49 | ||||
-rw-r--r-- | drivers/acpi/scan.c | 705 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-scmi.c | 5 | ||||
-rw-r--r-- | drivers/pci/hotplug/acpiphp_ibm.c | 1 | ||||
-rw-r--r-- | drivers/platform/x86/thinkpad_acpi.c | 632 | ||||
-rw-r--r-- | drivers/pnp/pnpacpi/core.c | 21 |
6 files changed, 731 insertions, 682 deletions
diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index 135fbfe1825..74119152435 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -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, diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 408ebde1898..468921bed22 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -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); } @@ -1621,24 +1469,15 @@ int __init acpi_scan_init(void) } /* - * 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; } diff --git a/drivers/i2c/busses/i2c-scmi.c b/drivers/i2c/busses/i2c-scmi.c index 276a046ac93..b4a55d407bf 100644 --- a/drivers/i2c/busses/i2c-scmi.c +++ b/drivers/i2c/busses/i2c-scmi.c @@ -369,9 +369,8 @@ static int acpi_smbus_cmi_add(struct acpi_device *device) goto err; snprintf(smbus_cmi->adapter.name, sizeof(smbus_cmi->adapter.name), - "SMBus CMI adapter %s (%s)", - acpi_device_name(device), - acpi_device_uid(device)); + "SMBus CMI adapter %s", + acpi_device_name(device)); smbus_cmi->adapter.owner = THIS_MODULE; smbus_cmi->adapter.algo = &acpi_smbus_cmi_algorithm; smbus_cmi->adapter.algo_data = smbus_cmi; diff --git a/drivers/pci/hotplug/acpiphp_ibm.c b/drivers/pci/hotplug/acpiphp_ibm.c index a9d926b7d80..e7be66dbac2 100644 --- a/drivers/pci/hotplug/acpiphp_ibm.c +++ b/drivers/pci/hotplug/acpiphp_ibm.c @@ -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) || diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index f78d2750392..3910f2f3ead 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -22,7 +22,7 @@ */ #define TPACPI_VERSION "0.23" -#define TPACPI_SYSFS_VERSION 0x020400 +#define TPACPI_SYSFS_VERSION 0x020500 /* * Changelog: @@ -145,6 +145,51 @@ enum { TP_ACPI_WGSV_STATE_UWBPWR = 0x0020, /* UWB radio enabled */ }; +/* HKEY events */ +enum tpacpi_hkey_event_t { + /* Hotkey-related */ + TP_HKEY_EV_HOTKEY_BASE = 0x1001, /* first hotkey (FN+F1) */ + TP_HKEY_EV_BRGHT_UP = 0x1010, /* Brightness up */ + TP_HKEY_EV_BRGHT_DOWN = 0x1011, /* Brightness down */ + TP_HKEY_EV_VOL_UP = 0x1015, /* Volume up or unmute */ + TP_HKEY_EV_VOL_DOWN = 0x1016, /* Volume down or unmute */ + TP_HKEY_EV_VOL_MUTE = 0x1017, /* Mixer output mute */ + + /* Reasons for waking up from S3/S4 */ + TP_HKEY_EV_WKUP_S3_UNDOCK = 0x2304, /* undock requested, S3 */ + TP_HKEY_EV_WKUP_S4_UNDOCK = 0x2404, /* undock requested, S4 */ + TP_HKEY_EV_WKUP_S3_BAYEJ = 0x2305, /* bay ejection req, S3 */ + TP_HKEY_EV_WKUP_S4_BAYEJ = 0x2405, /* bay ejection req, S4 */ + TP_HKEY_EV_WKUP_S3_BATLOW = 0x2313, /* battery empty, S3 */ + TP_HKEY_EV_WKUP_S4_BATLOW = 0x2413, /* battery empty, S4 */ + + /* Auto-sleep after eject request */ + TP_HKEY_EV_BAYEJ_ACK = 0x3003, /* bay ejection complete */ + TP_HKEY_EV_UNDOCK_ACK = 0x4003, /* undock complete */ + + /* Misc bay events */ + TP_HKEY_EV_OPTDRV_EJ = 0x3006, /* opt. drive tray ejected */ + + /* User-interface events */ + TP_HKEY_EV_LID_CLOSE = 0x5001, /* laptop lid closed */ + TP_HKEY_EV_LID_OPEN = 0x5002, /* laptop lid opened */ + TP_HKEY_EV_TABLET_TABLET = 0x5009, /* tablet swivel up */ + TP_HKEY_EV_TABLET_NOTEBOOK = 0x500a, /* tablet swivel down */ + TP_HKEY_EV_PEN_INSERTED = 0x500b, /* tablet pen inserted */ + TP_HKEY_EV_PEN_REMOVED = 0x500c, /* tablet pen removed */ + TP_HKEY_EV_BRGHT_CHANGED = 0x5010, /* backlight control event */ + + /* Thermal events */ + TP_HKEY_EV_ALARM_BAT_HOT = 0x6011, /* battery too hot */ + TP_HKEY_EV_ALARM_BAT_XHOT = 0x6012, /* battery critically hot */ + TP_HKEY_EV_ALARM_SENSOR_HOT = 0x6021, /* sensor too hot */ + TP_HKEY_EV_ALARM_SENSOR_XHOT = 0x6022, /* sensor critically hot */ + TP_HKEY_EV_THM_TABLE_CHANGED = 0x6030, /* thermal table changed */ + + /* Misc */ + TP_HKEY_EV_RFKILL_CHANGED = 0x7000, /* rfkill switch changed */ +}; + /**************************************************************************** * Main driver */ @@ -1848,6 +1893,27 @@ static struct ibm_struct thinkpad_acpi_driver_data = { * Hotkey subdriver */ +/* + * ThinkPad firmware event model + * + * The ThinkPad firmware has two main event interfaces: normal ACPI + * notifications (which follow the ACPI standard), and a private event + * interface. + * + * The private event interface also issues events for the hotkeys. As + * the driver gained features, the event handling code ended up being + * built around the hotkey subdriver. This will need to be refactored + * to a more formal event API eventually. + * + * Some "hotkeys" are actually supposed to be used as event reports, + * such as "brightness has changed", "volume has changed", depending on + * the ThinkPad model and how the firmware is operating. + * + * Unlike other classes, hotkey-class events have mask/unmask control on + * non-ancient firmware. However, how it behaves changes a lot with the + * firmware model and version. + */ + enum { /* hot key scan codes (derived from ACPI DSDT) */ TP_ACPI_HOTKEYSCAN_FNF1 = 0, TP_ACPI_HOTKEYSCAN_FNF2, @@ -1875,7 +1941,7 @@ enum { /* hot key scan codes (derived from ACPI DSDT) */ TP_ACPI_HOTKEYSCAN_THINKPAD, }; -enum { /* Keys available through NVRAM polling */ +enum { /* Keys/events available through NVRAM polling */ TPACPI_HKEY_NVRAM_KNOWN_MASK = 0x00fb88c0U, TPACPI_HKEY_NVRAM_GOOD_MASK = 0x00fb8000U, }; @@ -1930,8 +1996,11 @@ static struct task_struct *tpacpi_hotkey_task; static struct mutex hotkey_thread_mutex; /* - * Acquire mutex to write poller control variables. - * Increment hotkey_config_change when changing them. + * Acquire mutex to write poller control variables as an + * atomic block. + * + * Increment hotkey_config_change when changing them if you + * want the kthread to forget old state. * * See HOTKEY_CONFIG_CRITICAL_START/HOTKEY_CONFIG_CRITICAL_END */ @@ -1942,6 +2011,11 @@ static unsigned int hotkey_config_change; * hotkey poller control variables * * Must be atomic or readers will also need to acquire mutex + * + * HOTKEY_CONFIG_CRITICAL_START/HOTKEY_CONFIG_CRITICAL_END + * should be used only when the changes need to be taken as + * a block, OR when one needs to force the kthread to forget + * old state. */ static u32 hotkey_source_mask; /* bit mask 0=ACPI,1=NVRAM */ static unsigned int hotkey_poll_freq = 10; /* Hz */ @@ -1972,10 +2046,12 @@ static enum { /* Reasons for waking up */ static int hotkey_autosleep_ack; -static u32 hotkey_orig_mask; -static u32 hotkey_all_mask; -static u32 hotkey_reserved_mask; -static u32 hotkey_mask; +static u32 hotkey_orig_mask; /* events the BIOS had enabled */ +static u32 hotkey_all_mask; /* all events supported in fw */ +static u32 hotkey_reserved_mask; /* events better left disabled */ +static u32 hotkey_driver_mask; /* events needed by the driver */ +static u32 hotkey_user_mask; /* events visible to userspace */ +static u32 hotkey_acpi_mask; /* events enabled in firmware */ static unsigned int hotkey_report_mode; @@ -1983,6 +2059,9 @@ static u16 *hotkey_keycode_map; static struct attribute_set *hotkey_dev_attributes; +static void tpacpi_driver_event(const unsigned int hkey_event); +static void hotkey_driver_event(const unsigned int scancode); + /* HKEY.MHKG() return bits */ #define TP_HOTKEY_TABLET_MASK (1 << 3) @@ -2017,24 +2096,53 @@ static int hotkey_get_tablet_mode(int *status) } /* + * Reads current event mask from firmware, and updates + * hotkey_acpi_mask accordingly. Also resets any bits + * from hotkey_user_mask that are unavailable to be + * delivered (shadow requirement of the userspace ABI). + * * Call with hotkey_mutex held */ static int hotkey_mask_get(void) { - u32 m = 0; - if (tp_features.hotkey_mask) { + u32 m = 0; + if (!acpi_evalf(hkey_handle, &m, "DHKN", "d")) return -EIO; + + hotkey_acpi_mask = m; + } else { + /* no mask support doesn't mean no event support... */ + hotkey_acpi_mask = hotkey_all_mask; } - HOTKEY_CONFIG_CRITICAL_START - hotkey_mask = m | (hotkey_source_mask & hotkey_mask); - HOTKEY_CONFIG_CRITICAL_END + + /* sync userspace-visible mask */ + hotkey_user_mask &= (hotkey_acpi_mask | hotkey_source_mask); return 0; } +void static hotkey_mask_warn_incomplete_mask(void) +{ + /* log only what the user can fix... */ + const u32 wantedmask = hotkey_driver_mask & + ~(hotkey_acpi_mask | hotkey_source_mask) & + (hotkey_all_mask | TPACPI_HKEY_NVRAM_KNOWN_MASK); + + if (wantedmask) + printk(TPACPI_NOTICE + "required events 0x%08x not enabled!\n", + wantedmask); +} + /* + * Set the firmware mask when supported + * + * Also calls hotkey_mask_get to update hotkey_acpi_mask. + * + * NOTE: does not set bits in hotkey_user_mask, but may reset them. + * * Call with hotkey_mutex held */ static int hotkey_mask_set(u32 mask) @@ -2042,66 +2150,98 @@ static int hotkey_mask_set(u32 mask) int i; int rc = 0; - if (tp_features.hotkey_mask) { - if (!tp_warned.hotkey_mask_ff && - (mask == 0xffff || mask == 0xffffff || - mask == 0xffffffff)) { - tp_warned.hotkey_mask_ff = 1; - printk(TPACPI_NOTICE - "setting the hotkey mask to 0x%08x is likely " - "not the best way to go about it\n", mask); - printk(TPACPI_NOTICE - "please consider using the driver defaults, " - "and refer to up-to-date thinkpad-acpi " - "documentation\n"); - } + const u32 fwmask = mask & ~hotkey_source_mask; - HOTKEY_CONFIG_CRITICAL_START + if (tp_features.hotkey_mask) { for (i = 0; i < 32; i++) { - u32 m = 1 << i; - /* enable in firmware mask only keys not in NVRAM - * mode, but enable the key in the cached hotkey_mask - * regardless of mode, or the key will end up - * disabled by hotkey_mask_get() */ if (!acpi_evalf(hkey_handle, NULL, "MHKM", "vdd", i + 1, - !!((mask & ~hotkey_source_mask) & m))) { + !!(mask & (1 << i)))) { rc = -EIO; break; - } else { - hotkey_mask = (hotkey_mask & ~m) | (mask & m); } } - HOTKEY_CONFIG_CRITICAL_END + } - /* hotkey_mask_get must be called unconditionally below */ - if (!hotkey_mask_get() && !rc && - (hotkey_mask & ~hotkey_source_mask) != - (mask & ~hotkey_source_mask)) { - printk(TPACPI_NOTICE - "requested hot key mask 0x%08x, but " - "firmware forced it to 0x%08x\n", - mask, hotkey_mask); - } - } else { -#ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL - HOTKEY_CONFIG_CRITICAL_START - hotkey_mask = mask & hotkey_source_mask; - HOTKEY_CONFIG_CRITICAL_END - hotkey_mask_get(); - if (hotkey_mask != mask) { - printk(TPACPI_NOTICE - "requested hot key mask 0x%08x, " - "forced to 0x%08x (NVRAM poll mask is " - "0x%08x): no firmware mask support\n", - mask, hotkey_mask, hotkey_source_mask); - } -#else - hotkey_mask_get(); - rc = -ENXIO; -#endif /* CONFIG_THINKPAD_ACPI_HOTKEY_POLL */ + /* + * We *must* make an inconditional call to hotkey_mask_get to + * refresh hotkey_acpi_mask and update hotkey_user_mask + * + * Take the opportunity to also log when we cannot _enable_ + * a given event. + */ + if (!hotkey_mask_get() && !rc && (fwmask & ~hotkey_acpi_mask)) { + printk(TPACPI_NOTICE + "asked for hotkey mask 0x%08x, but " + "firmware forced it to 0x%08x\n", + fwmask, hotkey_acpi_mask); } + hotkey_mask_warn_incomplete_mask(); + + return rc; +} + +/* + * Sets hotkey_user_mask and tries to set the firmware mask + * + * Call with hotkey_mutex held + */ +static int hotkey_user_mask_set(const u32 mask) +{ + int rc; + + /* Give people a chance to notice they are doing something that + * is bound to go boom on their users sooner or later */ + if (!tp_warned.hotkey_mask_ff && + (mask == 0xffff || mask == 0xffffff || + mask == 0xffffffff)) { + tp_warned.hotkey_mask_ff = 1; + printk(TPACPI_NOTICE + "setting the hotkey mask to 0x%08x is likely " + "not the best way to go about it\n", mask); + printk(TPACPI_NOTICE + "please consider using the driver defaults, " + "and refer to up-to-date thinkpad-acpi " + "documentation\n"); + } + + /* Try to enable what the user asked for, plus whatever we need. + * this syncs everything but won't enable bits in hotkey_user_mask */ + rc = hotkey_mask_set((mask | hotkey_driver_mask) & ~hotkey_source_mask); + + /* Enable the available bits in hotkey_user_mask */ + hotkey_user_mask = mask & (hotkey_acpi_mask | hotkey_source_mask); + + return rc; +} + +/* + * Sets the driver hotkey mask. + * + * Can be called even if the hotkey subdriver is inactive + */ +static int tpacpi_hotkey_driver_mask_set(const u32 mask) +{ + int rc; + + /* Do the right thing if hotkey_init has not been called yet */ + if (!tp_features.hotkey) { + hotkey_driver_mask = mask; + return 0; + } + + mutex_lock(&hotkey_mutex); + + HOTKEY_CONFIG_CRITICAL_START + hotkey_driver_mask = mask; + hotkey_source_mask |= (mask & ~hotkey_all_mask); + HOTKEY_CONFIG_CRITICAL_END + + rc = hotkey_mask_set((hotkey_acpi_mask | hotkey_driver_mask) & + ~hotkey_source_mask); + mutex_unlock(&hotkey_mutex); + return rc; } @@ -2137,11 +2277,10 @@ static void tpacpi_input_send_tabletsw(void) } } -static void tpacpi_input_send_key(unsigned int scancode) +/* Do NOT call without validating scancode first */ +static void tpacpi_input_send_key(const unsigned int scancode) { - unsigned int keycode; - - keycode = hotkey_keycode_map[scancode]; + const unsigned int keycode = hotkey_keycode_map[scancode]; if (keycode != KEY_RESERVED) { mutex_lock(&tpacpi_inputdev_send_mutex); @@ -2162,19 +2301,28 @@ static void tpacpi_input_send_key(unsigned int scancode) } } +/* Do NOT call without validating scancode first */ +static void tpacpi_input_send_key_masked(const unsigned int scancode) +{ + hotkey_driver_event(scancode); + if (hotkey_user_mask & (1 << scancode)) + tpacpi_input_send_key(scancode); +} + #ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL static struct tp_acpi_drv_struct ibm_hotkey_acpidriver; +/* Do NOT call without validating scancode first */ static void tpacpi_hotkey_send_key(unsigned int scancode) { - tpacpi_input_send_key(scancode); + tpacpi_input_send_key_masked(scancode); if (hotkey_report_mode < 2) { acpi_bus_generate_proc_event(ibm_hotkey_acpidriver.device, - 0x80, 0x1001 + scancode); + 0x80, TP_HKEY_EV_HOTKEY_BASE + scancode); } } -static void hotkey_read_nvram(struct tp_nvram_state *n, u32 m) +static void hotkey_read_nvram(struct tp_nvram_state *n, const u32 m) { u8 d; @@ -2210,21 +2358,24 @@ static void hotkey_read_nvram(struct tp_nvram_state *n, u32 m) } } +static void hotkey_compare_and_issue_event(struct tp_nvram_state *oldn, + struct tp_nvram_state *newn, + const u32 event_mask) +{ + #define TPACPI_COMPARE_KEY(__scancode, __member) \ do { \ - if ((mask & (1 << __scancode)) && \ + if ((event_mask & (1 << __scancode)) && \ oldn->__member != newn->__member) \ - tpacpi_hotkey_send_key(__scancode); \ + tpacpi_hotkey_send_key(__scancode); \ } while (0) #define TPACPI_MAY_SEND_KEY(__scancode) \ - do { if (mask & (1 << __scancode)) \ - tpacpi_hotkey_send_key(__scancode); } while (0) + do { \ + if (event_mask & (1 << __scancode)) \ + tpacpi_hotkey_send_key(__scancode); \ + } while (0) -static void hotkey_compare_and_issue_event(struct tp_nvram_state *oldn, - struct tp_nvram_state *newn, - u32 mask) -{ TPACPI_COMPARE_KEY(TP_ACPI_HOTKEYSCAN_THINKPAD, thinkpad_toggle); TPACPI_COMPARE_KEY(TP_ACPI_HOTKEYSCAN_FNSPACE, zoom_toggle); TPACPI_COMPARE_KEY(TP_ACPI_HOTKEYSCAN_FNF7, display_toggle); @@ -2270,15 +2421,22 @@ static void hotkey_compare_and_issue_event(struct tp_nvram_state *oldn, } } } -} #undef TPACPI_COMPARE_KEY #undef TPACPI_MAY_SEND_KEY +} +/* + * Polling driver + * + * We track all events in hotkey_source_mask all the time, since + * most of them are edge-based. We only issue those requested by + * hotkey_user_mask or hotkey_driver_mask, though. + */ static int hotkey_kthread(void *data) { struct tp_nvram_state s[2]; - u32 mask; + u32 poll_mask, event_mask; unsigned int si, so; unsigned long t; unsigned int change_detector, must_reset; @@ -2298,10 +2456,12 @@ static int hotkey_kthread(void *data) /* Initial state for compares */ mutex_lock(&hotkey_thread_data_mutex); change_detector = hotkey_config_change; - mask = hotkey_source_mask & hotkey_mask; + poll_mask = hotkey_source_mask; + event_mask = hotkey_source_mask & + (hotkey_driver_mask | hotkey_user_mask); poll_freq = hotkey_poll_freq; mutex_unlock(&hotkey_thread_data_mutex); - hotkey_read_nvram(&s[so], mask); + hotkey_read_nvram(&s[so], poll_mask); while (!kthread_should_stop()) { if (t == 0) { @@ -2324,15 +2484,17 @@ static int hotkey_kthread(void *data) t = 0; change_detector = hotkey_config_change; } - mask = hotkey_source_mask & hotkey_mask; + poll_mask = hotkey_source_mask; + event_mask = hotkey_source_mask & + (hotkey_driver_mask | hotkey_user_mask); poll_freq = hotkey_poll_freq; mutex_unlock(&hotkey_thread_data_mutex); - if (likely(mask)) { - hotkey_read_nvram(&s[si], mask); + if (likely(poll_mask)) { + hotkey_read_nvram(&s[si], poll_mask); if (likely(si != so)) { hotkey_compare_and_issue_event(&s[so], &s[si], - mask); + event_mask); } } @@ -2364,10 +2526,12 @@ static void hotkey_poll_stop_sync(void) /* call with hotkey_mutex held */ static void hotkey_poll_setup(bool may_warn) { - u32 hotkeys_to_poll = hotkey_source_mask & hotkey_mask; + const u32 poll_driver_mask = hotkey_driver_mask & hotkey_source_mask; + const u32 poll_user_mask = hotkey_user_mask & hotkey_source_mask; - if (hotkeys_to_poll != 0 && hotkey_poll_freq > 0 && - (tpacpi_inputdev->users > 0 || hotkey_report_mode < 2)) { + if (hotkey_poll_freq > 0 && + (poll_driver_mask || + (poll_user_mask && tpacpi_inputdev->users > 0))) { if (!tpacpi_hotkey_task) { tpacpi_hotkey_task = kthread_run(hotkey_kthread, NULL, TPACPI_NVRAM_KTHREAD_NAME); @@ -2380,12 +2544,13 @@ static void hotkey_poll_setup(bool may_warn) } } else { hotkey_poll_stop_sync(); - if (may_warn && hotkeys_to_poll != 0 && + if (may_warn && (poll_driver_mask || poll_user_mask) && hotkey_poll_freq == 0) { printk(TPACPI_NOTICE - "hot keys 0x%08x require polling, " - "which is currently disabled\n", - hotkeys_to_poll); + "hot keys 0x%08x and/or events 0x%08x " + "require polling, which is currently " + "disabled\n", + poll_user_mask, poll_driver_mask); } } } @@ -2403,9 +2568,7 @@ static void hotkey_poll_set_freq(unsigned int freq) if (!freq) hotkey_poll_stop_sync(); - HOTKEY_CONFIG_CRITICAL_START hotkey_poll_freq = freq; - HOTKEY_CONFIG_CRITICAL_END } #else /* CONFIG_THINKPAD_ACPI_HOTKEY_POLL */ @@ -2440,7 +2603,8 @@ static int hotkey_inputdev_open(struct input_dev *dev) static void hotkey_inputdev_close(struct input_dev *dev) { /* disable hotkey polling when possible */ - if (tpacpi_lifecycle == TPACPI_LIFE_RUNNING) + if (tpacpi_lifecycle == TPACPI_LIFE_RUNNING && + !(hotkey_source_mask & hotkey_driver_mask)) hotkey_poll_setup_safe(false); } @@ -2488,15 +2652,7 @@ static ssize_t hotkey_mask_show(struct device *dev, struct device_attribute *attr, char *buf) { - int res; - - if (mutex_lock_killable(&hotkey_mutex)) - return -ERESTARTSYS; - res = hotkey_mask_get(); - mutex_unlock(&hotkey_mutex); - - return (res)? - res : snprintf(buf, PAGE_SIZE, "0x%08x\n", hotkey_mask); + return snprintf(buf, PAGE_SIZE, "0x%08x\n", hotkey_user_mask); } static ssize_t hotkey_mask_store(struct device *dev, @@ -2512,7 +2668,7 @@ static ssize_t hotkey_mask_store(struct device *dev, if (mutex_lock_killable(&hotkey_mutex)) return -ERESTARTSYS; - res = hotkey_mask_set(t); + res = hotkey_user_mask_set(t); #ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL hotkey_poll_setup(true); @@ -2594,6 +2750,8 @@ static ssize_t hotkey_source_mask_store(struct device *dev, const char *buf, size_t count) { unsigned long t; + u32 r_ev; + int rc; if (parse_strtoul(buf, 0xffffffffUL, &t) || ((t & ~TPACPI_HKEY_NVRAM_KNOWN_MASK) != 0)) @@ -2606,14 +2764,28 @@ static ssize_t hotkey_source_mask_store(struct device *dev, hotkey_source_mask = t; HOTKEY_CONFIG_CRITICAL_END + rc = hotkey_mask_set((hotkey_user_mask | hotkey_driver_mask) & + ~hotkey_source_mask); hotkey_poll_setup(true); - hotkey_mask_set(hotkey_mask); + + /* check if events needed by the driver got disabled */ + r_ev = hotkey_driver_mask & ~(hotkey_acpi_mask & hotkey_all_mask) + & ~hotkey_source_mask & TPACPI_HKEY_NVRAM_KNOWN_MASK; mutex_unlock(&hotkey_mutex); + if (rc < 0) + printk(TPACPI_ERR "hotkey_source_mask: failed to update the" + "firmware event mask!\n"); + + if (r_ev) + printk(TPACPI_NOTICE "hotkey_source_mask: " + "some important events were disabled: " + "0x%04x\n", r_ev); + tpacpi_disclose_usertask("hotkey_source_mask", "set to 0x%08lx\n", t); - return count; + return (rc < 0) ? rc : count; } static struct device_attribute dev_attr_hotkey_source_mask = @@ -2731,9 +2903,8 @@ static struct device_attribute dev_attr_hotkey_wakeup_reason = static void hotkey_wakeup_reason_notify_change(void) { - if (tp_features.hotkey_mask) - sysfs_notify(&tpacpi_pdev->dev.kobj, NULL, - "wakeup_reason"); + sysfs_notify(&tpacpi_pdev->dev.kobj, NULL, + "wakeup_reason"); } /* sysfs wakeup hotunplug_complete (pollable) -------------------------- */ @@ -2750,9 +2921,8 @@ static struct device_attribute dev_attr_hotkey_wakeup_hotunplug_complete = static void hotkey_wakeup_hotunplug_complete_notify_change(void) { - if (tp_features.hotkey_mask) - sysfs_notify(&tpacpi_pdev->dev.kobj, NULL, - "wakeup_hotunplug_complete"); + sysfs_notify(&tpacpi_pdev->dev.kobj, NULL, + "wakeup_hotunplug_complete"); } /* --------------------------------------------------------------------- */ @@ -2760,27 +2930,19 @@ static void hotkey_wakeup_hotunplug_complete_notify_change(void) static struct attribute *hotkey_attributes[] __initdata = { &dev_attr_hotkey_enable.attr, &dev_attr_hotkey_bios_enabled.attr, + &dev_attr_hotkey_bios_mask.attr, &dev_attr_hotkey_report_mode.attr, -#ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL + &dev_attr_hotkey_wakeup_reason.attr, + &dev_attr_hotkey_wakeup_hotunplug_complete.attr, &dev_attr_hotkey_mask.attr, &dev_attr_hotkey_all_mask.attr, &dev_attr_hotkey_recommended_mask.attr, +#ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL &dev_attr_hotkey_source_mask.attr, &dev_attr_hotkey_poll_freq.attr, #endif }; -static struct attribute *hotkey_mask_attributes[] __initdata = { - &dev_attr_hotkey_bios_mask.attr, -#ifndef CONFIG_THINKPAD_ACPI_HOTKEY_POLL - &dev_attr_hotkey_mask.attr, - &dev_attr_hotkey_all_mask.attr, - &dev_attr_hotkey_recommended_mask.attr, -#endif - &dev_attr_hotkey_wakeup_reason.attr, - &dev_attr_hotkey_wakeup_hotunplug_complete.attr, -}; - /* * Sync both the hw and sw blocking state of all switches */ @@ -2843,16 +3005,16 @@ static void hotkey_exit(void) kfree(hotkey_keycode_map); - if (tp_features.hotkey) { - dbg_printk(TPACPI_DBG_EXIT | TPACPI_DBG_HKEY, - "restoring original hot key mask\n"); - /* no short-circuit boolean operator below! */ - if ((hotkey_mask_set(hotkey_orig_mask) | - hotkey_status_set(false)) != 0) - printk(TPACPI_ERR - "failed to restore hot key mask " - "to BIOS defaults\n"); - } + dbg_printk(TPACPI_DBG_EXIT | TPACPI_DBG_HKEY, + "restoring original HKEY status and mask\n"); + /* yes, there is a bitwise or below, we want the + * functions to be called even if one of them fail */ + if (((tp_features.hotkey_mask && + hotkey_mask_set(hotkey_orig_mask)) | + hotkey_status_set(false)) != 0) + printk(TPACPI_ERR + "failed to restore hot key mask " + "to BIOS defaults\n"); } static void __init hotkey_unmap(const unsigned int scancode) @@ -2864,6 +3026,35 @@ static void __init hotkey_unmap(const unsigned int scancode) } } +/* + * HKEY quirks: + * TPACPI_HK_Q_INIMASK: Supports FN+F3,FN+F4,FN+F12 + */ + +#define TPACPI_HK_Q_INIMASK 0x0001 + +static const struct tpacpi_quirk tpacpi_hotkey_qtable[] __initconst = { + TPACPI_Q_IBM('I', 'H', TPACPI_HK_Q_INIMASK), /* 600E */ + TPACPI_Q_IBM('I', 'N', TPACPI_HK_Q_INIMASK), /* 600E */ + TPACPI_Q_IBM('I', 'D', TPACPI_HK_Q_INIMASK), /* 770, 770E, 770ED */ + TPACPI_Q_IBM('I', 'W', TPACPI_HK_Q_INIMASK), /* A20m */ + TPACPI_Q_IBM('I', 'V', TPACPI_HK_Q_INIMASK), /* A20p */ + TPACPI_Q_IBM('1', '0', TPACPI_HK_Q_INIMASK), /* A21e, A22e */ + TPACPI_Q_IBM('K', 'U', TPACPI_HK_Q_INIMASK), /* A21e */ + TPACPI_Q_IBM('K', 'X', TPACPI_HK_Q_INIMASK), /* A21m, A22m */ + TPACPI_Q_IBM('K', 'Y', TPACPI_HK_Q_INIMASK), /* A21p, A22p */ + TPACPI_Q_IBM('1', 'B', TPACPI_HK_Q_INIMASK), /* A22e */ + TPACPI_Q_IBM('1', '3', TPACPI_HK_Q_INIMASK), /* A22m */ + TPACPI_Q_IBM('1', 'E', TPACPI_HK_Q_INIMASK), /* A30/p (0) */ + TPACPI_Q_IBM('1', 'C', TPACPI_HK_Q_INIMASK), /* R30 */ + TPACPI_Q_IBM('1', 'F', TPACPI_HK_Q_INIMASK), /* R31 */ + TPACPI_Q_IBM('I', 'Y', TPACPI_HK_Q_INIMASK), /* T20 */ + TPACPI_Q_IBM('K', 'Z', TPACPI_HK_Q_INIMASK), /* T21 */ + TPACPI_Q_IBM('1', '6', TPACPI_HK_Q_INIMASK), /* T22 */ + TPACPI_Q_IBM('I', 'Z', TPACPI_HK_Q_INIMASK), /* X20, X21 */ + TPACPI_Q_IBM('1', 'D', TPACPI_HK_Q_INIMASK), /* X22, X23, X24 */ +}; + static int __init hotkey_init(struct ibm_init_struct *iibm) { /* Requirements for changing the default keymaps: @@ -2906,9 +3097,7 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) KEY_UNKNOWN, /* 0x0D: FN+INSERT */ KEY_UNKNOWN, /* 0x0E: FN+DELETE */ - /* brightness: firmware always reacts to them, unless - * X.org did some tricks in the radeon BIOS scratch - * registers of *some* models */ + /* brightness: firmware always reacts to them */ KEY_RESERVED, /* 0x0F: FN+HOME (brightness up) */ KEY_RESERVED, /* 0x10: FN+END (brightness down) */ @@ -2983,6 +3172,8 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) int status; int hkeyv; + unsigned long quirks; + vdbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_HKEY, "initializing hotkey subdriver\n"); @@ -3008,9 +3199,16 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) if (!tp_features.hotkey) return 1; + quirks = tpacpi_check_quirks(tpacpi_hotkey_qtable, + ARRAY_SIZE(tpacpi_hotkey_qtable)); + tpacpi_disable_brightness_delay(); - hotkey_dev_attributes = create_attr_set(13, NULL); + /* MUST have enough space for all attributes to be added to + * hotkey_dev_attributes */ + hotkey_dev_attributes = create_attr_set( + ARRAY_SIZE(hotkey_attributes) + 2, + NULL); if (!hotkey_dev_attributes) return -ENOMEM; res = add_many_to_attr_set(hotkey_dev_attributes, @@ -3019,7 +3217,7 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) if (res) goto err_exit; - /* mask not supported on 570, 600e/x, 770e, 770x, A21e, A2xm/p, + /* mask not supported on 600e/x, 770e, 770x, A21e, A2xm/p, A30, R30, R31, T20-22, X20-21, X22-24. Detected by checking for HKEY interface version 0x100 */ if (acpi_evalf(hkey_handle, &hkeyv, "MHKV", "qd")) { @@ -3033,10 +3231,22 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) * MHKV 0x100 in A31, R40, R40e, * T4x, X31, and later */ - tp_features.hotkey_mask = 1; vdbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_HKEY, "firmware HKEY interface version: 0x%x\n", hkeyv); + + /* Paranoia check AND init hotkey_all_mask */ + if (!acpi_evalf(hkey_handle, &hotkey_all_mask, + "MHKA", "qd")) { + printk(TPACPI_ERR + "missing MHKA handler, " + "please report this to %s\n", + TPACPI_MAIL); + /* Fallback: pre-init for FN+F3,F4,F12 */ + hotkey_all_mask = 0x080cU; + } else { + tp_features.hotkey_mask = 1; + } } } @@ -3044,32 +3254,23 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) "hotkey masks are %s\n", str_supported(tp_features.hotkey_mask)); - if (tp_features.hotkey_mask) { - if (!acpi_evalf(hkey_handle, &hotkey_all_mask, - "MHKA", "qd")) { - printk(TPACPI_ERR - "missing MHKA handler, " - "please report this to %s\n", - TPACPI_MAIL); - /* FN+F12, FN+F4, FN+F3 */ - hotkey_all_mask = 0x080cU; - } - } + /* Init hotkey_all_mask if not initialized yet */ + if (!tp_features.hotkey_mask && !hotkey_all_mask && + (quirks & TPACPI_HK_Q_INIMASK)) + hotkey_all_mask = 0x080cU; /* FN+F12, FN+F4, FN+F3 */ - /* hotkey_source_mask *must* be zero for - * the first hotkey_mask_get */ + /* Init hotkey_acpi_mask and hotkey_orig_mask */ if (tp_features.hotkey_mask) { + /* hotkey_source_mask *must* be zero for + * the first hotkey_mask_get to return hotkey_orig_mask */ res = hotkey_mask_get(); if (res) goto err_exit; - hotkey_orig_mask = hotkey_mask; - res = add_many_to_attr_set( - hotkey_dev_attributes, - hotkey_mask_attributes, - ARRAY_SIZE(hotkey_mask_attributes)); - if (res) - goto err_exit; + hotkey_orig_mask = hotkey_acpi_mask; + } else { + hotkey_orig_mask = hotkey_all_mask; + hotkey_acpi_mask = hotkey_all_mask; } #ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES @@ -3183,14 +3384,9 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) } #ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL - if (tp_features.hotkey_mask) { - hotkey_source_mask = TPACPI_HKEY_NVRAM_GOOD_MASK - & ~hotkey_all_mask - & ~hotkey_reserved_mask; - } else { - hotkey_source_mask = TPACPI_HKEY_NVRAM_GOOD_MASK - & ~hotkey_reserved_mask; - } + hotkey_source_mask = TPACPI_HKEY_NVRAM_GOOD_MASK + & ~hotkey_all_mask + & ~hotkey_reserved_mask; vdbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_HKEY, "hotkey source mask 0x%08x, polling freq %u\n", @@ -3204,13 +3400,18 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) hotkey_exit(); return res; } - res = hotkey_mask_set(((hotkey_all_mask | hotkey_source_mask) - & ~hotkey_reserved_mask) - | hotkey_orig_mask); + res = hotkey_mask_set(((hotkey_all_mask & ~hotkey_reserved_mask) + | hotkey_driver_mask) + & ~hotkey_source_mask); if (res < 0 && res != -ENXIO) { hotkey_exit(); return res; } + hotkey_user_mask = (hotkey_acpi_mask | hotkey_source_mask) + & ~hotkey_reserved_mask; + vdbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_HKEY, + "initial masks: user=0x%08x, fw=0x%08x, poll=0x%08x\n", + hotkey_user_mask, hotkey_acpi_mask, hotkey_source_mask); dbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_HKEY, "legacy ibm/hotkey event reporting over procfs %s\n", @@ -3245,7 +3446,7 @@ static bool hotkey_notify_hotkey(const u32 hkey, if (scancode > 0 && scancode < 0x21) { scancode--; if (!(hotkey_source_mask & (1 << scancode))) { - tpacpi_input_send_key(scancode); + tpacpi_input_send_key_masked(scancode); *send_acpi_ev = false; } else { *ignore_acpi_ev = true; @@ -3264,20 +3465,20 @@ static bool hotkey_notify_wakeup(const u32 hkey, *ignore_acpi_ev = false; switch (hkey) { - case 0x2304: /* suspend, undock */ - case 0x2404: /* hibernation, undock */ + case TP_HKEY_EV_WKUP_S3_UNDOCK: /* suspend, undock */ + case TP_HKEY_EV_WKUP_S4_UNDOCK: /* hibernation, undock */ hotkey_wakeup_reason = TP_ACPI_WAKEUP_UNDOCK; *ignore_acpi_ev = true; break; - case 0x2305: /* suspend, bay eject */ - case 0x2405: /* hibernation, bay eject */ + case TP_HKEY_EV_WKUP_S3_BAYEJ: /* suspend, bay eject */ + case TP_HKEY_EV_WKUP_S4_BAYEJ: /* hibernation, bay eject */ hotkey_wakeup_reason = TP_ACPI_WAKEUP_BAYEJ; *ignore_acpi_ev = true; break; - case 0x2313: /* Battery on critical low level (S3) */ - case 0x2413: /* Battery on critical low level (S4) */ + case TP_HKEY_EV_WKUP_S3_BATLOW: /* Battery on critical low level/S3 */ + case TP_HKEY_EV_WKUP_S4_BATLOW: /* Battery on critical low level/S4 */ printk(TPACPI_ALERT "EMERGENCY WAKEUP: battery almost empty\n"); /* how to auto-heal: */ @@ -3307,21 +3508,21 @@ static bool hotkey_notify_usrevent(const u32 hkey, *ignore_acpi_ev = false; switch (hkey) { - case 0x5010: /* Lenovo new BIOS: brightness changed */ - case 0x500b: /* X61t: tablet pen inserted into bay */ - case 0x500c: /* X61t: tablet pen removed from bay */ + case TP_HKEY_EV_PEN_INSERTED: /* X61t: tablet pen inserted into bay */ + case TP_HKEY_EV_PEN_REMOVED: /* X61t: tablet pen removed from bay */ return true; - case 0x5009: /* X41t-X61t: swivel up (tablet mode) */ - case 0x500a: /* X41t-X61t: swivel down (normal mode) */ + case TP_HKEY_EV_TABLET_TABLET: /* X41t-X61t: tablet mode */ + case TP_HKEY_EV_TABLET_NOTEBOOK: /* X41t-X61t: normal mode */ tpacpi_input_send_tabletsw(); hotkey_tablet_mode_notify_change(); *send_acpi_ev = false; return true; - case 0x5001: - case 0x5002: - /* LID switch events. Do not propagate */ + case TP_HKEY_EV_LID_CLOSE: /* Lid closed */ + case TP_HKEY_EV_LID_OPEN: /* Lid opened */ + case TP_HKEY_EV_BRGHT_CHANGED: /* brightness changed */ + /* do not propagate these events */ *ignore_acpi_ev = true; return true; @@ -3339,30 +3540,30 @@ static bool hotkey_notify_thermal(const u32 hkey, *ignore_acpi_ev = false; switch (hkey) { - case 0x6011: + case TP_HKEY_EV_ALARM_BAT_HOT: printk(TPACPI_CRIT "THERMAL ALARM: battery is too hot!\n"); /* recommended action: warn user through gui */ return true; - case 0x6012: + case TP_HKEY_EV_ALARM_BAT_XHOT: printk(TPACPI_ALERT "THERMAL EMERGENCY: battery is extremely hot!\n"); /* recommended action: immediate sleep/hibernate */ return true; - case 0x6021: + case TP_HKEY_EV_ALARM_SENSOR_HOT: printk(TPACPI_CRIT "THERMAL ALARM: " "a sensor reports something is too hot!\n"); /* recommended action: warn user through gui, that */ /* some internal component is too hot */ return true; - case 0x6022: + case TP_HKEY_EV_ALARM_SENSOR_XHOT: printk(TPACPI_ALERT "THERMAL EMERGENCY: " "a sensor reports something is extremely hot!\n"); /* recommended action: immediate sleep/hibernate */ return true; - case 0x6030: + case TP_HKEY_EV_THM_TABLE_CHANGED: printk(TPACPI_INFO "EC reports that Thermal Table has changed\n"); /* recommended action: do nothing, we don't have @@ -3420,7 +3621,7 @@ static void hotkey_notify(struct ibm_struct *ibm, u32 event) break; case 3: /* 0x3000-0x3FFF: bay-related wakeups */ - if (hkey == 0x3003) { + if (hkey == TP_HKEY_EV_BAYEJ_ACK) { hotkey_autosleep_ack = 1; printk(TPACPI_INFO "bay ejected\n"); @@ -3432,7 +3633,7 @@ static void hotkey_notify(struct ibm_struct *ibm, u32 event) break; case 4: /* 0x4000-0x4FFF: dock-related wakeups */ - if (hkey == 0x4003) { + if (hkey == TP_HKEY_EV_UNDOCK_ACK) { hotkey_autosleep_ack = 1; printk(TPACPI_INFO "undocked\n"); @@ -3454,7 +3655,8 @@ static void hotkey_notify(struct ibm_struct *ibm, u32 event) break; case 7: /* 0x7000-0x7FFF: misc */ - if (tp_features.hotkey_wlsw && hkey == 0x7000) { + if (tp_features.hotkey_wlsw && + hkey == TP_HKEY_EV_RFKILL_CHANGED) { tpacpi_send_radiosw_update(); send_acpi_ev = 0; known_ev = true; @@ -3500,10 +3702,12 @@ static void hotkey_resume(void) { tpacpi_disable_brightness_delay(); - if (hotkey_mask_get()) + if (hotkey_status_set(true) < 0 || + hotkey_mask_set(hotkey_acpi_mask) < 0) printk(TPACPI_ERR - "error while trying to read hot key mask " - "from firmware\n"); + "error while attempting to reset the event " + "firmware interface\n"); + tpacpi_send_radiosw_update(); hotkey_tablet_mode_notify_change(); hotkey_wakeup_reason_notify_change(); @@ -3532,8 +3736,8 @@ static int hotkey_read(char *p) return res; len += sprintf(p + len, "status:\t\t%s\n", enabled(status, 0)); - if (tp_features.hotkey_mask) { - len += sprintf(p + len, "mask:\t\t0x%08x\n", hotkey_mask); + if (hotkey_all_mask) { + len += sprintf(p + len, "mask:\t\t0x%08x\n", hotkey_user_mask); len += sprintf(p + len, "commands:\tenable, disable, reset, <mask>\n"); } else { @@ -3570,7 +3774,7 @@ static int hotkey_write(char *buf) if (mutex_lock_killable(&hotkey_mutex)) return -ERESTARTSYS; - mask = hotkey_mask; + mask = hotkey_user_mask; res = 0; while ((cmd = next_cmd(&buf))) { @@ -3592,12 +3796,11 @@ static int hotkey_write(char *buf) } } - if (!res) + if (!res) { tpacpi_disclose_usertask("procfs hotkey", "set mask to 0x%08x\n", mask); - - if (!res && mask != hotkey_mask) - res = hotkey_mask_set(mask); + res = hotkey_user_mask_set(mask); + } errexit: mutex_unlock(&hotkey_mutex); @@ -6010,8 +6213,10 @@ static int __init brightness_init(struct ibm_init_struct *iibm) TPACPI_BACKLIGHT_DEV_NAME, NULL, NULL, &ibm_backlight_data); if (IS_ERR(ibm_backlight_device)) { + int rc = PTR_ERR(ibm_backlight_device); + ibm_backlight_device = NULL; printk(TPACPI_ERR "Could not register backlight device\n"); - return PTR_ERR(ibm_backlight_device); + return rc; } vdbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_BRGHT, "brightness is supported\n"); @@ -7499,6 +7704,21 @@ static struct ibm_struct fan_driver_data = { **************************************************************************** ****************************************************************************/ +/* + * HKEY event callout for other subdrivers go here + * (yes, it is ugly, but it is quick, safe, and gets the job done + */ +static void tpacpi_driver_event(const unsigned int hkey_event) +{ +} + + + +static void hotkey_driver_event(const unsigned int scancode) +{ + tpacpi_driver_event(TP_HKEY_EV_HOTKEY_BASE + scancode); +} + /* sysfs name ---------------------------------------------------------- */ static ssize_t thinkpad_acpi_pdev_name_show(struct device *dev, struct device_attribute *attr, diff --git a/drivers/pnp/pnpacpi/core.c b/drivers/pnp/pnpacpi/core.c index c07fdb94d66..83b8b5ac49c 100644 --- a/drivers/pnp/pnpacpi/core.c +++ b/drivers/pnp/pnpacpi/core.c @@ -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) |