Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

platform/x86: wmi: Pass event data directly to legacy notify handlers

The current legacy WMI handlers are susceptible to picking up wrong
WMI event data on systems where different WMI devices share some
notification IDs.

Prevent this by letting the WMI driver core taking care of retrieving
the event data. This also simplifies the legacy WMI handlers and their
implementation inside the WMI driver core.

Reviewed-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
Reviewed-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Armin Wolf <W_Armin@gmx.de>
Link: https://lore.kernel.org/r/20240901031055.3030-3-W_Armin@gmx.de
Signed-off-by: Hans de Goede <hdegoede@redhat.com>

authored by

Armin Wolf and committed by
Hans de Goede
e04e2b76 56d8b784

+37 -156
+6 -16
drivers/hwmon/hp-wmi-sensors.c
··· 1597 1597 } 1598 1598 1599 1599 /* hp_wmi_notify - WMI event notification handler */ 1600 - static void hp_wmi_notify(u32 value, void *context) 1600 + static void hp_wmi_notify(union acpi_object *wobj, void *context) 1601 1601 { 1602 1602 struct hp_wmi_info *temp_info[HP_WMI_MAX_INSTANCES] = {}; 1603 - struct acpi_buffer out = { ACPI_ALLOCATE_BUFFER, NULL }; 1604 1603 struct hp_wmi_sensors *state = context; 1605 1604 struct device *dev = &state->wdev->dev; 1606 1605 struct hp_wmi_event event = {}; 1607 1606 struct hp_wmi_info *fan_info; 1608 - union acpi_object *wobj; 1609 1607 acpi_status err; 1610 1608 int event_type; 1611 1609 u8 count; ··· 1628 1630 * HPBIOS_BIOSEvent instance. 1629 1631 */ 1630 1632 1631 - mutex_lock(&state->lock); 1632 - 1633 - err = wmi_get_event_data(value, &out); 1634 - if (ACPI_FAILURE(err)) 1635 - goto out_unlock; 1636 - 1637 - wobj = out.pointer; 1638 1633 if (!wobj) 1639 - goto out_unlock; 1634 + return; 1635 + 1636 + mutex_lock(&state->lock); 1640 1637 1641 1638 err = populate_event_from_wobj(dev, &event, wobj); 1642 1639 if (err) { 1643 1640 dev_warn(dev, "Bad event data (ACPI type %d)\n", wobj->type); 1644 - goto out_free_wobj; 1641 + goto out_free; 1645 1642 } 1646 1643 1647 1644 event_type = classify_event(event.name, event.category); ··· 1661 1668 break; 1662 1669 } 1663 1670 1664 - out_free_wobj: 1665 - kfree(wobj); 1666 - 1671 + out_free: 1667 1672 devm_kfree(dev, event.name); 1668 1673 devm_kfree(dev, event.description); 1669 1674 1670 - out_unlock: 1671 1675 mutex_unlock(&state->lock); 1672 1676 } 1673 1677
+1 -15
drivers/platform/x86/acer-wmi.c
··· 2223 2223 } 2224 2224 } 2225 2225 2226 - static void acer_wmi_notify(u32 value, void *context) 2226 + static void acer_wmi_notify(union acpi_object *obj, void *context) 2227 2227 { 2228 - struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL }; 2229 - union acpi_object *obj; 2230 2228 struct event_return_value return_value; 2231 - acpi_status status; 2232 2229 u16 device_state; 2233 2230 const struct key_entry *key; 2234 2231 u32 scancode; 2235 - 2236 - status = wmi_get_event_data(value, &response); 2237 - if (status != AE_OK) { 2238 - pr_warn("bad event status 0x%x\n", status); 2239 - return; 2240 - } 2241 - 2242 - obj = (union acpi_object *)response.pointer; 2243 2232 2244 2233 if (!obj) 2245 2234 return; 2246 2235 if (obj->type != ACPI_TYPE_BUFFER) { 2247 2236 pr_warn("Unknown response received %d\n", obj->type); 2248 - kfree(obj); 2249 2237 return; 2250 2238 } 2251 2239 if (obj->buffer.length != 8) { 2252 2240 pr_warn("Unknown buffer length %d\n", obj->buffer.length); 2253 - kfree(obj); 2254 2241 return; 2255 2242 } 2256 2243 2257 2244 return_value = *((struct event_return_value *)obj->buffer.pointer); 2258 - kfree(obj); 2259 2245 2260 2246 switch (return_value.function) { 2261 2247 case WMID_HOTKEY_EVENT:
+3 -16
drivers/platform/x86/asus-wmi.c
··· 4201 4201 4202 4202 /* WMI events *****************************************************************/ 4203 4203 4204 - static int asus_wmi_get_event_code(u32 value) 4204 + static int asus_wmi_get_event_code(union acpi_object *obj) 4205 4205 { 4206 - struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL }; 4207 - union acpi_object *obj; 4208 - acpi_status status; 4209 4206 int code; 4210 - 4211 - status = wmi_get_event_data(value, &response); 4212 - if (ACPI_FAILURE(status)) { 4213 - pr_warn("Failed to get WMI notify code: %s\n", 4214 - acpi_format_exception(status)); 4215 - return -EIO; 4216 - } 4217 - 4218 - obj = (union acpi_object *)response.pointer; 4219 4207 4220 4208 if (obj && obj->type == ACPI_TYPE_INTEGER) 4221 4209 code = (int)(obj->integer.value & WMI_EVENT_MASK); 4222 4210 else 4223 4211 code = -EIO; 4224 4212 4225 - kfree(obj); 4226 4213 return code; 4227 4214 } 4228 4215 ··· 4275 4288 pr_info("Unknown key code 0x%x\n", code); 4276 4289 } 4277 4290 4278 - static void asus_wmi_notify(u32 value, void *context) 4291 + static void asus_wmi_notify(union acpi_object *obj, void *context) 4279 4292 { 4280 4293 struct asus_wmi *asus = context; 4281 - int code = asus_wmi_get_event_code(value); 4294 + int code = asus_wmi_get_event_code(obj); 4282 4295 4283 4296 if (code < 0) { 4284 4297 pr_warn("Failed to get notify code: %d\n", code);
+1 -12
drivers/platform/x86/dell/dell-wmi-aio.c
··· 70 70 return false; 71 71 } 72 72 73 - static void dell_wmi_aio_notify(u32 value, void *context) 73 + static void dell_wmi_aio_notify(union acpi_object *obj, void *context) 74 74 { 75 - struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL }; 76 - union acpi_object *obj; 77 75 struct dell_wmi_event *event; 78 - acpi_status status; 79 76 80 - status = wmi_get_event_data(value, &response); 81 - if (status != AE_OK) { 82 - pr_info("bad event status 0x%x\n", status); 83 - return; 84 - } 85 - 86 - obj = (union acpi_object *)response.pointer; 87 77 if (obj) { 88 78 unsigned int scancode = 0; 89 79 ··· 104 114 break; 105 115 } 106 116 } 107 - kfree(obj); 108 117 } 109 118 110 119 static int __init dell_wmi_aio_input_setup(void)
+1 -15
drivers/platform/x86/hp/hp-wmi.c
··· 834 834 }; 835 835 ATTRIBUTE_GROUPS(hp_wmi); 836 836 837 - static void hp_wmi_notify(u32 value, void *context) 837 + static void hp_wmi_notify(union acpi_object *obj, void *context) 838 838 { 839 - struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL }; 840 839 u32 event_id, event_data; 841 - union acpi_object *obj; 842 - acpi_status status; 843 840 u32 *location; 844 841 int key_code; 845 - 846 - status = wmi_get_event_data(value, &response); 847 - if (status != AE_OK) { 848 - pr_info("bad event status 0x%x\n", status); 849 - return; 850 - } 851 - 852 - obj = (union acpi_object *)response.pointer; 853 842 854 843 if (!obj) 855 844 return; 856 845 if (obj->type != ACPI_TYPE_BUFFER) { 857 846 pr_info("Unknown response received %d\n", obj->type); 858 - kfree(obj); 859 847 return; 860 848 } 861 849 ··· 860 872 event_data = *(location + 2); 861 873 } else { 862 874 pr_info("Unknown buffer length %d\n", obj->buffer.length); 863 - kfree(obj); 864 875 return; 865 876 } 866 - kfree(obj); 867 877 868 878 switch (event_id) { 869 879 case HPWMI_DOCK_EVENT:
+1 -13
drivers/platform/x86/huawei-wmi.c
··· 734 734 sparse_keymap_report_entry(idev, key, 1, true); 735 735 } 736 736 737 - static void huawei_wmi_input_notify(u32 value, void *context) 737 + static void huawei_wmi_input_notify(union acpi_object *obj, void *context) 738 738 { 739 739 struct input_dev *idev = (struct input_dev *)context; 740 - struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL }; 741 - union acpi_object *obj; 742 - acpi_status status; 743 740 744 - status = wmi_get_event_data(value, &response); 745 - if (ACPI_FAILURE(status)) { 746 - dev_err(&idev->dev, "Unable to get event data\n"); 747 - return; 748 - } 749 - 750 - obj = (union acpi_object *)response.pointer; 751 741 if (obj && obj->type == ACPI_TYPE_INTEGER) 752 742 huawei_wmi_process_key(idev, obj->integer.value); 753 743 else 754 744 dev_err(&idev->dev, "Bad response type\n"); 755 - 756 - kfree(response.pointer); 757 745 } 758 746 759 747 static int huawei_wmi_input_setup(struct device *dev, const char *guid)
+1 -12
drivers/platform/x86/lg-laptop.c
··· 205 205 return (union acpi_object *)buffer.pointer; 206 206 } 207 207 208 - static void wmi_notify(u32 value, void *context) 208 + static void wmi_notify(union acpi_object *obj, void *context) 209 209 { 210 - struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL }; 211 - union acpi_object *obj; 212 - acpi_status status; 213 210 long data = (long)context; 214 211 215 212 pr_debug("event guid %li\n", data); 216 - status = wmi_get_event_data(value, &response); 217 - if (ACPI_FAILURE(status)) { 218 - pr_err("Bad event status 0x%x\n", status); 219 - return; 220 - } 221 - 222 - obj = (union acpi_object *)response.pointer; 223 213 if (!obj) 224 214 return; 225 215 ··· 231 241 232 242 pr_debug("Type: %i Eventcode: 0x%llx\n", obj->type, 233 243 obj->integer.value); 234 - kfree(response.pointer); 235 244 } 236 245 237 246 static void wmi_input_setup(void)
+3 -17
drivers/platform/x86/msi-wmi.c
··· 170 170 .update_status = bl_set_status, 171 171 }; 172 172 173 - static void msi_wmi_notify(u32 value, void *context) 173 + static void msi_wmi_notify(union acpi_object *obj, void *context) 174 174 { 175 - struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL }; 176 175 struct key_entry *key; 177 - union acpi_object *obj; 178 - acpi_status status; 179 - 180 - status = wmi_get_event_data(value, &response); 181 - if (status != AE_OK) { 182 - pr_info("bad event status 0x%x\n", status); 183 - return; 184 - } 185 - 186 - obj = (union acpi_object *)response.pointer; 187 176 188 177 if (obj && obj->type == ACPI_TYPE_INTEGER) { 189 178 int eventcode = obj->integer.value; ··· 181 192 eventcode); 182 193 if (!key) { 183 194 pr_info("Unknown key pressed - %x\n", eventcode); 184 - goto msi_wmi_notify_exit; 195 + return; 185 196 } 186 197 187 198 if (event_wmi->quirk_last_pressed) { ··· 193 204 pr_debug("Suppressed key event 0x%X - " 194 205 "Last press was %lld us ago\n", 195 206 key->code, ktime_to_us(diff)); 196 - goto msi_wmi_notify_exit; 207 + return; 197 208 } 198 209 last_pressed = cur; 199 210 } ··· 210 221 } 211 222 } else 212 223 pr_info("Unknown event received\n"); 213 - 214 - msi_wmi_notify_exit: 215 - kfree(response.pointer); 216 224 } 217 225 218 226 static int __init msi_wmi_backlight_setup(void)
+1 -14
drivers/platform/x86/toshiba-wmi.c
··· 32 32 { KE_END, 0 } 33 33 }; 34 34 35 - static void toshiba_wmi_notify(u32 value, void *context) 35 + static void toshiba_wmi_notify(union acpi_object *obj, void *context) 36 36 { 37 - struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL }; 38 - union acpi_object *obj; 39 - acpi_status status; 40 - 41 - status = wmi_get_event_data(value, &response); 42 - if (ACPI_FAILURE(status)) { 43 - pr_err("Bad event status 0x%x\n", status); 44 - return; 45 - } 46 - 47 - obj = (union acpi_object *)response.pointer; 48 37 if (!obj) 49 38 return; 50 39 51 40 /* TODO: Add proper checks once we have data */ 52 41 pr_debug("Unknown event received, obj type %x\n", obj->type); 53 - 54 - kfree(response.pointer); 55 42 } 56 43 57 44 static const struct dmi_system_id toshiba_wmi_dmi_table[] __initconst = {
+18 -25
drivers/platform/x86/wmi.c
··· 1227 1227 if (!(wblock->gblock.flags & ACPI_WMI_EVENT && wblock->gblock.notify_id == *event)) 1228 1228 return 0; 1229 1229 1230 + /* The ACPI WMI specification says that _WED should be 1231 + * evaluated every time an notification is received, even 1232 + * if no consumers are present. 1233 + * 1234 + * Some firmware implementations actually depend on this 1235 + * by using a queue for events which will fill up if the 1236 + * WMI driver core stops evaluating _WED due to missing 1237 + * WMI event consumers. 1238 + */ 1239 + ret = wmi_get_notify_data(wblock, &obj); 1240 + if (ret < 0) 1241 + return -EIO; 1242 + 1230 1243 down_read(&wblock->notify_lock); 1231 1244 /* The WMI driver notify handler conflicts with the legacy WMI handler. 1232 1245 * Because of this the WMI driver notify handler takes precedence. 1233 1246 */ 1234 1247 if (wblock->dev.dev.driver && wblock->driver_ready) { 1235 - ret = wmi_get_notify_data(wblock, &obj); 1236 - if (ret >= 0) { 1237 - wmi_notify_driver(wblock, obj); 1238 - kfree(obj); 1239 - } 1248 + wmi_notify_driver(wblock, obj); 1240 1249 } else { 1241 - if (wblock->handler) { 1242 - wblock->handler(*event, wblock->handler_data); 1243 - } else { 1244 - /* The ACPI WMI specification says that _WED should be 1245 - * evaluated every time an notification is received, even 1246 - * if no consumers are present. 1247 - * 1248 - * Some firmware implementations actually depend on this 1249 - * by using a queue for events which will fill up if the 1250 - * WMI driver core stops evaluating _WED due to missing 1251 - * WMI event consumers. 1252 - * 1253 - * Because of this we need this seemingly useless call to 1254 - * wmi_get_notify_data() which in turn evaluates _WED. 1255 - */ 1256 - ret = wmi_get_notify_data(wblock, &obj); 1257 - if (ret >= 0) 1258 - kfree(obj); 1259 - } 1260 - 1250 + if (wblock->handler) 1251 + wblock->handler(obj, wblock->handler_data); 1261 1252 } 1262 1253 up_read(&wblock->notify_lock); 1254 + 1255 + kfree(obj); 1263 1256 1264 1257 acpi_bus_generate_netlink_event("wmi", acpi_dev_name(wblock->acpi_device), *event, 0); 1265 1258
+1 -1
include/linux/acpi.h
··· 386 386 387 387 #if defined(CONFIG_ACPI_WMI) || defined(CONFIG_ACPI_WMI_MODULE) 388 388 389 - typedef void (*wmi_notify_handler) (u32 value, void *context); 389 + typedef void (*wmi_notify_handler) (union acpi_object *data, void *context); 390 390 391 391 int wmi_instance_count(const char *guid); 392 392