Re: [PATCH v12] platform/chrome: Add ChromeOS ACPI device driver

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Thu, May 12, 2022 at 7:34 AM Muhammad Usama Anjum
<usama.anjum@xxxxxxxxxxxxx> wrote:
>
> From: Enric Balletbo i Serra <enric.balletbo@xxxxxxxxxxxxx>
>
> The x86 Chromebooks have the ChromeOS ACPI device. This driver attaches
> to the ChromeOS ACPI device and exports the values reported by ACPI in a
> sysfs directory. This data isn't present in ACPI tables when read
> through ACPI tools, hence a driver is needed to do it. The driver gets
> data from firmware using the ACPI component of the kernel. The ACPI values
> are presented in string form (numbers as decimal values) or binary
> blobs, and can be accessed as the contents of the appropriate read only
> files in the standard ACPI device's sysfs directory tree. This data is
> consumed by the ChromeOS user space.
>
> Reviewed-by: Greg Kroah-Hartman <gregkh@xxxxxxxxxxxxxxxxxxx>
> Signed-off-by: Enric Balletbo i Serra <enric.balletbo@xxxxxxxxxxxxx>
> Co-developed-by: Muhammad Usama Anjum <usama.anjum@xxxxxxxxxxxxx>
> Signed-off-by: Muhammad Usama Anjum <usama.anjum@xxxxxxxxxxxxx>

Acked-by: Rafael J. Wysocki <rafael.j.wysocki@xxxxxxxxx>

