]> www.infradead.org Git - users/dwmw2/linux.git/commitdiff
platform/x86: wmi: Support reading/writing 16 bit EC values
authorArmin Wolf <W_Armin@gmx.de>
Thu, 14 Mar 2024 18:45:37 +0000 (19:45 +0100)
committerHans de Goede <hdegoede@redhat.com>
Mon, 25 Mar 2024 14:53:51 +0000 (15:53 +0100)
The ACPI EC address space handler currently only supports
reading/writing 8 bit values. Some firmware implementations however
want to access for example 16 bit values, which is perfectly legal
according to the ACPI spec.

Add support for reading/writing such values.

Tested on a Dell Inspiron 3505 and a Asus Prime B650-Plus.

Reviewed-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
Signed-off-by: Armin Wolf <W_Armin@gmx.de>
Reviewed-by: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com>
Link: https://lore.kernel.org/r/20240314184538.2933-1-W_Armin@gmx.de
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
drivers/platform/x86/wmi.c

index 1920e115da893a11335495d8238f260e13c9b9df..9602658711cf31366303aeeeacb0f9bc6e46d8d2 100644 (file)
@@ -1153,6 +1153,34 @@ static int parse_wdg(struct device *wmi_bus_dev, struct platform_device *pdev)
        return 0;
 }
 
+static int ec_read_multiple(u8 address, u8 *buffer, size_t bytes)
+{
+       size_t i;
+       int ret;
+
+       for (i = 0; i < bytes; i++) {
+               ret = ec_read(address + i, &buffer[i]);
+               if (ret < 0)
+                       return ret;
+       }
+
+       return 0;
+}
+
+static int ec_write_multiple(u8 address, u8 *buffer, size_t bytes)
+{
+       size_t i;
+       int ret;
+
+       for (i = 0; i < bytes; i++) {
+               ret = ec_write(address + i, buffer[i]);
+               if (ret < 0)
+                       return ret;
+       }
+
+       return 0;
+}
+
 /*
  * WMI can have EmbeddedControl access regions. In which case, we just want to
  * hand these off to the EC driver.
@@ -1162,27 +1190,27 @@ acpi_wmi_ec_space_handler(u32 function, acpi_physical_address address,
                          u32 bits, u64 *value,
                          void *handler_context, void *region_context)
 {
-       int result = 0;
-       u8 temp = 0;
+       int bytes = bits / BITS_PER_BYTE;
+       int ret;
 
-       if ((address > 0xFF) || !value)
+       if (!value)
+               return AE_NULL_ENTRY;
+
+       if (!bytes || bytes > sizeof(*value))
                return AE_BAD_PARAMETER;
 
-       if (function != ACPI_READ && function != ACPI_WRITE)
+       if (address > U8_MAX || address + bytes - 1 > U8_MAX)
                return AE_BAD_PARAMETER;
 
-       if (bits != 8)
+       if (function != ACPI_READ && function != ACPI_WRITE)
                return AE_BAD_PARAMETER;
 
-       if (function == ACPI_READ) {
-               result = ec_read(address, &temp);
-               *value = temp;
-       } else {
-               temp = 0xff & *value;
-               result = ec_write(address, temp);
-       }
+       if (function == ACPI_READ)
+               ret = ec_read_multiple(address, (u8 *)value, bytes);
+       else
+               ret = ec_write_multiple(address, (u8 *)value, bytes);
 
-       switch (result) {
+       switch (ret) {
        case -EINVAL:
                return AE_BAD_PARAMETER;
        case -ENODEV: