^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-or-later
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * ACPI-WMI mapping driver
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Copyright (C) 2007-2008 Carlos Corbacho <carlos@strangeworlds.co.uk>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * GUID parsing code from ldm.c is:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * Copyright (C) 2001,2002 Richard Russon <ldm@flatcap.org>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) * Copyright (c) 2001-2007 Anton Altaparmakov
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) * Copyright (C) 2001,2002 Jakob Kemi <jakob.kemi@telia.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) * WMI bus infrastructure by Andrew Lutomirski and Darren Hart:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) * Copyright (C) 2015 Andrew Lutomirski
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) * Copyright (C) 2017 VMware, Inc. All Rights Reserved.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <linux/acpi.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #include <linux/device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #include <linux/init.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #include <linux/list.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #include <linux/miscdevice.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) #include <linux/platform_device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) #include <linux/types.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) #include <linux/uaccess.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) #include <linux/uuid.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) #include <linux/wmi.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) #include <linux/fs.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) #include <uapi/linux/wmi.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) ACPI_MODULE_NAME("wmi");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) MODULE_AUTHOR("Carlos Corbacho");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) MODULE_DESCRIPTION("ACPI-WMI Mapping Driver");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) MODULE_LICENSE("GPL");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) static LIST_HEAD(wmi_block_list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) struct guid_block {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) char guid[16];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) union {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) char object_id[2];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) struct {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) unsigned char notify_id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) unsigned char reserved;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) u8 instance_count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) u8 flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) struct wmi_block {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) struct wmi_device dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) struct list_head list;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) struct guid_block gblock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) struct miscdevice char_dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) struct mutex char_mutex;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) struct acpi_device *acpi_device;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) wmi_notify_handler handler;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) void *handler_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) u64 req_buf_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) bool read_takes_no_args;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) * If the GUID data block is marked as expensive, we must enable and
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) * explicitily disable data collection.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) #define ACPI_WMI_EXPENSIVE 0x1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) #define ACPI_WMI_METHOD 0x2 /* GUID is a method */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) #define ACPI_WMI_STRING 0x4 /* GUID takes & returns a string */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) #define ACPI_WMI_EVENT 0x8 /* GUID is an event */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) static bool debug_event;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) module_param(debug_event, bool, 0444);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) MODULE_PARM_DESC(debug_event,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) "Log WMI Events [0/1]");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) static bool debug_dump_wdg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) module_param(debug_dump_wdg, bool, 0444);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) MODULE_PARM_DESC(debug_dump_wdg,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) "Dump available WMI interfaces [0/1]");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) static int acpi_wmi_remove(struct platform_device *device);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) static int acpi_wmi_probe(struct platform_device *device);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) static const struct acpi_device_id wmi_device_ids[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) {"PNP0C14", 0},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) {"pnp0c14", 0},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) {"", 0},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) MODULE_DEVICE_TABLE(acpi, wmi_device_ids);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) static struct platform_driver acpi_wmi_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) .driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) .name = "acpi-wmi",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) .acpi_match_table = wmi_device_ids,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) .probe = acpi_wmi_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) .remove = acpi_wmi_remove,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) * GUID parsing functions
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) static bool find_guid(const char *guid_string, struct wmi_block **out)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) guid_t guid_input;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) struct wmi_block *wblock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) struct guid_block *block;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) if (guid_parse(guid_string, &guid_input))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) return false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) list_for_each_entry(wblock, &wmi_block_list, list) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) block = &wblock->gblock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) if (memcmp(block->guid, &guid_input, 16) == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) if (out)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) *out = wblock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) return true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) return false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) static const void *find_guid_context(struct wmi_block *wblock,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) struct wmi_driver *wdriver)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) const struct wmi_device_id *id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) guid_t guid_input;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) if (wblock == NULL || wdriver == NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) if (wdriver->id_table == NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) id = wdriver->id_table;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) while (*id->guid_string) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) if (guid_parse(id->guid_string, &guid_input))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) if (!memcmp(wblock->gblock.guid, &guid_input, 16))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) return id->context;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) id++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) static int get_subobj_info(acpi_handle handle, const char *pathname,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) struct acpi_device_info **info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) struct acpi_device_info *dummy_info, **info_ptr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) acpi_handle subobj_handle;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) acpi_status status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) status = acpi_get_handle(handle, (char *)pathname, &subobj_handle);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) if (status == AE_NOT_FOUND)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) return -ENOENT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) else if (ACPI_FAILURE(status))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) return -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) info_ptr = info ? info : &dummy_info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) status = acpi_get_object_info(subobj_handle, info_ptr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) if (ACPI_FAILURE(status))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) return -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) if (!info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) kfree(dummy_info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) static acpi_status wmi_method_enable(struct wmi_block *wblock, int enable)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) struct guid_block *block = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) char method[5];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) acpi_status status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) acpi_handle handle;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) block = &wblock->gblock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) handle = wblock->acpi_device->handle;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) snprintf(method, 5, "WE%02X", block->notify_id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) status = acpi_execute_simple_method(handle, method, enable);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) if (status != AE_OK && status != AE_NOT_FOUND)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) return status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) return AE_OK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) * Exported WMI functions
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) * set_required_buffer_size - Sets the buffer size needed for performing IOCTL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) * @wdev: A wmi bus device from a driver
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) * @length: Required buffer size
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) * Allocates memory needed for buffer, stores the buffer size in that memory
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) int set_required_buffer_size(struct wmi_device *wdev, u64 length)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) struct wmi_block *wblock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) wblock = container_of(wdev, struct wmi_block, dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) wblock->req_buf_size = length;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) EXPORT_SYMBOL_GPL(set_required_buffer_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) * wmi_evaluate_method - Evaluate a WMI method
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) * @guid_string: 36 char string of the form fa50ff2b-f2e8-45de-83fa-65417f2f49ba
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) * @instance: Instance index
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) * @method_id: Method ID to call
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) * @in: Buffer containing input for the method call
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) * @out: Empty buffer to return the method results
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) * Call an ACPI-WMI method
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) acpi_status wmi_evaluate_method(const char *guid_string, u8 instance,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) u32 method_id, const struct acpi_buffer *in, struct acpi_buffer *out)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) struct wmi_block *wblock = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) if (!find_guid(guid_string, &wblock))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) return AE_ERROR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) return wmidev_evaluate_method(&wblock->dev, instance, method_id,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) in, out);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) EXPORT_SYMBOL_GPL(wmi_evaluate_method);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) * wmidev_evaluate_method - Evaluate a WMI method
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) * @wdev: A wmi bus device from a driver
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) * @instance: Instance index
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) * @method_id: Method ID to call
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) * @in: Buffer containing input for the method call
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) * @out: Empty buffer to return the method results
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) * Call an ACPI-WMI method
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) acpi_status wmidev_evaluate_method(struct wmi_device *wdev, u8 instance,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) u32 method_id, const struct acpi_buffer *in, struct acpi_buffer *out)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) struct guid_block *block = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) struct wmi_block *wblock = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) acpi_handle handle;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) acpi_status status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) struct acpi_object_list input;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) union acpi_object params[3];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) char method[5] = "WM";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) wblock = container_of(wdev, struct wmi_block, dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) block = &wblock->gblock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) handle = wblock->acpi_device->handle;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) if (!(block->flags & ACPI_WMI_METHOD))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) return AE_BAD_DATA;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) if (block->instance_count <= instance)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) return AE_BAD_PARAMETER;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) input.count = 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) input.pointer = params;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) params[0].type = ACPI_TYPE_INTEGER;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) params[0].integer.value = instance;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) params[1].type = ACPI_TYPE_INTEGER;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) params[1].integer.value = method_id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) if (in) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) input.count = 3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) if (block->flags & ACPI_WMI_STRING) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) params[2].type = ACPI_TYPE_STRING;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) params[2].type = ACPI_TYPE_BUFFER;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) params[2].buffer.length = in->length;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) params[2].buffer.pointer = in->pointer;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) strncat(method, block->object_id, 2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) status = acpi_evaluate_object(handle, method, &input, out);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) return status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) EXPORT_SYMBOL_GPL(wmidev_evaluate_method);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) static acpi_status __query_block(struct wmi_block *wblock, u8 instance,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) struct acpi_buffer *out)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) struct guid_block *block = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) acpi_handle handle;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) acpi_status status, wc_status = AE_ERROR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) struct acpi_object_list input;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) union acpi_object wq_params[1];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) char method[5];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) char wc_method[5] = "WC";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) if (!out)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) return AE_BAD_PARAMETER;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) block = &wblock->gblock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) handle = wblock->acpi_device->handle;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) if (block->instance_count <= instance)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) return AE_BAD_PARAMETER;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) /* Check GUID is a data block */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) if (block->flags & (ACPI_WMI_EVENT | ACPI_WMI_METHOD))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) return AE_ERROR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) input.count = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) input.pointer = wq_params;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) wq_params[0].type = ACPI_TYPE_INTEGER;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) wq_params[0].integer.value = instance;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) if (instance == 0 && wblock->read_takes_no_args)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) input.count = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) * If ACPI_WMI_EXPENSIVE, call the relevant WCxx method first to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) * enable collection.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) if (block->flags & ACPI_WMI_EXPENSIVE) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) strncat(wc_method, block->object_id, 2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) * Some GUIDs break the specification by declaring themselves
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) * expensive, but have no corresponding WCxx method. So we
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) * should not fail if this happens.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) wc_status = acpi_execute_simple_method(handle, wc_method, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) strcpy(method, "WQ");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) strncat(method, block->object_id, 2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) status = acpi_evaluate_object(handle, method, &input, out);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) * If ACPI_WMI_EXPENSIVE, call the relevant WCxx method, even if
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) * the WQxx method failed - we should disable collection anyway.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) if ((block->flags & ACPI_WMI_EXPENSIVE) && ACPI_SUCCESS(wc_status)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) * Ignore whether this WCxx call succeeds or not since
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) * the previously executed WQxx method call might have
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) * succeeded, and returning the failing status code
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) * of this call would throw away the result of the WQxx
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) * call, potentially leaking memory.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) acpi_execute_simple_method(handle, wc_method, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) return status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) * wmi_query_block - Return contents of a WMI block (deprecated)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) * @guid_string: 36 char string of the form fa50ff2b-f2e8-45de-83fa-65417f2f49ba
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) * @instance: Instance index
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) * @out: Empty buffer to return the contents of the data block to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) * Return the contents of an ACPI-WMI data block to a buffer
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) acpi_status wmi_query_block(const char *guid_string, u8 instance,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) struct acpi_buffer *out)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) struct wmi_block *wblock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) if (!guid_string)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) return AE_BAD_PARAMETER;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) if (!find_guid(guid_string, &wblock))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) return AE_ERROR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) return __query_block(wblock, instance, out);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) EXPORT_SYMBOL_GPL(wmi_query_block);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) union acpi_object *wmidev_block_query(struct wmi_device *wdev, u8 instance)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) struct acpi_buffer out = { ACPI_ALLOCATE_BUFFER, NULL };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) struct wmi_block *wblock = container_of(wdev, struct wmi_block, dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) if (ACPI_FAILURE(__query_block(wblock, instance, &out)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) return (union acpi_object *)out.pointer;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) EXPORT_SYMBOL_GPL(wmidev_block_query);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) * wmi_set_block - Write to a WMI block
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) * @guid_string: 36 char string of the form fa50ff2b-f2e8-45de-83fa-65417f2f49ba
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) * @instance: Instance index
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) * @in: Buffer containing new values for the data block
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) * Write the contents of the input buffer to an ACPI-WMI data block
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) acpi_status wmi_set_block(const char *guid_string, u8 instance,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) const struct acpi_buffer *in)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) struct guid_block *block = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) struct wmi_block *wblock = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) acpi_handle handle;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) struct acpi_object_list input;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) union acpi_object params[2];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) char method[5] = "WS";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) if (!guid_string || !in)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) return AE_BAD_DATA;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) if (!find_guid(guid_string, &wblock))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) return AE_ERROR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) block = &wblock->gblock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) handle = wblock->acpi_device->handle;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) if (block->instance_count <= instance)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) return AE_BAD_PARAMETER;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) /* Check GUID is a data block */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) if (block->flags & (ACPI_WMI_EVENT | ACPI_WMI_METHOD))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) return AE_ERROR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) input.count = 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) input.pointer = params;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) params[0].type = ACPI_TYPE_INTEGER;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) params[0].integer.value = instance;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) if (block->flags & ACPI_WMI_STRING) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) params[1].type = ACPI_TYPE_STRING;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) params[1].type = ACPI_TYPE_BUFFER;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) params[1].buffer.length = in->length;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) params[1].buffer.pointer = in->pointer;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) strncat(method, block->object_id, 2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) return acpi_evaluate_object(handle, method, &input, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456) EXPORT_SYMBOL_GPL(wmi_set_block);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) static void wmi_dump_wdg(const struct guid_block *g)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) pr_info("%pUL:\n", g->guid);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461) if (g->flags & ACPI_WMI_EVENT)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) pr_info("\tnotify_id: 0x%02X\n", g->notify_id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) pr_info("\tobject_id: %2pE\n", g->object_id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465) pr_info("\tinstance_count: %d\n", g->instance_count);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466) pr_info("\tflags: %#x", g->flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467) if (g->flags) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) if (g->flags & ACPI_WMI_EXPENSIVE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469) pr_cont(" ACPI_WMI_EXPENSIVE");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470) if (g->flags & ACPI_WMI_METHOD)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) pr_cont(" ACPI_WMI_METHOD");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472) if (g->flags & ACPI_WMI_STRING)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) pr_cont(" ACPI_WMI_STRING");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) if (g->flags & ACPI_WMI_EVENT)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475) pr_cont(" ACPI_WMI_EVENT");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477) pr_cont("\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481) static void wmi_notify_debug(u32 value, void *context)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) union acpi_object *obj;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485) acpi_status status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) status = wmi_get_event_data(value, &response);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488) if (status != AE_OK) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) pr_info("bad event status 0x%x\n", status);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493) obj = (union acpi_object *)response.pointer;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495) if (!obj)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498) pr_info("DEBUG Event ");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) switch(obj->type) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) case ACPI_TYPE_BUFFER:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501) pr_cont("BUFFER_TYPE - length %d\n", obj->buffer.length);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503) case ACPI_TYPE_STRING:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504) pr_cont("STRING_TYPE - %s\n", obj->string.pointer);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506) case ACPI_TYPE_INTEGER:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507) pr_cont("INTEGER_TYPE - %llu\n", obj->integer.value);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509) case ACPI_TYPE_PACKAGE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510) pr_cont("PACKAGE_TYPE - %d elements\n", obj->package.count);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513) pr_cont("object type 0x%X\n", obj->type);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515) kfree(obj);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519) * wmi_install_notify_handler - Register handler for WMI events
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520) * @guid: 36 char string of the form fa50ff2b-f2e8-45de-83fa-65417f2f49ba
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521) * @handler: Function to handle notifications
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522) * @data: Data to be returned to handler when event is fired
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524) * Register a handler for events sent to the ACPI-WMI mapper device.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526) acpi_status wmi_install_notify_handler(const char *guid,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527) wmi_notify_handler handler, void *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529) struct wmi_block *block;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530) acpi_status status = AE_NOT_EXIST;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531) guid_t guid_input;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533) if (!guid || !handler)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534) return AE_BAD_PARAMETER;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536) if (guid_parse(guid, &guid_input))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537) return AE_BAD_PARAMETER;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539) list_for_each_entry(block, &wmi_block_list, list) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540) acpi_status wmi_status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542) if (memcmp(block->gblock.guid, &guid_input, 16) == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543) if (block->handler &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544) block->handler != wmi_notify_debug)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545) return AE_ALREADY_ACQUIRED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547) block->handler = handler;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548) block->handler_data = data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550) wmi_status = wmi_method_enable(block, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551) if ((wmi_status != AE_OK) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552) ((wmi_status == AE_OK) && (status == AE_NOT_EXIST)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553) status = wmi_status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557) return status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559) EXPORT_SYMBOL_GPL(wmi_install_notify_handler);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562) * wmi_uninstall_notify_handler - Unregister handler for WMI events
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563) * @guid: 36 char string of the form fa50ff2b-f2e8-45de-83fa-65417f2f49ba
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565) * Unregister handler for events sent to the ACPI-WMI mapper device.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567) acpi_status wmi_remove_notify_handler(const char *guid)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569) struct wmi_block *block;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570) acpi_status status = AE_NOT_EXIST;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571) guid_t guid_input;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573) if (!guid)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574) return AE_BAD_PARAMETER;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576) if (guid_parse(guid, &guid_input))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577) return AE_BAD_PARAMETER;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579) list_for_each_entry(block, &wmi_block_list, list) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580) acpi_status wmi_status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582) if (memcmp(block->gblock.guid, &guid_input, 16) == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583) if (!block->handler ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584) block->handler == wmi_notify_debug)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585) return AE_NULL_ENTRY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587) if (debug_event) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588) block->handler = wmi_notify_debug;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589) status = AE_OK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 590) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 591) wmi_status = wmi_method_enable(block, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 592) block->handler = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 593) block->handler_data = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 594) if ((wmi_status != AE_OK) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 595) ((wmi_status == AE_OK) &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 596) (status == AE_NOT_EXIST)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 597) status = wmi_status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 598) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 599) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 600) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 601)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 602) return status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 603) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 604) EXPORT_SYMBOL_GPL(wmi_remove_notify_handler);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 605)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 606) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 607) * wmi_get_event_data - Get WMI data associated with an event
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 608) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 609) * @event: Event to find
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 610) * @out: Buffer to hold event data. out->pointer should be freed with kfree()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 611) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 612) * Returns extra data associated with an event in WMI.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 613) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 614) acpi_status wmi_get_event_data(u32 event, struct acpi_buffer *out)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 615) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 616) struct acpi_object_list input;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 617) union acpi_object params[1];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 618) struct guid_block *gblock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 619) struct wmi_block *wblock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 620)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 621) input.count = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 622) input.pointer = params;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 623) params[0].type = ACPI_TYPE_INTEGER;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 624) params[0].integer.value = event;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 625)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 626) list_for_each_entry(wblock, &wmi_block_list, list) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 627) gblock = &wblock->gblock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 628)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 629) if ((gblock->flags & ACPI_WMI_EVENT) &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 630) (gblock->notify_id == event))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 631) return acpi_evaluate_object(wblock->acpi_device->handle,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 632) "_WED", &input, out);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 633) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 634)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 635) return AE_NOT_FOUND;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 636) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 637) EXPORT_SYMBOL_GPL(wmi_get_event_data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 638)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 639) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 640) * wmi_has_guid - Check if a GUID is available
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 641) * @guid_string: 36 char string of the form fa50ff2b-f2e8-45de-83fa-65417f2f49ba
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 642) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 643) * Check if a given GUID is defined by _WDG
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 644) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 645) bool wmi_has_guid(const char *guid_string)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 646) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 647) return find_guid(guid_string, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 648) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 649) EXPORT_SYMBOL_GPL(wmi_has_guid);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 650)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 651) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 652) * wmi_get_acpi_device_uid() - Get _UID name of ACPI device that defines GUID
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 653) * @guid_string: 36 char string of the form fa50ff2b-f2e8-45de-83fa-65417f2f49ba
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 654) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 655) * Find the _UID of ACPI device associated with this WMI GUID.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 656) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 657) * Return: The ACPI _UID field value or NULL if the WMI GUID was not found
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 658) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 659) char *wmi_get_acpi_device_uid(const char *guid_string)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 660) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 661) struct wmi_block *wblock = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 662)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 663) if (!find_guid(guid_string, &wblock))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 664) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 665)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 666) return acpi_device_uid(wblock->acpi_device);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 667) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 668) EXPORT_SYMBOL_GPL(wmi_get_acpi_device_uid);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 669)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 670) static struct wmi_block *dev_to_wblock(struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 671) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 672) return container_of(dev, struct wmi_block, dev.dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 673) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 674)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 675) static struct wmi_device *dev_to_wdev(struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 676) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 677) return container_of(dev, struct wmi_device, dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 678) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 679)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 680) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 681) * sysfs interface
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 682) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 683) static ssize_t modalias_show(struct device *dev, struct device_attribute *attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 684) char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 685) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 686) struct wmi_block *wblock = dev_to_wblock(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 687)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 688) return sprintf(buf, "wmi:%pUL\n", wblock->gblock.guid);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 689) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 690) static DEVICE_ATTR_RO(modalias);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 691)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 692) static ssize_t guid_show(struct device *dev, struct device_attribute *attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 693) char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 694) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 695) struct wmi_block *wblock = dev_to_wblock(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 696)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 697) return sprintf(buf, "%pUL\n", wblock->gblock.guid);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 698) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 699) static DEVICE_ATTR_RO(guid);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 700)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 701) static ssize_t instance_count_show(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 702) struct device_attribute *attr, char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 703) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 704) struct wmi_block *wblock = dev_to_wblock(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 705)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 706) return sprintf(buf, "%d\n", (int)wblock->gblock.instance_count);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 707) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 708) static DEVICE_ATTR_RO(instance_count);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 709)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 710) static ssize_t expensive_show(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 711) struct device_attribute *attr, char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 712) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 713) struct wmi_block *wblock = dev_to_wblock(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 714)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 715) return sprintf(buf, "%d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 716) (wblock->gblock.flags & ACPI_WMI_EXPENSIVE) != 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 717) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 718) static DEVICE_ATTR_RO(expensive);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 719)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 720) static struct attribute *wmi_attrs[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 721) &dev_attr_modalias.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 722) &dev_attr_guid.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 723) &dev_attr_instance_count.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 724) &dev_attr_expensive.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 725) NULL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 726) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 727) ATTRIBUTE_GROUPS(wmi);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 728)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 729) static ssize_t notify_id_show(struct device *dev, struct device_attribute *attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 730) char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 731) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 732) struct wmi_block *wblock = dev_to_wblock(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 733)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 734) return sprintf(buf, "%02X\n", (unsigned int)wblock->gblock.notify_id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 735) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 736) static DEVICE_ATTR_RO(notify_id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 737)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 738) static struct attribute *wmi_event_attrs[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 739) &dev_attr_notify_id.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 740) NULL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 741) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 742) ATTRIBUTE_GROUPS(wmi_event);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 743)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 744) static ssize_t object_id_show(struct device *dev, struct device_attribute *attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 745) char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 746) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 747) struct wmi_block *wblock = dev_to_wblock(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 748)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 749) return sprintf(buf, "%c%c\n", wblock->gblock.object_id[0],
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 750) wblock->gblock.object_id[1]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 751) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 752) static DEVICE_ATTR_RO(object_id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 753)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 754) static ssize_t setable_show(struct device *dev, struct device_attribute *attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 755) char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 756) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 757) struct wmi_device *wdev = dev_to_wdev(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 758)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 759) return sprintf(buf, "%d\n", (int)wdev->setable);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 760) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 761) static DEVICE_ATTR_RO(setable);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 762)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 763) static struct attribute *wmi_data_attrs[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 764) &dev_attr_object_id.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 765) &dev_attr_setable.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 766) NULL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 767) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 768) ATTRIBUTE_GROUPS(wmi_data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 769)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 770) static struct attribute *wmi_method_attrs[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 771) &dev_attr_object_id.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 772) NULL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 773) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 774) ATTRIBUTE_GROUPS(wmi_method);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 775)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 776) static int wmi_dev_uevent(struct device *dev, struct kobj_uevent_env *env)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 777) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 778) struct wmi_block *wblock = dev_to_wblock(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 779)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 780) if (add_uevent_var(env, "MODALIAS=wmi:%pUL", wblock->gblock.guid))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 781) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 782)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 783) if (add_uevent_var(env, "WMI_GUID=%pUL", wblock->gblock.guid))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 784) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 785)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 786) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 787) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 788)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 789) static void wmi_dev_release(struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 790) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 791) struct wmi_block *wblock = dev_to_wblock(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 792)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 793) kfree(wblock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 794) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 795)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 796) static int wmi_dev_match(struct device *dev, struct device_driver *driver)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 797) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 798) struct wmi_driver *wmi_driver =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 799) container_of(driver, struct wmi_driver, driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 800) struct wmi_block *wblock = dev_to_wblock(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 801) const struct wmi_device_id *id = wmi_driver->id_table;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 802)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 803) if (id == NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 804) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 805)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 806) while (*id->guid_string) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 807) guid_t driver_guid;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 808)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 809) if (WARN_ON(guid_parse(id->guid_string, &driver_guid)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 810) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 811) if (!memcmp(&driver_guid, wblock->gblock.guid, 16))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 812) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 813)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 814) id++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 815) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 816)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 817) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 818) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 819) static int wmi_char_open(struct inode *inode, struct file *filp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 820) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 821) const char *driver_name = filp->f_path.dentry->d_iname;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 822) struct wmi_block *wblock = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 823) struct wmi_block *next = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 824)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 825) list_for_each_entry_safe(wblock, next, &wmi_block_list, list) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 826) if (!wblock->dev.dev.driver)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 827) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 828) if (strcmp(driver_name, wblock->dev.dev.driver->name) == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 829) filp->private_data = wblock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 830) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 831) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 832) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 833)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 834) if (!filp->private_data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 835) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 836)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 837) return nonseekable_open(inode, filp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 838) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 839)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 840) static ssize_t wmi_char_read(struct file *filp, char __user *buffer,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 841) size_t length, loff_t *offset)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 842) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 843) struct wmi_block *wblock = filp->private_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 844)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 845) return simple_read_from_buffer(buffer, length, offset,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 846) &wblock->req_buf_size,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 847) sizeof(wblock->req_buf_size));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 848) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 849)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 850) static long wmi_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 851) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 852) struct wmi_ioctl_buffer __user *input =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 853) (struct wmi_ioctl_buffer __user *) arg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 854) struct wmi_block *wblock = filp->private_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 855) struct wmi_ioctl_buffer *buf = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 856) struct wmi_driver *wdriver = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 857) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 858)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 859) if (_IOC_TYPE(cmd) != WMI_IOC)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 860) return -ENOTTY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 861)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 862) /* make sure we're not calling a higher instance than exists*/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 863) if (_IOC_NR(cmd) >= wblock->gblock.instance_count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 864) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 865)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 866) mutex_lock(&wblock->char_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 867) buf = wblock->handler_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 868) if (get_user(buf->length, &input->length)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 869) dev_dbg(&wblock->dev.dev, "Read length from user failed\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 870) ret = -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 871) goto out_ioctl;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 872) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 873) /* if it's too small, abort */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 874) if (buf->length < wblock->req_buf_size) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 875) dev_err(&wblock->dev.dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 876) "Buffer %lld too small, need at least %lld\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 877) buf->length, wblock->req_buf_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 878) ret = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 879) goto out_ioctl;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 880) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 881) /* if it's too big, warn, driver will only use what is needed */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 882) if (buf->length > wblock->req_buf_size)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 883) dev_warn(&wblock->dev.dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 884) "Buffer %lld is bigger than required %lld\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 885) buf->length, wblock->req_buf_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 886)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 887) /* copy the structure from userspace */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 888) if (copy_from_user(buf, input, wblock->req_buf_size)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 889) dev_dbg(&wblock->dev.dev, "Copy %llu from user failed\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 890) wblock->req_buf_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 891) ret = -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 892) goto out_ioctl;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 893) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 894)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 895) /* let the driver do any filtering and do the call */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 896) wdriver = container_of(wblock->dev.dev.driver,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 897) struct wmi_driver, driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 898) if (!try_module_get(wdriver->driver.owner)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 899) ret = -EBUSY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 900) goto out_ioctl;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 901) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 902) ret = wdriver->filter_callback(&wblock->dev, cmd, buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 903) module_put(wdriver->driver.owner);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 904) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 905) goto out_ioctl;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 906)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 907) /* return the result (only up to our internal buffer size) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 908) if (copy_to_user(input, buf, wblock->req_buf_size)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 909) dev_dbg(&wblock->dev.dev, "Copy %llu to user failed\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 910) wblock->req_buf_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 911) ret = -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 912) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 913)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 914) out_ioctl:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 915) mutex_unlock(&wblock->char_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 916) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 917) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 918)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 919) static const struct file_operations wmi_fops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 920) .owner = THIS_MODULE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 921) .read = wmi_char_read,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 922) .open = wmi_char_open,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 923) .unlocked_ioctl = wmi_ioctl,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 924) .compat_ioctl = compat_ptr_ioctl,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 925) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 926)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 927) static int wmi_dev_probe(struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 928) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 929) struct wmi_block *wblock = dev_to_wblock(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 930) struct wmi_driver *wdriver =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 931) container_of(dev->driver, struct wmi_driver, driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 932) int ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 933) char *buf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 934)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 935) if (ACPI_FAILURE(wmi_method_enable(wblock, 1)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 936) dev_warn(dev, "failed to enable device -- probing anyway\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 937)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 938) if (wdriver->probe) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 939) ret = wdriver->probe(dev_to_wdev(dev),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 940) find_guid_context(wblock, wdriver));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 941) if (ret != 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 942) goto probe_failure;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 943) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 944)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 945) /* driver wants a character device made */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 946) if (wdriver->filter_callback) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 947) /* check that required buffer size declared by driver or MOF */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 948) if (!wblock->req_buf_size) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 949) dev_err(&wblock->dev.dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 950) "Required buffer size not set\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 951) ret = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 952) goto probe_failure;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 953) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 954)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 955) wblock->handler_data = kmalloc(wblock->req_buf_size,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 956) GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 957) if (!wblock->handler_data) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 958) ret = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 959) goto probe_failure;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 960) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 961)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 962) buf = kasprintf(GFP_KERNEL, "wmi/%s", wdriver->driver.name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 963) if (!buf) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 964) ret = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 965) goto probe_string_failure;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 966) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 967) wblock->char_dev.minor = MISC_DYNAMIC_MINOR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 968) wblock->char_dev.name = buf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 969) wblock->char_dev.fops = &wmi_fops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 970) wblock->char_dev.mode = 0444;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 971) ret = misc_register(&wblock->char_dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 972) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 973) dev_warn(dev, "failed to register char dev: %d\n", ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 974) ret = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 975) goto probe_misc_failure;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 976) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 977) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 978)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 979) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 980)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 981) probe_misc_failure:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 982) kfree(buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 983) probe_string_failure:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 984) kfree(wblock->handler_data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 985) probe_failure:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 986) if (ACPI_FAILURE(wmi_method_enable(wblock, 0)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 987) dev_warn(dev, "failed to disable device\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 988) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 989) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 990)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 991) static int wmi_dev_remove(struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 992) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 993) struct wmi_block *wblock = dev_to_wblock(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 994) struct wmi_driver *wdriver =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 995) container_of(dev->driver, struct wmi_driver, driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 996) int ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 997)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 998) if (wdriver->filter_callback) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 999) misc_deregister(&wblock->char_dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1000) kfree(wblock->char_dev.name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1001) kfree(wblock->handler_data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1002) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1003)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1004) if (wdriver->remove)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1005) ret = wdriver->remove(dev_to_wdev(dev));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1006)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1007) if (ACPI_FAILURE(wmi_method_enable(wblock, 0)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1008) dev_warn(dev, "failed to disable device\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1009)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1010) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1011) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1012)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1013) static struct class wmi_bus_class = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1014) .name = "wmi_bus",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1015) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1016)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1017) static struct bus_type wmi_bus_type = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1018) .name = "wmi",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1019) .dev_groups = wmi_groups,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1020) .match = wmi_dev_match,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1021) .uevent = wmi_dev_uevent,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1022) .probe = wmi_dev_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1023) .remove = wmi_dev_remove,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1024) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1025)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1026) static const struct device_type wmi_type_event = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1027) .name = "event",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1028) .groups = wmi_event_groups,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1029) .release = wmi_dev_release,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1030) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1031)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1032) static const struct device_type wmi_type_method = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1033) .name = "method",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1034) .groups = wmi_method_groups,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1035) .release = wmi_dev_release,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1036) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1037)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1038) static const struct device_type wmi_type_data = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1039) .name = "data",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1040) .groups = wmi_data_groups,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1041) .release = wmi_dev_release,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1042) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1043)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1044) static int wmi_create_device(struct device *wmi_bus_dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1045) const struct guid_block *gblock,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1046) struct wmi_block *wblock,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1047) struct acpi_device *device)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1048) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1049) struct acpi_device_info *info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1050) char method[5];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1051) int result;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1052)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1053) if (gblock->flags & ACPI_WMI_EVENT) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1054) wblock->dev.dev.type = &wmi_type_event;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1055) goto out_init;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1056) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1057)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1058) if (gblock->flags & ACPI_WMI_METHOD) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1059) wblock->dev.dev.type = &wmi_type_method;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1060) mutex_init(&wblock->char_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1061) goto out_init;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1062) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1063)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1064) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1065) * Data Block Query Control Method (WQxx by convention) is
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1066) * required per the WMI documentation. If it is not present,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1067) * we ignore this data block.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1068) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1069) strcpy(method, "WQ");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1070) strncat(method, wblock->gblock.object_id, 2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1071) result = get_subobj_info(device->handle, method, &info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1072)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1073) if (result) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1074) dev_warn(wmi_bus_dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1075) "%s data block query control method not found\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1076) method);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1077) return result;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1078) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1079)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1080) wblock->dev.dev.type = &wmi_type_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1081)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1082) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1083) * The Microsoft documentation specifically states:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1084) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1085) * Data blocks registered with only a single instance
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1086) * can ignore the parameter.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1087) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1088) * ACPICA will get mad at us if we call the method with the wrong number
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1089) * of arguments, so check what our method expects. (On some Dell
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1090) * laptops, WQxx may not be a method at all.)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1091) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1092) if (info->type != ACPI_TYPE_METHOD || info->param_count == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1093) wblock->read_takes_no_args = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1094)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1095) kfree(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1096)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1097) strcpy(method, "WS");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1098) strncat(method, wblock->gblock.object_id, 2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1099) result = get_subobj_info(device->handle, method, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1100)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1101) if (result == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1102) wblock->dev.setable = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1103)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1104) out_init:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1105) wblock->dev.dev.bus = &wmi_bus_type;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1106) wblock->dev.dev.parent = wmi_bus_dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1107)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1108) dev_set_name(&wblock->dev.dev, "%pUL", gblock->guid);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1109)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1110) device_initialize(&wblock->dev.dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1111)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1112) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1113) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1114)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1115) static void wmi_free_devices(struct acpi_device *device)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1116) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1117) struct wmi_block *wblock, *next;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1118)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1119) /* Delete devices for all the GUIDs */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1120) list_for_each_entry_safe(wblock, next, &wmi_block_list, list) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1121) if (wblock->acpi_device == device) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1122) list_del(&wblock->list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1123) device_unregister(&wblock->dev.dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1124) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1125) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1126) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1127)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1128) static bool guid_already_parsed(struct acpi_device *device, const u8 *guid)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1129) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1130) struct wmi_block *wblock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1131)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1132) list_for_each_entry(wblock, &wmi_block_list, list) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1133) if (memcmp(wblock->gblock.guid, guid, 16) == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1134) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1135) * Because we historically didn't track the relationship
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1136) * between GUIDs and ACPI nodes, we don't know whether
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1137) * we need to suppress GUIDs that are unique on a
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1138) * given node but duplicated across nodes.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1139) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1140) dev_warn(&device->dev, "duplicate WMI GUID %pUL (first instance was on %s)\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1141) guid, dev_name(&wblock->acpi_device->dev));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1142) return true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1143) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1144) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1145)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1146) return false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1147) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1148)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1149) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1150) * Parse the _WDG method for the GUID data blocks
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1151) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1152) static int parse_wdg(struct device *wmi_bus_dev, struct acpi_device *device)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1153) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1154) struct acpi_buffer out = {ACPI_ALLOCATE_BUFFER, NULL};
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1155) const struct guid_block *gblock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1156) struct wmi_block *wblock, *next;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1157) union acpi_object *obj;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1158) acpi_status status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1159) int retval = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1160) u32 i, total;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1161)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1162) status = acpi_evaluate_object(device->handle, "_WDG", NULL, &out);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1163) if (ACPI_FAILURE(status))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1164) return -ENXIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1165)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1166) obj = (union acpi_object *) out.pointer;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1167) if (!obj)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1168) return -ENXIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1169)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1170) if (obj->type != ACPI_TYPE_BUFFER) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1171) retval = -ENXIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1172) goto out_free_pointer;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1173) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1174)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1175) gblock = (const struct guid_block *)obj->buffer.pointer;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1176) total = obj->buffer.length / sizeof(struct guid_block);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1177)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1178) for (i = 0; i < total; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1179) if (debug_dump_wdg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1180) wmi_dump_wdg(&gblock[i]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1181)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1182) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1183) * Some WMI devices, like those for nVidia hooks, have a
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1184) * duplicate GUID. It's not clear what we should do in this
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1185) * case yet, so for now, we'll just ignore the duplicate
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1186) * for device creation.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1187) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1188) if (guid_already_parsed(device, gblock[i].guid))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1189) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1190)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1191) wblock = kzalloc(sizeof(struct wmi_block), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1192) if (!wblock) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1193) retval = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1194) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1195) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1196)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1197) wblock->acpi_device = device;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1198) wblock->gblock = gblock[i];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1199)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1200) retval = wmi_create_device(wmi_bus_dev, &gblock[i], wblock, device);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1201) if (retval) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1202) kfree(wblock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1203) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1204) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1205)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1206) list_add_tail(&wblock->list, &wmi_block_list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1207)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1208) if (debug_event) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1209) wblock->handler = wmi_notify_debug;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1210) wmi_method_enable(wblock, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1211) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1212) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1213)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1214) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1215) * Now that all of the devices are created, add them to the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1216) * device tree and probe subdrivers.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1217) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1218) list_for_each_entry_safe(wblock, next, &wmi_block_list, list) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1219) if (wblock->acpi_device != device)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1220) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1221)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1222) retval = device_add(&wblock->dev.dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1223) if (retval) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1224) dev_err(wmi_bus_dev, "failed to register %pUL\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1225) wblock->gblock.guid);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1226) if (debug_event)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1227) wmi_method_enable(wblock, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1228) list_del(&wblock->list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1229) put_device(&wblock->dev.dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1230) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1231) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1232)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1233) out_free_pointer:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1234) kfree(out.pointer);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1235) return retval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1236) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1237)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1238) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1239) * WMI can have EmbeddedControl access regions. In which case, we just want to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1240) * hand these off to the EC driver.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1241) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1242) static acpi_status
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1243) acpi_wmi_ec_space_handler(u32 function, acpi_physical_address address,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1244) u32 bits, u64 *value,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1245) void *handler_context, void *region_context)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1246) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1247) int result = 0, i = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1248) u8 temp = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1249)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1250) if ((address > 0xFF) || !value)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1251) return AE_BAD_PARAMETER;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1252)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1253) if (function != ACPI_READ && function != ACPI_WRITE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1254) return AE_BAD_PARAMETER;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1255)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1256) if (bits != 8)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1257) return AE_BAD_PARAMETER;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1258)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1259) if (function == ACPI_READ) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1260) result = ec_read(address, &temp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1261) (*value) |= ((u64)temp) << i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1262) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1263) temp = 0xff & ((*value) >> i);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1264) result = ec_write(address, temp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1265) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1266)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1267) switch (result) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1268) case -EINVAL:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1269) return AE_BAD_PARAMETER;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1270) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1271) case -ENODEV:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1272) return AE_NOT_FOUND;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1273) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1274) case -ETIME:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1275) return AE_TIME;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1276) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1277) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1278) return AE_OK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1279) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1280) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1281)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1282) static void acpi_wmi_notify_handler(acpi_handle handle, u32 event,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1283) void *context)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1284) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1285) struct guid_block *block;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1286) struct wmi_block *wblock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1287) bool found_it = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1288)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1289) list_for_each_entry(wblock, &wmi_block_list, list) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1290) block = &wblock->gblock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1291)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1292) if (wblock->acpi_device->handle == handle &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1293) (block->flags & ACPI_WMI_EVENT) &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1294) (block->notify_id == event))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1295) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1296) found_it = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1297) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1298) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1299) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1300)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1301) if (!found_it)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1302) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1303)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1304) /* If a driver is bound, then notify the driver. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1305) if (wblock->dev.dev.driver) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1306) struct wmi_driver *driver;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1307) struct acpi_object_list input;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1308) union acpi_object params[1];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1309) struct acpi_buffer evdata = { ACPI_ALLOCATE_BUFFER, NULL };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1310) acpi_status status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1311)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1312) driver = container_of(wblock->dev.dev.driver,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1313) struct wmi_driver, driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1314)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1315) input.count = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1316) input.pointer = params;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1317) params[0].type = ACPI_TYPE_INTEGER;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1318) params[0].integer.value = event;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1319)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1320) status = acpi_evaluate_object(wblock->acpi_device->handle,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1321) "_WED", &input, &evdata);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1322) if (ACPI_FAILURE(status)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1323) dev_warn(&wblock->dev.dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1324) "failed to get event data\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1325) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1326) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1327)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1328) if (driver->notify)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1329) driver->notify(&wblock->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1330) (union acpi_object *)evdata.pointer);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1331)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1332) kfree(evdata.pointer);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1333) } else if (wblock->handler) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1334) /* Legacy handler */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1335) wblock->handler(event, wblock->handler_data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1336) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1337)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1338) if (debug_event)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1339) pr_info("DEBUG Event GUID: %pUL\n", wblock->gblock.guid);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1340)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1341) acpi_bus_generate_netlink_event(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1342) wblock->acpi_device->pnp.device_class,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1343) dev_name(&wblock->dev.dev),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1344) event, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1345)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1346) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1347)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1348) static int acpi_wmi_remove(struct platform_device *device)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1349) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1350) struct acpi_device *acpi_device = ACPI_COMPANION(&device->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1351)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1352) acpi_remove_notify_handler(acpi_device->handle, ACPI_DEVICE_NOTIFY,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1353) acpi_wmi_notify_handler);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1354) acpi_remove_address_space_handler(acpi_device->handle,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1355) ACPI_ADR_SPACE_EC, &acpi_wmi_ec_space_handler);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1356) wmi_free_devices(acpi_device);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1357) device_destroy(&wmi_bus_class, MKDEV(0, 0));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1358)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1359) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1360) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1361)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1362) static int acpi_wmi_probe(struct platform_device *device)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1363) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1364) struct acpi_device *acpi_device;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1365) struct device *wmi_bus_dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1366) acpi_status status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1367) int error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1368)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1369) acpi_device = ACPI_COMPANION(&device->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1370) if (!acpi_device) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1371) dev_err(&device->dev, "ACPI companion is missing\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1372) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1373) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1374)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1375) status = acpi_install_address_space_handler(acpi_device->handle,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1376) ACPI_ADR_SPACE_EC,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1377) &acpi_wmi_ec_space_handler,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1378) NULL, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1379) if (ACPI_FAILURE(status)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1380) dev_err(&device->dev, "Error installing EC region handler\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1381) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1382) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1383)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1384) status = acpi_install_notify_handler(acpi_device->handle,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1385) ACPI_DEVICE_NOTIFY,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1386) acpi_wmi_notify_handler,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1387) NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1388) if (ACPI_FAILURE(status)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1389) dev_err(&device->dev, "Error installing notify handler\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1390) error = -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1391) goto err_remove_ec_handler;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1392) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1393)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1394) wmi_bus_dev = device_create(&wmi_bus_class, &device->dev, MKDEV(0, 0),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1395) NULL, "wmi_bus-%s", dev_name(&device->dev));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1396) if (IS_ERR(wmi_bus_dev)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1397) error = PTR_ERR(wmi_bus_dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1398) goto err_remove_notify_handler;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1399) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1400) dev_set_drvdata(&device->dev, wmi_bus_dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1401)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1402) error = parse_wdg(wmi_bus_dev, acpi_device);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1403) if (error) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1404) pr_err("Failed to parse WDG method\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1405) goto err_remove_busdev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1406) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1407)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1408) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1409)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1410) err_remove_busdev:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1411) device_destroy(&wmi_bus_class, MKDEV(0, 0));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1412)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1413) err_remove_notify_handler:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1414) acpi_remove_notify_handler(acpi_device->handle, ACPI_DEVICE_NOTIFY,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1415) acpi_wmi_notify_handler);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1416)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1417) err_remove_ec_handler:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1418) acpi_remove_address_space_handler(acpi_device->handle,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1419) ACPI_ADR_SPACE_EC,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1420) &acpi_wmi_ec_space_handler);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1421)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1422) return error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1423) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1424)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1425) int __must_check __wmi_driver_register(struct wmi_driver *driver,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1426) struct module *owner)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1427) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1428) driver->driver.owner = owner;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1429) driver->driver.bus = &wmi_bus_type;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1430)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1431) return driver_register(&driver->driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1432) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1433) EXPORT_SYMBOL(__wmi_driver_register);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1434)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1435) void wmi_driver_unregister(struct wmi_driver *driver)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1436) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1437) driver_unregister(&driver->driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1438) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1439) EXPORT_SYMBOL(wmi_driver_unregister);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1440)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1441) static int __init acpi_wmi_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1442) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1443) int error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1444)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1445) if (acpi_disabled)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1446) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1447)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1448) error = class_register(&wmi_bus_class);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1449) if (error)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1450) return error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1451)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1452) error = bus_register(&wmi_bus_type);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1453) if (error)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1454) goto err_unreg_class;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1455)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1456) error = platform_driver_register(&acpi_wmi_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1457) if (error) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1458) pr_err("Error loading mapper\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1459) goto err_unreg_bus;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1460) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1461)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1462) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1463)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1464) err_unreg_bus:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1465) bus_unregister(&wmi_bus_type);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1466)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1467) err_unreg_class:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1468) class_unregister(&wmi_bus_class);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1469)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1470) return error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1471) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1472)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1473) static void __exit acpi_wmi_exit(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1474) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1475) platform_driver_unregister(&acpi_wmi_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1476) bus_unregister(&wmi_bus_type);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1477) class_unregister(&wmi_bus_class);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1478) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1479)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1480) subsys_initcall_sync(acpi_wmi_init);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1481) module_exit(acpi_wmi_exit);