> ---
> Changes in v12:
> - Use one type of correct commenting style
> - Optimize parse_attr_name
> - Made code a little more readable at some places
> - Remove usage of ACPI_PTR
>
> Changes in v11:
> - Use __ATTR macro
> - Remove local variable length and return instead
>
> Changes in v10:
> - Remove COMPILE_TEST as driver depends on ACPI component which isn't
>   enabled by COMPILE_TEST itself.
> - Fix build warnings
>
> Changes in v9:
> - Changed the implementation completely
> - Move the driver to drivers/platform/chrome
> - Remove Acked-by Rafael as driver has changed
> - Corrected some typos
> - Changed the author of the module
>
> Changes in v8:
> - Change struct platform_driver name from chromeos_acpi_driver to
>   chromeos_acpi_device_driver
>
> Changes in v7:
> - Rename acpi_chromeos Kconfig option to chromeos_acpi
> - Change this acpi driver to platform driver
> - Minor cosmetic changes
>
> There were the following concerns on v4 which have been delt with in
> v5/v6:
> - Remove BINF.{0,1,4} from sysfs as they are reserved and not used
>   anymore
> - Reword the description of MECK
> - Change function name from chromeos_acpi_alloc_name() to
>   chromeos_acpi_gen_file_name()
> - Remove local variable obj in chromeos_acpi_add_method()
> - Replace usage of dev_info() to dev_dbg()
> - Improve the description of the patch
> - Add the firmware interface document which serves as primary
>   documentation and garantees that this interface will not change
> - GGL0001 is valid PNP ID of the Google. PNP ID can be used with the
>   ACPI devices. Consensus was developed on it in discussion of v4.
>
> Changes in v6:
> - Correct authorship and path email's From
> - Add changelog between v4 and v5 in detail
> - Add copywrite year 2022
> - Improve the description and add concerns from V4 which have been fixed
>
> Changes in v5:
> - Improve the description of the patch
> - Document firmware interface
> - Update sysfs interface documentation
> - Remove binf{0,1,4} as they have been deprecated
> - Update some cleanup logic in case of error
>   - Remove freeing of chromeos_acpi.root explicitely in
>     chromeos_acpi_device_remove() as it'll be automatically freed by
>     chromeos_acpi_remove_groups()
>   - If sysfs_create_groups() fails in chromeos_acpi_process_mlst(),
>     cleanup all groups
> - Cosmetic changes
>
> Changes in v4:
> https://lore.kernel.org/lkml/20200413134611.478441-1-enric.balletbo@xxxxxxxxxxxxx/t/
> - Add COMPILE_TEST to increase build coverage.
> - Add sysfs ABI documentation.
> - Rebased on top of 5.7-rc1 and solve conflicts.
> - Cc ACPI maintainers.
>
> Changes in v3:
> - Use attribute groups instead of adding files "by hand".
> - Do not use "raw" kobject to create directories.
> - Do not abuse of the platform_device interface. Remove it.
>
> Changes in v2:
> - Note that this version is a total rework, with those major changes:
> - Use lists to track dinamically allocated attributes and groups.
> - Use sysfs binary attributes to store the ACPI contents.
> - Remove all the functionalities except the one that creates the sysfs files.
> ---
>  .../ABI/testing/sysfs-driver-chromeos-acpi    | 126 ++++++
>  .../acpi/chromeos-acpi-device.rst             | 363 ++++++++++++++++++
>  Documentation/firmware-guide/acpi/index.rst   |   1 +
>  drivers/platform/chrome/Kconfig               |  11 +
>  drivers/platform/chrome/Makefile              |   1 +
>  drivers/platform/chrome/chromeos_acpi.c       | 259 +++++++++++++
>  6 files changed, 761 insertions(+)
>  create mode 100644 Documentation/ABI/testing/sysfs-driver-chromeos-acpi
>  create mode 100644 Documentation/firmware-guide/acpi/chromeos-acpi-device.rst
>  create mode 100644 drivers/platform/chrome/chromeos_acpi.c
>
> diff --git a/Documentation/ABI/testing/sysfs-driver-chromeos-acpi b/Documentation/ABI/testing/sysfs-driver-chromeos-acpi
> new file mode 100644
> index 0000000000000..5b59ef9d7b371
> --- /dev/null
> +++ b/Documentation/ABI/testing/sysfs-driver-chromeos-acpi
> @@ -0,0 +1,126 @@
> +What:          /sys/bus/platform/devices/GGL0001:*/BINF.2
> +Date:          May 2022
> +KernelVersion: 5.19
> +Description:
> +               This file shows information about the current boot of
> +               the active EC firmware.
> +                 * 0 - Read only (recovery) firmware.
> +                 * 1 - Rewritable firmware.
> +
> +What:          /sys/bus/platform/devices/GGL0001:*/BINF.3
> +Date:          May 2022
> +KernelVersion: 5.19
> +Description:
> +               This file shows information about the current boot of
> +               the active main firmware type.
> +                 * 0 - Recovery.
> +                 * 1 - Normal.
> +                 * 2 - Developer.
> +                 * 3 - Netboot (factory installation only).
> +
> +What:          /sys/bus/platform/devices/GGL0001:*/CHSW
> +Date:          May 2022
> +KernelVersion: 5.19
> +Description:
> +               This file shows the switch position for the Chrome OS specific
> +               hardware switches.
> +                 * 0   - No changes.
> +                 * 2   - Recovery button was pressed when firmware booted.
> +                 * 4   - Recovery button was pressed when EC firmware booted.
> +                 * 32  - Developer switch was enabled when firmware booted.
> +                 * 512 - Firmware write protection was disabled when firmware
> +                         booted.
> +
> +What:          /sys/bus/platform/devices/GGL0001:*/FMAP
> +Date:          May 2022
> +KernelVersion: 5.19
> +Description:
> +               This file shows the physical memory address of the start of
> +               the main processor firmware flashmap.
> +
> +What:          /sys/bus/platform/devices/GGL0001:*/FRID
> +Date:          May 2022
> +KernelVersion: 5.19
> +Description:
> +               This file shows the firmware version for the read-only portion
> +               of the main processor firmware.
> +
> +What:          /sys/bus/platform/devices/GGL0001:*/FWID
> +Date:          May 2022
> +KernelVersion: 5.19
> +Description:
> +               This file shows the firmware version for the rewritable portion
> +               of the main processor firmware.
> +
> +What:          /sys/bus/platform/devices/GGL0001:*/GPIO.X/GPIO.0
> +Date:          May 2022
> +KernelVersion: 5.19
> +Description:
> +               This file shows the type of the GPIO signal for the Chrome OS
> +               specific GPIO assignments.
> +                 * 1   - Recovery button.
> +                 * 2   - Developer mode switch.
> +                 * 3   - Firmware write protection switch.
> +                 * 256 to 511 - Debug header GPIO 0 to GPIO 255.
> +
> +What:          /sys/bus/platform/devices/GGL0001:*/GPIO.X/GPIO.1
> +Date:          May 2022
> +KernelVersion: 5.19
> +Description:
> +               This file shows the signal attributes of the GPIO signal.
> +                 * 0 - Signal is active low.
> +                 * 1 - Signal is active high.
> +
> +What:          /sys/bus/platform/devices/GGL0001:*/GPIO.X/GPIO.2
> +Date:          May 2022
> +KernelVersion: 5.19
> +Description:
> +               This file shows the GPIO number on the specified GPIO
> +               controller.
> +
> +What:          /sys/bus/platform/devices/GGL0001:*/GPIO.X/GPIO.3
> +Date:          May 2022
> +KernelVersion: 5.19
> +Description:
> +               This file shows the name of the GPIO controller.
> +
> +What:          /sys/bus/platform/devices/GGL0001:*/HWID
> +Date:          May 2022
> +KernelVersion: 5.19
> +Description:
> +               This file shows the hardware ID for the Chromebook.
> +
> +What:          /sys/bus/platform/devices/GGL0001:*/MECK
> +Date:          May 2022
> +KernelVersion: 5.19
> +Description:
> +               This binary file returns the SHA-1 or SHA-256 hash that is
> +               read out of the Management Engine extended registers during
> +               boot. The hash is exported vi ACPI so the OS can verify that
> +               the Management Engine firmware has not changed. If Management
> +               Engine is not present, or if the firmware was unable to read the
> +               extended registers, this buffer size can be zero.
> +
> +What:          /sys/bus/platform/devices/GGL0001:*/VBNV.0
> +Date:          May 2022
> +KernelVersion: 5.19
> +Description:
> +               This file shows the offset in CMOS bank 0 of the verified boot
> +               non-volatile storage block, counting from the first writable
> +               CMOS byte (that is, 'offset = 0' is the byte following the 14
> +               bytes of clock data).
> +
> +What:          /sys/bus/platform/devices/GGL0001:*/VBNV.1
> +Date:          May 2022
> +KernelVersion: 5.19
> +Description:
> +               This file shows the size in bytes of the verified boot
> +               non-volatile storage block.
> +
> +What:          /sys/bus/platform/devices/GGL0001:*/VDAT
> +Date:          May 2022
> +KernelVersion: 5.19
> +Description:
> +               This binary file returns the verified boot data block shared
> +               between the firmware verification step and the kernel
> +               verification step.
> diff --git a/Documentation/firmware-guide/acpi/chromeos-acpi-device.rst b/Documentation/firmware-guide/acpi/chromeos-acpi-device.rst
> new file mode 100644
> index 0000000000000..f37fc90ce340e
> --- /dev/null
> +++ b/Documentation/firmware-guide/acpi/chromeos-acpi-device.rst
> @@ -0,0 +1,363 @@
> +.. SPDX-License-Identifier: GPL-2.0
> +
> +=====================
> +Chrome OS ACPI Device
> +=====================
> +
> +Hardware functionality specific to Chrome OS is exposed through a Chrome OS ACPI device.
> +The plug and play ID of a Chrome OS ACPI device is GGL0001. GGL is a valid PNP ID of Google.
> +PNP ID can be used with the ACPI devices according to the guidelines. The following ACPI
> +objects are supported:
> +
> +.. flat-table:: Supported ACPI Objects
> +   :widths: 1 2
> +   :header-rows: 1
> +
> +   * - Object
> +     - Description
> +
> +   * - CHSW
> +     - Chrome OS switch positions
> +
> +   * - HWID
> +     - Chrome OS hardware ID
> +
> +   * - FWID
> +     - Chrome OS firmware version
> +
> +   * - FRID
> +     - Chrome OS read-only firmware version
> +
> +   * - BINF
> +     - Chrome OS boot information
> +
> +   * - GPIO
> +     - Chrome OS GPIO assignments
> +
> +   * - VBNV
> +     - Chrome OS NVRAM locations
> +
> +   * - VDTA
> +     - Chrome OS verified boot data
> +
> +   * - FMAP
> +     - Chrome OS flashmap base address
> +
> +   * - MLST
> +     - Chrome OS method list
> +
> +CHSW (Chrome OS switch positions)
> +=================================
> +This control method returns the switch positions for Chrome OS specific hardware switches.
> +
> +Arguments:
> +----------
> +None
> +
> +Result code:
> +------------
> +An integer containing the switch positions as bitfields:
> +
> +.. flat-table::
> +   :widths: 1 2
> +
> +   * - 0x00000002
> +     - Recovery button was pressed when x86 firmware booted.
> +
> +   * - 0x00000004
> +     - Recovery button was pressed when EC firmware booted. (required if EC EEPROM is
> +       rewritable; otherwise optional)
> +
> +   * - 0x00000020
> +     - Developer switch was enabled when x86 firmware booted.
> +
> +   * - 0x00000200
> +     - Firmware write protection was disabled when x86 firmware booted. (required if
> +       firmware write protection is controlled through x86 BIOS; otherwise optional)
> +
> +All other bits are reserved and should be set to 0.
> +
> +HWID (Chrome OS hardware ID)
> +============================
> +This control method returns the hardware ID for the Chromebook.
> +
> +Arguments:
> +----------
> +None
> +
> +Result code:
> +------------
> +A null-terminated ASCII string containing the hardware ID from the Model-Specific Data area of
> +EEPROM.
> +
> +Note that the hardware ID can be up to 256 characters long, including the terminating null.
> +
> +FWID (Chrome OS firmware version)
> +=================================
> +This control method returns the firmware version for the rewritable portion of the main
> +processor firmware.
> +
> +Arguments:
> +----------
> +None
> +
> +Result code:
> +------------
> +A null-terminated ASCII string containing the complete firmware version for the rewritable
> +portion of the main processor firmware.
> +
> +FRID (Chrome OS read-only firmware version)
> +===========================================
> +This control method returns the firmware version for the read-only portion of the main
> +processor firmware.
> +
> +Arguments:
> +----------
> +None
> +
> +Result code:
> +------------
> +A null-terminated ASCII string containing the complete firmware version for the read-only
> +(bootstrap + recovery ) portion of the main processor firmware.
> +
> +BINF (Chrome OS boot information)
> +=================================
> +This control method returns information about the current boot.
> +
> +Arguments:
> +----------
> +None
> +
> +Result code:
> +------------
> +
> +.. code-block::
> +
> +   Package {
> +           Reserved1
> +           Reserved2
> +           Active EC Firmware
> +           Active Main Firmware Type
> +           Reserved5
> +   }
> +
> +.. flat-table::
> +   :widths: 1 1 2
> +   :header-rows: 1
> +
> +   * - Field
> +     - Format
> +     - Description
> +
> +   * - Reserved1
> +     - DWORD
> +     - Set to 256 (0x100). This indicates this field is no longer used.
> +
> +   * - Reserved2
> +     - DWORD
> +     - Set to 256 (0x100). This indicates this field is no longer used.
> +
> +   * - Active EC firmware
> +     - DWORD
> +     - The EC firmware which was used during boot.
> +
> +       - 0 - Read-only (recovery) firmware
> +       - 1 - Rewritable firmware.
> +
> +       Set to 0 if EC firmware is always read-only.
> +
> +   * - Active Main Firmware Type
> +     - DWORD
> +     - The main firmware type which was used during boot.
> +
> +       - 0 - Recovery
> +       - 1 - Normal
> +       - 2 - Developer
> +       - 3 - netboot (factory installation only)
> +
> +       Other values are reserved.
> +
> +   * - Reserved5
> +     - DWORD
> +     - Set to 256 (0x100). This indicates this field is no longer used.
> +
> +GPIO (Chrome OS GPIO assignments)
> +=================================
> +This control method returns information about Chrome OS specific GPIO assignments for
> +Chrome OS hardware, so the kernel can directly control that hardware.
> +
> +Arguments:
> +----------
> +None
> +
> +Result code:
> +------------
> +.. code-block::
> +
> +        Package {
> +                Package {
> +                        // First GPIO assignment
> +                        Signal Type        //DWORD
> +                        Attributes         //DWORD
> +                        Controller Offset  //DWORD
> +                        Controller Name    //ASCIIZ
> +                },
> +                ...
> +                Package {
> +                        // Last GPIO assignment
> +                        Signal Type        //DWORD
> +                        Attributes         //DWORD
> +                        Controller Offset  //DWORD
> +                        Controller Name    //ASCIIZ
> +                }
> +        }
> +
> +Where ASCIIZ means a null-terminated ASCII string.
> +
> +.. flat-table::
> +   :widths: 1 1 2
> +   :header-rows: 1
> +
> +   * - Field
> +     - Format
> +     - Description
> +
> +   * - Signal Type
> +     - DWORD
> +     - Type of GPIO signal
> +
> +       - 0x00000001 - Recovery button
> +       - 0x00000002 - Developer mode switch
> +       - 0x00000003 - Firmware write protection switch
> +       - 0x00000100 - Debug header GPIO 0
> +       - ...
> +       - 0x000001FF - Debug header GPIO 255
> +
> +       Other values are reserved.
> +
> +   * - Attributes
> +     - DWORD
> +     - Signal attributes as bitfields:
> +
> +       - 0x00000001 - Signal is active-high (for button, a GPIO value
> +         of 1 means the button is pressed; for switches, a GPIO value
> +         of 1 means the switch is enabled). If this bit is 0, the signal
> +         is active low. Set to 0 for debug header GPIOs.
> +
> +   * - Controller Offset
> +     - DWORD
> +     - GPIO number on the specified controller.
> +
> +   * - Controller Name
> +     - ASCIIZ
> +     - Name of the controller for the GPIO.
> +       Currently supported names:
> +       "NM10" - Intel NM10 chip
> +
> +VBNV (Chrome OS NVRAM locations)
> +================================
> +This control method returns information about the NVRAM (CMOS) locations used to
> +communicate with the BIOS.
> +
> +Arguments:
> +----------
> +None
> +
> +Result code:
> +------------
> +.. code-block::
> +
> +        Package {
> +                NV Storage Block Offset  //DWORD
> +                NV Storage Block Size    //DWORD
> +        }
> +
> +.. flat-table::
> +   :widths: 1 1 2
> +   :header-rows: 1
> +
> +   * - Field
> +     - Format
> +     - Description
> +
> +   * - NV Storage Block Offset
> +     - DWORD
> +     - Offset in CMOS bank 0 of the verified boot non-volatile storage block, counting from
> +       the first writable CMOS byte (that is, offset=0 is the byte following the 14 bytes of
> +       clock data).
> +
> +   * - NV Storage Block Size
> +     - DWORD
> +     - Size in bytes of the verified boot non-volatile storage block.
> +
> +FMAP (Chrome OS flashmap address)
> +=================================
> +This control method returns the physical memory address of the start of the main processor
> +firmware flashmap.
> +
> +Arguments:
> +----------
> +None
> +
> +NoneResult code:
> +----------------
> +A DWORD containing the physical memory address of the start of the main processor firmware
> +flashmap.
> +
> +VDTA (Chrome OS verified boot data)
> +===================================
> +This control method returns the verified boot data block shared between the firmware
> +verification step and the kernel verification step.
> +
> +Arguments:
> +----------
> +None
> +
> +Result code:
> +------------
> +A buffer containing the verified boot data block.
> +
> +MECK (Management Engine Checksum)
> +=================================
> +This control method returns the SHA-1 or SHA-256 hash that is read out of the Management
> +Engine extended registers during boot. The hash is exported via ACPI so the OS can verify that
> +the ME firmware has not changed. If Management Engine is not present, or if the firmware was
> +unable to read the extended registers, this buffer can be zero.
> +
> +Arguments:
> +----------
> +None
> +
> +Result code:
> +------------
> +A buffer containing the ME hash.
> +
> +MLST (Chrome OS method list)
> +============================
> +This control method returns a list of the other control methods supported by the Chrome OS
> +hardware device.
> +
> +Arguments:
> +----------
> +None
> +
> +Result code:
> +------------
> +A package containing a list of null-terminated ASCII strings, one for each control method
> +supported by the Chrome OS hardware device, not including the MLST method itself.
> +For this version of the specification, the result is:
> +
> +.. code-block::
> +
> +        Package {
> +                "CHSW",
> +                "FWID",
> +                "HWID",
> +                "FRID",
> +                "BINF",
> +                "GPIO",
> +                "VBNV",
> +                "FMAP",
> +                "VDTA",
> +                "MECK"
> +        }
> diff --git a/Documentation/firmware-guide/acpi/index.rst b/Documentation/firmware-guide/acpi/index.rst
> index b053b0c3d6969..b6a42f4ffe032 100644
> --- a/Documentation/firmware-guide/acpi/index.rst
> +++ b/Documentation/firmware-guide/acpi/index.rst
> @@ -29,3 +29,4 @@ ACPI Support
>     non-d0-probe
>     extcon-intel-int3496
>     intel-pmc-mux
> +   chromeos-acpi-device
> diff --git a/drivers/platform/chrome/Kconfig b/drivers/platform/chrome/Kconfig
> index 75e93efd669f0..717299cbccac6 100644
> --- a/drivers/platform/chrome/Kconfig
> +++ b/drivers/platform/chrome/Kconfig
> @@ -15,6 +15,17 @@ menuconfig CHROME_PLATFORMS
>
>  if CHROME_PLATFORMS
>
> +config CHROMEOS_ACPI
> +       tristate "ChromeOS specific ACPI extensions"
> +       depends on ACPI
> +       help
> +         This driver provides the firmware interface for the services
> +         exported through the ChromeOS interfaces when using ChromeOS
> +         ACPI firmware.
> +
> +         If you have an ACPI-compatible Chromebook, say Y or M here.
> +         The module will be called chromeos_acpi.
> +
>  config CHROMEOS_LAPTOP
>         tristate "Chrome OS Laptop"
>         depends on I2C && DMI && X86
> diff --git a/drivers/platform/chrome/Makefile b/drivers/platform/chrome/Makefile
> index 6420ca129548e..52f5a2dde8b81 100644
> --- a/drivers/platform/chrome/Makefile
> +++ b/drivers/platform/chrome/Makefile
> @@ -4,6 +4,7 @@
>  CFLAGS_cros_ec_trace.o:=               -I$(src)
>  CFLAGS_cros_ec_sensorhub_ring.o:=      -I$(src)
>
> +obj-$(CONFIG_CHROMEOS_ACPI)            += chromeos_acpi.o
>  obj-$(CONFIG_CHROMEOS_LAPTOP)          += chromeos_laptop.o
>  obj-$(CONFIG_CHROMEOS_PRIVACY_SCREEN)  += chromeos_privacy_screen.o
>  obj-$(CONFIG_CHROMEOS_PSTORE)          += chromeos_pstore.o
> diff --git a/drivers/platform/chrome/chromeos_acpi.c b/drivers/platform/chrome/chromeos_acpi.c
> new file mode 100644
> index 0000000000000..0434e15569046
> --- /dev/null
> +++ b/drivers/platform/chrome/chromeos_acpi.c
> @@ -0,0 +1,259 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * ChromeOS specific ACPI extensions
> + *
> + * Copyright 2022 Google LLC
> + *
> + * This driver attaches to the ChromeOS ACPI device and then exports the
> + * values reported by the ACPI in a sysfs directory. All values are
> + * presented in the string form (numbers as decimal values) and can be
> + * accessed as the contents of the appropriate read only files in the
> + * sysfs directory tree.
> + */
> +#include <linux/acpi.h>
> +#include <linux/platform_device.h>
> +#include <linux/kernel.h>
> +#include <linux/list.h>
> +#include <linux/module.h>
> +
> +#define ACPI_ATTR_NAME_LEN 4
> +
> +#define DEV_ATTR(_var, _name)                                  \
> +       static struct device_attribute dev_attr_##_var =        \
> +               __ATTR(_name, 0444, chromeos_first_level_attr_show, NULL);
> +
> +#define GPIO_ATTR_GROUP(_group, _name, _num)                                           \
> +       static umode_t attr_is_visible_gpio_##_num(struct kobject *kobj,                \
> +                                                  struct attribute *attr, int n)       \
> +       {                                                                               \
> +               if (_num < chromeos_acpi_gpio_groups)                                   \
> +                       return attr->mode;                                              \
> +               return 0;                                                               \
> +       }                                                                               \
> +       static ssize_t chromeos_attr_show_gpio_##_num(struct device *dev,               \
> +                                                     struct device_attribute *attr,    \
> +                                                     char *buf)                        \
> +       {                                                                               \
> +               char name[ACPI_ATTR_NAME_LEN + 1];                                      \
> +               int ret, num;                                                           \
> +                                                                                       \
> +               ret = parse_attr_name(attr->attr.name, name, &num);                     \
> +               if (ret)                                                                \
> +                       return ret;                                                     \
> +               ret = chromeos_acpi_evaluate_method(dev, _num, num, name, buf);         \
> +               return ret;                                                             \
> +       }                                                                               \
> +       static struct device_attribute dev_attr_0_##_group =                            \
> +               __ATTR(GPIO.0, 0444, chromeos_attr_show_gpio_##_num, NULL);             \
> +       static struct device_attribute dev_attr_1_##_group =                            \
> +               __ATTR(GPIO.1, 0444, chromeos_attr_show_gpio_##_num, NULL);             \
> +       static struct device_attribute dev_attr_2_##_group =                            \
> +               __ATTR(GPIO.2, 0444, chromeos_attr_show_gpio_##_num, NULL);             \
> +       static struct device_attribute dev_attr_3_##_group =                            \
> +               __ATTR(GPIO.3, 0444, chromeos_attr_show_gpio_##_num, NULL);             \
> +                                                                                       \
> +       static struct attribute *attrs_##_group[] = {                                   \
> +               &dev_attr_0_##_group.attr,                                              \
> +               &dev_attr_1_##_group.attr,                                              \
> +               &dev_attr_2_##_group.attr,                                              \
> +               &dev_attr_3_##_group.attr,                                              \
> +               NULL                                                                    \
> +       };                                                                              \
> +       static const struct attribute_group attr_group_##_group = {                     \
> +               .name = _name,                                                          \
> +               .is_visible = attr_is_visible_gpio_##_num,                              \
> +               .attrs = attrs_##_group,                                                \
> +       };
> +
> +static unsigned int chromeos_acpi_gpio_groups;
> +
> +/* Parse the ACPI package and return the data related to that attribute */
> +static int chromeos_acpi_handle_package(struct device *dev, union acpi_object *obj,
> +                                       int pkg_num, int sub_pkg_num, char *name, char *buf)
> +{
> +       union acpi_object *element = obj->package.elements;
> +
> +       if (pkg_num >= obj->package.count)
> +               return -EINVAL;
> +       element += pkg_num;
> +
> +       if (element->type == ACPI_TYPE_PACKAGE) {
> +               if (sub_pkg_num >= element->package.count)
> +                       return -EINVAL;
> +               /* select sub element inside this package */
> +               element = element->package.elements;
> +               element += sub_pkg_num;
> +       }
> +
> +       switch (element->type) {
> +       case ACPI_TYPE_INTEGER:
> +               return sysfs_emit(buf, "%d\n", (int)element->integer.value);
> +       case ACPI_TYPE_STRING:
> +               return sysfs_emit(buf, "%s\n", element->string.pointer);
> +       case ACPI_TYPE_BUFFER:
> +               return sysfs_emit(buf, "%s\n", element->buffer.pointer);
> +       default:
> +               dev_err(dev, "element type %d not supported\n", element->type);
> +               return -EINVAL;
> +       }
> +}
> +
> +static int chromeos_acpi_evaluate_method(struct device *dev, int pkg_num, int sub_pkg_num,
> +                                        char *name, char *buf)
> +{
> +       struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
> +       acpi_status status;
> +       int ret = -EINVAL;
> +
> +       status = acpi_evaluate_object(ACPI_HANDLE(dev), name, NULL, &output);
> +       if (ACPI_FAILURE(status)) {
> +               dev_err(dev, "failed to retrieve %s. %s\n", name, acpi_format_exception(status));
> +               return ret;
> +       }
> +
> +       if (((union acpi_object *)output.pointer)->type == ACPI_TYPE_PACKAGE)
> +               ret = chromeos_acpi_handle_package(dev, output.pointer, pkg_num, sub_pkg_num,
> +                                                  name, buf);
> +
> +       kfree(output.pointer);
> +       return ret;
> +}
> +
> +static int parse_attr_name(const char *name, char *attr_name, int *attr_num)
> +{
> +       int ret;
> +
> +       ret = strscpy(attr_name, name, ACPI_ATTR_NAME_LEN + 1);
> +       if (ret == -E2BIG)
> +               return kstrtoint(&name[ACPI_ATTR_NAME_LEN + 1], 0, attr_num);
> +       return 0;
> +}
> +
> +static ssize_t chromeos_first_level_attr_show(struct device *dev, struct device_attribute *attr,
> +                                             char *buf)
> +{
> +       char attr_name[ACPI_ATTR_NAME_LEN + 1];
> +       int ret, attr_num = 0;
> +
> +       ret = parse_attr_name(attr->attr.name, attr_name, &attr_num);
> +       if (ret)
> +               return 0;
> +       ret = chromeos_acpi_evaluate_method(dev, attr_num, 0, attr_name, buf);
> +       return ret;
> +}
> +
> +static unsigned int get_gpio_pkg_num(struct device *dev)
> +{
> +       struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
> +       union acpi_object *obj;
> +       acpi_status status;
> +       unsigned int count = 0;
> +       char *name = "GPIO";
> +
> +       status = acpi_evaluate_object(ACPI_HANDLE(dev), name, NULL, &output);
> +       if (ACPI_FAILURE(status)) {
> +               dev_err(dev, "failed to retrieve %s. %s\n", name, acpi_format_exception(status));
> +               return count;
> +       }
> +
> +       obj = output.pointer;
> +
> +       if (obj->type == ACPI_TYPE_PACKAGE)
> +               count = obj->package.count;
> +
> +       kfree(output.pointer);
> +       return count;
> +}
> +
> +DEV_ATTR(binf2, BINF.2)
> +DEV_ATTR(binf3, BINF.3)
> +DEV_ATTR(chsw, CHSW)
> +DEV_ATTR(fmap, FMAP)
> +DEV_ATTR(frid, FRID)
> +DEV_ATTR(fwid, FWID)
> +DEV_ATTR(hwid, HWID)
> +DEV_ATTR(meck, MECK)
> +DEV_ATTR(vbnv0, VBNV.0)
> +DEV_ATTR(vbnv1, VBNV.1)
> +DEV_ATTR(vdat, VDAT)
> +
> +static struct attribute *first_level_attrs[] = {
> +       &dev_attr_binf2.attr,
> +       &dev_attr_binf3.attr,
> +       &dev_attr_chsw.attr,
> +       &dev_attr_fmap.attr,
> +       &dev_attr_frid.attr,
> +       &dev_attr_fwid.attr,
> +       &dev_attr_hwid.attr,
> +       &dev_attr_meck.attr,
> +       &dev_attr_vbnv0.attr,
> +       &dev_attr_vbnv1.attr,
> +       &dev_attr_vdat.attr,
> +       NULL
> +};
> +
> +static const struct attribute_group first_level_attr_group = {
> +       .attrs = first_level_attrs,
> +};
> +
> +/*
> + * Every platform can have a different number of GPIO attribute groups.
> + * Define upper limit groups. At run time, the platform decides to show
> + * the present number of groups only, others are hidden.
> + */
> +GPIO_ATTR_GROUP(gpio0, "GPIO.0", 0)
> +GPIO_ATTR_GROUP(gpio1, "GPIO.1", 1)
> +GPIO_ATTR_GROUP(gpio2, "GPIO.2", 2)
> +GPIO_ATTR_GROUP(gpio3, "GPIO.3", 3)
> +GPIO_ATTR_GROUP(gpio4, "GPIO.4", 4)
> +GPIO_ATTR_GROUP(gpio5, "GPIO.5", 5)
> +GPIO_ATTR_GROUP(gpio6, "GPIO.6", 6)
> +GPIO_ATTR_GROUP(gpio7, "GPIO.7", 7)
> +
> +static const struct attribute_group *chromeos_acpi_all_groups[] = {
> +       &first_level_attr_group,
> +       &attr_group_gpio0,
> +       &attr_group_gpio1,
> +       &attr_group_gpio2,
> +       &attr_group_gpio3,
> +       &attr_group_gpio4,
> +       &attr_group_gpio5,
> +       &attr_group_gpio6,
> +       &attr_group_gpio7,
> +       NULL
> +};
> +
> +static int chromeos_acpi_device_probe(struct platform_device *pdev)
> +{
> +       chromeos_acpi_gpio_groups = get_gpio_pkg_num(&pdev->dev);
> +
> +       /*
> +        * If the platform has more GPIO attribute groups than the number of
> +        * groups this driver supports, give out a warning message.
> +        */
> +       if (chromeos_acpi_gpio_groups > ARRAY_SIZE(chromeos_acpi_all_groups) - 2)
> +               dev_warn(&pdev->dev, "Only %zu GPIO attr groups supported by the driver out of total %u.\n",
> +                        ARRAY_SIZE(chromeos_acpi_all_groups) - 2, chromeos_acpi_gpio_groups);
> +       return 0;
> +}
> +
> +/* GGL is valid PNP ID of Google. PNP ID can be used with the ACPI devices. */
> +static const struct acpi_device_id chromeos_device_ids[] = {
> +       { "GGL0001", 0 },
> +       {}
> +};
> +MODULE_DEVICE_TABLE(acpi, chromeos_device_ids);
> +
> +static struct platform_driver chromeos_acpi_device_driver = {
> +       .probe = chromeos_acpi_device_probe,
> +       .driver = {
> +               .name = KBUILD_MODNAME,
> +               .dev_groups = chromeos_acpi_all_groups,
> +               .acpi_match_table = chromeos_device_ids,
> +       }
> +};
> +module_platform_driver(chromeos_acpi_device_driver);
> +
> +MODULE_AUTHOR("Muhammad Usama Anjum <usama.anjum@xxxxxxxxxxxxx>");
> +MODULE_LICENSE("GPL");
> +MODULE_DESCRIPTION("ChromeOS specific ACPI extensions");
> --
> 2.30.2
>



[Index of Archives]     [Linux Kernel Development]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux