aboutsummaryrefslogtreecommitdiff
path: root/SOURCES/t2linux.patch
diff options
context:
space:
mode:
Diffstat (limited to 'SOURCES/t2linux.patch')
-rw-r--r--SOURCES/t2linux.patch10690
1 files changed, 4775 insertions, 5915 deletions
diff --git a/SOURCES/t2linux.patch b/SOURCES/t2linux.patch
index 9fbe2e2..566de6c 100644
--- a/SOURCES/t2linux.patch
+++ b/SOURCES/t2linux.patch
@@ -1,35 +1,86 @@
-From fb72b7575a091284a3e2bd0a955aa2c61a6f5bc4 Mon Sep 17 00:00:00 2001
-From: Aditya Garg <gargaditya08@live.com>
-Date: Thu, 14 Mar 2024 06:51:34 +0000
-Subject: [PATCH] Add apple-bce driver
+From c8abbeaccc5bbcc5a1239c15298e453a90c76add Mon Sep 17 00:00:00 2001
+From: Peter Jung <admin@ptr1337.dev>
+Date: Sat, 3 Aug 2024 09:34:40 +0200
+Subject: [PATCH 11/12] t2
+Signed-off-by: Peter Jung <admin@ptr1337.dev>
---
- drivers/staging/apple-bce/Makefile | 28 +
- drivers/staging/apple-bce/apple_bce.c | 443 ++++++++++
- drivers/staging/apple-bce/apple_bce.h | 38 +
- drivers/staging/apple-bce/audio/audio.c | 711 ++++++++++++++++
- drivers/staging/apple-bce/audio/audio.h | 125 +++
- drivers/staging/apple-bce/audio/description.h | 42 +
- drivers/staging/apple-bce/audio/pcm.c | 308 +++++++
- drivers/staging/apple-bce/audio/pcm.h | 16 +
- drivers/staging/apple-bce/audio/protocol.c | 347 ++++++++
- drivers/staging/apple-bce/audio/protocol.h | 147 ++++
- .../staging/apple-bce/audio/protocol_bce.c | 226 ++++++
- .../staging/apple-bce/audio/protocol_bce.h | 72 ++
- drivers/staging/apple-bce/mailbox.c | 151 ++++
- drivers/staging/apple-bce/mailbox.h | 53 ++
- drivers/staging/apple-bce/queue.c | 390 +++++++++
- drivers/staging/apple-bce/queue.h | 177 ++++
- drivers/staging/apple-bce/queue_dma.c | 220 +++++
- drivers/staging/apple-bce/queue_dma.h | 50 ++
- drivers/staging/apple-bce/vhci/command.h | 204 +++++
- drivers/staging/apple-bce/vhci/queue.c | 268 +++++++
- drivers/staging/apple-bce/vhci/queue.h | 76 ++
- drivers/staging/apple-bce/vhci/transfer.c | 661 +++++++++++++++
- drivers/staging/apple-bce/vhci/transfer.h | 73 ++
- drivers/staging/apple-bce/vhci/vhci.c | 759 ++++++++++++++++++
- drivers/staging/apple-bce/vhci/vhci.h | 52 ++
- 25 files changed, 5637 insertions(+)
+ .../ABI/testing/sysfs-driver-hid-appletb-kbd | 13 +
+ Documentation/core-api/printk-formats.rst | 32 +
+ MAINTAINERS | 12 +
+ drivers/acpi/video_detect.c | 16 +
+ drivers/firmware/efi/libstub/Makefile | 2 +-
+ drivers/firmware/efi/libstub/arm64.c | 3 +-
+ drivers/firmware/efi/libstub/efistub.h | 9 +-
+ drivers/firmware/efi/libstub/smbios.c | 43 +-
+ drivers/firmware/efi/libstub/x86-stub.c | 71 +-
+ drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c | 3 +
+ drivers/gpu/drm/drm_format_helper.c | 54 +
+ drivers/gpu/drm/i915/display/intel_ddi.c | 4 +
+ drivers/gpu/drm/i915/display/intel_fbdev.c | 6 +-
+ drivers/gpu/drm/i915/display/intel_quirks.c | 15 +
+ drivers/gpu/drm/i915/display/intel_quirks.h | 1 +
+ .../gpu/drm/tests/drm_format_helper_test.c | 81 ++
+ drivers/gpu/drm/tiny/Kconfig | 12 +
+ drivers/gpu/drm/tiny/Makefile | 1 +
+ drivers/gpu/drm/tiny/appletbdrm.c | 624 +++++++++
+ drivers/gpu/vga/vga_switcheroo.c | 7 +-
+ drivers/hid/Kconfig | 22 +
+ drivers/hid/Makefile | 2 +
+ drivers/hid/hid-apple.c | 87 ++
+ drivers/hid/hid-appletb-bl.c | 193 +++
+ drivers/hid/hid-appletb-kbd.c | 289 +++++
+ drivers/hid/hid-core.c | 25 +
+ drivers/hid/hid-google-hammer.c | 27 +-
+ drivers/hid/hid-multitouch.c | 60 +-
+ drivers/hid/hid-quirks.c | 8 +-
+ drivers/hwmon/applesmc.c | 1138 ++++++++++++-----
+ drivers/input/mouse/bcm5974.c | 138 ++
+ drivers/pci/vgaarb.c | 1 +
+ drivers/platform/x86/apple-gmux.c | 18 +
+ drivers/staging/Kconfig | 2 +
+ drivers/staging/Makefile | 1 +
+ drivers/staging/apple-bce/Kconfig | 18 +
+ drivers/staging/apple-bce/Makefile | 28 +
+ drivers/staging/apple-bce/apple_bce.c | 445 +++++++
+ drivers/staging/apple-bce/apple_bce.h | 38 +
+ drivers/staging/apple-bce/audio/audio.c | 711 ++++++++++
+ drivers/staging/apple-bce/audio/audio.h | 125 ++
+ drivers/staging/apple-bce/audio/description.h | 42 +
+ drivers/staging/apple-bce/audio/pcm.c | 308 +++++
+ drivers/staging/apple-bce/audio/pcm.h | 16 +
+ drivers/staging/apple-bce/audio/protocol.c | 347 +++++
+ drivers/staging/apple-bce/audio/protocol.h | 147 +++
+ .../staging/apple-bce/audio/protocol_bce.c | 226 ++++
+ .../staging/apple-bce/audio/protocol_bce.h | 72 ++
+ drivers/staging/apple-bce/mailbox.c | 151 +++
+ drivers/staging/apple-bce/mailbox.h | 53 +
+ drivers/staging/apple-bce/queue.c | 390 ++++++
+ drivers/staging/apple-bce/queue.h | 177 +++
+ drivers/staging/apple-bce/queue_dma.c | 220 ++++
+ drivers/staging/apple-bce/queue_dma.h | 50 +
+ drivers/staging/apple-bce/vhci/command.h | 204 +++
+ drivers/staging/apple-bce/vhci/queue.c | 268 ++++
+ drivers/staging/apple-bce/vhci/queue.h | 76 ++
+ drivers/staging/apple-bce/vhci/transfer.c | 661 ++++++++++
+ drivers/staging/apple-bce/vhci/transfer.h | 73 ++
+ drivers/staging/apple-bce/vhci/vhci.c | 759 +++++++++++
+ drivers/staging/apple-bce/vhci/vhci.h | 52 +
+ drivers/usb/core/driver.c | 14 +
+ drivers/usb/storage/uas.c | 5 +-
+ include/drm/drm_format_helper.h | 3 +
+ include/linux/efi.h | 5 +-
+ include/linux/hid.h | 2 +
+ include/linux/usb.h | 3 +
+ lib/test_printf.c | 20 +-
+ lib/vsprintf.c | 36 +-
+ scripts/checkpatch.pl | 2 +-
+ 70 files changed, 8374 insertions(+), 393 deletions(-)
+ create mode 100644 Documentation/ABI/testing/sysfs-driver-hid-appletb-kbd
+ create mode 100644 drivers/gpu/drm/tiny/appletbdrm.c
+ create mode 100644 drivers/hid/hid-appletb-bl.c
+ create mode 100644 drivers/hid/hid-appletb-kbd.c
+ create mode 100644 drivers/staging/apple-bce/Kconfig
create mode 100644 drivers/staging/apple-bce/Makefile
create mode 100644 drivers/staging/apple-bce/apple_bce.c
create mode 100644 drivers/staging/apple-bce/apple_bce.h
@@ -56,14 +107,4567 @@ Subject: [PATCH] Add apple-bce driver
create mode 100644 drivers/staging/apple-bce/vhci/vhci.c
create mode 100644 drivers/staging/apple-bce/vhci/vhci.h
+diff --git a/Documentation/ABI/testing/sysfs-driver-hid-appletb-kbd b/Documentation/ABI/testing/sysfs-driver-hid-appletb-kbd
+new file mode 100644
+index 000000000000..2a19584d091e
+--- /dev/null
++++ b/Documentation/ABI/testing/sysfs-driver-hid-appletb-kbd
+@@ -0,0 +1,13 @@
++What: /sys/bus/hid/drivers/hid-appletb-kbd/<dev>/mode
++Date: September, 2023
++KernelVersion: 6.5
++Contact: linux-input@vger.kernel.org
++Description:
++ The set of keys displayed on the Touch Bar.
++ Valid values are:
++ == =================
++ 0 Escape key only
++ 1 Function keys
++ 2 Media/brightness keys
++ 3 None
++ == =================
+diff --git a/Documentation/core-api/printk-formats.rst b/Documentation/core-api/printk-formats.rst
+index 4451ef501936..c726a846f752 100644
+--- a/Documentation/core-api/printk-formats.rst
++++ b/Documentation/core-api/printk-formats.rst
+@@ -632,6 +632,38 @@ Examples::
+ %p4cc Y10 little-endian (0x20303159)
+ %p4cc NV12 big-endian (0xb231564e)
+
++Generic FourCC code
++-------------------
++
++::
++ %p4c[hnbl] gP00 (0x67503030)
++
++Print a generic FourCC code, as both ASCII characters and its numerical
++value as hexadecimal.
++
++The additional ``h``, ``r``, ``b``, and ``l`` specifiers are used to specify
++host, reversed, big or little endian order data respectively. Host endian
++order means the data is interpreted as a 32-bit integer and the most
++significant byte is printed first; that is, the character code as printed
++matches the byte order stored in memory on big-endian systems, and is reversed
++on little-endian systems.
++
++Passed by reference.
++
++Examples for a little-endian machine, given &(u32)0x67503030::
++
++ %p4ch gP00 (0x67503030)
++ %p4cl gP00 (0x67503030)
++ %p4cb 00Pg (0x30305067)
++ %p4cr 00Pg (0x30305067)
++
++Examples for a big-endian machine, given &(u32)0x67503030::
++
++ %p4ch gP00 (0x67503030)
++ %p4cl 00Pg (0x30305067)
++ %p4cb gP00 (0x67503030)
++ %p4cr 00Pg (0x30305067)
++
+ Rust
+ ----
+
+diff --git a/MAINTAINERS b/MAINTAINERS
+index 4112729fc23a..064156d69e75 100644
+--- a/MAINTAINERS
++++ b/MAINTAINERS
+@@ -6728,6 +6728,12 @@ S: Supported
+ T: git https://gitlab.freedesktop.org/drm/misc/kernel.git
+ F: drivers/gpu/drm/sun4i/sun8i*
+
++DRM DRIVER FOR APPLE TOUCH BARS
++M: Kerem Karabay <kekrby@gmail.com>
++L: dri-devel@lists.freedesktop.org
++S: Maintained
++F: drivers/gpu/drm/tiny/appletbdrm.c
++
+ DRM DRIVER FOR ARM PL111 CLCD
+ S: Orphan
+ T: git https://gitlab.freedesktop.org/drm/misc/kernel.git
+@@ -9733,6 +9739,12 @@ F: include/linux/pm.h
+ F: include/linux/suspend.h
+ F: kernel/power/
+
++HID APPLE TOUCH BAR DRIVERS
++M: Kerem Karabay <kekrby@gmail.com>
++L: linux-input@vger.kernel.org
++S: Maintained
++F: drivers/hid/hid-appletb-*
++
+ HID CORE LAYER
+ M: Jiri Kosina <jikos@kernel.org>
+ M: Benjamin Tissoires <bentiss@kernel.org>
+diff --git a/drivers/acpi/video_detect.c b/drivers/acpi/video_detect.c
+index 2cc3821b2b16..c11cbe5b6eaa 100644
+--- a/drivers/acpi/video_detect.c
++++ b/drivers/acpi/video_detect.c
+@@ -539,6 +539,14 @@ static const struct dmi_system_id video_detect_dmi_table[] = {
+ DMI_MATCH(DMI_PRODUCT_NAME, "iMac12,2"),
+ },
+ },
++ {
++ .callback = video_detect_force_native,
++ /* Apple MacBook Air 9,1 */
++ .matches = {
++ DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
++ DMI_MATCH(DMI_PRODUCT_NAME, "MacBookAir9,1"),
++ },
++ },
+ {
+ /* https://bugzilla.redhat.com/show_bug.cgi?id=1217249 */
+ .callback = video_detect_force_native,
+@@ -548,6 +556,14 @@ static const struct dmi_system_id video_detect_dmi_table[] = {
+ DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro12,1"),
+ },
+ },
++ {
++ .callback = video_detect_force_native,
++ /* Apple MacBook Pro 16,2 */
++ .matches = {
++ DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
++ DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro16,2"),
++ },
++ },
+ {
+ .callback = video_detect_force_native,
+ /* Dell Inspiron N4010 */
+diff --git a/drivers/firmware/efi/libstub/Makefile b/drivers/firmware/efi/libstub/Makefile
+index 06f0428a723c..1f32d6cf98d6 100644
+--- a/drivers/firmware/efi/libstub/Makefile
++++ b/drivers/firmware/efi/libstub/Makefile
+@@ -76,7 +76,7 @@ lib-$(CONFIG_EFI_GENERIC_STUB) += efi-stub.o string.o intrinsics.o systable.o \
+
+ lib-$(CONFIG_ARM) += arm32-stub.o
+ lib-$(CONFIG_ARM64) += kaslr.o arm64.o arm64-stub.o smbios.o
+-lib-$(CONFIG_X86) += x86-stub.o
++lib-$(CONFIG_X86) += x86-stub.o smbios.o
+ lib-$(CONFIG_X86_64) += x86-5lvl.o
+ lib-$(CONFIG_RISCV) += kaslr.o riscv.o riscv-stub.o
+ lib-$(CONFIG_LOONGARCH) += loongarch.o loongarch-stub.o
+diff --git a/drivers/firmware/efi/libstub/arm64.c b/drivers/firmware/efi/libstub/arm64.c
+index 446e35eaf3d9..e57cd3de0a00 100644
+--- a/drivers/firmware/efi/libstub/arm64.c
++++ b/drivers/firmware/efi/libstub/arm64.c
+@@ -39,8 +39,7 @@ static bool system_needs_vamap(void)
+ static char const emag[] = "eMAG";
+
+ default:
+- version = efi_get_smbios_string(&record->header, 4,
+- processor_version);
++ version = efi_get_smbios_string(record, processor_version);
+ if (!version || (strncmp(version, altra, sizeof(altra) - 1) &&
+ strncmp(version, emag, sizeof(emag) - 1)))
+ break;
+diff --git a/drivers/firmware/efi/libstub/efistub.h b/drivers/firmware/efi/libstub/efistub.h
+index 27abb4ce0291..d33ccbc4a2c6 100644
+--- a/drivers/firmware/efi/libstub/efistub.h
++++ b/drivers/firmware/efi/libstub/efistub.h
+@@ -1204,14 +1204,13 @@ struct efi_smbios_type4_record {
+ u16 thread_enabled;
+ };
+
+-#define efi_get_smbios_string(__record, __type, __name) ({ \
+- int off = offsetof(struct efi_smbios_type ## __type ## _record, \
+- __name); \
+- __efi_get_smbios_string((__record), __type, off); \
++#define efi_get_smbios_string(__record, __field) ({ \
++ __typeof__(__record) __rec = __record; \
++ __efi_get_smbios_string(&__rec->header, &__rec->__field); \
+ })
+
+ const u8 *__efi_get_smbios_string(const struct efi_smbios_record *record,
+- u8 type, int offset);
++ const u8 *offset);
+
+ void efi_remap_image(unsigned long image_base, unsigned alloc_size,
+ unsigned long code_size);
+diff --git a/drivers/firmware/efi/libstub/smbios.c b/drivers/firmware/efi/libstub/smbios.c
+index c217de2cc8d5..f31410d7e7e1 100644
+--- a/drivers/firmware/efi/libstub/smbios.c
++++ b/drivers/firmware/efi/libstub/smbios.c
+@@ -6,20 +6,31 @@
+
+ #include "efistub.h"
+
+-typedef struct efi_smbios_protocol efi_smbios_protocol_t;
+-
+-struct efi_smbios_protocol {
+- efi_status_t (__efiapi *add)(efi_smbios_protocol_t *, efi_handle_t,
+- u16 *, struct efi_smbios_record *);
+- efi_status_t (__efiapi *update_string)(efi_smbios_protocol_t *, u16 *,
+- unsigned long *, u8 *);
+- efi_status_t (__efiapi *remove)(efi_smbios_protocol_t *, u16);
+- efi_status_t (__efiapi *get_next)(efi_smbios_protocol_t *, u16 *, u8 *,
+- struct efi_smbios_record **,
+- efi_handle_t *);
+-
+- u8 major_version;
+- u8 minor_version;
++typedef union efi_smbios_protocol efi_smbios_protocol_t;
++
++union efi_smbios_protocol {
++ struct {
++ efi_status_t (__efiapi *add)(efi_smbios_protocol_t *, efi_handle_t,
++ u16 *, struct efi_smbios_record *);
++ efi_status_t (__efiapi *update_string)(efi_smbios_protocol_t *, u16 *,
++ unsigned long *, u8 *);
++ efi_status_t (__efiapi *remove)(efi_smbios_protocol_t *, u16);
++ efi_status_t (__efiapi *get_next)(efi_smbios_protocol_t *, u16 *, u8 *,
++ struct efi_smbios_record **,
++ efi_handle_t *);
++
++ u8 major_version;
++ u8 minor_version;
++ };
++ struct {
++ u32 add;
++ u32 update_string;
++ u32 remove;
++ u32 get_next;
++
++ u8 major_version;
++ u8 minor_version;
++ } mixed_mode;
+ };
+
+ const struct efi_smbios_record *efi_get_smbios_record(u8 type)
+@@ -38,7 +49,7 @@ const struct efi_smbios_record *efi_get_smbios_record(u8 type)
+ }
+
+ const u8 *__efi_get_smbios_string(const struct efi_smbios_record *record,
+- u8 type, int offset)
++ const u8 *offset)
+ {
+ const u8 *strtable;
+
+@@ -46,7 +57,7 @@ const u8 *__efi_get_smbios_string(const struct efi_smbios_record *record,
+ return NULL;
+
+ strtable = (u8 *)record + record->length;
+- for (int i = 1; i < ((u8 *)record)[offset]; i++) {
++ for (int i = 1; i < *offset; i++) {
+ int len = strlen(strtable);
+
+ if (!len)
+diff --git a/drivers/firmware/efi/libstub/x86-stub.c b/drivers/firmware/efi/libstub/x86-stub.c
+index 99d39eda5134..0a2342c0bc16 100644
+--- a/drivers/firmware/efi/libstub/x86-stub.c
++++ b/drivers/firmware/efi/libstub/x86-stub.c
+@@ -225,6 +225,68 @@ static void retrieve_apple_device_properties(struct boot_params *boot_params)
+ }
+ }
+
++static bool apple_match_product_name(void)
++{
++ static const char type1_product_matches[][15] = {
++ "MacBookPro11,3",
++ "MacBookPro11,5",
++ "MacBookPro13,3",
++ "MacBookPro14,3",
++ "MacBookPro15,1",
++ "MacBookPro15,3",
++ "MacBookPro16,1",
++ "MacBookPro16,4",
++ };
++ const struct efi_smbios_type1_record *record;
++ const u8 *product;
++
++ record = (struct efi_smbios_type1_record *)efi_get_smbios_record(1);
++ if (!record)
++ return false;
++
++ product = efi_get_smbios_string(record, product_name);
++ if (!product)
++ return false;
++
++ for (int i = 0; i < ARRAY_SIZE(type1_product_matches); i++) {
++ if (!strcmp(product, type1_product_matches[i]))
++ return true;
++ }
++
++ return false;
++}
++
++static void apple_set_os(void)
++{
++ struct {
++ unsigned long version;
++ efi_status_t (__efiapi *set_os_version)(const char *);
++ efi_status_t (__efiapi *set_os_vendor)(const char *);
++ } *set_os;
++ efi_status_t status;
++
++ if (!efi_is_64bit() || !apple_match_product_name())
++ return;
++
++ status = efi_bs_call(locate_protocol, &APPLE_SET_OS_PROTOCOL_GUID, NULL,
++ (void **)&set_os);
++ if (status != EFI_SUCCESS)
++ return;
++
++ if (set_os->version >= 2) {
++ status = set_os->set_os_vendor("Apple Inc.");
++ if (status != EFI_SUCCESS)
++ efi_err("Failed to set OS vendor via apple_set_os\n");
++ }
++
++ if (set_os->version > 0) {
++ /* The version being set doesn't seem to matter */
++ status = set_os->set_os_version("Mac OS X 10.9");
++ if (status != EFI_SUCCESS)
++ efi_err("Failed to set OS version via apple_set_os\n");
++ }
++}
++
+ efi_status_t efi_adjust_memory_range_protection(unsigned long start,
+ unsigned long size)
+ {
+@@ -335,9 +397,12 @@ static const efi_char16_t apple[] = L"Apple";
+
+ static void setup_quirks(struct boot_params *boot_params)
+ {
+- if (IS_ENABLED(CONFIG_APPLE_PROPERTIES) &&
+- !memcmp(efistub_fw_vendor(), apple, sizeof(apple)))
+- retrieve_apple_device_properties(boot_params);
++ if (!memcmp(efistub_fw_vendor(), apple, sizeof(apple))) {
++ if (IS_ENABLED(CONFIG_APPLE_PROPERTIES))
++ retrieve_apple_device_properties(boot_params);
++
++ apple_set_os();
++ }
+ }
+
+ /*
+diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
+index bb0b636d0d75..a05ed98da785 100644
+--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
+@@ -2211,6 +2211,9 @@ static int amdgpu_pci_probe(struct pci_dev *pdev,
+ int ret, retry = 0, i;
+ bool supports_atomic = false;
+
++ if (vga_switcheroo_client_probe_defer(pdev))
++ return -EPROBE_DEFER;
++
+ /* skip devices which are owned by radeon */
+ for (i = 0; i < ARRAY_SIZE(amdgpu_unsupported_pciidlist); i++) {
+ if (amdgpu_unsupported_pciidlist[i] == pdev->device)
+diff --git a/drivers/gpu/drm/drm_format_helper.c b/drivers/gpu/drm/drm_format_helper.c
+index b1be458ed4dd..28c0e76a1e88 100644
+--- a/drivers/gpu/drm/drm_format_helper.c
++++ b/drivers/gpu/drm/drm_format_helper.c
+@@ -702,6 +702,57 @@ void drm_fb_xrgb8888_to_rgb888(struct iosys_map *dst, const unsigned int *dst_pi
+ }
+ EXPORT_SYMBOL(drm_fb_xrgb8888_to_rgb888);
+
++static void drm_fb_xrgb8888_to_bgr888_line(void *dbuf, const void *sbuf, unsigned int pixels)
++{
++ u8 *dbuf8 = dbuf;
++ const __le32 *sbuf32 = sbuf;
++ unsigned int x;
++ u32 pix;
++
++ for (x = 0; x < pixels; x++) {
++ pix = le32_to_cpu(sbuf32[x]);
++ /* write red-green-blue to output in little endianness */
++ *dbuf8++ = (pix & 0x00FF0000) >> 16;
++ *dbuf8++ = (pix & 0x0000FF00) >> 8;
++ *dbuf8++ = (pix & 0x000000FF) >> 0;
++ }
++}
++
++/**
++ * drm_fb_xrgb8888_to_bgr888 - Convert XRGB8888 to BGR888 clip buffer
++ * @dst: Array of BGR888 destination buffers
++ * @dst_pitch: Array of numbers of bytes between the start of two consecutive scanlines
++ * within @dst; can be NULL if scanlines are stored next to each other.
++ * @src: Array of XRGB8888 source buffers
++ * @fb: DRM framebuffer
++ * @clip: Clip rectangle area to copy
++ * @state: Transform and conversion state
++ *
++ * This function copies parts of a framebuffer to display memory and converts the
++ * color format during the process. Destination and framebuffer formats must match. The
++ * parameters @dst, @dst_pitch and @src refer to arrays. Each array must have at
++ * least as many entries as there are planes in @fb's format. Each entry stores the
++ * value for the format's respective color plane at the same index.
++ *
++ * This function does not apply clipping on @dst (i.e. the destination is at the
++ * top-left corner).
++ *
++ * Drivers can use this function for BGR888 devices that don't natively
++ * support XRGB8888.
++ */
++void drm_fb_xrgb8888_to_bgr888(struct iosys_map *dst, const unsigned int *dst_pitch,
++ const struct iosys_map *src, const struct drm_framebuffer *fb,
++ const struct drm_rect *clip, struct drm_format_conv_state *state)
++{
++ static const u8 dst_pixsize[DRM_FORMAT_MAX_PLANES] = {
++ 3,
++ };
++
++ drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false, state,
++ drm_fb_xrgb8888_to_bgr888_line);
++}
++EXPORT_SYMBOL(drm_fb_xrgb8888_to_bgr888);
++
+ static void drm_fb_xrgb8888_to_argb8888_line(void *dbuf, const void *sbuf, unsigned int pixels)
+ {
+ __le32 *dbuf32 = dbuf;
+@@ -1035,6 +1086,9 @@ int drm_fb_blit(struct iosys_map *dst, const unsigned int *dst_pitch, uint32_t d
+ } else if (dst_format == DRM_FORMAT_RGB888) {
+ drm_fb_xrgb8888_to_rgb888(dst, dst_pitch, src, fb, clip, state);
+ return 0;
++ } else if (dst_format == DRM_FORMAT_BGR888) {
++ drm_fb_xrgb8888_to_bgr888(dst, dst_pitch, src, fb, clip, state);
++ return 0;
+ } else if (dst_format == DRM_FORMAT_ARGB8888) {
+ drm_fb_xrgb8888_to_argb8888(dst, dst_pitch, src, fb, clip, state);
+ return 0;
+diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c
+index 6bff169fa8d4..8d80ae00b838 100644
+--- a/drivers/gpu/drm/i915/display/intel_ddi.c
++++ b/drivers/gpu/drm/i915/display/intel_ddi.c
+@@ -4648,6 +4648,7 @@ intel_ddi_init_hdmi_connector(struct intel_digital_port *dig_port)
+
+ static bool intel_ddi_a_force_4_lanes(struct intel_digital_port *dig_port)
+ {
++ struct intel_display *display = to_intel_display(dig_port);
+ struct drm_i915_private *dev_priv = to_i915(dig_port->base.base.dev);
+
+ if (dig_port->base.port != PORT_A)
+@@ -4656,6 +4657,9 @@ static bool intel_ddi_a_force_4_lanes(struct intel_digital_port *dig_port)
+ if (dig_port->saved_port_bits & DDI_A_4_LANES)
+ return false;
+
++ if (intel_has_quirk(display, QUIRK_DDI_A_FORCE_4_LANES))
++ return true;
++
+ /* Broxton/Geminilake: Bspec says that DDI_A_4_LANES is the only
+ * supported configuration
+ */
+diff --git a/drivers/gpu/drm/i915/display/intel_fbdev.c b/drivers/gpu/drm/i915/display/intel_fbdev.c
+index bda702c2cab8..1647e141ae78 100644
+--- a/drivers/gpu/drm/i915/display/intel_fbdev.c
++++ b/drivers/gpu/drm/i915/display/intel_fbdev.c
+@@ -196,10 +196,10 @@ static int intelfb_create(struct drm_fb_helper *helper,
+ return ret;
+
+ if (intel_fb &&
+- (sizes->fb_width > intel_fb->base.width ||
+- sizes->fb_height > intel_fb->base.height)) {
++ (sizes->fb_width != intel_fb->base.width ||
++ sizes->fb_height != intel_fb->base.height)) {
+ drm_dbg_kms(&dev_priv->drm,
+- "BIOS fb too small (%dx%d), we require (%dx%d),"
++ "BIOS fb not valid (%dx%d), we require (%dx%d),"
+ " releasing it\n",
+ intel_fb->base.width, intel_fb->base.height,
+ sizes->fb_width, sizes->fb_height);
+diff --git a/drivers/gpu/drm/i915/display/intel_quirks.c b/drivers/gpu/drm/i915/display/intel_quirks.c
+index 14d5fefc9c5b..727639b8f6a6 100644
+--- a/drivers/gpu/drm/i915/display/intel_quirks.c
++++ b/drivers/gpu/drm/i915/display/intel_quirks.c
+@@ -59,6 +59,18 @@ static void quirk_increase_ddi_disabled_time(struct intel_display *display)
+ drm_info(display->drm, "Applying Increase DDI Disabled quirk\n");
+ }
+
++/*
++ * In some cases, the firmware might not set the lane count to 4 (for example,
++ * when booting in some dual GPU Macs with the dGPU as the default GPU), this
++ * quirk is used to force it as otherwise it might not be possible to compute a
++ * valid link configuration.
++ */
++static void quirk_ddi_a_force_4_lanes(struct intel_display *display)
++{
++ intel_set_quirk(display, QUIRK_DDI_A_FORCE_4_LANES);
++ drm_info(display->drm, "Applying DDI A Forced 4 Lanes quirk\n");
++}
++
+ static void quirk_no_pps_backlight_power_hook(struct intel_display *display)
+ {
+ intel_set_quirk(display, QUIRK_NO_PPS_BACKLIGHT_POWER_HOOK);
+@@ -201,6 +213,9 @@ static struct intel_quirk intel_quirks[] = {
+ { 0x3184, 0x1019, 0xa94d, quirk_increase_ddi_disabled_time },
+ /* HP Notebook - 14-r206nv */
+ { 0x0f31, 0x103c, 0x220f, quirk_invert_brightness },
++
++ /* Apple MacBookPro15,1 */
++ { 0x3e9b, 0x106b, 0x0176, quirk_ddi_a_force_4_lanes },
+ };
+
+ void intel_init_quirks(struct intel_display *display)
+diff --git a/drivers/gpu/drm/i915/display/intel_quirks.h b/drivers/gpu/drm/i915/display/intel_quirks.h
+index 151c8f4ae576..46e7feba88f4 100644
+--- a/drivers/gpu/drm/i915/display/intel_quirks.h
++++ b/drivers/gpu/drm/i915/display/intel_quirks.h
+@@ -17,6 +17,7 @@ enum intel_quirk_id {
+ QUIRK_INVERT_BRIGHTNESS,
+ QUIRK_LVDS_SSC_DISABLE,
+ QUIRK_NO_PPS_BACKLIGHT_POWER_HOOK,
++ QUIRK_DDI_A_FORCE_4_LANES,
+ };
+
+ void intel_init_quirks(struct intel_display *display);
+diff --git a/drivers/gpu/drm/tests/drm_format_helper_test.c b/drivers/gpu/drm/tests/drm_format_helper_test.c
+index 08992636ec05..35cd3405d045 100644
+--- a/drivers/gpu/drm/tests/drm_format_helper_test.c
++++ b/drivers/gpu/drm/tests/drm_format_helper_test.c
+@@ -60,6 +60,11 @@ struct convert_to_rgb888_result {
+ const u8 expected[TEST_BUF_SIZE];
+ };
+
++struct convert_to_bgr888_result {
++ unsigned int dst_pitch;
++ const u8 expected[TEST_BUF_SIZE];
++};
++
+ struct convert_to_argb8888_result {
+ unsigned int dst_pitch;
+ const u32 expected[TEST_BUF_SIZE];
+@@ -107,6 +112,7 @@ struct convert_xrgb8888_case {
+ struct convert_to_argb1555_result argb1555_result;
+ struct convert_to_rgba5551_result rgba5551_result;
+ struct convert_to_rgb888_result rgb888_result;
++ struct convert_to_bgr888_result bgr888_result;
+ struct convert_to_argb8888_result argb8888_result;
+ struct convert_to_xrgb2101010_result xrgb2101010_result;
+ struct convert_to_argb2101010_result argb2101010_result;
+@@ -151,6 +157,10 @@ static struct convert_xrgb8888_case convert_xrgb8888_cases[] = {
+ .dst_pitch = TEST_USE_DEFAULT_PITCH,
+ .expected = { 0x00, 0x00, 0xFF },
+ },
++ .bgr888_result = {
++ .dst_pitch = TEST_USE_DEFAULT_PITCH,
++ .expected = { 0xFF, 0x00, 0x00 },
++ },
+ .argb8888_result = {
+ .dst_pitch = TEST_USE_DEFAULT_PITCH,
+ .expected = { 0xFFFF0000 },
+@@ -217,6 +227,10 @@ static struct convert_xrgb8888_case convert_xrgb8888_cases[] = {
+ .dst_pitch = TEST_USE_DEFAULT_PITCH,
+ .expected = { 0x00, 0x00, 0xFF },
+ },
++ .bgr888_result = {
++ .dst_pitch = TEST_USE_DEFAULT_PITCH,
++ .expected = { 0xFF, 0x00, 0x00 },
++ },
+ .argb8888_result = {
+ .dst_pitch = TEST_USE_DEFAULT_PITCH,
+ .expected = { 0xFFFF0000 },
+@@ -330,6 +344,15 @@ static struct convert_xrgb8888_case convert_xrgb8888_cases[] = {
+ 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
+ },
+ },
++ .bgr888_result = {
++ .dst_pitch = TEST_USE_DEFAULT_PITCH,
++ .expected = {
++ 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00,
++ 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00,
++ 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF,
++ 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF,
++ },
++ },
+ .argb8888_result = {
+ .dst_pitch = TEST_USE_DEFAULT_PITCH,
+ .expected = {
+@@ -468,6 +491,17 @@ static struct convert_xrgb8888_case convert_xrgb8888_cases[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ },
+ },
++ .bgr888_result = {
++ .dst_pitch = 15,
++ .expected = {
++ 0x0E, 0x44, 0x9C, 0x11, 0x4D, 0x05, 0xA8, 0xF3, 0x03,
++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++ 0x6C, 0xF0, 0x73, 0x0E, 0x44, 0x9C, 0x11, 0x4D, 0x05,
++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++ 0xA8, 0x03, 0x03, 0x6C, 0xF0, 0x73, 0x0E, 0x44, 0x9C,
++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++ },
++ },
+ .argb8888_result = {
+ .dst_pitch = 20,
+ .expected = {
+@@ -914,6 +948,52 @@ static void drm_test_fb_xrgb8888_to_rgb888(struct kunit *test)
+ KUNIT_EXPECT_MEMEQ(test, buf, result->expected, dst_size);
+ }
+
++static void drm_test_fb_xrgb8888_to_bgr888(struct kunit *test)
++{
++ const struct convert_xrgb8888_case *params = test->param_value;
++ const struct convert_to_bgr888_result *result = &params->bgr888_result;
++ size_t dst_size;
++ u8 *buf = NULL;
++ __le32 *xrgb8888 = NULL;
++ struct iosys_map dst, src;
++
++ struct drm_framebuffer fb = {
++ .format = drm_format_info(DRM_FORMAT_XRGB8888),
++ .pitches = { params->pitch, 0, 0 },
++ };
++
++ dst_size = conversion_buf_size(DRM_FORMAT_BGR888, result->dst_pitch,
++ &params->clip, 0);
++ KUNIT_ASSERT_GT(test, dst_size, 0);
++
++ buf = kunit_kzalloc(test, dst_size, GFP_KERNEL);
++ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, buf);
++ iosys_map_set_vaddr(&dst, buf);
++
++ xrgb8888 = cpubuf_to_le32(test, params->xrgb8888, TEST_BUF_SIZE);
++ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, xrgb8888);
++ iosys_map_set_vaddr(&src, xrgb8888);
++
++ /*
++ * BGR888 expected results are already in little-endian
++ * order, so there's no need to convert the test output.
++ */
++ drm_fb_xrgb8888_to_bgr888(&dst, &result->dst_pitch, &src, &fb, &params->clip,
++ &fmtcnv_state);
++ KUNIT_EXPECT_MEMEQ(test, buf, result->expected, dst_size);
++
++ buf = dst.vaddr; /* restore original value of buf */
++ memset(buf, 0, dst_size);
++
++ int blit_result = 0;
++
++ blit_result = drm_fb_blit(&dst, &result->dst_pitch, DRM_FORMAT_BGR888, &src, &fb, &params->clip,
++ &fmtcnv_state);
++
++ KUNIT_EXPECT_FALSE(test, blit_result);
++ KUNIT_EXPECT_MEMEQ(test, buf, result->expected, dst_size);
++}
++
+ static void drm_test_fb_xrgb8888_to_argb8888(struct kunit *test)
+ {
+ const struct convert_xrgb8888_case *params = test->param_value;
+@@ -1851,6 +1931,7 @@ static struct kunit_case drm_format_helper_test_cases[] = {
+ KUNIT_CASE_PARAM(drm_test_fb_xrgb8888_to_argb1555, convert_xrgb8888_gen_params),
+ KUNIT_CASE_PARAM(drm_test_fb_xrgb8888_to_rgba5551, convert_xrgb8888_gen_params),
+ KUNIT_CASE_PARAM(drm_test_fb_xrgb8888_to_rgb888, convert_xrgb8888_gen_params),
++ KUNIT_CASE_PARAM(drm_test_fb_xrgb8888_to_bgr888, convert_xrgb8888_gen_params),
+ KUNIT_CASE_PARAM(drm_test_fb_xrgb8888_to_argb8888, convert_xrgb8888_gen_params),
+ KUNIT_CASE_PARAM(drm_test_fb_xrgb8888_to_xrgb2101010, convert_xrgb8888_gen_params),
+ KUNIT_CASE_PARAM(drm_test_fb_xrgb8888_to_argb2101010, convert_xrgb8888_gen_params),
+diff --git a/drivers/gpu/drm/tiny/Kconfig b/drivers/gpu/drm/tiny/Kconfig
+index f6889f649bc1..559a97bce12c 100644
+--- a/drivers/gpu/drm/tiny/Kconfig
++++ b/drivers/gpu/drm/tiny/Kconfig
+@@ -1,5 +1,17 @@
+ # SPDX-License-Identifier: GPL-2.0-only
+
++config DRM_APPLETBDRM
++ tristate "DRM support for Apple Touch Bars"
++ depends on DRM && USB && MMU
++ select DRM_KMS_HELPER
++ select DRM_GEM_SHMEM_HELPER
++ help
++ Say Y here if you want support for the display of Touch Bars on x86
++ MacBook Pros.
++
++ To compile this driver as a module, choose M here: the
++ module will be called appletbdrm.
++
+ config DRM_ARCPGU
+ tristate "ARC PGU"
+ depends on DRM && OF
+diff --git a/drivers/gpu/drm/tiny/Makefile b/drivers/gpu/drm/tiny/Makefile
+index 76dde89a044b..9a1b412e764a 100644
+--- a/drivers/gpu/drm/tiny/Makefile
++++ b/drivers/gpu/drm/tiny/Makefile
+@@ -1,5 +1,6 @@
+ # SPDX-License-Identifier: GPL-2.0-only
+
++obj-$(CONFIG_DRM_APPLETBDRM) += appletbdrm.o
+ obj-$(CONFIG_DRM_ARCPGU) += arcpgu.o
+ obj-$(CONFIG_DRM_BOCHS) += bochs.o
+ obj-$(CONFIG_DRM_CIRRUS_QEMU) += cirrus.o
+diff --git a/drivers/gpu/drm/tiny/appletbdrm.c b/drivers/gpu/drm/tiny/appletbdrm.c
+new file mode 100644
+index 000000000000..b9440ce0064e
+--- /dev/null
++++ b/drivers/gpu/drm/tiny/appletbdrm.c
+@@ -0,0 +1,624 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * Apple Touch Bar DRM Driver
++ *
++ * Copyright (c) 2023 Kerem Karabay <kekrby@gmail.com>
++ */
++
++#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
++
++#include <asm/unaligned.h>
++
++#include <linux/usb.h>
++#include <linux/module.h>
++
++#include <drm/drm_drv.h>
++#include <drm/drm_fourcc.h>
++#include <drm/drm_probe_helper.h>
++#include <drm/drm_atomic_helper.h>
++#include <drm/drm_damage_helper.h>
++#include <drm/drm_format_helper.h>
++#include <drm/drm_gem_shmem_helper.h>
++#include <drm/drm_gem_atomic_helper.h>
++#include <drm/drm_simple_kms_helper.h>
++#include <drm/drm_gem_framebuffer_helper.h>
++
++#define _APPLETBDRM_FOURCC(s) (((s)[0] << 24) | ((s)[1] << 16) | ((s)[2] << 8) | (s)[3])
++#define APPLETBDRM_FOURCC(s) _APPLETBDRM_FOURCC(#s)
++
++#define APPLETBDRM_PIXEL_FORMAT APPLETBDRM_FOURCC(RGBA) /* The actual format is BGR888 */
++#define APPLETBDRM_BITS_PER_PIXEL 24
++
++#define APPLETBDRM_MSG_CLEAR_DISPLAY APPLETBDRM_FOURCC(CLRD)
++#define APPLETBDRM_MSG_GET_INFORMATION APPLETBDRM_FOURCC(GINF)
++#define APPLETBDRM_MSG_UPDATE_COMPLETE APPLETBDRM_FOURCC(UDCL)
++#define APPLETBDRM_MSG_SIGNAL_READINESS APPLETBDRM_FOURCC(REDY)
++
++#define APPLETBDRM_BULK_MSG_TIMEOUT 1000
++
++#define drm_to_adev(_drm) container_of(_drm, struct appletbdrm_device, drm)
++#define adev_to_udev(adev) interface_to_usbdev(to_usb_interface(adev->dev))
++
++struct appletbdrm_device {
++ struct device *dev;
++
++ u8 in_ep;
++ u8 out_ep;
++
++ u32 width;
++ u32 height;
++
++ struct drm_device drm;
++ struct drm_display_mode mode;
++ struct drm_connector connector;
++ struct drm_simple_display_pipe pipe;
++
++ bool readiness_signal_received;
++};
++
++struct appletbdrm_request_header {
++ __le16 unk_00;
++ __le16 unk_02;
++ __le32 unk_04;
++ __le32 unk_08;
++ __le32 size;
++} __packed;
++
++struct appletbdrm_response_header {
++ u8 unk_00[16];
++ u32 msg;
++} __packed;
++
++struct appletbdrm_simple_request {
++ struct appletbdrm_request_header header;
++ u32 msg;
++ u8 unk_14[8];
++ __le32 size;
++} __packed;
++
++struct appletbdrm_information {
++ struct appletbdrm_response_header header;
++ u8 unk_14[12];
++ __le32 width;
++ __le32 height;
++ u8 bits_per_pixel;
++ __le32 bytes_per_row;
++ __le32 orientation;
++ __le32 bitmap_info;
++ u32 pixel_format;
++ __le32 width_inches; /* floating point */
++ __le32 height_inches; /* floating point */
++} __packed;
++
++struct appletbdrm_frame {
++ __le16 begin_x;
++ __le16 begin_y;
++ __le16 width;
++ __le16 height;
++ __le32 buf_size;
++ u8 buf[];
++} __packed;
++
++struct appletbdrm_fb_request_footer {
++ u8 unk_00[12];
++ __le32 unk_0c;
++ u8 unk_10[12];
++ __le32 unk_1c;
++ __le64 timestamp;
++ u8 unk_28[12];
++ __le32 unk_34;
++ u8 unk_38[20];
++ __le32 unk_4c;
++} __packed;
++
++struct appletbdrm_fb_request {
++ struct appletbdrm_request_header header;
++ __le16 unk_10;
++ u8 msg_id;
++ u8 unk_13[29];
++ /*
++ * Contents of `data`:
++ * - struct appletbdrm_frame frames[];
++ * - struct appletbdrm_fb_request_footer footer;
++ * - padding to make the total size a multiple of 16
++ */
++ u8 data[];
++} __packed;
++
++struct appletbdrm_fb_request_response {
++ struct appletbdrm_response_header header;
++ u8 unk_14[12];
++ __le64 timestamp;
++} __packed;
++
++static int appletbdrm_send_request(struct appletbdrm_device *adev,
++ struct appletbdrm_request_header *request, size_t size)
++{
++ struct usb_device *udev = adev_to_udev(adev);
++ struct drm_device *drm = &adev->drm;
++ int ret, actual_size;
++
++ ret = usb_bulk_msg(udev, usb_sndbulkpipe(udev, adev->out_ep),
++ request, size, &actual_size, APPLETBDRM_BULK_MSG_TIMEOUT);
++ if (ret) {
++ drm_err(drm, "Failed to send message (%pe)\n", ERR_PTR(ret));
++ return ret;
++ }
++
++ if (actual_size != size) {
++ drm_err(drm, "Actual size (%d) doesn't match expected size (%lu)\n",
++ actual_size, size);
++ return -EIO;
++ }
++
++ return ret;
++}
++
++static int appletbdrm_read_response(struct appletbdrm_device *adev,
++ struct appletbdrm_response_header *response,
++ size_t size, u32 expected_response)
++{
++ struct usb_device *udev = adev_to_udev(adev);
++ struct drm_device *drm = &adev->drm;
++ int ret, actual_size;
++
++retry:
++ ret = usb_bulk_msg(udev, usb_rcvbulkpipe(udev, adev->in_ep),
++ response, size, &actual_size, APPLETBDRM_BULK_MSG_TIMEOUT);
++ if (ret) {
++ drm_err(drm, "Failed to read response (%pe)\n", ERR_PTR(ret));
++ return ret;
++ }
++
++ /*
++ * The device responds to the first request sent in a particular
++ * timeframe after the USB device configuration is set with a readiness
++ * signal, in which case the response should be read again
++ */
++ if (response->msg == APPLETBDRM_MSG_SIGNAL_READINESS) {
++ if (!adev->readiness_signal_received) {
++ adev->readiness_signal_received = true;
++ goto retry;
++ }
++
++ drm_err(drm, "Encountered unexpected readiness signal\n");
++ return -EIO;
++ }
++
++ if (actual_size != size) {
++ drm_err(drm, "Actual size (%d) doesn't match expected size (%lu)\n",
++ actual_size, size);
++ return -EIO;
++ }
++
++ if (response->msg != expected_response) {
++ drm_err(drm, "Unexpected response from device (expected %p4ch found %p4ch)\n",
++ &expected_response, &response->msg);
++ return -EIO;
++ }
++
++ return 0;
++}
++
++static int appletbdrm_send_msg(struct appletbdrm_device *adev, u32 msg)
++{
++ struct appletbdrm_simple_request *request;
++ int ret;
++
++ request = kzalloc(sizeof(*request), GFP_KERNEL);
++ if (!request)
++ return -ENOMEM;
++
++ request->header.unk_00 = cpu_to_le16(2);
++ request->header.unk_02 = cpu_to_le16(0x1512);
++ request->header.size = cpu_to_le32(sizeof(*request) - sizeof(request->header));
++ request->msg = msg;
++ request->size = request->header.size;
++
++ ret = appletbdrm_send_request(adev, &request->header, sizeof(*request));
++
++ kfree(request);
++
++ return ret;
++}
++
++static int appletbdrm_clear_display(struct appletbdrm_device *adev)
++{
++ return appletbdrm_send_msg(adev, APPLETBDRM_MSG_CLEAR_DISPLAY);
++}
++
++static int appletbdrm_signal_readiness(struct appletbdrm_device *adev)
++{
++ return appletbdrm_send_msg(adev, APPLETBDRM_MSG_SIGNAL_READINESS);
++}
++
++static int appletbdrm_get_information(struct appletbdrm_device *adev)
++{
++ struct appletbdrm_information *info;
++ struct drm_device *drm = &adev->drm;
++ u8 bits_per_pixel;
++ u32 pixel_format;
++ int ret;
++
++ info = kzalloc(sizeof(*info), GFP_KERNEL);
++ if (!info)
++ return -ENOMEM;
++
++ ret = appletbdrm_send_msg(adev, APPLETBDRM_MSG_GET_INFORMATION);
++ if (ret)
++ return ret;
++
++ ret = appletbdrm_read_response(adev, &info->header, sizeof(*info),
++ APPLETBDRM_MSG_GET_INFORMATION);
++ if (ret)
++ goto free_info;
++
++ bits_per_pixel = info->bits_per_pixel;
++ pixel_format = get_unaligned(&info->pixel_format);
++
++ adev->width = get_unaligned_le32(&info->width);
++ adev->height = get_unaligned_le32(&info->height);
++
++ if (bits_per_pixel != APPLETBDRM_BITS_PER_PIXEL) {
++ drm_err(drm, "Encountered unexpected bits per pixel value (%d)\n", bits_per_pixel);
++ ret = -EINVAL;
++ goto free_info;
++ }
++
++ if (pixel_format != APPLETBDRM_PIXEL_FORMAT) {
++ drm_err(drm, "Encountered unknown pixel format (%p4ch)\n", &pixel_format);
++ ret = -EINVAL;
++ goto free_info;
++ }
++
++free_info:
++ kfree(info);
++
++ return ret;
++}
++
++static u32 rect_size(struct drm_rect *rect)
++{
++ return drm_rect_width(rect) * drm_rect_height(rect) * (APPLETBDRM_BITS_PER_PIXEL / 8);
++}
++
++static int appletbdrm_flush_damage(struct appletbdrm_device *adev,
++ struct drm_plane_state *old_state,
++ struct drm_plane_state *state)
++{
++ struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(state);
++ struct appletbdrm_fb_request_response *response;
++ struct appletbdrm_fb_request_footer *footer;
++ struct drm_atomic_helper_damage_iter iter;
++ struct drm_framebuffer *fb = state->fb;
++ struct appletbdrm_fb_request *request;
++ struct drm_device *drm = &adev->drm;
++ struct appletbdrm_frame *frame;
++ u64 timestamp = ktime_get_ns();
++ struct drm_rect damage;
++ size_t frames_size = 0;
++ size_t request_size;
++ int ret;
++
++ drm_atomic_helper_damage_iter_init(&iter, old_state, state);
++ drm_atomic_for_each_plane_damage(&iter, &damage) {
++ frames_size += struct_size(frame, buf, rect_size(&damage));
++ }
++
++ if (!frames_size)
++ return 0;
++
++ request_size = ALIGN(sizeof(*request) + frames_size + sizeof(*footer), 16);
++
++ request = kzalloc(request_size, GFP_KERNEL);
++ if (!request)
++ return -ENOMEM;
++
++ response = kzalloc(sizeof(*response), GFP_KERNEL);
++ if (!response) {
++ ret = -ENOMEM;
++ goto free_request;
++ }
++
++ ret = drm_gem_fb_begin_cpu_access(fb, DMA_FROM_DEVICE);
++ if (ret) {
++ drm_err(drm, "Failed to start CPU framebuffer access (%pe)\n", ERR_PTR(ret));
++ goto free_response;
++ }
++
++ request->header.unk_00 = cpu_to_le16(2);
++ request->header.unk_02 = cpu_to_le16(0x12);
++ request->header.unk_04 = cpu_to_le32(9);
++ request->header.size = cpu_to_le32(request_size - sizeof(request->header));
++ request->unk_10 = cpu_to_le16(1);
++ request->msg_id = timestamp & 0xff;
++
++ frame = (struct appletbdrm_frame *)request->data;
++
++ drm_atomic_helper_damage_iter_init(&iter, old_state, state);
++ drm_atomic_for_each_plane_damage(&iter, &damage) {
++ struct iosys_map dst = IOSYS_MAP_INIT_VADDR(frame->buf);
++ u32 buf_size = rect_size(&damage);
++
++ /*
++ * The coordinates need to be translated to the coordinate
++ * system the device expects, see the comment in
++ * appletbdrm_setup_mode_config
++ */
++ frame->begin_x = cpu_to_le16(damage.y1);
++ frame->begin_y = cpu_to_le16(adev->height - damage.x2);
++ frame->width = cpu_to_le16(drm_rect_height(&damage));
++ frame->height = cpu_to_le16(drm_rect_width(&damage));
++ frame->buf_size = cpu_to_le32(buf_size);
++
++ ret = drm_fb_blit(&dst, NULL, DRM_FORMAT_BGR888,
++ &shadow_plane_state->data[0], fb, &damage, &shadow_plane_state->fmtcnv_state);
++ if (ret) {
++ drm_err(drm, "Failed to copy damage clip (%pe)\n", ERR_PTR(ret));
++ goto end_fb_cpu_access;
++ }
++
++ frame = (void *)frame + struct_size(frame, buf, buf_size);
++ }
++
++ footer = (struct appletbdrm_fb_request_footer *)&request->data[frames_size];
++
++ footer->unk_0c = cpu_to_le32(0xfffe);
++ footer->unk_1c = cpu_to_le32(0x80001);
++ footer->unk_34 = cpu_to_le32(0x80002);
++ footer->unk_4c = cpu_to_le32(0xffff);
++ footer->timestamp = cpu_to_le64(timestamp);
++
++ ret = appletbdrm_send_request(adev, &request->header, request_size);
++ if (ret)
++ goto end_fb_cpu_access;
++
++ ret = appletbdrm_read_response(adev, &response->header, sizeof(*response),
++ APPLETBDRM_MSG_UPDATE_COMPLETE);
++ if (ret)
++ goto end_fb_cpu_access;
++
++ if (response->timestamp != footer->timestamp) {
++ drm_err(drm, "Response timestamp (%llu) doesn't match request timestamp (%llu)\n",
++ le64_to_cpu(response->timestamp), timestamp);
++ goto end_fb_cpu_access;
++ }
++
++end_fb_cpu_access:
++ drm_gem_fb_end_cpu_access(fb, DMA_FROM_DEVICE);
++free_response:
++ kfree(response);
++free_request:
++ kfree(request);
++
++ return ret;
++}
++
++static int appletbdrm_connector_helper_get_modes(struct drm_connector *connector)
++{
++ struct appletbdrm_device *adev = drm_to_adev(connector->dev);
++
++ return drm_connector_helper_get_modes_fixed(connector, &adev->mode);
++}
++
++static enum drm_mode_status appletbdrm_pipe_mode_valid(struct drm_simple_display_pipe *pipe,
++ const struct drm_display_mode *mode)
++{
++ struct drm_crtc *crtc = &pipe->crtc;
++ struct appletbdrm_device *adev = drm_to_adev(crtc->dev);
++
++ return drm_crtc_helper_mode_valid_fixed(crtc, mode, &adev->mode);
++}
++
++static void appletbdrm_pipe_disable(struct drm_simple_display_pipe *pipe)
++{
++ struct appletbdrm_device *adev = drm_to_adev(pipe->crtc.dev);
++ int idx;
++
++ if (!drm_dev_enter(&adev->drm, &idx))
++ return;
++
++ appletbdrm_clear_display(adev);
++
++ drm_dev_exit(idx);
++}
++
++static void appletbdrm_pipe_update(struct drm_simple_display_pipe *pipe,
++ struct drm_plane_state *old_state)
++{
++ struct drm_crtc *crtc = &pipe->crtc;
++ struct appletbdrm_device *adev = drm_to_adev(crtc->dev);
++ int idx;
++
++ if (!crtc->state->active || !drm_dev_enter(&adev->drm, &idx))
++ return;
++
++ appletbdrm_flush_damage(adev, old_state, pipe->plane.state);
++
++ drm_dev_exit(idx);
++}
++
++static const u32 appletbdrm_formats[] = {
++ DRM_FORMAT_BGR888,
++ DRM_FORMAT_XRGB8888, /* emulated */
++};
++
++static const struct drm_mode_config_funcs appletbdrm_mode_config_funcs = {
++ .fb_create = drm_gem_fb_create_with_dirty,
++ .atomic_check = drm_atomic_helper_check,
++ .atomic_commit = drm_atomic_helper_commit,
++};
++
++static const struct drm_connector_funcs appletbdrm_connector_funcs = {
++ .reset = drm_atomic_helper_connector_reset,
++ .destroy = drm_connector_cleanup,
++ .fill_modes = drm_helper_probe_single_connector_modes,
++ .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
++ .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
++};
++
++static const struct drm_connector_helper_funcs appletbdrm_connector_helper_funcs = {
++ .get_modes = appletbdrm_connector_helper_get_modes,
++};
++
++static const struct drm_simple_display_pipe_funcs appletbdrm_pipe_funcs = {
++ DRM_GEM_SIMPLE_DISPLAY_PIPE_SHADOW_PLANE_FUNCS,
++ .update = appletbdrm_pipe_update,
++ .disable = appletbdrm_pipe_disable,
++ .mode_valid = appletbdrm_pipe_mode_valid,
++};
++
++DEFINE_DRM_GEM_FOPS(appletbdrm_drm_fops);
++
++static const struct drm_driver appletbdrm_drm_driver = {
++ DRM_GEM_SHMEM_DRIVER_OPS,
++ .name = "appletbdrm",
++ .desc = "Apple Touch Bar DRM Driver",
++ .date = "20230910",
++ .major = 1,
++ .minor = 0,
++ .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_ATOMIC,
++ .fops = &appletbdrm_drm_fops,
++};
++
++static int appletbdrm_setup_mode_config(struct appletbdrm_device *adev)
++{
++ struct drm_connector *connector = &adev->connector;
++ struct drm_device *drm = &adev->drm;
++ struct device *dev = adev->dev;
++ int ret;
++
++ ret = drmm_mode_config_init(drm);
++ if (ret)
++ return dev_err_probe(dev, ret, "Failed to initialize mode configuration\n");
++
++ /*
++ * The coordinate system used by the device is different from the
++ * coordinate system of the framebuffer in that the x and y axes are
++ * swapped, and that the y axis is inverted; so what the device reports
++ * as the height is actually the width of the framebuffer and vice
++ * versa
++ */
++ drm->mode_config.min_width = 0;
++ drm->mode_config.min_height = 0;
++ drm->mode_config.max_width = max(adev->height, DRM_SHADOW_PLANE_MAX_WIDTH);
++ drm->mode_config.max_height = max(adev->width, DRM_SHADOW_PLANE_MAX_HEIGHT);
++ drm->mode_config.preferred_depth = APPLETBDRM_BITS_PER_PIXEL;
++ drm->mode_config.funcs = &appletbdrm_mode_config_funcs;
++
++ adev->mode = (struct drm_display_mode) {
++ DRM_MODE_INIT(60, adev->height, adev->width,
++ DRM_MODE_RES_MM(adev->height, 218),
++ DRM_MODE_RES_MM(adev->width, 218))
++ };
++
++ ret = drm_connector_init(drm, connector,
++ &appletbdrm_connector_funcs, DRM_MODE_CONNECTOR_USB);
++ if (ret)
++ return dev_err_probe(dev, ret, "Failed to initialize connector\n");
++
++ drm_connector_helper_add(connector, &appletbdrm_connector_helper_funcs);
++
++ ret = drm_connector_set_panel_orientation(connector,
++ DRM_MODE_PANEL_ORIENTATION_RIGHT_UP);
++ if (ret)
++ return dev_err_probe(dev, ret, "Failed to set panel orientation\n");
++
++ connector->display_info.non_desktop = true;
++ ret = drm_object_property_set_value(&connector->base,
++ drm->mode_config.non_desktop_property, true);
++ if (ret)
++ return dev_err_probe(dev, ret, "Failed to set non-desktop property\n");
++
++ ret = drm_simple_display_pipe_init(drm, &adev->pipe, &appletbdrm_pipe_funcs,
++ appletbdrm_formats, ARRAY_SIZE(appletbdrm_formats),
++ NULL, &adev->connector);
++ if (ret)
++ return dev_err_probe(dev, ret, "Failed to initialize simple display pipe\n");
++
++ drm_plane_enable_fb_damage_clips(&adev->pipe.plane);
++
++ drm_mode_config_reset(drm);
++
++ ret = drm_dev_register(drm, 0);
++ if (ret)
++ return dev_err_probe(dev, ret, "Failed to register DRM device\n");
++
++ return 0;
++}
++
++static int appletbdrm_probe(struct usb_interface *intf,
++ const struct usb_device_id *id)
++{
++ struct usb_endpoint_descriptor *bulk_in, *bulk_out;
++ struct device *dev = &intf->dev;
++ struct appletbdrm_device *adev;
++ int ret;
++
++ ret = usb_find_common_endpoints(intf->cur_altsetting, &bulk_in, &bulk_out, NULL, NULL);
++ if (ret)
++ return dev_err_probe(dev, ret, "Failed to find bulk endpoints\n");
++
++ adev = devm_drm_dev_alloc(dev, &appletbdrm_drm_driver, struct appletbdrm_device, drm);
++ if (IS_ERR(adev))
++ return PTR_ERR(adev);
++
++ adev->dev = dev;
++ adev->in_ep = bulk_in->bEndpointAddress;
++ adev->out_ep = bulk_out->bEndpointAddress;
++
++ usb_set_intfdata(intf, adev);
++
++ ret = appletbdrm_get_information(adev);
++ if (ret)
++ return dev_err_probe(dev, ret, "Failed to get display information\n");
++
++ ret = appletbdrm_signal_readiness(adev);
++ if (ret)
++ return dev_err_probe(dev, ret, "Failed to signal readiness\n");
++
++ ret = appletbdrm_clear_display(adev);
++ if (ret)
++ return dev_err_probe(dev, ret, "Failed to clear display\n");
++
++ return appletbdrm_setup_mode_config(adev);
++}
++
++static void appletbdrm_disconnect(struct usb_interface *intf)
++{
++ struct appletbdrm_device *adev = usb_get_intfdata(intf);
++ struct drm_device *drm = &adev->drm;
++
++ drm_dev_unplug(drm);
++ drm_atomic_helper_shutdown(drm);
++}
++
++static void appletbdrm_shutdown(struct usb_interface *intf)
++{
++ struct appletbdrm_device *adev = usb_get_intfdata(intf);
++
++ /*
++ * The framebuffer needs to be cleared on shutdown since its content
++ * persists across boots
++ */
++ drm_atomic_helper_shutdown(&adev->drm);
++}
++
++static const struct usb_device_id appletbdrm_usb_id_table[] = {
++ { USB_DEVICE_INTERFACE_CLASS(0x05ac, 0x8302, USB_CLASS_AUDIO_VIDEO) },
++ {}
++};
++MODULE_DEVICE_TABLE(usb, appletbdrm_usb_id_table);
++
++static struct usb_driver appletbdrm_usb_driver = {
++ .name = "appletbdrm",
++ .probe = appletbdrm_probe,
++ .disconnect = appletbdrm_disconnect,
++ .shutdown = appletbdrm_shutdown,
++ .id_table = appletbdrm_usb_id_table,
++};
++module_usb_driver(appletbdrm_usb_driver);
++
++MODULE_AUTHOR("Kerem Karabay <kekrby@gmail.com>");
++MODULE_DESCRIPTION("Apple Touch Bar DRM Driver");
++MODULE_LICENSE("GPL");
+diff --git a/drivers/gpu/vga/vga_switcheroo.c b/drivers/gpu/vga/vga_switcheroo.c
+index 365e6ddbe90f..cf357cd3389d 100644
+--- a/drivers/gpu/vga/vga_switcheroo.c
++++ b/drivers/gpu/vga/vga_switcheroo.c
+@@ -438,12 +438,7 @@ find_active_client(struct list_head *head)
+ bool vga_switcheroo_client_probe_defer(struct pci_dev *pdev)
+ {
+ if ((pdev->class >> 16) == PCI_BASE_CLASS_DISPLAY) {
+- /*
+- * apple-gmux is needed on pre-retina MacBook Pro
+- * to probe the panel if pdev is the inactive GPU.
+- */
+- if (apple_gmux_present() && pdev != vga_default_device() &&
+- !vgasr_priv.handler_flags)
++ if (apple_gmux_present() && !vgasr_priv.handler_flags)
+ return true;
+ }
+
+diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
+index 08446c89eff6..35ef5d4ef068 100644
+--- a/drivers/hid/Kconfig
++++ b/drivers/hid/Kconfig
+@@ -148,6 +148,27 @@ config HID_APPLEIR
+
+ Say Y here if you want support for Apple infrared remote control.
+
++config HID_APPLETB_BL
++ tristate "Apple Touch Bar Backlight"
++ depends on BACKLIGHT_CLASS_DEVICE
++ help
++ Say Y here if you want support for the backlight of Touch Bars on x86
++ MacBook Pros.
++
++ To compile this driver as a module, choose M here: the
++ module will be called hid-appletb-bl.
++
++config HID_APPLETB_KBD
++ tristate "Apple Touch Bar Keyboard Mode"
++ depends on USB_HID
++ help
++ Say Y here if you want support for the keyboard mode (escape,
++ function, media and brightness keys) of Touch Bars on x86 MacBook
++ Pros.
++
++ To compile this driver as a module, choose M here: the
++ module will be called hid-appletb-kbd.
++
+ config HID_ASUS
+ tristate "Asus"
+ depends on USB_HID
+@@ -723,6 +744,7 @@ config HID_MULTITOUCH
+ Say Y here if you have one of the following devices:
+ - 3M PCT touch screens
+ - ActionStar dual touch panels
++ - Touch Bars on x86 MacBook Pros
+ - Atmel panels
+ - Cando dual touch panels
+ - Chunghwa panels
+diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile
+index ce71b53ea6c5..fecec1d61393 100644
+--- a/drivers/hid/Makefile
++++ b/drivers/hid/Makefile
+@@ -29,6 +29,8 @@ obj-$(CONFIG_HID_ALPS) += hid-alps.o
+ obj-$(CONFIG_HID_ACRUX) += hid-axff.o
+ obj-$(CONFIG_HID_APPLE) += hid-apple.o
+ obj-$(CONFIG_HID_APPLEIR) += hid-appleir.o
++obj-$(CONFIG_HID_APPLETB_BL) += hid-appletb-bl.o
++obj-$(CONFIG_HID_APPLETB_KBD) += hid-appletb-kbd.o
+ obj-$(CONFIG_HID_CREATIVE_SB0540) += hid-creative-sb0540.o
+ obj-$(CONFIG_HID_ASUS) += hid-asus.o
+ obj-$(CONFIG_HID_AUREAL) += hid-aureal.o
+diff --git a/drivers/hid/hid-apple.c b/drivers/hid/hid-apple.c
+index bd022e004356..6dedb84d7cc3 100644
+--- a/drivers/hid/hid-apple.c
++++ b/drivers/hid/hid-apple.c
+@@ -8,6 +8,8 @@
+ * Copyright (c) 2006-2007 Jiri Kosina
+ * Copyright (c) 2008 Jiri Slaby <jirislaby@gmail.com>
+ * Copyright (c) 2019 Paul Pawlowski <paul@mrarm.io>
++ * Copyright (c) 2023 Orlando Chamberlain <orlandoch.dev@gmail.com>
++ * Copyright (c) 2024 Aditya Garg <gargaditya08@live.com>
+ */
+
+ /*
+@@ -23,6 +25,7 @@
+ #include <linux/timer.h>
+ #include <linux/string.h>
+ #include <linux/leds.h>
++#include <dt-bindings/leds/common.h>
+
+ #include "hid-ids.h"
+
+@@ -38,12 +41,17 @@
+ #define APPLE_RDESC_BATTERY BIT(9)
+ #define APPLE_BACKLIGHT_CTL BIT(10)
+ #define APPLE_IS_NON_APPLE BIT(11)
++#define APPLE_MAGIC_BACKLIGHT BIT(12)
+
+ #define APPLE_FLAG_FKEY 0x01
+
+ #define HID_COUNTRY_INTERNATIONAL_ISO 13
+ #define APPLE_BATTERY_TIMEOUT_MS 60000
+
++#define HID_USAGE_MAGIC_BL 0xff00000f
++#define APPLE_MAGIC_REPORT_ID_POWER 3
++#define APPLE_MAGIC_REPORT_ID_BRIGHTNESS 1
++
+ static unsigned int fnmode = 3;
+ module_param(fnmode, uint, 0644);
+ MODULE_PARM_DESC(fnmode, "Mode of fn key on Apple keyboards (0 = disabled, "
+@@ -81,6 +89,12 @@ struct apple_sc_backlight {
+ struct hid_device *hdev;
+ };
+
++struct apple_magic_backlight {
++ struct led_classdev cdev;
++ struct hid_report *brightness;
++ struct hid_report *power;
++};
++
+ struct apple_sc {
+ struct hid_device *hdev;
+ unsigned long quirks;
+@@ -822,6 +836,66 @@ static int apple_backlight_init(struct hid_device *hdev)
+ return ret;
+ }
+
++static void apple_magic_backlight_report_set(struct hid_report *rep, s32 value, u8 rate)
++{
++ rep->field[0]->value[0] = value;
++ rep->field[1]->value[0] = 0x5e; /* Mimic Windows */
++ rep->field[1]->value[0] |= rate << 8;
++
++ hid_hw_request(rep->device, rep, HID_REQ_SET_REPORT);
++}
++
++static void apple_magic_backlight_set(struct apple_magic_backlight *backlight,
++ int brightness, char rate)
++{
++ apple_magic_backlight_report_set(backlight->power, brightness ? 1 : 0, rate);
++ if (brightness)
++ apple_magic_backlight_report_set(backlight->brightness, brightness, rate);
++}
++
++static int apple_magic_backlight_led_set(struct led_classdev *led_cdev,
++ enum led_brightness brightness)
++{
++ struct apple_magic_backlight *backlight = container_of(led_cdev,
++ struct apple_magic_backlight, cdev);
++
++ apple_magic_backlight_set(backlight, brightness, 1);
++ return 0;
++}
++
++static int apple_magic_backlight_init(struct hid_device *hdev)
++{
++ struct apple_magic_backlight *backlight;
++ struct hid_report_enum *report_enum;
++
++ /*
++ * Ensure this usb endpoint is for the keyboard backlight, not touchbar
++ * backlight.
++ */
++ if (hdev->collection[0].usage != HID_USAGE_MAGIC_BL)
++ return -ENODEV;
++
++ backlight = devm_kzalloc(&hdev->dev, sizeof(*backlight), GFP_KERNEL);
++ if (!backlight)
++ return -ENOMEM;
++
++ report_enum = &hdev->report_enum[HID_FEATURE_REPORT];
++ backlight->brightness = report_enum->report_id_hash[APPLE_MAGIC_REPORT_ID_BRIGHTNESS];
++ backlight->power = report_enum->report_id_hash[APPLE_MAGIC_REPORT_ID_POWER];
++
++ if (!backlight->brightness || !backlight->power)
++ return -ENODEV;
++
++ backlight->cdev.name = ":white:" LED_FUNCTION_KBD_BACKLIGHT;
++ backlight->cdev.max_brightness = backlight->brightness->field[0]->logical_maximum;
++ backlight->cdev.brightness_set_blocking = apple_magic_backlight_led_set;
++
++ apple_magic_backlight_set(backlight, 0, 0);
++
++ return devm_led_classdev_register(&hdev->dev, &backlight->cdev);
++
++}
++
+ static int apple_probe(struct hid_device *hdev,
+ const struct hid_device_id *id)
+ {
+@@ -860,7 +934,18 @@ static int apple_probe(struct hid_device *hdev,
+ if (quirks & APPLE_BACKLIGHT_CTL)
+ apple_backlight_init(hdev);
+
++ if (quirks & APPLE_MAGIC_BACKLIGHT) {
++ ret = apple_magic_backlight_init(hdev);
++ if (ret)
++ goto out_err;
++ }
++
+ return 0;
++
++out_err:
++ del_timer_sync(&asc->battery_timer);
++ hid_hw_stop(hdev);
++ return ret;
+ }
+
+ static void apple_remove(struct hid_device *hdev)
+@@ -1073,6 +1158,8 @@ static const struct hid_device_id apple_devices[] = {
+ .driver_data = APPLE_HAS_FN | APPLE_ISO_TILDE_QUIRK | APPLE_RDESC_BATTERY },
+ { HID_BLUETOOTH_DEVICE(BT_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_NUMPAD_2021),
+ .driver_data = APPLE_HAS_FN | APPLE_ISO_TILDE_QUIRK },
++ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_TOUCHBAR_BACKLIGHT),
++ .driver_data = APPLE_MAGIC_BACKLIGHT },
+
+ { }
+ };
+diff --git a/drivers/hid/hid-appletb-bl.c b/drivers/hid/hid-appletb-bl.c
+new file mode 100644
+index 000000000000..0c5e4b776851
+--- /dev/null
++++ b/drivers/hid/hid-appletb-bl.c
+@@ -0,0 +1,193 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * Apple Touch Bar Backlight Driver
++ *
++ * Copyright (c) 2017-2018 Ronald Tschalär
++ * Copyright (c) 2022-2023 Kerem Karabay <kekrby@gmail.com>
++ */
++
++#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
++
++#include <linux/hid.h>
++#include <linux/backlight.h>
++
++#include "hid-ids.h"
++
++#define APPLETB_BL_ON 1
++#define APPLETB_BL_DIM 3
++#define APPLETB_BL_OFF 4
++
++#define HID_UP_APPLEVENDOR_TB_BL 0xff120000
++
++#define HID_VD_APPLE_TB_BRIGHTNESS 0xff120001
++#define HID_USAGE_AUX1 0xff120020
++#define HID_USAGE_BRIGHTNESS 0xff120021
++
++struct appletb_bl {
++ struct hid_field *aux1_field, *brightness_field;
++ struct backlight_device *bdev;
++
++ bool full_on;
++};
++
++const u8 appletb_bl_brightness_map[] = {
++ APPLETB_BL_OFF,
++ APPLETB_BL_DIM,
++ APPLETB_BL_ON
++};
++
++static int appletb_bl_set_brightness(struct appletb_bl *bl, u8 brightness)
++{
++ struct hid_report *report = bl->brightness_field->report;
++ struct hid_device *hdev = report->device;
++ int ret;
++
++ ret = hid_set_field(bl->aux1_field, 0, 1);
++ if (ret) {
++ hid_err(hdev, "Failed to set auxiliary field (%pe)\n", ERR_PTR(ret));
++ return ret;
++ }
++
++ ret = hid_set_field(bl->brightness_field, 0, brightness);
++ if (ret) {
++ hid_err(hdev, "Failed to set brightness field (%pe)\n", ERR_PTR(ret));
++ return ret;
++ }
++
++ if (!bl->full_on) {
++ ret = hid_hw_power(hdev, PM_HINT_FULLON);
++ if (ret < 0) {
++ hid_err(hdev, "Device didn't power on (%pe)\n", ERR_PTR(ret));
++ return ret;
++ }
++
++ bl->full_on = true;
++ }
++
++ hid_hw_request(hdev, report, HID_REQ_SET_REPORT);
++
++ if (brightness == APPLETB_BL_OFF) {
++ hid_hw_power(hdev, PM_HINT_NORMAL);
++ bl->full_on = false;
++ }
++
++ return 0;
++}
++
++static int appletb_bl_update_status(struct backlight_device *bdev)
++{
++ struct appletb_bl *bl = bl_get_data(bdev);
++ u16 brightness;
++
++ if (bdev->props.state & BL_CORE_SUSPENDED)
++ brightness = 0;
++ else
++ brightness = backlight_get_brightness(bdev);
++
++ return appletb_bl_set_brightness(bl, appletb_bl_brightness_map[brightness]);
++}
++
++static const struct backlight_ops appletb_bl_backlight_ops = {
++ .options = BL_CORE_SUSPENDRESUME,
++ .update_status = appletb_bl_update_status,
++};
++
++static int appletb_bl_probe(struct hid_device *hdev, const struct hid_device_id *id)
++{
++ struct hid_field *aux1_field, *brightness_field;
++ struct backlight_properties bl_props = { 0 };
++ struct device *dev = &hdev->dev;
++ struct appletb_bl *bl;
++ int ret;
++
++ ret = hid_parse(hdev);
++ if (ret)
++ return dev_err_probe(dev, ret, "HID parse failed\n");
++
++ aux1_field = hid_find_field(hdev, HID_FEATURE_REPORT,
++ HID_VD_APPLE_TB_BRIGHTNESS, HID_USAGE_AUX1);
++
++ brightness_field = hid_find_field(hdev, HID_FEATURE_REPORT,
++ HID_VD_APPLE_TB_BRIGHTNESS, HID_USAGE_BRIGHTNESS);
++
++ if (!aux1_field || !brightness_field)
++ return -ENODEV;
++
++ if (aux1_field->report != brightness_field->report)
++ return dev_err_probe(dev, -ENODEV, "Encountered unexpected report structure\n");
++
++ bl = devm_kzalloc(dev, sizeof(*bl), GFP_KERNEL);
++ if (!bl)
++ return -ENOMEM;
++
++ ret = hid_hw_start(hdev, HID_CONNECT_DRIVER);
++ if (ret)
++ return dev_err_probe(dev, ret, "HID hardware start failed\n");
++
++ ret = hid_hw_open(hdev);
++ if (ret) {
++ dev_err_probe(dev, ret, "HID hardware open failed\n");
++ goto stop_hw;
++ }
++
++ bl->aux1_field = aux1_field;
++ bl->brightness_field = brightness_field;
++
++ ret = appletb_bl_set_brightness(bl, APPLETB_BL_OFF);
++ if (ret) {
++ dev_err_probe(dev, ret, "Failed to set touch bar brightness to off\n");
++ goto close_hw;
++ }
++
++ bl_props.type = BACKLIGHT_RAW;
++ bl_props.max_brightness = ARRAY_SIZE(appletb_bl_brightness_map) - 1;
++
++ bl->bdev = devm_backlight_device_register(dev, "appletb_backlight", dev, bl,
++ &appletb_bl_backlight_ops, &bl_props);
++ if (IS_ERR(bl->bdev)) {
++ ret = PTR_ERR(bl->bdev);
++ dev_err_probe(dev, ret, "Failed to register backlight device\n");
++ goto close_hw;
++ }
++
++ hid_set_drvdata(hdev, bl);
++
++ return 0;
++
++close_hw:
++ hid_hw_close(hdev);
++stop_hw:
++ hid_hw_stop(hdev);
++
++ return ret;
++}
++
++static void appletb_bl_remove(struct hid_device *hdev)
++{
++ struct appletb_bl *bl = hid_get_drvdata(hdev);
++
++ appletb_bl_set_brightness(bl, APPLETB_BL_OFF);
++
++ hid_hw_close(hdev);
++ hid_hw_stop(hdev);
++}
++
++static const struct hid_device_id appletb_bl_hid_ids[] = {
++ /* MacBook Pro's 2018, 2019, with T2 chip: iBridge DFR Brightness */
++ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_TOUCHBAR_BACKLIGHT) },
++ { }
++};
++MODULE_DEVICE_TABLE(hid, appletb_bl_hid_ids);
++
++static struct hid_driver appletb_bl_hid_driver = {
++ .name = "hid-appletb-bl",
++ .id_table = appletb_bl_hid_ids,
++ .probe = appletb_bl_probe,
++ .remove = appletb_bl_remove,
++};
++module_hid_driver(appletb_bl_hid_driver);
++
++MODULE_AUTHOR("Ronald Tschalär");
++MODULE_AUTHOR("Kerem Karabay <kekrby@gmail.com>");
++MODULE_DESCRIPTION("MacBookPro Touch Bar Backlight Driver");
++MODULE_LICENSE("GPL");
+diff --git a/drivers/hid/hid-appletb-kbd.c b/drivers/hid/hid-appletb-kbd.c
+new file mode 100644
+index 000000000000..bc004c40805f
+--- /dev/null
++++ b/drivers/hid/hid-appletb-kbd.c
+@@ -0,0 +1,289 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * Apple Touch Bar Keyboard Mode Driver
++ *
++ * Copyright (c) 2017-2018 Ronald Tschalär
++ * Copyright (c) 2022-2023 Kerem Karabay <kekrby@gmail.com>
++ */
++
++#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
++
++#include <linux/hid.h>
++#include <linux/usb.h>
++#include <linux/input.h>
++#include <linux/sysfs.h>
++#include <linux/bitops.h>
++#include <linux/module.h>
++#include <linux/string.h>
++#include <linux/input/sparse-keymap.h>
++
++#include "hid-ids.h"
++
++#define APPLETB_KBD_MODE_ESC 0
++#define APPLETB_KBD_MODE_FN 1
++#define APPLETB_KBD_MODE_SPCL 2
++#define APPLETB_KBD_MODE_OFF 3
++#define APPLETB_KBD_MODE_MAX APPLETB_KBD_MODE_OFF
++
++#define HID_USAGE_MODE 0x00ff0004
++
++struct appletb_kbd {
++ struct hid_field *mode_field;
++
++ u8 saved_mode;
++ u8 current_mode;
++};
++
++static const struct key_entry appletb_kbd_keymap[] = {
++ { KE_KEY, KEY_ESC, { KEY_ESC } },
++ { KE_KEY, KEY_F1, { KEY_BRIGHTNESSDOWN } },
++ { KE_KEY, KEY_F2, { KEY_BRIGHTNESSUP } },
++ { KE_KEY, KEY_F3, { KEY_RESERVED } },
++ { KE_KEY, KEY_F4, { KEY_RESERVED } },
++ { KE_KEY, KEY_F5, { KEY_KBDILLUMDOWN } },
++ { KE_KEY, KEY_F6, { KEY_KBDILLUMUP } },
++ { KE_KEY, KEY_F7, { KEY_PREVIOUSSONG } },
++ { KE_KEY, KEY_F8, { KEY_PLAYPAUSE } },
++ { KE_KEY, KEY_F9, { KEY_NEXTSONG } },
++ { KE_KEY, KEY_F10, { KEY_MUTE } },
++ { KE_KEY, KEY_F11, { KEY_VOLUMEDOWN } },
++ { KE_KEY, KEY_F12, { KEY_VOLUMEUP } },
++ { KE_END, 0 }
++};
++
++static int appletb_kbd_set_mode(struct appletb_kbd *kbd, u8 mode)
++{
++ struct hid_report *report = kbd->mode_field->report;
++ struct hid_device *hdev = report->device;
++ int ret;
++
++ ret = hid_hw_power(hdev, PM_HINT_FULLON);
++ if (ret) {
++ hid_err(hdev, "Device didn't resume (%pe)\n", ERR_PTR(ret));
++ return ret;
++ }
++
++ ret = hid_set_field(kbd->mode_field, 0, mode);
++ if (ret) {
++ hid_err(hdev, "Failed to set mode field to %u (%pe)\n", mode, ERR_PTR(ret));
++ goto power_normal;
++ }
++
++ hid_hw_request(hdev, report, HID_REQ_SET_REPORT);
++
++ kbd->current_mode = mode;
++
++power_normal:
++ hid_hw_power(hdev, PM_HINT_NORMAL);
++
++ return ret;
++}
++
++static ssize_t mode_show(struct device *dev,
++ struct device_attribute *attr, char *buf)
++{
++ struct appletb_kbd *kbd = dev_get_drvdata(dev);
++
++ return sysfs_emit(buf, "%d\n", kbd->current_mode);
++}
++
++static ssize_t mode_store(struct device *dev,
++ struct device_attribute *attr,
++ const char *buf, size_t size)
++{
++ struct appletb_kbd *kbd = dev_get_drvdata(dev);
++ u8 mode;
++ int ret;
++
++ ret = kstrtou8(buf, 0, &mode);
++ if (ret)
++ return ret;
++
++ if (mode > APPLETB_KBD_MODE_MAX)
++ return -EINVAL;
++
++ ret = appletb_kbd_set_mode(kbd, mode);
++
++ return ret < 0 ? ret : size;
++}
++static DEVICE_ATTR_RW(mode);
++
++struct attribute *appletb_kbd_attrs[] = {
++ &dev_attr_mode.attr,
++ NULL
++};
++ATTRIBUTE_GROUPS(appletb_kbd);
++
++static int appletb_tb_key_to_slot(unsigned int code)
++{
++ switch (code) {
++ case KEY_ESC:
++ return 0;
++ case KEY_F1 ... KEY_F10:
++ return code - KEY_F1 + 1;
++ case KEY_F11 ... KEY_F12:
++ return code - KEY_F11 + 11;
++
++ default:
++ return -EINVAL;
++ }
++}
++
++static int appletb_kbd_hid_event(struct hid_device *hdev, struct hid_field *field,
++ struct hid_usage *usage, __s32 value)
++{
++ struct appletb_kbd *kbd = hid_get_drvdata(hdev);
++ struct key_entry *translation;
++ struct input_dev *input;
++ int slot;
++
++ if ((usage->hid & HID_USAGE_PAGE) != HID_UP_KEYBOARD || usage->type != EV_KEY)
++ return 0;
++
++ input = field->hidinput->input;
++
++ /*
++ * Skip non-touch-bar keys.
++ *
++ * Either the touch bar itself or usbhid generate a slew of key-down
++ * events for all the meta keys. None of which we're at all interested
++ * in.
++ */
++ slot = appletb_tb_key_to_slot(usage->code);
++ if (slot < 0)
++ return 0;
++
++ translation = sparse_keymap_entry_from_scancode(input, usage->code);
++
++ if (translation && kbd->current_mode == APPLETB_KBD_MODE_SPCL) {
++ input_event(input, usage->type, translation->keycode, value);
++
++ return 1;
++ }
++
++ return kbd->current_mode == APPLETB_KBD_MODE_OFF;
++}
++
++static int appletb_kbd_input_configured(struct hid_device *hdev, struct hid_input *hidinput)
++{
++ struct input_dev *input = hidinput->input;
++
++ /*
++ * Clear various input capabilities that are blindly set by the hid
++ * driver (usbkbd.c)
++ */
++ memset(input->evbit, 0, sizeof(input->evbit));
++ memset(input->keybit, 0, sizeof(input->keybit));
++ memset(input->ledbit, 0, sizeof(input->ledbit));
++
++ __set_bit(EV_REP, input->evbit);
++
++ return sparse_keymap_setup(input, appletb_kbd_keymap, NULL);
++}
++
++static int appletb_kbd_probe(struct hid_device *hdev, const struct hid_device_id *id)
++{
++ struct appletb_kbd *kbd;
++ struct device *dev = &hdev->dev;
++ struct hid_field *mode_field;
++ int ret;
++
++ ret = hid_parse(hdev);
++ if (ret)
++ return dev_err_probe(dev, ret, "HID parse failed\n");
++
++ mode_field = hid_find_field(hdev, HID_OUTPUT_REPORT,
++ HID_GD_KEYBOARD, HID_USAGE_MODE);
++ if (!mode_field)
++ return -ENODEV;
++
++ kbd = devm_kzalloc(dev, sizeof(*kbd), GFP_KERNEL);
++ if (!kbd)
++ return -ENOMEM;
++
++ kbd->mode_field = mode_field;
++
++ ret = hid_hw_start(hdev, HID_CONNECT_HIDINPUT);
++ if (ret)
++ return dev_err_probe(dev, ret, "HID hw start failed\n");
++
++ ret = hid_hw_open(hdev);
++ if (ret) {
++ dev_err_probe(dev, ret, "HID hw open failed\n");
++ goto stop_hw;
++ }
++
++ ret = appletb_kbd_set_mode(kbd, APPLETB_KBD_MODE_OFF);
++ if (ret) {
++ dev_err_probe(dev, ret, "Failed to set touchbar mode\n");
++ goto close_hw;
++ }
++
++ hid_set_drvdata(hdev, kbd);
++
++ return 0;
++
++close_hw:
++ hid_hw_close(hdev);
++stop_hw:
++ hid_hw_stop(hdev);
++ return ret;
++}
++
++static void appletb_kbd_remove(struct hid_device *hdev)
++{
++ struct appletb_kbd *kbd = hid_get_drvdata(hdev);
++
++ appletb_kbd_set_mode(kbd, APPLETB_KBD_MODE_OFF);
++
++ hid_hw_close(hdev);
++ hid_hw_stop(hdev);
++}
++
++#ifdef CONFIG_PM
++static int appletb_kbd_suspend(struct hid_device *hdev, pm_message_t msg)
++{
++ struct appletb_kbd *kbd = hid_get_drvdata(hdev);
++
++ kbd->saved_mode = kbd->current_mode;
++ appletb_kbd_set_mode(kbd, APPLETB_KBD_MODE_OFF);
++
++ return 0;
++}
++
++static int appletb_kbd_reset_resume(struct hid_device *hdev)
++{
++ struct appletb_kbd *kbd = hid_get_drvdata(hdev);
++
++ appletb_kbd_set_mode(kbd, kbd->saved_mode);
++
++ return 0;
++}
++#endif
++
++static const struct hid_device_id appletb_kbd_hid_ids[] = {
++ /* MacBook Pro's 2018, 2019, with T2 chip: iBridge Display */
++ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_TOUCHBAR_DISPLAY) },
++ { }
++};
++MODULE_DEVICE_TABLE(hid, appletb_kbd_hid_ids);
++
++static struct hid_driver appletb_kbd_hid_driver = {
++ .name = "hid-appletb-kbd",
++ .id_table = appletb_kbd_hid_ids,
++ .probe = appletb_kbd_probe,
++ .remove = appletb_kbd_remove,
++ .event = appletb_kbd_hid_event,
++ .input_configured = appletb_kbd_input_configured,
++#ifdef CONFIG_PM
++ .suspend = appletb_kbd_suspend,
++ .reset_resume = appletb_kbd_reset_resume,
++#endif
++ .driver.dev_groups = appletb_kbd_groups,
++};
++module_hid_driver(appletb_kbd_hid_driver);
++
++MODULE_AUTHOR("Ronald Tschalär");
++MODULE_AUTHOR("Kerem Karabay <kekrby@gmail.com>");
++MODULE_DESCRIPTION("MacBookPro Touch Bar Keyboard Mode Driver");
++MODULE_LICENSE("GPL");
+diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
+index 74efda212c55..f4379efdbf30 100644
+--- a/drivers/hid/hid-core.c
++++ b/drivers/hid/hid-core.c
+@@ -1912,6 +1912,31 @@ int hid_set_field(struct hid_field *field, unsigned offset, __s32 value)
+ }
+ EXPORT_SYMBOL_GPL(hid_set_field);
+
++struct hid_field *hid_find_field(struct hid_device *hdev, unsigned int report_type,
++ unsigned int application, unsigned int usage)
++{
++ struct list_head *report_list = &hdev->report_enum[report_type].report_list;
++ struct hid_report *report;
++ int i, j;
++
++ list_for_each_entry(report, report_list, list) {
++ if (report->application != application)
++ continue;
++
++ for (i = 0; i < report->maxfield; i++) {
++ struct hid_field *field = report->field[i];
++
++ for (j = 0; j < field->maxusage; j++) {
++ if (field->usage[j].hid == usage)
++ return field;
++ }
++ }
++ }
++
++ return NULL;
++}
++EXPORT_SYMBOL_GPL(hid_find_field);
++
+ static struct hid_report *hid_get_report(struct hid_report_enum *report_enum,
+ const u8 *data)
+ {
+diff --git a/drivers/hid/hid-google-hammer.c b/drivers/hid/hid-google-hammer.c
+index 25331695ae32..3380694ba18c 100644
+--- a/drivers/hid/hid-google-hammer.c
++++ b/drivers/hid/hid-google-hammer.c
+@@ -418,38 +418,15 @@ static int hammer_event(struct hid_device *hid, struct hid_field *field,
+ return 0;
+ }
+
+-static bool hammer_has_usage(struct hid_device *hdev, unsigned int report_type,
+- unsigned application, unsigned usage)
+-{
+- struct hid_report_enum *re = &hdev->report_enum[report_type];
+- struct hid_report *report;
+- int i, j;
+-
+- list_for_each_entry(report, &re->report_list, list) {
+- if (report->application != application)
+- continue;
+-
+- for (i = 0; i < report->maxfield; i++) {
+- struct hid_field *field = report->field[i];
+-
+- for (j = 0; j < field->maxusage; j++)
+- if (field->usage[j].hid == usage)
+- return true;
+- }
+- }
+-
+- return false;
+-}
+-
+ static bool hammer_has_folded_event(struct hid_device *hdev)
+ {
+- return hammer_has_usage(hdev, HID_INPUT_REPORT,
++ return !!hid_find_field(hdev, HID_INPUT_REPORT,
+ HID_GD_KEYBOARD, HID_USAGE_KBD_FOLDED);
+ }
+
+ static bool hammer_has_backlight_control(struct hid_device *hdev)
+ {
+- return hammer_has_usage(hdev, HID_OUTPUT_REPORT,
++ return !!hid_find_field(hdev, HID_OUTPUT_REPORT,
+ HID_GD_KEYBOARD, HID_AD_BRIGHTNESS);
+ }
+
+diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c
+index 56fc78841f24..0fed955364c3 100644
+--- a/drivers/hid/hid-multitouch.c
++++ b/drivers/hid/hid-multitouch.c
+@@ -78,6 +78,7 @@
+ #define MT_QUIRK_ORIENTATION_INVERT BIT(22)
+ #define MT_QUIRK_HAS_TYPE_COVER_BACKLIGHT BIT(23)
+ #define MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH BIT(24)
++#define MT_QUIRK_TOUCH_IS_TIPSTATE BIT(25)
+
+ #define MT_INPUTMODE_TOUCHSCREEN 0x02
+ #define MT_INPUTMODE_TOUCHPAD 0x03
+@@ -145,6 +146,7 @@ struct mt_class {
+ __s32 sn_height; /* Signal/noise ratio for height events */
+ __s32 sn_pressure; /* Signal/noise ratio for pressure events */
+ __u8 maxcontacts;
++ bool is_direct; /* true for touchscreens */
+ bool is_indirect; /* true for touchpads */
+ bool export_all_inputs; /* do not ignore mouse, keyboards, etc... */
+ };
+@@ -225,6 +225,7 @@
+ #define MT_CLS_RAZER_BLADE_STEALTH 0x0112
+ #define MT_CLS_SMART_TECH 0x0113
+ #define MT_CLS_WIN_8_MS_SURFACE_TYPE_COVER 0x0114
++#define MT_CLS_APPLE_TOUCHBAR 0x0115
+
+ #define MT_DEFAULT_MAXCONTACT 10
+ #define MT_MAX_MAXCONTACT 250
+@@ -420,6 +420,13 @@
+ MT_QUIRK_WIN8_PTP_BUTTONS,
+ .export_all_inputs = true
+ },
++ { .name = MT_CLS_APPLE_TOUCHBAR,
++ .quirks = MT_QUIRK_HOVERING |
++ MT_QUIRK_TOUCH_IS_TIPSTATE |
++ MT_QUIRK_SLOT_IS_CONTACTID_MINUS_ONE,
++ .is_direct = true,
++ .maxcontacts = 11,
++ },
+ { }
+ };
+
+@@ -489,9 +499,6 @@ static void mt_feature_mapping(struct hid_device *hdev,
+ if (!td->maxcontacts &&
+ field->logical_maximum <= MT_MAX_MAXCONTACT)
+ td->maxcontacts = field->logical_maximum;
+- if (td->mtclass.maxcontacts)
+- /* check if the maxcontacts is given by the class */
+- td->maxcontacts = td->mtclass.maxcontacts;
+
+ break;
+ case HID_DG_BUTTONTYPE:
+@@ -565,13 +572,13 @@ static struct mt_application *mt_allocate_application(struct mt_device *td,
+ mt_application->application = application;
+ INIT_LIST_HEAD(&mt_application->mt_usages);
+
+- if (application == HID_DG_TOUCHSCREEN)
++ if (application == HID_DG_TOUCHSCREEN && !td->mtclass.is_indirect)
+ mt_application->mt_flags |= INPUT_MT_DIRECT;
+
+ /*
+ * Model touchscreens providing buttons as touchpads.
+ */
+- if (application == HID_DG_TOUCHPAD) {
++ if (application == HID_DG_TOUCHPAD && !td->mtclass.is_direct) {
+ mt_application->mt_flags |= INPUT_MT_POINTER;
+ td->inputmode_value = MT_INPUTMODE_TOUCHPAD;
+ }
+@@ -635,7 +642,9 @@ static struct mt_report_data *mt_allocate_report_data(struct mt_device *td,
+
+ if (field->logical == HID_DG_FINGER || td->hdev->group != HID_GROUP_MULTITOUCH_WIN_8) {
+ for (n = 0; n < field->report_count; n++) {
+- if (field->usage[n].hid == HID_DG_CONTACTID) {
++ unsigned int hid = field->usage[n].hid;
++
++ if (hid == HID_DG_CONTACTID || hid == HID_DG_TRANSDUCER_INDEX) {
+ rdata->is_mt_collection = true;
+ break;
+ }
+@@ -807,6 +816,15 @@ static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi,
+
+ MT_STORE_FIELD(confidence_state);
+ return 1;
++ case HID_DG_TOUCH:
++ /*
++ * Legacy devices use TIPSWITCH and not TOUCH.
++ * Let's just ignore this field unless the quirk is set.
++ */
++ if (!(cls->quirks & MT_QUIRK_TOUCH_IS_TIPSTATE))
++ return -1;
++
++ fallthrough;
+ case HID_DG_TIPSWITCH:
+ if (field->application != HID_GD_SYSTEM_MULTIAXIS)
+ input_set_capability(hi->input,
+@@ -814,6 +832,7 @@ static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi,
+ MT_STORE_FIELD(tip_state);
+ return 1;
+ case HID_DG_CONTACTID:
++ case HID_DG_TRANSDUCER_INDEX:
+ MT_STORE_FIELD(contactid);
+ app->touches_by_report++;
+ return 1;
+@@ -869,10 +888,6 @@ static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi,
+ case HID_DG_CONTACTMAX:
+ /* contact max are global to the report */
+ return -1;
+- case HID_DG_TOUCH:
+- /* Legacy devices use TIPSWITCH and not TOUCH.
+- * Let's just ignore this field. */
+- return -1;
+ }
+ /* let hid-input decide for the others */
+ return 0;
+@@ -1300,6 +1315,10 @@ static int mt_touch_input_configured(struct hid_device *hdev,
+ struct input_dev *input = hi->input;
+ int ret;
+
++ /* check if the maxcontacts is given by the class */
++ if (cls->maxcontacts)
++ td->maxcontacts = cls->maxcontacts;
++
+ if (!td->maxcontacts)
+ td->maxcontacts = MT_DEFAULT_MAXCONTACT;
+
+@@ -1307,6 +1326,9 @@ static int mt_touch_input_configured(struct hid_device *hdev,
+ if (td->serial_maybe)
+ mt_post_parse_default_settings(td, app);
+
++ if (cls->is_direct)
++ app->mt_flags |= INPUT_MT_DIRECT;
++
+ if (cls->is_indirect)
+ app->mt_flags |= INPUT_MT_POINTER;
+
+@@ -1882,6 +1882,17 @@
+ }
+ }
+
++ ret = hid_parse(hdev);
++ if (ret != 0) {
++ unregister_pm_notifier(&td->pm_notifier);
++ return ret;
++ }
++
++ if (mtclass->name == MT_CLS_APPLE_TOUCHBAR &&
++ !hid_find_field(hdev, HID_INPUT_REPORT,
++ HID_DG_TOUCHPAD, HID_DG_TRANSDUCER_INDEX))
++ return -ENODEV;
++
+ td = devm_kzalloc(&hdev->dev, sizeof(struct mt_device), GFP_KERNEL);
+ if (!td) {
+ dev_err(&hdev->dev, "cannot allocate multitouch data\n");
+@@ -1932,12 +1943,6 @@
+
+ timer_setup(&td->release_timer, mt_expired_timeout, 0);
+
+- ret = hid_parse(hdev);
+- if (ret != 0) {
+- unregister_pm_notifier(&td->pm_notifier);
+- return ret;
+- }
+-
+ if (mtclass->quirks & MT_QUIRK_FIX_CONST_CONTACT_ID)
+ mt_fix_const_fields(hdev, HID_DG_CONTACTID);
+
+@@ -2427,6 +2427,11 @@
+ HID_DEVICE(HID_BUS_ANY, HID_GROUP_ANY,
+ USB_VENDOR_ID_MICROSOFT, 0x09c0) },
+
++ /* Apple Touch Bars */
++ { .driver_data = MT_CLS_APPLE_TOUCHBAR,
++ HID_USB_DEVICE(USB_VENDOR_ID_APPLE,
++ USB_DEVICE_ID_APPLE_TOUCHBAR_DISPLAY) },
++
+ /* Google MT devices */
+ { .driver_data = MT_CLS_GOOGLE,
+ HID_DEVICE(HID_BUS_ANY, HID_GROUP_ANY, USB_VENDOR_ID_GOOGLE,
+diff --git a/drivers/hid/hid-quirks.c b/drivers/hid/hid-quirks.c
+index e0bbf0c6345d..7c576d6540fe 100644
+--- a/drivers/hid/hid-quirks.c
++++ b/drivers/hid/hid-quirks.c
+@@ -328,8 +328,6 @@ static const struct hid_device_id hid_have_special_driver[] = {
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_2021) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_FINGERPRINT_2021) },
+- { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_TOUCHBAR_BACKLIGHT) },
+- { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_TOUCHBAR_DISPLAY) },
+ #endif
+ #if IS_ENABLED(CONFIG_HID_APPLEIR)
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL) },
+@@ -338,6 +336,12 @@ static const struct hid_device_id hid_have_special_driver[] = {
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL4) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL5) },
+ #endif
++#if IS_ENABLED(CONFIG_HID_APPLETB_BL)
++ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_TOUCHBAR_BACKLIGHT) },
++#endif
++#if IS_ENABLED(CONFIG_HID_APPLETB_KBD)
++ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_TOUCHBAR_DISPLAY) },
++#endif
+ #if IS_ENABLED(CONFIG_HID_ASUS)
+ { HID_I2C_DEVICE(USB_VENDOR_ID_ASUSTEK, USB_DEVICE_ID_ASUSTEK_I2C_KEYBOARD) },
+ { HID_I2C_DEVICE(USB_VENDOR_ID_ASUSTEK, USB_DEVICE_ID_ASUSTEK_I2C_TOUCHPAD) },
+diff --git a/drivers/hwmon/applesmc.c b/drivers/hwmon/applesmc.c
+index fc6d6a9053ce..698f44794453 100644
+--- a/drivers/hwmon/applesmc.c
++++ b/drivers/hwmon/applesmc.c
+@@ -6,6 +6,7 @@
+ *
+ * Copyright (C) 2007 Nicolas Boichat <nicolas@boichat.ch>
+ * Copyright (C) 2010 Henrik Rydberg <rydberg@euromail.se>
++ * Copyright (C) 2019 Paul Pawlowski <paul@mrarm.io>
+ *
+ * Based on hdaps.c driver:
+ * Copyright (C) 2005 Robert Love <rml@novell.com>
+@@ -18,7 +19,7 @@
+ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+ #include <linux/delay.h>
+-#include <linux/platform_device.h>
++#include <linux/acpi.h>
+ #include <linux/input.h>
+ #include <linux/kernel.h>
+ #include <linux/slab.h>
+@@ -35,12 +36,24 @@
+ #include <linux/bits.h>
+
+ /* data port used by Apple SMC */
+-#define APPLESMC_DATA_PORT 0x300
++#define APPLESMC_DATA_PORT 0
+ /* command/status port used by Apple SMC */
+-#define APPLESMC_CMD_PORT 0x304
++#define APPLESMC_CMD_PORT 4
+
+ #define APPLESMC_NR_PORTS 32 /* 0x300-0x31f */
+
++#define APPLESMC_IOMEM_KEY_DATA 0
++#define APPLESMC_IOMEM_KEY_STATUS 0x4005
++#define APPLESMC_IOMEM_KEY_NAME 0x78
++#define APPLESMC_IOMEM_KEY_DATA_LEN 0x7D
++#define APPLESMC_IOMEM_KEY_SMC_ID 0x7E
++#define APPLESMC_IOMEM_KEY_CMD 0x7F
++#define APPLESMC_IOMEM_MIN_SIZE 0x4006
++
++#define APPLESMC_IOMEM_KEY_TYPE_CODE 0
++#define APPLESMC_IOMEM_KEY_TYPE_DATA_LEN 5
++#define APPLESMC_IOMEM_KEY_TYPE_FLAGS 6
++
+ #define APPLESMC_MAX_DATA_LENGTH 32
+
+ /* Apple SMC status bits */
+@@ -74,6 +87,7 @@
+ #define FAN_ID_FMT "F%dID" /* r-o char[16] */
+
+ #define TEMP_SENSOR_TYPE "sp78"
++#define FLOAT_TYPE "flt "
+
+ /* List of keys used to read/write fan speeds */
+ static const char *const fan_speed_fmt[] = {
+@@ -83,6 +97,7 @@ static const char *const fan_speed_fmt[] = {
+ "F%dSf", /* safe speed - not all models */
+ "F%dTg", /* target speed (manual: rw) */
+ };
++#define FAN_MANUAL_FMT "F%dMd"
+
+ #define INIT_TIMEOUT_MSECS 5000 /* wait up to 5s for device init ... */
+ #define INIT_WAIT_MSECS 50 /* ... in 50ms increments */
+@@ -119,7 +134,7 @@ struct applesmc_entry {
+ };
+
+ /* Register lookup and registers common to all SMCs */
+-static struct applesmc_registers {
++struct applesmc_registers {
+ struct mutex mutex; /* register read/write mutex */
+ unsigned int key_count; /* number of SMC registers */
+ unsigned int fan_count; /* number of fans */
+@@ -133,26 +148,38 @@ static struct applesmc_registers {
+ bool init_complete; /* true when fully initialized */
+ struct applesmc_entry *cache; /* cached key entries */
+ const char **index; /* temperature key index */
+-} smcreg = {
+- .mutex = __MUTEX_INITIALIZER(smcreg.mutex),
+ };
+
+-static const int debug;
+-static struct platform_device *pdev;
+-static s16 rest_x;
+-static s16 rest_y;
+-static u8 backlight_state[2];
++struct applesmc_device {
++ struct acpi_device *dev;
++ struct device *ldev;
++ struct applesmc_registers reg;
+
+-static struct device *hwmon_dev;
+-static struct input_dev *applesmc_idev;
++ bool port_base_set, iomem_base_set;
++ u16 port_base;
++ u8 *__iomem iomem_base;
++ u32 iomem_base_addr, iomem_base_size;
+
+-/*
+- * Last index written to key_at_index sysfs file, and value to use for all other
+- * key_at_index_* sysfs files.
+- */
+-static unsigned int key_at_index;
++ s16 rest_x;
++ s16 rest_y;
++
++ u8 backlight_state[2];
++
++ struct device *hwmon_dev;
++ struct input_dev *idev;
++
++ /*
++ * Last index written to key_at_index sysfs file, and value to use for all other
++ * key_at_index_* sysfs files.
++ */
++ unsigned int key_at_index;
+
+-static struct workqueue_struct *applesmc_led_wq;
++ struct workqueue_struct *backlight_wq;
++ struct work_struct backlight_work;
++ struct led_classdev backlight_dev;
++};
++
++static const int debug;
+
+ /*
+ * Wait for specific status bits with a mask on the SMC.
+@@ -162,7 +189,7 @@ static struct workqueue_struct *applesmc_led_wq;
+ * run out past 500ms.
+ */
+
+-static int wait_status(u8 val, u8 mask)
++static int port_wait_status(struct applesmc_device *smc, u8 val, u8 mask)
+ {
+ u8 status;
+ int us;
+@@ -170,7 +197,7 @@ static int wait_status(u8 val, u8 mask)
+
+ us = APPLESMC_MIN_WAIT;
+ for (i = 0; i < 24 ; i++) {
+- status = inb(APPLESMC_CMD_PORT);
++ status = inb(smc->port_base + APPLESMC_CMD_PORT);
+ if ((status & mask) == val)
+ return 0;
+ usleep_range(us, us * 2);
+@@ -180,13 +207,13 @@ static int wait_status(u8 val, u8 mask)
+ return -EIO;
+ }
+
+-/* send_byte - Write to SMC data port. Callers must hold applesmc_lock. */
++/* port_send_byte - Write to SMC data port. Callers must hold applesmc_lock. */
+
+-static int send_byte(u8 cmd, u16 port)
++static int port_send_byte(struct applesmc_device *smc, u8 cmd, u16 port)
+ {
+ int status;
+
+- status = wait_status(0, SMC_STATUS_IB_CLOSED);
++ status = port_wait_status(smc, 0, SMC_STATUS_IB_CLOSED);
+ if (status)
+ return status;
+ /*
+@@ -195,24 +222,25 @@ static int send_byte(u8 cmd, u16 port)
+ * this extra read may not happen if status returns both
+ * simultaneously and this would appear to be required.
+ */
+- status = wait_status(SMC_STATUS_BUSY, SMC_STATUS_BUSY);
++ status = port_wait_status(smc, SMC_STATUS_BUSY, SMC_STATUS_BUSY);
+ if (status)
+ return status;
+
+- outb(cmd, port);
++ outb(cmd, smc->port_base + port);
+ return 0;
+ }
+
+-/* send_command - Write a command to the SMC. Callers must hold applesmc_lock. */
++/* port_send_command - Write a command to the SMC. Callers must hold applesmc_lock. */
+
+-static int send_command(u8 cmd)
++static int port_send_command(struct applesmc_device *smc, u8 cmd)
+ {
+ int ret;
+
+- ret = wait_status(0, SMC_STATUS_IB_CLOSED);
++ ret = port_wait_status(smc, 0, SMC_STATUS_IB_CLOSED);
+ if (ret)
+ return ret;
+- outb(cmd, APPLESMC_CMD_PORT);
++
++ outb(cmd, smc->port_base + APPLESMC_CMD_PORT);
+ return 0;
+ }
+
+@@ -222,110 +250,304 @@ static int send_command(u8 cmd)
+ * If busy is stuck high after the command then the SMC is jammed.
+ */
+
+-static int smc_sane(void)
++static int port_smc_sane(struct applesmc_device *smc)
+ {
+ int ret;
+
+- ret = wait_status(0, SMC_STATUS_BUSY);
++ ret = port_wait_status(smc, 0, SMC_STATUS_BUSY);
+ if (!ret)
+ return ret;
+- ret = send_command(APPLESMC_READ_CMD);
++ ret = port_send_command(smc, APPLESMC_READ_CMD);
+ if (ret)
+ return ret;
+- return wait_status(0, SMC_STATUS_BUSY);
++ return port_wait_status(smc, 0, SMC_STATUS_BUSY);
+ }
+
+-static int send_argument(const char *key)
++static int port_send_argument(struct applesmc_device *smc, const char *key)
+ {
+ int i;
+
+ for (i = 0; i < 4; i++)
+- if (send_byte(key[i], APPLESMC_DATA_PORT))
++ if (port_send_byte(smc, key[i], APPLESMC_DATA_PORT))
+ return -EIO;
+ return 0;
+ }
+
+-static int read_smc(u8 cmd, const char *key, u8 *buffer, u8 len)
++static int port_read_smc(struct applesmc_device *smc, u8 cmd, const char *key,
++ u8 *buffer, u8 len)
+ {
+ u8 status, data = 0;
+ int i;
+ int ret;
+
+- ret = smc_sane();
++ ret = port_smc_sane(smc);
+ if (ret)
+ return ret;
+
+- if (send_command(cmd) || send_argument(key)) {
++ if (port_send_command(smc, cmd) || port_send_argument(smc, key)) {
+ pr_warn("%.4s: read arg fail\n", key);
+ return -EIO;
+ }
+
+ /* This has no effect on newer (2012) SMCs */
+- if (send_byte(len, APPLESMC_DATA_PORT)) {
++ if (port_send_byte(smc, len, APPLESMC_DATA_PORT)) {
+ pr_warn("%.4s: read len fail\n", key);
+ return -EIO;
+ }
+
+ for (i = 0; i < len; i++) {
+- if (wait_status(SMC_STATUS_AWAITING_DATA | SMC_STATUS_BUSY,
++ if (port_wait_status(smc,
++ SMC_STATUS_AWAITING_DATA | SMC_STATUS_BUSY,
+ SMC_STATUS_AWAITING_DATA | SMC_STATUS_BUSY)) {
+ pr_warn("%.4s: read data[%d] fail\n", key, i);
+ return -EIO;
+ }
+- buffer[i] = inb(APPLESMC_DATA_PORT);
++ buffer[i] = inb(smc->port_base + APPLESMC_DATA_PORT);
+ }
+
+ /* Read the data port until bit0 is cleared */
+ for (i = 0; i < 16; i++) {
+ udelay(APPLESMC_MIN_WAIT);
+- status = inb(APPLESMC_CMD_PORT);
++ status = inb(smc->port_base + APPLESMC_CMD_PORT);
+ if (!(status & SMC_STATUS_AWAITING_DATA))
+ break;
+- data = inb(APPLESMC_DATA_PORT);
++ data = inb(smc->port_base + APPLESMC_DATA_PORT);
+ }
+ if (i)
+ pr_warn("flushed %d bytes, last value is: %d\n", i, data);
+
+- return wait_status(0, SMC_STATUS_BUSY);
++ return port_wait_status(smc, 0, SMC_STATUS_BUSY);
+ }
+
+-static int write_smc(u8 cmd, const char *key, const u8 *buffer, u8 len)
++static int port_write_smc(struct applesmc_device *smc, u8 cmd, const char *key,
++ const u8 *buffer, u8 len)
+ {
+ int i;
+ int ret;
+
+- ret = smc_sane();
++ ret = port_smc_sane(smc);
+ if (ret)
+ return ret;
+
+- if (send_command(cmd) || send_argument(key)) {
++ if (port_send_command(smc, cmd) || port_send_argument(smc, key)) {
+ pr_warn("%s: write arg fail\n", key);
+ return -EIO;
+ }
+
+- if (send_byte(len, APPLESMC_DATA_PORT)) {
++ if (port_send_byte(smc, len, APPLESMC_DATA_PORT)) {
+ pr_warn("%.4s: write len fail\n", key);
+ return -EIO;
+ }
+
+ for (i = 0; i < len; i++) {
+- if (send_byte(buffer[i], APPLESMC_DATA_PORT)) {
++ if (port_send_byte(smc, buffer[i], APPLESMC_DATA_PORT)) {
+ pr_warn("%s: write data fail\n", key);
+ return -EIO;
+ }
+ }
+
+- return wait_status(0, SMC_STATUS_BUSY);
++ return port_wait_status(smc, 0, SMC_STATUS_BUSY);
+ }
+
+-static int read_register_count(unsigned int *count)
++static int port_get_smc_key_info(struct applesmc_device *smc,
++ const char *key, struct applesmc_entry *info)
+ {
+- __be32 be;
+ int ret;
++ u8 raw[6];
+
+- ret = read_smc(APPLESMC_READ_CMD, KEY_COUNT_KEY, (u8 *)&be, 4);
++ ret = port_read_smc(smc, APPLESMC_GET_KEY_TYPE_CMD, key, raw, 6);
+ if (ret)
+ return ret;
++ info->len = raw[0];
++ memcpy(info->type, &raw[1], 4);
++ info->flags = raw[5];
++ return 0;
++}
++
++
++/*
++ * MMIO based communication.
++ * TODO: Use updated mechanism for cmd timeout/retry
++ */
++
++static void iomem_clear_status(struct applesmc_device *smc)
++{
++ if (ioread8(smc->iomem_base + APPLESMC_IOMEM_KEY_STATUS))
++ iowrite8(0, smc->iomem_base + APPLESMC_IOMEM_KEY_STATUS);
++}
++
++static int iomem_wait_read(struct applesmc_device *smc)
++{
++ u8 status;
++ int us;
++ int i;
++
++ us = APPLESMC_MIN_WAIT;
++ for (i = 0; i < 24 ; i++) {
++ status = ioread8(smc->iomem_base + APPLESMC_IOMEM_KEY_STATUS);
++ if (status & 0x20)
++ return 0;
++ usleep_range(us, us * 2);
++ if (i > 9)
++ us <<= 1;
++ }
++
++ dev_warn(smc->ldev, "%s... timeout\n", __func__);
++ return -EIO;
++}
++
++static int iomem_read_smc(struct applesmc_device *smc, u8 cmd, const char *key,
++ u8 *buffer, u8 len)
++{
++ u8 err, remote_len;
++ u32 key_int = *((u32 *) key);
++
++ iomem_clear_status(smc);
++ iowrite32(key_int, smc->iomem_base + APPLESMC_IOMEM_KEY_NAME);
++ iowrite32(0, smc->iomem_base + APPLESMC_IOMEM_KEY_SMC_ID);
++ iowrite32(cmd, smc->iomem_base + APPLESMC_IOMEM_KEY_CMD);
++
++ if (iomem_wait_read(smc))
++ return -EIO;
++
++ err = ioread8(smc->iomem_base + APPLESMC_IOMEM_KEY_CMD);
++ if (err != 0) {
++ dev_warn(smc->ldev, "read_smc_mmio(%x %8x/%.4s) failed: %u\n",
++ cmd, key_int, key, err);
++ return -EIO;
++ }
++
++ if (cmd == APPLESMC_READ_CMD) {
++ remote_len = ioread8(smc->iomem_base + APPLESMC_IOMEM_KEY_DATA_LEN);
++ if (remote_len != len) {
++ dev_warn(smc->ldev,
++ "read_smc_mmio(%x %8x/%.4s) failed: buffer length mismatch (remote = %u, requested = %u)\n",
++ cmd, key_int, key, remote_len, len);
++ return -EINVAL;
++ }
++ } else {
++ remote_len = len;
++ }
++
++ memcpy_fromio(buffer, smc->iomem_base + APPLESMC_IOMEM_KEY_DATA,
++ remote_len);
++
++ dev_dbg(smc->ldev, "read_smc_mmio(%x %8x/%.4s): buflen=%u reslen=%u\n",
++ cmd, key_int, key, len, remote_len);
++ print_hex_dump_bytes("read_smc_mmio(): ", DUMP_PREFIX_NONE, buffer, remote_len);
++ return 0;
++}
++
++static int iomem_get_smc_key_type(struct applesmc_device *smc, const char *key,
++ struct applesmc_entry *e)
++{
++ u8 err;
++ u8 cmd = APPLESMC_GET_KEY_TYPE_CMD;
++ u32 key_int = *((u32 *) key);
++
++ iomem_clear_status(smc);
++ iowrite32(key_int, smc->iomem_base + APPLESMC_IOMEM_KEY_NAME);
++ iowrite32(0, smc->iomem_base + APPLESMC_IOMEM_KEY_SMC_ID);
++ iowrite32(cmd, smc->iomem_base + APPLESMC_IOMEM_KEY_CMD);
++
++ if (iomem_wait_read(smc))
++ return -EIO;
++
++ err = ioread8(smc->iomem_base + APPLESMC_IOMEM_KEY_CMD);
++ if (err != 0) {
++ dev_warn(smc->ldev, "get_smc_key_type_mmio(%.4s) failed: %u\n", key, err);
++ return -EIO;
++ }
++
++ e->len = ioread8(smc->iomem_base + APPLESMC_IOMEM_KEY_TYPE_DATA_LEN);
++ *((uint32_t *) e->type) = ioread32(
++ smc->iomem_base + APPLESMC_IOMEM_KEY_TYPE_CODE);
++ e->flags = ioread8(smc->iomem_base + APPLESMC_IOMEM_KEY_TYPE_FLAGS);
++
++ dev_dbg(smc->ldev, "get_smc_key_type_mmio(%.4s): len=%u type=%.4s flags=%x\n",
++ key, e->len, e->type, e->flags);
++ return 0;
++}
++
++static int iomem_write_smc(struct applesmc_device *smc, u8 cmd, const char *key,
++ const u8 *buffer, u8 len)
++{
++ u8 err;
++ u32 key_int = *((u32 *) key);
++
++ iomem_clear_status(smc);
++ iowrite32(key_int, smc->iomem_base + APPLESMC_IOMEM_KEY_NAME);
++ memcpy_toio(smc->iomem_base + APPLESMC_IOMEM_KEY_DATA, buffer, len);
++ iowrite32(len, smc->iomem_base + APPLESMC_IOMEM_KEY_DATA_LEN);
++ iowrite32(0, smc->iomem_base + APPLESMC_IOMEM_KEY_SMC_ID);
++ iowrite32(cmd, smc->iomem_base + APPLESMC_IOMEM_KEY_CMD);
++
++ if (iomem_wait_read(smc))
++ return -EIO;
++
++ err = ioread8(smc->iomem_base + APPLESMC_IOMEM_KEY_CMD);
++ if (err != 0) {
++ dev_warn(smc->ldev, "write_smc_mmio(%x %.4s) failed: %u\n", cmd, key, err);
++ print_hex_dump_bytes("write_smc_mmio(): ", DUMP_PREFIX_NONE, buffer, len);
++ return -EIO;
++ }
++
++ dev_dbg(smc->ldev, "write_smc_mmio(%x %.4s): buflen=%u\n", cmd, key, len);
++ print_hex_dump_bytes("write_smc_mmio(): ", DUMP_PREFIX_NONE, buffer, len);
++ return 0;
++}
++
++
++static int read_smc(struct applesmc_device *smc, const char *key,
++ u8 *buffer, u8 len)
++{
++ if (smc->iomem_base_set)
++ return iomem_read_smc(smc, APPLESMC_READ_CMD, key, buffer, len);
++ else
++ return port_read_smc(smc, APPLESMC_READ_CMD, key, buffer, len);
++}
++
++static int write_smc(struct applesmc_device *smc, const char *key,
++ const u8 *buffer, u8 len)
++{
++ if (smc->iomem_base_set)
++ return iomem_write_smc(smc, APPLESMC_WRITE_CMD, key, buffer, len);
++ else
++ return port_write_smc(smc, APPLESMC_WRITE_CMD, key, buffer, len);
++}
++
++static int get_smc_key_by_index(struct applesmc_device *smc,
++ unsigned int index, char *key)
++{
++ __be32 be;
++
++ be = cpu_to_be32(index);
++ if (smc->iomem_base_set)
++ return iomem_read_smc(smc, APPLESMC_GET_KEY_BY_INDEX_CMD,
++ (const char *) &be, (u8 *) key, 4);
++ else
++ return port_read_smc(smc, APPLESMC_GET_KEY_BY_INDEX_CMD,
++ (const char *) &be, (u8 *) key, 4);
++}
++
++static int get_smc_key_info(struct applesmc_device *smc, const char *key,
++ struct applesmc_entry *info)
++{
++ if (smc->iomem_base_set)
++ return iomem_get_smc_key_type(smc, key, info);
++ else
++ return port_get_smc_key_info(smc, key, info);
++}
++
++static int read_register_count(struct applesmc_device *smc,
++ unsigned int *count)
++{
++ __be32 be;
++ int ret;
++
++ ret = read_smc(smc, KEY_COUNT_KEY, (u8 *)&be, 4);
++ if (ret < 0)
++ return ret;
+
+ *count = be32_to_cpu(be);
+ return 0;
+@@ -338,76 +560,73 @@ static int read_register_count(unsigned int *count)
+ * All functions below are concurrency safe - callers should NOT hold lock.
+ */
+
+-static int applesmc_read_entry(const struct applesmc_entry *entry,
+- u8 *buf, u8 len)
++static int applesmc_read_entry(struct applesmc_device *smc,
++ const struct applesmc_entry *entry, u8 *buf, u8 len)
+ {
+ int ret;
+
+ if (entry->len != len)
+ return -EINVAL;
+- mutex_lock(&smcreg.mutex);
+- ret = read_smc(APPLESMC_READ_CMD, entry->key, buf, len);
+- mutex_unlock(&smcreg.mutex);
++ mutex_lock(&smc->reg.mutex);
++ ret = read_smc(smc, entry->key, buf, len);
++ mutex_unlock(&smc->reg.mutex);
+
+ return ret;
+ }
+
+-static int applesmc_write_entry(const struct applesmc_entry *entry,
+- const u8 *buf, u8 len)
++static int applesmc_write_entry(struct applesmc_device *smc,
++ const struct applesmc_entry *entry, const u8 *buf, u8 len)
+ {
+ int ret;
+
+ if (entry->len != len)
+ return -EINVAL;
+- mutex_lock(&smcreg.mutex);
+- ret = write_smc(APPLESMC_WRITE_CMD, entry->key, buf, len);
+- mutex_unlock(&smcreg.mutex);
++ mutex_lock(&smc->reg.mutex);
++ ret = write_smc(smc, entry->key, buf, len);
++ mutex_unlock(&smc->reg.mutex);
+ return ret;
+ }
+
+-static const struct applesmc_entry *applesmc_get_entry_by_index(int index)
++static const struct applesmc_entry *applesmc_get_entry_by_index(
++ struct applesmc_device *smc, int index)
+ {
+- struct applesmc_entry *cache = &smcreg.cache[index];
+- u8 key[4], info[6];
+- __be32 be;
++ struct applesmc_entry *cache = &smc->reg.cache[index];
++ char key[4];
+ int ret = 0;
+
+ if (cache->valid)
+ return cache;
+
+- mutex_lock(&smcreg.mutex);
++ mutex_lock(&smc->reg.mutex);
+
+ if (cache->valid)
+ goto out;
+- be = cpu_to_be32(index);
+- ret = read_smc(APPLESMC_GET_KEY_BY_INDEX_CMD, (u8 *)&be, key, 4);
++ ret = get_smc_key_by_index(smc, index, key);
+ if (ret)
+ goto out;
+- ret = read_smc(APPLESMC_GET_KEY_TYPE_CMD, key, info, 6);
++ memcpy(cache->key, key, 4);
++
++ ret = get_smc_key_info(smc, key, cache);
+ if (ret)
+ goto out;
+-
+- memcpy(cache->key, key, 4);
+- cache->len = info[0];
+- memcpy(cache->type, &info[1], 4);
+- cache->flags = info[5];
+ cache->valid = true;
+
+ out:
+- mutex_unlock(&smcreg.mutex);
++ mutex_unlock(&smc->reg.mutex);
+ if (ret)
+ return ERR_PTR(ret);
+ return cache;
+ }
+
+-static int applesmc_get_lower_bound(unsigned int *lo, const char *key)
++static int applesmc_get_lower_bound(struct applesmc_device *smc,
++ unsigned int *lo, const char *key)
+ {
+- int begin = 0, end = smcreg.key_count;
++ int begin = 0, end = smc->reg.key_count;
+ const struct applesmc_entry *entry;
+
+ while (begin != end) {
+ int middle = begin + (end - begin) / 2;
+- entry = applesmc_get_entry_by_index(middle);
++ entry = applesmc_get_entry_by_index(smc, middle);
+ if (IS_ERR(entry)) {
+ *lo = 0;
+ return PTR_ERR(entry);
+@@ -422,16 +641,17 @@ static int applesmc_get_lower_bound(unsigned int *lo, const char *key)
+ return 0;
+ }
+
+-static int applesmc_get_upper_bound(unsigned int *hi, const char *key)
++static int applesmc_get_upper_bound(struct applesmc_device *smc,
++ unsigned int *hi, const char *key)
+ {
+- int begin = 0, end = smcreg.key_count;
++ int begin = 0, end = smc->reg.key_count;
+ const struct applesmc_entry *entry;
+
+ while (begin != end) {
+ int middle = begin + (end - begin) / 2;
+- entry = applesmc_get_entry_by_index(middle);
++ entry = applesmc_get_entry_by_index(smc, middle);
+ if (IS_ERR(entry)) {
+- *hi = smcreg.key_count;
++ *hi = smc->reg.key_count;
+ return PTR_ERR(entry);
+ }
+ if (strcmp(key, entry->key) < 0)
+@@ -444,50 +664,54 @@ static int applesmc_get_upper_bound(unsigned int *hi, const char *key)
+ return 0;
+ }
+
+-static const struct applesmc_entry *applesmc_get_entry_by_key(const char *key)
++static const struct applesmc_entry *applesmc_get_entry_by_key(
++ struct applesmc_device *smc, const char *key)
+ {
+ int begin, end;
+ int ret;
+
+- ret = applesmc_get_lower_bound(&begin, key);
++ ret = applesmc_get_lower_bound(smc, &begin, key);
+ if (ret)
+ return ERR_PTR(ret);
+- ret = applesmc_get_upper_bound(&end, key);
++ ret = applesmc_get_upper_bound(smc, &end, key);
+ if (ret)
+ return ERR_PTR(ret);
+ if (end - begin != 1)
+ return ERR_PTR(-EINVAL);
+
+- return applesmc_get_entry_by_index(begin);
++ return applesmc_get_entry_by_index(smc, begin);
+ }
+
+-static int applesmc_read_key(const char *key, u8 *buffer, u8 len)
++static int applesmc_read_key(struct applesmc_device *smc,
++ const char *key, u8 *buffer, u8 len)
+ {
+ const struct applesmc_entry *entry;
+
+- entry = applesmc_get_entry_by_key(key);
++ entry = applesmc_get_entry_by_key(smc, key);
+ if (IS_ERR(entry))
+ return PTR_ERR(entry);
+
+- return applesmc_read_entry(entry, buffer, len);
++ return applesmc_read_entry(smc, entry, buffer, len);
+ }
+
+-static int applesmc_write_key(const char *key, const u8 *buffer, u8 len)
++static int applesmc_write_key(struct applesmc_device *smc,
++ const char *key, const u8 *buffer, u8 len)
+ {
+ const struct applesmc_entry *entry;
+
+- entry = applesmc_get_entry_by_key(key);
++ entry = applesmc_get_entry_by_key(smc, key);
+ if (IS_ERR(entry))
+ return PTR_ERR(entry);
+
+- return applesmc_write_entry(entry, buffer, len);
++ return applesmc_write_entry(smc, entry, buffer, len);
+ }
+
+-static int applesmc_has_key(const char *key, bool *value)
++static int applesmc_has_key(struct applesmc_device *smc,
++ const char *key, bool *value)
+ {
+ const struct applesmc_entry *entry;
+
+- entry = applesmc_get_entry_by_key(key);
++ entry = applesmc_get_entry_by_key(smc, key);
+ if (IS_ERR(entry) && PTR_ERR(entry) != -EINVAL)
+ return PTR_ERR(entry);
+
+@@ -498,12 +722,13 @@ static int applesmc_has_key(const char *key, bool *value)
+ /*
+ * applesmc_read_s16 - Read 16-bit signed big endian register
+ */
+-static int applesmc_read_s16(const char *key, s16 *value)
++static int applesmc_read_s16(struct applesmc_device *smc,
++ const char *key, s16 *value)
+ {
+ u8 buffer[2];
+ int ret;
+
+- ret = applesmc_read_key(key, buffer, 2);
++ ret = applesmc_read_key(smc, key, buffer, 2);
+ if (ret)
+ return ret;
+
+@@ -511,31 +736,68 @@ static int applesmc_read_s16(const char *key, s16 *value)
+ return 0;
+ }
+
++/**
++ * applesmc_float_to_u32 - Retrieve the integral part of a float.
++ * This is needed because Apple made fans use float values in the T2.
++ * The fractional point is not significantly useful though, and the integral
++ * part can be easily extracted.
++ */
++static inline u32 applesmc_float_to_u32(u32 d)
++{
++ u8 sign = (u8) ((d >> 31) & 1);
++ s32 exp = (s32) ((d >> 23) & 0xff) - 0x7f;
++ u32 fr = d & ((1u << 23) - 1);
++
++ if (sign || exp < 0)
++ return 0;
++
++ return (u32) ((1u << exp) + (fr >> (23 - exp)));
++}
++
++/**
++ * applesmc_u32_to_float - Convert an u32 into a float.
++ * See applesmc_float_to_u32 for a rationale.
++ */
++static inline u32 applesmc_u32_to_float(u32 d)
++{
++ u32 dc = d, bc = 0, exp;
++
++ if (!d)
++ return 0;
++
++ while (dc >>= 1)
++ ++bc;
++ exp = 0x7f + bc;
++
++ return (u32) ((exp << 23) |
++ ((d << (23 - (exp - 0x7f))) & ((1u << 23) - 1)));
++}
+ /*
+ * applesmc_device_init - initialize the accelerometer. Can sleep.
+ */
+-static void applesmc_device_init(void)
++static void applesmc_device_init(struct applesmc_device *smc)
+ {
+ int total;
+ u8 buffer[2];
+
+- if (!smcreg.has_accelerometer)
++ if (!smc->reg.has_accelerometer)
+ return;
+
+ for (total = INIT_TIMEOUT_MSECS; total > 0; total -= INIT_WAIT_MSECS) {
+- if (!applesmc_read_key(MOTION_SENSOR_KEY, buffer, 2) &&
++ if (!applesmc_read_key(smc, MOTION_SENSOR_KEY, buffer, 2) &&
+ (buffer[0] != 0x00 || buffer[1] != 0x00))
+ return;
+ buffer[0] = 0xe0;
+ buffer[1] = 0x00;
+- applesmc_write_key(MOTION_SENSOR_KEY, buffer, 2);
++ applesmc_write_key(smc, MOTION_SENSOR_KEY, buffer, 2);
+ msleep(INIT_WAIT_MSECS);
+ }
+
+ pr_warn("failed to init the device\n");
+ }
+
+-static int applesmc_init_index(struct applesmc_registers *s)
++static int applesmc_init_index(struct applesmc_device *smc,
++ struct applesmc_registers *s)
+ {
+ const struct applesmc_entry *entry;
+ unsigned int i;
+@@ -548,7 +810,7 @@ static int applesmc_init_index(struct applesmc_registers *s)
+ return -ENOMEM;
+
+ for (i = s->temp_begin; i < s->temp_end; i++) {
+- entry = applesmc_get_entry_by_index(i);
++ entry = applesmc_get_entry_by_index(smc, i);
+ if (IS_ERR(entry))
+ continue;
+ if (strcmp(entry->type, TEMP_SENSOR_TYPE))
+@@ -562,9 +824,9 @@ static int applesmc_init_index(struct applesmc_registers *s)
+ /*
+ * applesmc_init_smcreg_try - Try to initialize register cache. Idempotent.
+ */
+-static int applesmc_init_smcreg_try(void)
++static int applesmc_init_smcreg_try(struct applesmc_device *smc)
+ {
+- struct applesmc_registers *s = &smcreg;
++ struct applesmc_registers *s = &smc->reg;
+ bool left_light_sensor = false, right_light_sensor = false;
+ unsigned int count;
+ u8 tmp[1];
+@@ -573,7 +835,7 @@ static int applesmc_init_smcreg_try(void)
+ if (s->init_complete)
+ return 0;
+
+- ret = read_register_count(&count);
++ ret = read_register_count(smc, &count);
+ if (ret)
+ return ret;
+
+@@ -590,35 +852,35 @@ static int applesmc_init_smcreg_try(void)
+ if (!s->cache)
+ return -ENOMEM;
+
+- ret = applesmc_read_key(FANS_COUNT, tmp, 1);
++ ret = applesmc_read_key(smc, FANS_COUNT, tmp, 1);
+ if (ret)
+ return ret;
+ s->fan_count = tmp[0];
+ if (s->fan_count > 10)
+ s->fan_count = 10;
+
+- ret = applesmc_get_lower_bound(&s->temp_begin, "T");
++ ret = applesmc_get_lower_bound(smc, &s->temp_begin, "T");
+ if (ret)
+ return ret;
+- ret = applesmc_get_lower_bound(&s->temp_end, "U");
++ ret = applesmc_get_lower_bound(smc, &s->temp_end, "U");
+ if (ret)
+ return ret;
+ s->temp_count = s->temp_end - s->temp_begin;
+
+- ret = applesmc_init_index(s);
++ ret = applesmc_init_index(smc, s);
+ if (ret)
+ return ret;
+
+- ret = applesmc_has_key(LIGHT_SENSOR_LEFT_KEY, &left_light_sensor);
++ ret = applesmc_has_key(smc, LIGHT_SENSOR_LEFT_KEY, &left_light_sensor);
+ if (ret)
+ return ret;
+- ret = applesmc_has_key(LIGHT_SENSOR_RIGHT_KEY, &right_light_sensor);
++ ret = applesmc_has_key(smc, LIGHT_SENSOR_RIGHT_KEY, &right_light_sensor);
+ if (ret)
+ return ret;
+- ret = applesmc_has_key(MOTION_SENSOR_KEY, &s->has_accelerometer);
++ ret = applesmc_has_key(smc, MOTION_SENSOR_KEY, &s->has_accelerometer);
+ if (ret)
+ return ret;
+- ret = applesmc_has_key(BACKLIGHT_KEY, &s->has_key_backlight);
++ ret = applesmc_has_key(smc, BACKLIGHT_KEY, &s->has_key_backlight);
+ if (ret)
+ return ret;
+
+@@ -634,13 +896,13 @@ static int applesmc_init_smcreg_try(void)
+ return 0;
+ }
+
+-static void applesmc_destroy_smcreg(void)
++static void applesmc_destroy_smcreg(struct applesmc_device *smc)
+ {
+- kfree(smcreg.index);
+- smcreg.index = NULL;
+- kfree(smcreg.cache);
+- smcreg.cache = NULL;
+- smcreg.init_complete = false;
++ kfree(smc->reg.index);
++ smc->reg.index = NULL;
++ kfree(smc->reg.cache);
++ smc->reg.cache = NULL;
++ smc->reg.init_complete = false;
+ }
+
+ /*
+@@ -649,12 +911,12 @@ static void applesmc_destroy_smcreg(void)
+ * Retries until initialization is successful, or the operation times out.
+ *
+ */
+-static int applesmc_init_smcreg(void)
++static int applesmc_init_smcreg(struct applesmc_device *smc)
+ {
+ int ms, ret;
+
+ for (ms = 0; ms < INIT_TIMEOUT_MSECS; ms += INIT_WAIT_MSECS) {
+- ret = applesmc_init_smcreg_try();
++ ret = applesmc_init_smcreg_try(smc);
+ if (!ret) {
+ if (ms)
+ pr_info("init_smcreg() took %d ms\n", ms);
+@@ -663,50 +925,223 @@ static int applesmc_init_smcreg(void)
+ msleep(INIT_WAIT_MSECS);
+ }
+
+- applesmc_destroy_smcreg();
++ applesmc_destroy_smcreg(smc);
+
+ return ret;
+ }
+
+ /* Device model stuff */
+-static int applesmc_probe(struct platform_device *dev)
++
++static int applesmc_init_resources(struct applesmc_device *smc);
++static void applesmc_free_resources(struct applesmc_device *smc);
++static int applesmc_create_modules(struct applesmc_device *smc);
++static void applesmc_destroy_modules(struct applesmc_device *smc);
++
++static int applesmc_add(struct acpi_device *dev)
+ {
++ struct applesmc_device *smc;
+ int ret;
+
+- ret = applesmc_init_smcreg();
++ smc = kzalloc(sizeof(struct applesmc_device), GFP_KERNEL);
++ if (!smc)
++ return -ENOMEM;
++ smc->dev = dev;
++ smc->ldev = &dev->dev;
++ mutex_init(&smc->reg.mutex);
++
++ dev_set_drvdata(&dev->dev, smc);
++
++ ret = applesmc_init_resources(smc);
+ if (ret)
+- return ret;
++ goto out_mem;
++
++ ret = applesmc_init_smcreg(smc);
++ if (ret)
++ goto out_res;
++
++ applesmc_device_init(smc);
++
++ ret = applesmc_create_modules(smc);
++ if (ret)
++ goto out_reg;
++
++ return 0;
++
++out_reg:
++ applesmc_destroy_smcreg(smc);
++out_res:
++ applesmc_free_resources(smc);
++out_mem:
++ dev_set_drvdata(&dev->dev, NULL);
++ mutex_destroy(&smc->reg.mutex);
++ kfree(smc);
++
++ return ret;
++}
++
++static void applesmc_remove(struct acpi_device *dev)
++{
++ struct applesmc_device *smc = dev_get_drvdata(&dev->dev);
++
++ applesmc_destroy_modules(smc);
++ applesmc_destroy_smcreg(smc);
++ applesmc_free_resources(smc);
+
+- applesmc_device_init();
++ mutex_destroy(&smc->reg.mutex);
++ kfree(smc);
++
++ return;
++}
++
++static acpi_status applesmc_walk_resources(struct acpi_resource *res,
++ void *data)
++{
++ struct applesmc_device *smc = data;
++
++ switch (res->type) {
++ case ACPI_RESOURCE_TYPE_IO:
++ if (!smc->port_base_set) {
++ if (res->data.io.address_length < APPLESMC_NR_PORTS)
++ return AE_ERROR;
++ smc->port_base = res->data.io.minimum;
++ smc->port_base_set = true;
++ }
++ return AE_OK;
++
++ case ACPI_RESOURCE_TYPE_FIXED_MEMORY32:
++ if (!smc->iomem_base_set) {
++ if (res->data.fixed_memory32.address_length <
++ APPLESMC_IOMEM_MIN_SIZE) {
++ dev_warn(smc->ldev, "found iomem but it's too small: %u\n",
++ res->data.fixed_memory32.address_length);
++ return AE_OK;
++ }
++ smc->iomem_base_addr = res->data.fixed_memory32.address;
++ smc->iomem_base_size = res->data.fixed_memory32.address_length;
++ smc->iomem_base_set = true;
++ }
++ return AE_OK;
++
++ case ACPI_RESOURCE_TYPE_END_TAG:
++ if (smc->port_base_set)
++ return AE_OK;
++ else
++ return AE_NOT_FOUND;
++
++ default:
++ return AE_OK;
++ }
++}
++
++static int applesmc_try_enable_iomem(struct applesmc_device *smc);
++
++static int applesmc_init_resources(struct applesmc_device *smc)
++{
++ int ret;
++
++ ret = acpi_walk_resources(smc->dev->handle, METHOD_NAME__CRS,
++ applesmc_walk_resources, smc);
++ if (ACPI_FAILURE(ret))
++ return -ENXIO;
++
++ if (!request_region(smc->port_base, APPLESMC_NR_PORTS, "applesmc"))
++ return -ENXIO;
++
++ if (smc->iomem_base_set) {
++ if (applesmc_try_enable_iomem(smc))
++ smc->iomem_base_set = false;
++ }
++
++ return 0;
++}
++
++static int applesmc_try_enable_iomem(struct applesmc_device *smc)
++{
++ u8 test_val, ldkn_version;
++
++ dev_dbg(smc->ldev, "Trying to enable iomem based communication\n");
++ smc->iomem_base = ioremap(smc->iomem_base_addr, smc->iomem_base_size);
++ if (!smc->iomem_base)
++ goto out;
++
++ /* Apple's driver does this check for some reason */
++ test_val = ioread8(smc->iomem_base + APPLESMC_IOMEM_KEY_STATUS);
++ if (test_val == 0xff) {
++ dev_warn(smc->ldev,
++ "iomem enable failed: initial status is 0xff (is %x)\n",
++ test_val);
++ goto out_iomem;
++ }
++
++ if (read_smc(smc, "LDKN", &ldkn_version, 1)) {
++ dev_warn(smc->ldev, "iomem enable failed: ldkn read failed\n");
++ goto out_iomem;
++ }
++
++ if (ldkn_version < 2) {
++ dev_warn(smc->ldev,
++ "iomem enable failed: ldkn version %u is less than minimum (2)\n",
++ ldkn_version);
++ goto out_iomem;
++ }
+
+ return 0;
++
++out_iomem:
++ iounmap(smc->iomem_base);
++
++out:
++ return -ENXIO;
++}
++
++static void applesmc_free_resources(struct applesmc_device *smc)
++{
++ if (smc->iomem_base_set)
++ iounmap(smc->iomem_base);
++ release_region(smc->port_base, APPLESMC_NR_PORTS);
+ }
+
+ /* Synchronize device with memorized backlight state */
+ static int applesmc_pm_resume(struct device *dev)
+ {
+- if (smcreg.has_key_backlight)
+- applesmc_write_key(BACKLIGHT_KEY, backlight_state, 2);
++ struct applesmc_device *smc = dev_get_drvdata(dev);
++
++ if (smc->reg.has_key_backlight)
++ applesmc_write_key(smc, BACKLIGHT_KEY, smc->backlight_state, 2);
++
+ return 0;
+ }
+
+ /* Reinitialize device on resume from hibernation */
+ static int applesmc_pm_restore(struct device *dev)
+ {
+- applesmc_device_init();
++ struct applesmc_device *smc = dev_get_drvdata(dev);
++
++ applesmc_device_init(smc);
++
+ return applesmc_pm_resume(dev);
+ }
+
++static const struct acpi_device_id applesmc_ids[] = {
++ {"APP0001", 0},
++ {"", 0},
++};
++
+ static const struct dev_pm_ops applesmc_pm_ops = {
+ .resume = applesmc_pm_resume,
+ .restore = applesmc_pm_restore,
+ };
+
+-static struct platform_driver applesmc_driver = {
+- .probe = applesmc_probe,
+- .driver = {
+- .name = "applesmc",
+- .pm = &applesmc_pm_ops,
++static struct acpi_driver applesmc_driver = {
++ .name = "applesmc",
++ .class = "applesmc",
++ .ids = applesmc_ids,
++ .ops = {
++ .add = applesmc_add,
++ .remove = applesmc_remove
++ },
++ .drv = {
++ .pm = &applesmc_pm_ops
+ },
+ };
+
+@@ -714,25 +1149,26 @@ static struct platform_driver applesmc_driver = {
+ * applesmc_calibrate - Set our "resting" values. Callers must
+ * hold applesmc_lock.
+ */
+-static void applesmc_calibrate(void)
++static void applesmc_calibrate(struct applesmc_device *smc)
+ {
+- applesmc_read_s16(MOTION_SENSOR_X_KEY, &rest_x);
+- applesmc_read_s16(MOTION_SENSOR_Y_KEY, &rest_y);
+- rest_x = -rest_x;
++ applesmc_read_s16(smc, MOTION_SENSOR_X_KEY, &smc->rest_x);
++ applesmc_read_s16(smc, MOTION_SENSOR_Y_KEY, &smc->rest_y);
++ smc->rest_x = -smc->rest_x;
+ }
+
+ static void applesmc_idev_poll(struct input_dev *idev)
+ {
++ struct applesmc_device *smc = dev_get_drvdata(&idev->dev);
+ s16 x, y;
+
+- if (applesmc_read_s16(MOTION_SENSOR_X_KEY, &x))
++ if (applesmc_read_s16(smc, MOTION_SENSOR_X_KEY, &x))
+ return;
+- if (applesmc_read_s16(MOTION_SENSOR_Y_KEY, &y))
++ if (applesmc_read_s16(smc, MOTION_SENSOR_Y_KEY, &y))
+ return;
+
+ x = -x;
+- input_report_abs(idev, ABS_X, x - rest_x);
+- input_report_abs(idev, ABS_Y, y - rest_y);
++ input_report_abs(idev, ABS_X, x - smc->rest_x);
++ input_report_abs(idev, ABS_Y, y - smc->rest_y);
+ input_sync(idev);
+ }
+
+@@ -747,16 +1183,17 @@ static ssize_t applesmc_name_show(struct device *dev,
+ static ssize_t applesmc_position_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+ {
++ struct applesmc_device *smc = dev_get_drvdata(dev);
+ int ret;
+ s16 x, y, z;
+
+- ret = applesmc_read_s16(MOTION_SENSOR_X_KEY, &x);
++ ret = applesmc_read_s16(smc, MOTION_SENSOR_X_KEY, &x);
+ if (ret)
+ goto out;
+- ret = applesmc_read_s16(MOTION_SENSOR_Y_KEY, &y);
++ ret = applesmc_read_s16(smc, MOTION_SENSOR_Y_KEY, &y);
+ if (ret)
+ goto out;
+- ret = applesmc_read_s16(MOTION_SENSOR_Z_KEY, &z);
++ ret = applesmc_read_s16(smc, MOTION_SENSOR_Z_KEY, &z);
+ if (ret)
+ goto out;
+
+@@ -770,6 +1207,7 @@ static ssize_t applesmc_position_show(struct device *dev,
+ static ssize_t applesmc_light_show(struct device *dev,
+ struct device_attribute *attr, char *sysfsbuf)
+ {
++ struct applesmc_device *smc = dev_get_drvdata(dev);
+ const struct applesmc_entry *entry;
+ static int data_length;
+ int ret;
+@@ -777,7 +1215,7 @@ static ssize_t applesmc_light_show(struct device *dev,
+ u8 buffer[10];
+
+ if (!data_length) {
+- entry = applesmc_get_entry_by_key(LIGHT_SENSOR_LEFT_KEY);
++ entry = applesmc_get_entry_by_key(smc, LIGHT_SENSOR_LEFT_KEY);
+ if (IS_ERR(entry))
+ return PTR_ERR(entry);
+ if (entry->len > 10)
+@@ -786,7 +1224,7 @@ static ssize_t applesmc_light_show(struct device *dev,
+ pr_info("light sensor data length set to %d\n", data_length);
+ }
+
+- ret = applesmc_read_key(LIGHT_SENSOR_LEFT_KEY, buffer, data_length);
++ ret = applesmc_read_key(smc, LIGHT_SENSOR_LEFT_KEY, buffer, data_length);
+ if (ret)
+ goto out;
+ /* newer macbooks report a single 10-bit bigendian value */
+@@ -796,7 +1234,7 @@ static ssize_t applesmc_light_show(struct device *dev,
+ }
+ left = buffer[2];
+
+- ret = applesmc_read_key(LIGHT_SENSOR_RIGHT_KEY, buffer, data_length);
++ ret = applesmc_read_key(smc, LIGHT_SENSOR_RIGHT_KEY, buffer, data_length);
+ if (ret)
+ goto out;
+ right = buffer[2];
+@@ -812,7 +1250,8 @@ static ssize_t applesmc_light_show(struct device *dev,
+ static ssize_t applesmc_show_sensor_label(struct device *dev,
+ struct device_attribute *devattr, char *sysfsbuf)
+ {
+- const char *key = smcreg.index[to_index(devattr)];
++ struct applesmc_device *smc = dev_get_drvdata(dev);
++ const char *key = smc->reg.index[to_index(devattr)];
+
+ return sysfs_emit(sysfsbuf, "%s\n", key);
+ }
+@@ -821,12 +1260,13 @@ static ssize_t applesmc_show_sensor_label(struct device *dev,
+ static ssize_t applesmc_show_temperature(struct device *dev,
+ struct device_attribute *devattr, char *sysfsbuf)
+ {
+- const char *key = smcreg.index[to_index(devattr)];
++ struct applesmc_device *smc = dev_get_drvdata(dev);
++ const char *key = smc->reg.index[to_index(devattr)];
+ int ret;
+ s16 value;
+ int temp;
+
+- ret = applesmc_read_s16(key, &value);
++ ret = applesmc_read_s16(smc, key, &value);
+ if (ret)
+ return ret;
+
+@@ -838,6 +1278,8 @@ static ssize_t applesmc_show_temperature(struct device *dev,
+ static ssize_t applesmc_show_fan_speed(struct device *dev,
+ struct device_attribute *attr, char *sysfsbuf)
+ {
++ struct applesmc_device *smc = dev_get_drvdata(dev);
++ const struct applesmc_entry *entry;
+ int ret;
+ unsigned int speed = 0;
+ char newkey[5];
+@@ -846,11 +1288,21 @@ static ssize_t applesmc_show_fan_speed(struct device *dev,
+ scnprintf(newkey, sizeof(newkey), fan_speed_fmt[to_option(attr)],
+ to_index(attr));
+
+- ret = applesmc_read_key(newkey, buffer, 2);
++ entry = applesmc_get_entry_by_key(smc, newkey);
++ if (IS_ERR(entry))
++ return PTR_ERR(entry);
++
++ if (!strcmp(entry->type, FLOAT_TYPE)) {
++ ret = applesmc_read_entry(smc, entry, (u8 *) &speed, 4);
++ speed = applesmc_float_to_u32(speed);
++ } else {
++ ret = applesmc_read_entry(smc, entry, buffer, 2);
++ speed = ((buffer[0] << 8 | buffer[1]) >> 2);
++ }
++
+ if (ret)
+ return ret;
+
+- speed = ((buffer[0] << 8 | buffer[1]) >> 2);
+ return sysfs_emit(sysfsbuf, "%u\n", speed);
+ }
+
+@@ -858,6 +1310,8 @@ static ssize_t applesmc_store_fan_speed(struct device *dev,
+ struct device_attribute *attr,
+ const char *sysfsbuf, size_t count)
+ {
++ struct applesmc_device *smc = dev_get_drvdata(dev);
++ const struct applesmc_entry *entry;
+ int ret;
+ unsigned long speed;
+ char newkey[5];
+@@ -869,9 +1323,18 @@ static ssize_t applesmc_store_fan_speed(struct device *dev,
+ scnprintf(newkey, sizeof(newkey), fan_speed_fmt[to_option(attr)],
+ to_index(attr));
+
+- buffer[0] = (speed >> 6) & 0xff;
+- buffer[1] = (speed << 2) & 0xff;
+- ret = applesmc_write_key(newkey, buffer, 2);
++ entry = applesmc_get_entry_by_key(smc, newkey);
++ if (IS_ERR(entry))
++ return PTR_ERR(entry);
++
++ if (!strcmp(entry->type, FLOAT_TYPE)) {
++ speed = applesmc_u32_to_float(speed);
++ ret = applesmc_write_entry(smc, entry, (u8 *) &speed, 4);
++ } else {
++ buffer[0] = (speed >> 6) & 0xff;
++ buffer[1] = (speed << 2) & 0xff;
++ ret = applesmc_write_key(smc, newkey, buffer, 2);
++ }
+
+ if (ret)
+ return ret;
+@@ -882,15 +1345,30 @@ static ssize_t applesmc_store_fan_speed(struct device *dev,
+ static ssize_t applesmc_show_fan_manual(struct device *dev,
+ struct device_attribute *attr, char *sysfsbuf)
+ {
++ struct applesmc_device *smc = dev_get_drvdata(dev);
+ int ret;
+ u16 manual = 0;
+ u8 buffer[2];
++ char newkey[5];
++ bool has_newkey = false;
++
++ scnprintf(newkey, sizeof(newkey), FAN_MANUAL_FMT, to_index(attr));
++
++ ret = applesmc_has_key(smc, newkey, &has_newkey);
++ if (ret)
++ return ret;
++
++ if (has_newkey) {
++ ret = applesmc_read_key(smc, newkey, buffer, 1);
++ manual = buffer[0];
++ } else {
++ ret = applesmc_read_key(smc, FANS_MANUAL, buffer, 2);
++ manual = ((buffer[0] << 8 | buffer[1]) >> to_index(attr)) & 0x01;
++ }
+
+- ret = applesmc_read_key(FANS_MANUAL, buffer, 2);
+ if (ret)
+ return ret;
+
+- manual = ((buffer[0] << 8 | buffer[1]) >> to_index(attr)) & 0x01;
+ return sysfs_emit(sysfsbuf, "%d\n", manual);
+ }
+
+@@ -898,29 +1376,42 @@ static ssize_t applesmc_store_fan_manual(struct device *dev,
+ struct device_attribute *attr,
+ const char *sysfsbuf, size_t count)
+ {
++ struct applesmc_device *smc = dev_get_drvdata(dev);
+ int ret;
+ u8 buffer[2];
++ char newkey[5];
++ bool has_newkey = false;
+ unsigned long input;
+ u16 val;
+
+ if (kstrtoul(sysfsbuf, 10, &input) < 0)
+ return -EINVAL;
+
+- ret = applesmc_read_key(FANS_MANUAL, buffer, 2);
++ scnprintf(newkey, sizeof(newkey), FAN_MANUAL_FMT, to_index(attr));
++
++ ret = applesmc_has_key(smc, newkey, &has_newkey);
+ if (ret)
+- goto out;
++ return ret;
+
+- val = (buffer[0] << 8 | buffer[1]);
++ if (has_newkey) {
++ buffer[0] = input & 1;
++ ret = applesmc_write_key(smc, newkey, buffer, 1);
++ } else {
++ ret = applesmc_read_key(smc, FANS_MANUAL, buffer, 2);
++ val = (buffer[0] << 8 | buffer[1]);
++ if (ret)
++ goto out;
+
+- if (input)
+- val = val | (0x01 << to_index(attr));
+- else
+- val = val & ~(0x01 << to_index(attr));
++ if (input)
++ val = val | (0x01 << to_index(attr));
++ else
++ val = val & ~(0x01 << to_index(attr));
+
+- buffer[0] = (val >> 8) & 0xFF;
+- buffer[1] = val & 0xFF;
++ buffer[0] = (val >> 8) & 0xFF;
++ buffer[1] = val & 0xFF;
+
+- ret = applesmc_write_key(FANS_MANUAL, buffer, 2);
++ ret = applesmc_write_key(smc, FANS_MANUAL, buffer, 2);
++ }
+
+ out:
+ if (ret)
+@@ -932,13 +1423,14 @@ static ssize_t applesmc_store_fan_manual(struct device *dev,
+ static ssize_t applesmc_show_fan_position(struct device *dev,
+ struct device_attribute *attr, char *sysfsbuf)
+ {
++ struct applesmc_device *smc = dev_get_drvdata(dev);
+ int ret;
+ char newkey[5];
+ u8 buffer[17];
+
+ scnprintf(newkey, sizeof(newkey), FAN_ID_FMT, to_index(attr));
+
+- ret = applesmc_read_key(newkey, buffer, 16);
++ ret = applesmc_read_key(smc, newkey, buffer, 16);
+ buffer[16] = 0;
+
+ if (ret)
+@@ -950,43 +1442,79 @@ static ssize_t applesmc_show_fan_position(struct device *dev,
+ static ssize_t applesmc_calibrate_show(struct device *dev,
+ struct device_attribute *attr, char *sysfsbuf)
+ {
+- return sysfs_emit(sysfsbuf, "(%d,%d)\n", rest_x, rest_y);
++ struct applesmc_device *smc = dev_get_drvdata(dev);
++
++ return sysfs_emit(sysfsbuf, "(%d,%d)\n", smc->rest_x, smc->rest_y);
+ }
+
+ static ssize_t applesmc_calibrate_store(struct device *dev,
+ struct device_attribute *attr, const char *sysfsbuf, size_t count)
+ {
+- applesmc_calibrate();
++ struct applesmc_device *smc = dev_get_drvdata(dev);
++
++ applesmc_calibrate(smc);
+
+ return count;
+ }
+
+ static void applesmc_backlight_set(struct work_struct *work)
+ {
+- applesmc_write_key(BACKLIGHT_KEY, backlight_state, 2);
++ struct applesmc_device *smc = container_of(work, struct applesmc_device, backlight_work);
++
++ applesmc_write_key(smc, BACKLIGHT_KEY, smc->backlight_state, 2);
+ }
+-static DECLARE_WORK(backlight_work, &applesmc_backlight_set);
+
+ static void applesmc_brightness_set(struct led_classdev *led_cdev,
+ enum led_brightness value)
+ {
++ struct applesmc_device *smc = dev_get_drvdata(led_cdev->dev);
+ int ret;
+
+- backlight_state[0] = value;
+- ret = queue_work(applesmc_led_wq, &backlight_work);
++ smc->backlight_state[0] = value;
++ ret = queue_work(smc->backlight_wq, &smc->backlight_work);
+
+ if (debug && (!ret))
+ dev_dbg(led_cdev->dev, "work was already on the queue.\n");
+ }
+
++static ssize_t applesmc_BCLM_store(struct device *dev,
++ struct device_attribute *attr, char *sysfsbuf, size_t count)
++{
++ struct applesmc_device *smc = dev_get_drvdata(dev);
++ u8 val;
++
++ if (kstrtou8(sysfsbuf, 10, &val) < 0)
++ return -EINVAL;
++
++ if (val < 0 || val > 100)
++ return -EINVAL;
++
++ if (applesmc_write_key(smc, "BCLM", &val, 1))
++ return -ENODEV;
++ return count;
++}
++
++static ssize_t applesmc_BCLM_show(struct device *dev,
++ struct device_attribute *attr, char *sysfsbuf)
++{
++ struct applesmc_device *smc = dev_get_drvdata(dev);
++ u8 val;
++
++ if (applesmc_read_key(smc, "BCLM", &val, 1))
++ return -ENODEV;
++
++ return sysfs_emit(sysfsbuf, "%d\n", val);
++}
++
+ static ssize_t applesmc_key_count_show(struct device *dev,
+ struct device_attribute *attr, char *sysfsbuf)
+ {
++ struct applesmc_device *smc = dev_get_drvdata(dev);
+ int ret;
+ u8 buffer[4];
+ u32 count;
+
+- ret = applesmc_read_key(KEY_COUNT_KEY, buffer, 4);
++ ret = applesmc_read_key(smc, KEY_COUNT_KEY, buffer, 4);
+ if (ret)
+ return ret;
+
+@@ -998,13 +1526,14 @@ static ssize_t applesmc_key_count_show(struct device *dev,
+ static ssize_t applesmc_key_at_index_read_show(struct device *dev,
+ struct device_attribute *attr, char *sysfsbuf)
+ {
++ struct applesmc_device *smc = dev_get_drvdata(dev);
+ const struct applesmc_entry *entry;
+ int ret;
+
+- entry = applesmc_get_entry_by_index(key_at_index);
++ entry = applesmc_get_entry_by_index(smc, smc->key_at_index);
+ if (IS_ERR(entry))
+ return PTR_ERR(entry);
+- ret = applesmc_read_entry(entry, sysfsbuf, entry->len);
++ ret = applesmc_read_entry(smc, entry, sysfsbuf, entry->len);
+ if (ret)
+ return ret;
+
+@@ -1014,9 +1543,10 @@ static ssize_t applesmc_key_at_index_read_show(struct device *dev,
+ static ssize_t applesmc_key_at_index_data_length_show(struct device *dev,
+ struct device_attribute *attr, char *sysfsbuf)
+ {
++ struct applesmc_device *smc = dev_get_drvdata(dev);
+ const struct applesmc_entry *entry;
+
+- entry = applesmc_get_entry_by_index(key_at_index);
++ entry = applesmc_get_entry_by_index(smc, smc->key_at_index);
+ if (IS_ERR(entry))
+ return PTR_ERR(entry);
+
+@@ -1026,9 +1556,10 @@ static ssize_t applesmc_key_at_index_data_length_show(struct device *dev,
+ static ssize_t applesmc_key_at_index_type_show(struct device *dev,
+ struct device_attribute *attr, char *sysfsbuf)
+ {
++ struct applesmc_device *smc = dev_get_drvdata(dev);
+ const struct applesmc_entry *entry;
+
+- entry = applesmc_get_entry_by_index(key_at_index);
++ entry = applesmc_get_entry_by_index(smc, smc->key_at_index);
+ if (IS_ERR(entry))
+ return PTR_ERR(entry);
+
+@@ -1038,9 +1569,10 @@ static ssize_t applesmc_key_at_index_type_show(struct device *dev,
+ static ssize_t applesmc_key_at_index_name_show(struct device *dev,
+ struct device_attribute *attr, char *sysfsbuf)
+ {
++ struct applesmc_device *smc = dev_get_drvdata(dev);
+ const struct applesmc_entry *entry;
+
+- entry = applesmc_get_entry_by_index(key_at_index);
++ entry = applesmc_get_entry_by_index(smc, smc->key_at_index);
+ if (IS_ERR(entry))
+ return PTR_ERR(entry);
+
+@@ -1050,28 +1582,25 @@ static ssize_t applesmc_key_at_index_name_show(struct device *dev,
+ static ssize_t applesmc_key_at_index_show(struct device *dev,
+ struct device_attribute *attr, char *sysfsbuf)
+ {
+- return sysfs_emit(sysfsbuf, "%d\n", key_at_index);
++ struct applesmc_device *smc = dev_get_drvdata(dev);
++
++ return sysfs_emit(sysfsbuf, "%d\n", smc->key_at_index);
+ }
+
+ static ssize_t applesmc_key_at_index_store(struct device *dev,
+ struct device_attribute *attr, const char *sysfsbuf, size_t count)
+ {
++ struct applesmc_device *smc = dev_get_drvdata(dev);
+ unsigned long newkey;
+
+ if (kstrtoul(sysfsbuf, 10, &newkey) < 0
+- || newkey >= smcreg.key_count)
++ || newkey >= smc->reg.key_count)
+ return -EINVAL;
+
+- key_at_index = newkey;
++ smc->key_at_index = newkey;
+ return count;
+ }
+
+-static struct led_classdev applesmc_backlight = {
+- .name = "smc::kbd_backlight",
+- .default_trigger = "nand-disk",
+- .brightness_set = applesmc_brightness_set,
+-};
+-
+ static struct applesmc_node_group info_group[] = {
+ { "name", applesmc_name_show },
+ { "key_count", applesmc_key_count_show },
+@@ -1111,19 +1640,25 @@ static struct applesmc_node_group temp_group[] = {
+ { }
+ };
+
++static struct applesmc_node_group BCLM_group[] = {
++ { "battery_charge_limit", applesmc_BCLM_show, applesmc_BCLM_store },
++ { }
++};
++
+ /* Module stuff */
+
+ /*
+ * applesmc_destroy_nodes - remove files and free associated memory
+ */
+-static void applesmc_destroy_nodes(struct applesmc_node_group *groups)
++static void applesmc_destroy_nodes(struct applesmc_device *smc,
++ struct applesmc_node_group *groups)
+ {
+ struct applesmc_node_group *grp;
+ struct applesmc_dev_attr *node;
+
+ for (grp = groups; grp->nodes; grp++) {
+ for (node = grp->nodes; node->sda.dev_attr.attr.name; node++)
+- sysfs_remove_file(&pdev->dev.kobj,
++ sysfs_remove_file(&smc->dev->dev.kobj,
+ &node->sda.dev_attr.attr);
+ kfree(grp->nodes);
+ grp->nodes = NULL;
+@@ -1133,7 +1668,8 @@ static void applesmc_destroy_nodes(struct applesmc_node_group *groups)
+ /*
+ * applesmc_create_nodes - create a two-dimensional group of sysfs files
+ */
+-static int applesmc_create_nodes(struct applesmc_node_group *groups, int num)
++static int applesmc_create_nodes(struct applesmc_device *smc,
++ struct applesmc_node_group *groups, int num)
+ {
+ struct applesmc_node_group *grp;
+ struct applesmc_dev_attr *node;
+@@ -1157,7 +1693,7 @@ static int applesmc_create_nodes(struct applesmc_node_group *groups, int num)
+ sysfs_attr_init(attr);
+ attr->name = node->name;
+ attr->mode = 0444 | (grp->store ? 0200 : 0);
+- ret = sysfs_create_file(&pdev->dev.kobj, attr);
++ ret = sysfs_create_file(&smc->dev->dev.kobj, attr);
+ if (ret) {
+ attr->name = NULL;
+ goto out;
+@@ -1167,57 +1703,56 @@ static int applesmc_create_nodes(struct applesmc_node_group *groups, int num)
+
+ return 0;
+ out:
+- applesmc_destroy_nodes(groups);
++ applesmc_destroy_nodes(smc, groups);
+ return ret;
+ }
+
+ /* Create accelerometer resources */
+-static int applesmc_create_accelerometer(void)
++static int applesmc_create_accelerometer(struct applesmc_device *smc)
+ {
+ int ret;
+-
+- if (!smcreg.has_accelerometer)
++ if (!smc->reg.has_accelerometer)
+ return 0;
+
+- ret = applesmc_create_nodes(accelerometer_group, 1);
++ ret = applesmc_create_nodes(smc, accelerometer_group, 1);
+ if (ret)
+ goto out;
+
+- applesmc_idev = input_allocate_device();
+- if (!applesmc_idev) {
++ smc->idev = input_allocate_device();
++ if (!smc->idev) {
+ ret = -ENOMEM;
+ goto out_sysfs;
+ }
+
+ /* initial calibrate for the input device */
+- applesmc_calibrate();
++ applesmc_calibrate(smc);
+
+ /* initialize the input device */
+- applesmc_idev->name = "applesmc";
+- applesmc_idev->id.bustype = BUS_HOST;
+- applesmc_idev->dev.parent = &pdev->dev;
+- input_set_abs_params(applesmc_idev, ABS_X,
++ smc->idev->name = "applesmc";
++ smc->idev->id.bustype = BUS_HOST;
++ smc->idev->dev.parent = &smc->dev->dev;
++ input_set_abs_params(smc->idev, ABS_X,
+ -256, 256, APPLESMC_INPUT_FUZZ, APPLESMC_INPUT_FLAT);
+- input_set_abs_params(applesmc_idev, ABS_Y,
++ input_set_abs_params(smc->idev, ABS_Y,
+ -256, 256, APPLESMC_INPUT_FUZZ, APPLESMC_INPUT_FLAT);
+
+- ret = input_setup_polling(applesmc_idev, applesmc_idev_poll);
++ ret = input_setup_polling(smc->idev, applesmc_idev_poll);
+ if (ret)
+ goto out_idev;
+
+- input_set_poll_interval(applesmc_idev, APPLESMC_POLL_INTERVAL);
++ input_set_poll_interval(smc->idev, APPLESMC_POLL_INTERVAL);
+
+- ret = input_register_device(applesmc_idev);
++ ret = input_register_device(smc->idev);
+ if (ret)
+ goto out_idev;
+
+ return 0;
+
+ out_idev:
+- input_free_device(applesmc_idev);
++ input_free_device(smc->idev);
+
+ out_sysfs:
+- applesmc_destroy_nodes(accelerometer_group);
++ applesmc_destroy_nodes(smc, accelerometer_group);
+
+ out:
+ pr_warn("driver init failed (ret=%d)!\n", ret);
+@@ -1225,44 +1760,55 @@ static int applesmc_create_accelerometer(void)
+ }
+
+ /* Release all resources used by the accelerometer */
+-static void applesmc_release_accelerometer(void)
++static void applesmc_release_accelerometer(struct applesmc_device *smc)
+ {
+- if (!smcreg.has_accelerometer)
++ if (!smc->reg.has_accelerometer)
+ return;
+- input_unregister_device(applesmc_idev);
+- applesmc_destroy_nodes(accelerometer_group);
++ input_unregister_device(smc->idev);
++ applesmc_destroy_nodes(smc, accelerometer_group);
+ }
+
+-static int applesmc_create_light_sensor(void)
++static int applesmc_create_light_sensor(struct applesmc_device *smc)
+ {
+- if (!smcreg.num_light_sensors)
++ if (!smc->reg.num_light_sensors)
+ return 0;
+- return applesmc_create_nodes(light_sensor_group, 1);
++ return applesmc_create_nodes(smc, light_sensor_group, 1);
+ }
+
+-static void applesmc_release_light_sensor(void)
++static void applesmc_release_light_sensor(struct applesmc_device *smc)
+ {
+- if (!smcreg.num_light_sensors)
++ if (!smc->reg.num_light_sensors)
+ return;
+- applesmc_destroy_nodes(light_sensor_group);
++ applesmc_destroy_nodes(smc, light_sensor_group);
+ }
+
+-static int applesmc_create_key_backlight(void)
++static int applesmc_create_key_backlight(struct applesmc_device *smc)
+ {
+- if (!smcreg.has_key_backlight)
++ int ret;
++
++ if (!smc->reg.has_key_backlight)
+ return 0;
+- applesmc_led_wq = create_singlethread_workqueue("applesmc-led");
+- if (!applesmc_led_wq)
++ smc->backlight_wq = create_singlethread_workqueue("applesmc-led");
++ if (!smc->backlight_wq)
+ return -ENOMEM;
+- return led_classdev_register(&pdev->dev, &applesmc_backlight);
++
++ INIT_WORK(&smc->backlight_work, applesmc_backlight_set);
++ smc->backlight_dev.name = "smc::kbd_backlight";
++ smc->backlight_dev.default_trigger = "nand-disk";
++ smc->backlight_dev.brightness_set = applesmc_brightness_set;
++ ret = led_classdev_register(&smc->dev->dev, &smc->backlight_dev);
++ if (ret)
++ destroy_workqueue(smc->backlight_wq);
++
++ return ret;
+ }
+
+-static void applesmc_release_key_backlight(void)
++static void applesmc_release_key_backlight(struct applesmc_device *smc)
+ {
+- if (!smcreg.has_key_backlight)
++ if (!smc->reg.has_key_backlight)
+ return;
+- led_classdev_unregister(&applesmc_backlight);
+- destroy_workqueue(applesmc_led_wq);
++ led_classdev_unregister(&smc->backlight_dev);
++ destroy_workqueue(smc->backlight_wq);
+ }
+
+ static int applesmc_dmi_match(const struct dmi_system_id *id)
+@@ -1291,6 +1837,10 @@ static const struct dmi_system_id applesmc_whitelist[] __initconst = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Macmini") },
+ },
++ { applesmc_dmi_match, "Apple iMacPro", {
++ DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
++ DMI_MATCH(DMI_PRODUCT_NAME, "iMacPro") },
++ },
+ { applesmc_dmi_match, "Apple MacPro", {
+ DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "MacPro") },
+@@ -1306,90 +1856,91 @@ static const struct dmi_system_id applesmc_whitelist[] __initconst = {
+ { .ident = NULL }
+ };
+
+-static int __init applesmc_init(void)
++static int applesmc_create_modules(struct applesmc_device *smc)
+ {
+ int ret;
+
+- if (!dmi_check_system(applesmc_whitelist)) {
+- pr_warn("supported laptop not found!\n");
+- ret = -ENODEV;
+- goto out;
+- }
+-
+- if (!request_region(APPLESMC_DATA_PORT, APPLESMC_NR_PORTS,
+- "applesmc")) {
+- ret = -ENXIO;
+- goto out;
+- }
+-
+- ret = platform_driver_register(&applesmc_driver);
+- if (ret)
+- goto out_region;
+-
+- pdev = platform_device_register_simple("applesmc", APPLESMC_DATA_PORT,
+- NULL, 0);
+- if (IS_ERR(pdev)) {
+- ret = PTR_ERR(pdev);
+- goto out_driver;
+- }
+-
+- /* create register cache */
+- ret = applesmc_init_smcreg();
++ ret = applesmc_create_nodes(smc, info_group, 1);
+ if (ret)
+- goto out_device;
+-
+- ret = applesmc_create_nodes(info_group, 1);
++ goto out;
++ ret = applesmc_create_nodes(smc, BCLM_group, 1);
+ if (ret)
+- goto out_smcreg;
++ goto out_info;
+
+- ret = applesmc_create_nodes(fan_group, smcreg.fan_count);
++ ret = applesmc_create_nodes(smc, fan_group, smc->reg.fan_count);
+ if (ret)
+- goto out_info;
++ goto out_bclm;
+
+- ret = applesmc_create_nodes(temp_group, smcreg.index_count);
++ ret = applesmc_create_nodes(smc, temp_group, smc->reg.index_count);
+ if (ret)
+ goto out_fans;
+
+- ret = applesmc_create_accelerometer();
++ ret = applesmc_create_accelerometer(smc);
+ if (ret)
+ goto out_temperature;
+
+- ret = applesmc_create_light_sensor();
++ ret = applesmc_create_light_sensor(smc);
+ if (ret)
+ goto out_accelerometer;
+
+- ret = applesmc_create_key_backlight();
++ ret = applesmc_create_key_backlight(smc);
+ if (ret)
+ goto out_light_sysfs;
+
+- hwmon_dev = hwmon_device_register(&pdev->dev);
+- if (IS_ERR(hwmon_dev)) {
+- ret = PTR_ERR(hwmon_dev);
++ smc->hwmon_dev = hwmon_device_register(&smc->dev->dev);
++ if (IS_ERR(smc->hwmon_dev)) {
++ ret = PTR_ERR(smc->hwmon_dev);
+ goto out_light_ledclass;
+ }
+
+ return 0;
+
+ out_light_ledclass:
+- applesmc_release_key_backlight();
++ applesmc_release_key_backlight(smc);
+ out_light_sysfs:
+- applesmc_release_light_sensor();
++ applesmc_release_light_sensor(smc);
+ out_accelerometer:
+- applesmc_release_accelerometer();
++ applesmc_release_accelerometer(smc);
+ out_temperature:
+- applesmc_destroy_nodes(temp_group);
++ applesmc_destroy_nodes(smc, temp_group);
+ out_fans:
+- applesmc_destroy_nodes(fan_group);
++ applesmc_destroy_nodes(smc, fan_group);
++out_bclm:
++ applesmc_destroy_nodes(smc, BCLM_group);
+ out_info:
+- applesmc_destroy_nodes(info_group);
+-out_smcreg:
+- applesmc_destroy_smcreg();
+-out_device:
+- platform_device_unregister(pdev);
+-out_driver:
+- platform_driver_unregister(&applesmc_driver);
+-out_region:
+- release_region(APPLESMC_DATA_PORT, APPLESMC_NR_PORTS);
++ applesmc_destroy_nodes(smc, info_group);
++out:
++ return ret;
++}
++
++static void applesmc_destroy_modules(struct applesmc_device *smc)
++{
++ hwmon_device_unregister(smc->hwmon_dev);
++ applesmc_release_key_backlight(smc);
++ applesmc_release_light_sensor(smc);
++ applesmc_release_accelerometer(smc);
++ applesmc_destroy_nodes(smc, temp_group);
++ applesmc_destroy_nodes(smc, fan_group);
++ applesmc_destroy_nodes(smc, BCLM_group);
++ applesmc_destroy_nodes(smc, info_group);
++}
++
++static int __init applesmc_init(void)
++{
++ int ret;
++
++ if (!dmi_check_system(applesmc_whitelist)) {
++ pr_warn("supported laptop not found!\n");
++ ret = -ENODEV;
++ goto out;
++ }
++
++ ret = acpi_bus_register_driver(&applesmc_driver);
++ if (ret)
++ goto out;
++
++ return 0;
++
+ out:
+ pr_warn("driver init failed (ret=%d)!\n", ret);
+ return ret;
+@@ -1397,23 +1948,14 @@ static int __init applesmc_init(void)
+
+ static void __exit applesmc_exit(void)
+ {
+- hwmon_device_unregister(hwmon_dev);
+- applesmc_release_key_backlight();
+- applesmc_release_light_sensor();
+- applesmc_release_accelerometer();
+- applesmc_destroy_nodes(temp_group);
+- applesmc_destroy_nodes(fan_group);
+- applesmc_destroy_nodes(info_group);
+- applesmc_destroy_smcreg();
+- platform_device_unregister(pdev);
+- platform_driver_unregister(&applesmc_driver);
+- release_region(APPLESMC_DATA_PORT, APPLESMC_NR_PORTS);
++ acpi_bus_unregister_driver(&applesmc_driver);
+ }
+
+ module_init(applesmc_init);
+ module_exit(applesmc_exit);
+
+ MODULE_AUTHOR("Nicolas Boichat");
++MODULE_AUTHOR("Paul Pawlowski");
+ MODULE_DESCRIPTION("Apple SMC");
+ MODULE_LICENSE("GPL v2");
+ MODULE_DEVICE_TABLE(dmi, applesmc_whitelist);
+diff --git a/drivers/input/mouse/bcm5974.c b/drivers/input/mouse/bcm5974.c
+index ca150618d32f..4e692b272ae9 100644
+--- a/drivers/input/mouse/bcm5974.c
++++ b/drivers/input/mouse/bcm5974.c
+@@ -83,6 +83,24 @@
+ #define USB_DEVICE_ID_APPLE_WELLSPRING9_ISO 0x0273
+ #define USB_DEVICE_ID_APPLE_WELLSPRING9_JIS 0x0274
+
++/* T2-Attached Devices */
++/* MacbookAir8,1 (2018) */
++#define USB_DEVICE_ID_APPLE_WELLSPRINGT2_J140K 0x027a
++/* MacbookPro15,2 (2018) */
++#define USB_DEVICE_ID_APPLE_WELLSPRINGT2_J132 0x027b
++/* MacbookPro15,1 (2018) */
++#define USB_DEVICE_ID_APPLE_WELLSPRINGT2_J680 0x027c
++/* MacbookPro15,4 (2019) */
++#define USB_DEVICE_ID_APPLE_WELLSPRINGT2_J213 0x027d
++/* MacbookPro16,2 (2020) */
++#define USB_DEVICE_ID_APPLE_WELLSPRINGT2_J214K 0x027e
++/* MacbookPro16,3 (2020) */
++#define USB_DEVICE_ID_APPLE_WELLSPRINGT2_J223 0x027f
++/* MacbookAir9,1 (2020) */
++#define USB_DEVICE_ID_APPLE_WELLSPRINGT2_J230K 0x0280
++/* MacbookPro16,1 (2019)*/
++#define USB_DEVICE_ID_APPLE_WELLSPRINGT2_J152F 0x0340
++
+ #define BCM5974_DEVICE(prod) { \
+ .match_flags = (USB_DEVICE_ID_MATCH_DEVICE | \
+ USB_DEVICE_ID_MATCH_INT_CLASS | \
+@@ -147,6 +165,22 @@ static const struct usb_device_id bcm5974_table[] = {
+ BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING9_ANSI),
+ BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING9_ISO),
+ BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING9_JIS),
++ /* MacbookAir8,1 */
++ BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRINGT2_J140K),
++ /* MacbookPro15,2 */
++ BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRINGT2_J132),
++ /* MacbookPro15,1 */
++ BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRINGT2_J680),
++ /* MacbookPro15,4 */
++ BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRINGT2_J213),
++ /* MacbookPro16,2 */
++ BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRINGT2_J214K),
++ /* MacbookPro16,3 */
++ BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRINGT2_J223),
++ /* MacbookAir9,1 */
++ BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRINGT2_J230K),
++ /* MacbookPro16,1 */
++ BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRINGT2_J152F),
+ /* Terminating entry */
+ {}
+ };
+@@ -483,6 +517,110 @@ static const struct bcm5974_config bcm5974_config_table[] = {
+ { SN_COORD, -203, 6803 },
+ { SN_ORIENT, -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION }
+ },
++ {
++ USB_DEVICE_ID_APPLE_WELLSPRINGT2_J140K,
++ 0,
++ 0,
++ HAS_INTEGRATED_BUTTON,
++ 0, sizeof(struct bt_data),
++ 0x83, DATAFORMAT(TYPE4),
++ { SN_PRESSURE, 0, 300 },
++ { SN_WIDTH, 0, 2048 },
++ { SN_COORD, -6243, 6749 },
++ { SN_COORD, -170, 7685 },
++ { SN_ORIENT, -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION }
++ },
++ {
++ USB_DEVICE_ID_APPLE_WELLSPRINGT2_J132,
++ 0,
++ 0,
++ HAS_INTEGRATED_BUTTON,
++ 0, sizeof(struct bt_data),
++ 0x83, DATAFORMAT(TYPE4),
++ { SN_PRESSURE, 0, 300 },
++ { SN_WIDTH, 0, 2048 },
++ { SN_COORD, -6243, 6749 },
++ { SN_COORD, -170, 7685 },
++ { SN_ORIENT, -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION }
++ },
++ {
++ USB_DEVICE_ID_APPLE_WELLSPRINGT2_J680,
++ 0,
++ 0,
++ HAS_INTEGRATED_BUTTON,
++ 0, sizeof(struct bt_data),
++ 0x83, DATAFORMAT(TYPE4),
++ { SN_PRESSURE, 0, 300 },
++ { SN_WIDTH, 0, 2048 },
++ { SN_COORD, -7456, 7976 },
++ { SN_COORD, -1768, 7685 },
++ { SN_ORIENT, -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION }
++ },
++ {
++ USB_DEVICE_ID_APPLE_WELLSPRINGT2_J213,
++ 0,
++ 0,
++ HAS_INTEGRATED_BUTTON,
++ 0, sizeof(struct bt_data),
++ 0x83, DATAFORMAT(TYPE4),
++ { SN_PRESSURE, 0, 300 },
++ { SN_WIDTH, 0, 2048 },
++ { SN_COORD, -6243, 6749 },
++ { SN_COORD, -170, 7685 },
++ { SN_ORIENT, -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION }
++ },
++ {
++ USB_DEVICE_ID_APPLE_WELLSPRINGT2_J214K,
++ 0,
++ 0,
++ HAS_INTEGRATED_BUTTON,
++ 0, sizeof(struct bt_data),
++ 0x83, DATAFORMAT(TYPE4),
++ { SN_PRESSURE, 0, 300 },
++ { SN_WIDTH, 0, 2048 },
++ { SN_COORD, -7823, 8329 },
++ { SN_COORD, -370, 7925 },
++ { SN_ORIENT, -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION }
++ },
++ {
++ USB_DEVICE_ID_APPLE_WELLSPRINGT2_J223,
++ 0,
++ 0,
++ HAS_INTEGRATED_BUTTON,
++ 0, sizeof(struct bt_data),
++ 0x83, DATAFORMAT(TYPE4),
++ { SN_PRESSURE, 0, 300 },
++ { SN_WIDTH, 0, 2048 },
++ { SN_COORD, -6243, 6749 },
++ { SN_COORD, -170, 7685 },
++ { SN_ORIENT, -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION }
++ },
++ {
++ USB_DEVICE_ID_APPLE_WELLSPRINGT2_J230K,
++ 0,
++ 0,
++ HAS_INTEGRATED_BUTTON,
++ 0, sizeof(struct bt_data),
++ 0x83, DATAFORMAT(TYPE4),
++ { SN_PRESSURE, 0, 300 },
++ { SN_WIDTH, 0, 2048 },
++ { SN_COORD, -6243, 6749 },
++ { SN_COORD, -170, 7685 },
++ { SN_ORIENT, -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION }
++ },
++ {
++ USB_DEVICE_ID_APPLE_WELLSPRINGT2_J152F,
++ 0,
++ 0,
++ HAS_INTEGRATED_BUTTON,
++ 0, sizeof(struct bt_data),
++ 0x83, DATAFORMAT(TYPE4),
++ { SN_PRESSURE, 0, 300 },
++ { SN_WIDTH, 0, 2048 },
++ { SN_COORD, -8916, 9918 },
++ { SN_COORD, -1934, 9835 },
++ { SN_ORIENT, -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION }
++ },
+ {}
+ };
+
+diff --git a/drivers/pci/vgaarb.c b/drivers/pci/vgaarb.c
+index 78748e8d2dba..2b2b558cebe6 100644
+--- a/drivers/pci/vgaarb.c
++++ b/drivers/pci/vgaarb.c
+@@ -143,6 +143,7 @@ void vga_set_default_device(struct pci_dev *pdev)
+ pci_dev_put(vga_default);
+ vga_default = pci_dev_get(pdev);
+ }
++EXPORT_SYMBOL_GPL(vga_set_default_device);
+
+ /**
+ * vga_remove_vgacon - deactivate VGA console
+diff --git a/drivers/platform/x86/apple-gmux.c b/drivers/platform/x86/apple-gmux.c
+index 1417e230edbd..e69785af8e1d 100644
+--- a/drivers/platform/x86/apple-gmux.c
++++ b/drivers/platform/x86/apple-gmux.c
+@@ -21,6 +21,7 @@
+ #include <linux/delay.h>
+ #include <linux/pci.h>
+ #include <linux/vga_switcheroo.h>
++#include <linux/vgaarb.h>
+ #include <linux/debugfs.h>
+ #include <acpi/video.h>
+ #include <asm/io.h>
+@@ -107,6 +108,10 @@ struct apple_gmux_config {
+
+ # define MMIO_GMUX_MAX_BRIGHTNESS 0xffff
+
++static bool force_igd;
++module_param(force_igd, bool, 0);
++MODULE_PARM_DESC(force_idg, "Switch gpu to igd on module load. Make sure that you have apple-set-os set up and the iGPU is in `lspci -s 00:02.0`. (default: false) (bool)");
++
+ static u8 gmux_pio_read8(struct apple_gmux_data *gmux_data, int port)
+ {
+ return inb(gmux_data->iostart + port);
+@@ -945,6 +950,19 @@ static int gmux_probe(struct pnp_dev *pnp, const struct pnp_device_id *id)
+ gmux_enable_interrupts(gmux_data);
+ gmux_read_switch_state(gmux_data);
+
++ if (force_igd) {
++ struct pci_dev *pdev;
++
++ pdev = pci_get_domain_bus_and_slot(0, 0, PCI_DEVFN(2, 0));
++ if (pdev) {
++ pr_info("Switching to IGD");
++ gmux_switchto(VGA_SWITCHEROO_IGD);
++ vga_set_default_device(pdev);
++ } else {
++ pr_err("force_idg is true, but couldn't find iGPU at 00:02.0! Is apple-set-os working?");
++ }
++ }
++
+ /*
+ * Retina MacBook Pros cannot switch the panel's AUX separately
+ * and need eDP pre-calibration. They are distinguishable from
+diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig
+index db4a392841b1..580df4ce4f9f 100644
+--- a/drivers/staging/Kconfig
++++ b/drivers/staging/Kconfig
+@@ -66,4 +66,6 @@ source "drivers/staging/fieldbus/Kconfig"
+
+ source "drivers/staging/vme_user/Kconfig"
+
++source "drivers/staging/apple-bce/Kconfig"
++
+ endif # STAGING
+diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile
+index 5390879b5d1b..528be2d3b546 100644
+--- a/drivers/staging/Makefile
++++ b/drivers/staging/Makefile
+@@ -22,3 +22,4 @@ obj-$(CONFIG_GREYBUS) += greybus/
+ obj-$(CONFIG_BCM2835_VCHIQ) += vc04_services/
+ obj-$(CONFIG_XIL_AXIS_FIFO) += axis-fifo/
+ obj-$(CONFIG_FIELDBUS_DEV) += fieldbus/
++obj-$(CONFIG_APPLE_BCE) += apple-bce/
+diff --git a/drivers/staging/apple-bce/Kconfig b/drivers/staging/apple-bce/Kconfig
+new file mode 100644
+index 000000000000..fe92bc441e89
+--- /dev/null
++++ b/drivers/staging/apple-bce/Kconfig
+@@ -0,0 +1,18 @@
++config APPLE_BCE
++ tristate "Apple BCE driver (VHCI and Audio support)"
++ default m
++ depends on X86
++ select SOUND
++ select SND
++ select SND_PCM
++ select SND_JACK
++ help
++ VHCI and audio support on Apple MacBooks with the T2 Chip.
++ This driver is divided in three components:
++ - BCE (Buffer Copy Engine): which establishes a basic communication
++ channel with the T2 chip. This component is required by the other two:
++ - VHCI (Virtual Host Controller Interface): Access to keyboard, mouse
++ and other system devices depend on this virtual USB host controller
++ - Audio: a driver for the T2 audio interface.
++
++ If "M" is selected, the module will be called apple-bce.'
diff --git a/drivers/staging/apple-bce/Makefile b/drivers/staging/apple-bce/Makefile
new file mode 100644
-index 000000000..a6a656f06
+index 000000000000..8cfbd3f64af6
--- /dev/null
+++ b/drivers/staging/apple-bce/Makefile
@@ -0,0 +1,28 @@
+modname := apple-bce
-+obj-m += $(modname).o
++obj-$(CONFIG_APPLE_BCE) += $(modname).o
+
+apple-bce-objs := apple_bce.o mailbox.o queue.o queue_dma.o vhci/vhci.o vhci/queue.o vhci/transfer.o audio/audio.o audio/protocol.o audio/protocol_bce.o audio/pcm.o
+
@@ -92,10 +4696,10 @@ index 000000000..a6a656f06
+ $(MAKE) -C $(KDIR) M=$(PWD) modules_install
diff --git a/drivers/staging/apple-bce/apple_bce.c b/drivers/staging/apple-bce/apple_bce.c
new file mode 100644
-index 000000000..ad89632df
+index 000000000000..4fd2415d7028
--- /dev/null
+++ b/drivers/staging/apple-bce/apple_bce.c
-@@ -0,0 +1,443 @@
+@@ -0,0 +1,445 @@
+#include "apple_bce.h"
+#include <linux/module.h>
+#include <linux/crc32.h>
@@ -471,6 +5075,8 @@ index 000000000..ad89632df
+ { 0, },
+};
+
++MODULE_DEVICE_TABLE(pci, apple_bce_ids);
++
+struct dev_pm_ops apple_bce_pci_driver_pm = {
+ .suspend = apple_bce_suspend,
+ .resume = apple_bce_resume
@@ -541,7 +5147,7 @@ index 000000000..ad89632df
+module_exit(apple_bce_module_exit);
diff --git a/drivers/staging/apple-bce/apple_bce.h b/drivers/staging/apple-bce/apple_bce.h
new file mode 100644
-index 000000000..f13ab8d57
+index 000000000000..f13ab8d5742e
--- /dev/null
+++ b/drivers/staging/apple-bce/apple_bce.h
@@ -0,0 +1,38 @@
@@ -586,7 +5192,7 @@ index 000000000..f13ab8d57
\ No newline at end of file
diff --git a/drivers/staging/apple-bce/audio/audio.c b/drivers/staging/apple-bce/audio/audio.c
new file mode 100644
-index 000000000..bd16ddd16
+index 000000000000..bd16ddd16c1d
--- /dev/null
+++ b/drivers/staging/apple-bce/audio/audio.c
@@ -0,0 +1,711 @@
@@ -1303,7 +5909,7 @@ index 000000000..bd16ddd16
+MODULE_PARM_DESC(id, "ID string for Apple Internal Audio soundcard.");
diff --git a/drivers/staging/apple-bce/audio/audio.h b/drivers/staging/apple-bce/audio/audio.h
new file mode 100644
-index 000000000..004bc1e22
+index 000000000000..004bc1e22ea4
--- /dev/null
+++ b/drivers/staging/apple-bce/audio/audio.h
@@ -0,0 +1,125 @@
@@ -1434,7 +6040,7 @@ index 000000000..004bc1e22
+#endif //AAUDIO_H
diff --git a/drivers/staging/apple-bce/audio/description.h b/drivers/staging/apple-bce/audio/description.h
new file mode 100644
-index 000000000..dfef3ab68
+index 000000000000..dfef3ab68f27
--- /dev/null
+++ b/drivers/staging/apple-bce/audio/description.h
@@ -0,0 +1,42 @@
@@ -1482,7 +6088,7 @@ index 000000000..dfef3ab68
+#endif //AAUDIO_DESCRIPTION_H
diff --git a/drivers/staging/apple-bce/audio/pcm.c b/drivers/staging/apple-bce/audio/pcm.c
new file mode 100644
-index 000000000..1026e10a9
+index 000000000000..1026e10a9ac5
--- /dev/null
+++ b/drivers/staging/apple-bce/audio/pcm.c
@@ -0,0 +1,308 @@
@@ -1796,7 +6402,7 @@ index 000000000..1026e10a9
+}
diff --git a/drivers/staging/apple-bce/audio/pcm.h b/drivers/staging/apple-bce/audio/pcm.h
new file mode 100644
-index 000000000..ea5f35fbe
+index 000000000000..ea5f35fbe408
--- /dev/null
+++ b/drivers/staging/apple-bce/audio/pcm.h
@@ -0,0 +1,16 @@
@@ -1818,7 +6424,7 @@ index 000000000..ea5f35fbe
+#endif //AAUDIO_PCM_H
diff --git a/drivers/staging/apple-bce/audio/protocol.c b/drivers/staging/apple-bce/audio/protocol.c
new file mode 100644
-index 000000000..2314813ae
+index 000000000000..2314813aeead
--- /dev/null
+++ b/drivers/staging/apple-bce/audio/protocol.c
@@ -0,0 +1,347 @@
@@ -2172,7 +6778,7 @@ index 000000000..2314813ae
\ No newline at end of file
diff --git a/drivers/staging/apple-bce/audio/protocol.h b/drivers/staging/apple-bce/audio/protocol.h
new file mode 100644
-index 000000000..3427486f3
+index 000000000000..3427486f3f57
--- /dev/null
+++ b/drivers/staging/apple-bce/audio/protocol.h
@@ -0,0 +1,147 @@
@@ -2325,7 +6931,7 @@ index 000000000..3427486f3
+#endif //AAUDIO_PROTOCOL_H
diff --git a/drivers/staging/apple-bce/audio/protocol_bce.c b/drivers/staging/apple-bce/audio/protocol_bce.c
new file mode 100644
-index 000000000..28f2dfd44
+index 000000000000..28f2dfd44d67
--- /dev/null
+++ b/drivers/staging/apple-bce/audio/protocol_bce.c
@@ -0,0 +1,226 @@
@@ -2557,7 +7163,7 @@ index 000000000..28f2dfd44
+}
diff --git a/drivers/staging/apple-bce/audio/protocol_bce.h b/drivers/staging/apple-bce/audio/protocol_bce.h
new file mode 100644
-index 000000000..14d26c05d
+index 000000000000..14d26c05ddf9
--- /dev/null
+++ b/drivers/staging/apple-bce/audio/protocol_bce.h
@@ -0,0 +1,72 @@
@@ -2635,7 +7241,7 @@ index 000000000..14d26c05d
+#endif //AAUDIO_PROTOCOL_BCE_H
diff --git a/drivers/staging/apple-bce/mailbox.c b/drivers/staging/apple-bce/mailbox.c
new file mode 100644
-index 000000000..e24bd3521
+index 000000000000..e24bd35215c0
--- /dev/null
+++ b/drivers/staging/apple-bce/mailbox.c
@@ -0,0 +1,151 @@
@@ -2793,7 +7399,7 @@ index 000000000..e24bd3521
\ No newline at end of file
diff --git a/drivers/staging/apple-bce/mailbox.h b/drivers/staging/apple-bce/mailbox.h
new file mode 100644
-index 000000000..f3323f95b
+index 000000000000..f3323f95ba51
--- /dev/null
+++ b/drivers/staging/apple-bce/mailbox.h
@@ -0,0 +1,53 @@
@@ -2852,7 +7458,7 @@ index 000000000..f3323f95b
+#endif //BCEDRIVER_MAILBOX_H
diff --git a/drivers/staging/apple-bce/queue.c b/drivers/staging/apple-bce/queue.c
new file mode 100644
-index 000000000..bc9cd3bc6
+index 000000000000..bc9cd3bc6f0c
--- /dev/null
+++ b/drivers/staging/apple-bce/queue.c
@@ -0,0 +1,390 @@
@@ -3249,7 +7855,7 @@ index 000000000..bc9cd3bc6
\ No newline at end of file
diff --git a/drivers/staging/apple-bce/queue.h b/drivers/staging/apple-bce/queue.h
new file mode 100644
-index 000000000..8368ac5df
+index 000000000000..8368ac5dfca8
--- /dev/null
+++ b/drivers/staging/apple-bce/queue.h
@@ -0,0 +1,177 @@
@@ -3432,7 +8038,7 @@ index 000000000..8368ac5df
+#endif //BCEDRIVER_MAILBOX_H
diff --git a/drivers/staging/apple-bce/queue_dma.c b/drivers/staging/apple-bce/queue_dma.c
new file mode 100644
-index 000000000..b23661328
+index 000000000000..b236613285c0
--- /dev/null
+++ b/drivers/staging/apple-bce/queue_dma.c
@@ -0,0 +1,220 @@
@@ -3659,7 +8265,7 @@ index 000000000..b23661328
\ No newline at end of file
diff --git a/drivers/staging/apple-bce/queue_dma.h b/drivers/staging/apple-bce/queue_dma.h
new file mode 100644
-index 000000000..f8a57e50e
+index 000000000000..f8a57e50e7a3
--- /dev/null
+++ b/drivers/staging/apple-bce/queue_dma.h
@@ -0,0 +1,50 @@
@@ -3715,7 +8321,7 @@ index 000000000..f8a57e50e
+#endif //BCE_QUEUE_DMA_H
diff --git a/drivers/staging/apple-bce/vhci/command.h b/drivers/staging/apple-bce/vhci/command.h
new file mode 100644
-index 000000000..26619e0bc
+index 000000000000..26619e0bccfa
--- /dev/null
+++ b/drivers/staging/apple-bce/vhci/command.h
@@ -0,0 +1,204 @@
@@ -3925,7 +8531,7 @@ index 000000000..26619e0bc
+#endif //BCE_VHCI_COMMAND_H
diff --git a/drivers/staging/apple-bce/vhci/queue.c b/drivers/staging/apple-bce/vhci/queue.c
new file mode 100644
-index 000000000..7b0b50271
+index 000000000000..7b0b5027157b
--- /dev/null
+++ b/drivers/staging/apple-bce/vhci/queue.c
@@ -0,0 +1,268 @@
@@ -4199,7 +8805,7 @@ index 000000000..7b0b50271
+}
diff --git a/drivers/staging/apple-bce/vhci/queue.h b/drivers/staging/apple-bce/vhci/queue.h
new file mode 100644
-index 000000000..adb705b6b
+index 000000000000..adb705b6ba1d
--- /dev/null
+++ b/drivers/staging/apple-bce/vhci/queue.h
@@ -0,0 +1,76 @@
@@ -4281,7 +8887,7 @@ index 000000000..adb705b6b
+#endif //BCE_VHCI_QUEUE_H
diff --git a/drivers/staging/apple-bce/vhci/transfer.c b/drivers/staging/apple-bce/vhci/transfer.c
new file mode 100644
-index 000000000..8226363d6
+index 000000000000..8226363d69c8
--- /dev/null
+++ b/drivers/staging/apple-bce/vhci/transfer.c
@@ -0,0 +1,661 @@
@@ -4948,7 +9554,7 @@ index 000000000..8226363d6
+}
diff --git a/drivers/staging/apple-bce/vhci/transfer.h b/drivers/staging/apple-bce/vhci/transfer.h
new file mode 100644
-index 000000000..89ecad6bc
+index 000000000000..89ecad6bcf8f
--- /dev/null
+++ b/drivers/staging/apple-bce/vhci/transfer.h
@@ -0,0 +1,73 @@
@@ -5027,7 +9633,7 @@ index 000000000..89ecad6bc
+#endif //BCEDRIVER_TRANSFER_H
diff --git a/drivers/staging/apple-bce/vhci/vhci.c b/drivers/staging/apple-bce/vhci/vhci.c
new file mode 100644
-index 000000000..eb26f5500
+index 000000000000..eb26f55000d8
--- /dev/null
+++ b/drivers/staging/apple-bce/vhci/vhci.c
@@ -0,0 +1,759 @@
@@ -5792,7 +10398,7 @@ index 000000000..eb26f5500
+MODULE_PARM_DESC(vhci_port_mask, "Specifies which VHCI ports are enabled");
diff --git a/drivers/staging/apple-bce/vhci/vhci.h b/drivers/staging/apple-bce/vhci/vhci.h
new file mode 100644
-index 000000000..6c2e22622
+index 000000000000..6c2e22622f4c
--- /dev/null
+++ b/drivers/staging/apple-bce/vhci/vhci.h
@@ -0,0 +1,52 @@
@@ -5848,206 +10454,106 @@ index 000000000..6c2e22622
+struct bce_vhci *bce_vhci_from_hcd(struct usb_hcd *hcd);
+
+#endif //BCE_VHCI_H
---
-2.43.2
-
-From dc27d4db5787546ae5eacf3483f3b87f2d4fb1c1 Mon Sep 17 00:00:00 2001
-From: Redecorating <69827514+Redecorating@users.noreply.github.com>
-Date: Mon, 7 Nov 2022 14:56:34 +0530
-Subject: [PATCH] Put apple-bce in drivers/staging
-
----
- drivers/staging/Kconfig | 2 ++
- drivers/staging/Makefile | 1 +
- drivers/staging/apple-bce/Kconfig | 18 ++++++++++++++++++
- drivers/staging/apple-bce/Makefile | 2 +-
- 4 files changed, 22 insertions(+), 1 deletion(-)
- create mode 100644 drivers/staging/apple-bce/Kconfig
-
-diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig
-index 5cfabd537..3b8e61d26 100644
---- a/drivers/staging/Kconfig
-+++ b/drivers/staging/Kconfig
-@@ -80,4 +80,6 @@ source "drivers/staging/qlge/Kconfig"
-
- source "drivers/staging/vme_user/Kconfig"
-
-+source "drivers/staging/apple-bce/Kconfig"
-+
- endif # STAGING
-diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile
-index f8c3aa9c2..1e148d6c3 100644
---- a/drivers/staging/Makefile
-+++ b/drivers/staging/Makefile
-@@ -29,3 +29,4 @@ obj-$(CONFIG_PI433) += pi433/
- obj-$(CONFIG_PI433) += pi433/
- obj-$(CONFIG_XIL_AXIS_FIFO) += axis-fifo/
- obj-$(CONFIG_FIELDBUS_DEV) += fieldbus/
-+obj-$(CONFIG_APPLE_BCE) += apple-bce/
-diff --git a/drivers/staging/apple-bce/Kconfig b/drivers/staging/apple-bce/Kconfig
-new file mode 100644
-index 000000000..fe92bc441
---- /dev/null
-+++ b/drivers/staging/apple-bce/Kconfig
-@@ -0,0 +1,18 @@
-+config APPLE_BCE
-+ tristate "Apple BCE driver (VHCI and Audio support)"
-+ default m
-+ depends on X86
-+ select SOUND
-+ select SND
-+ select SND_PCM
-+ select SND_JACK
-+ help
-+ VHCI and audio support on Apple MacBooks with the T2 Chip.
-+ This driver is divided in three components:
-+ - BCE (Buffer Copy Engine): which establishes a basic communication
-+ channel with the T2 chip. This component is required by the other two:
-+ - VHCI (Virtual Host Controller Interface): Access to keyboard, mouse
-+ and other system devices depend on this virtual USB host controller
-+ - Audio: a driver for the T2 audio interface.
-+
-+ If "M" is selected, the module will be called apple-bce.'
-diff --git a/drivers/staging/apple-bce/Makefile b/drivers/staging/apple-bce/Makefile
-index a6a656f06..8cfbd3f64 100644
---- a/drivers/staging/apple-bce/Makefile
-+++ b/drivers/staging/apple-bce/Makefile
-@@ -1,5 +1,5 @@
- modname := apple-bce
--obj-m += $(modname).o
-+obj-$(CONFIG_APPLE_BCE) += $(modname).o
-
- apple-bce-objs := apple_bce.o mailbox.o queue.o queue_dma.o vhci/vhci.o vhci/queue.o vhci/transfer.o audio/audio.o audio/protocol.o audio/protocol_bce.o audio/pcm.o
-
---
-2.34.1
-From 153b587ed53135eaf244144f6f8bdd5a0fe6b69e Mon Sep 17 00:00:00 2001
-From: Redecorating <69827514+Redecorating@users.noreply.github.com>
-Date: Fri, 24 Dec 2021 18:12:25 +1100
-Subject: [PATCH 1/1] add modalias to apple-bce
-
----
- drivers/staging/apple-bce/apple_bce.c | 1 +
- 1 file changed, 1 insertion(+)
-
-diff --git a/drivers/staging/apple-bce/apple_bce.c b/drivers/staging/apple-bce/apple_bce.c
-index ad89632df..5e2f2f3b9 100644
---- a/drivers/staging/apple-bce/apple_bce.c
-+++ b/drivers/staging/apple-bce/apple_bce.c
-@@ -439,5 +439,6 @@ MODULE_LICENSE("GPL");
- MODULE_AUTHOR("MrARM");
- MODULE_DESCRIPTION("Apple BCE Driver");
- MODULE_VERSION("0.01");
-+MODULE_ALIAS("pci:v0000106Bd00001801sv*sd*bc*sc*i*");
- module_init(apple_bce_module_init);
- module_exit(apple_bce_module_exit);
---
-2.43.0
-
-From 75ca57b64ce6846622d8aefac5a76fc638a2123d Mon Sep 17 00:00:00 2001
-From: Kerem Karabay <kekrby@gmail.com>
-Date: Sun, 5 Mar 2023 19:12:53 +0300
-Subject: [PATCH 01/12] HID: core: add helper for finding a field with a
- certain usage
-
-This helper will allow HID drivers to easily determine if they should
-bind to a hid_device by checking for the prescence of a certain field
-when its ID is not enough, which can be the case on USB devices with
-multiple interfaces and/or configurations.
-
-Signed-off-by: Kerem Karabay <kekrby@gmail.com>
----
- drivers/hid/hid-core.c | 25 +++++++++++++++++++++++++
- drivers/hid/hid-google-hammer.c | 27 ++-------------------------
- include/linux/hid.h | 2 ++
- 3 files changed, 29 insertions(+), 25 deletions(-)
-
-diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
-index 8992e3c1e..6395bdc2e 100644
---- a/drivers/hid/hid-core.c
-+++ b/drivers/hid/hid-core.c
-@@ -1906,6 +1906,31 @@ int hid_set_field(struct hid_field *field, unsigned offset, __s32 value)
+diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c
+index e02ba15f6e34..b35734d03109 100644
+--- a/drivers/usb/core/driver.c
++++ b/drivers/usb/core/driver.c
+@@ -517,6 +517,19 @@ static int usb_unbind_interface(struct device *dev)
+ return 0;
}
- EXPORT_SYMBOL_GPL(hid_set_field);
-+struct hid_field *hid_find_field(struct hid_device *hdev, unsigned int report_type,
-+ unsigned int application, unsigned int usage)
++static void usb_shutdown_interface(struct device *dev)
+{
-+ struct list_head *report_list = &hdev->report_enum[report_type].report_list;
-+ struct hid_report *report;
-+ int i, j;
-+
-+ list_for_each_entry(report, report_list, list) {
-+ if (report->application != application)
-+ continue;
-+
-+ for (i = 0; i < report->maxfield; i++) {
-+ struct hid_field *field = report->field[i];
++ struct usb_interface *intf = to_usb_interface(dev);
++ struct usb_driver *driver;
+
-+ for (j = 0; j < field->maxusage; j++) {
-+ if (field->usage[j].hid == usage)
-+ return field;
-+ }
-+ }
-+ }
++ if (!dev->driver)
++ return;
+
-+ return NULL;
++ driver = to_usb_driver(dev->driver);
++ if (driver->shutdown)
++ driver->shutdown(intf);
+}
-+EXPORT_SYMBOL_GPL(hid_find_field);
+
- static struct hid_report *hid_get_report(struct hid_report_enum *report_enum,
- const u8 *data)
+ /**
+ * usb_driver_claim_interface - bind a driver to an interface
+ * @driver: the driver to be bound
+@@ -1059,6 +1072,7 @@ int usb_register_driver(struct usb_driver *new_driver, struct module *owner,
+ new_driver->driver.bus = &usb_bus_type;
+ new_driver->driver.probe = usb_probe_interface;
+ new_driver->driver.remove = usb_unbind_interface;
++ new_driver->driver.shutdown = usb_shutdown_interface;
+ new_driver->driver.owner = owner;
+ new_driver->driver.mod_name = mod_name;
+ new_driver->driver.dev_groups = new_driver->dev_groups;
+diff --git a/drivers/usb/storage/uas.c b/drivers/usb/storage/uas.c
+index b610a2de4ae5..0cdbcf82554f 100644
+--- a/drivers/usb/storage/uas.c
++++ b/drivers/usb/storage/uas.c
+@@ -1232,9 +1232,8 @@ static void uas_disconnect(struct usb_interface *intf)
+ * hang on reboot when the device is still in uas mode. Note the reset is
+ * necessary as some devices won't revert to usb-storage mode without it.
+ */
+-static void uas_shutdown(struct device *dev)
++static void uas_shutdown(struct usb_interface *intf)
{
-diff --git a/drivers/hid/hid-google-hammer.c b/drivers/hid/hid-google-hammer.c
-index c6bdb9c4e..fba3652aa 100644
---- a/drivers/hid/hid-google-hammer.c
-+++ b/drivers/hid/hid-google-hammer.c
-@@ -419,38 +419,15 @@ static int hammer_event(struct hid_device *hid, struct hid_field *field,
- return 0;
- }
+- struct usb_interface *intf = to_usb_interface(dev);
+ struct usb_device *udev = interface_to_usbdev(intf);
+ struct Scsi_Host *shost = usb_get_intfdata(intf);
+ struct uas_dev_info *devinfo = (struct uas_dev_info *)shost->hostdata;
+@@ -1257,7 +1256,7 @@ static struct usb_driver uas_driver = {
+ .suspend = uas_suspend,
+ .resume = uas_resume,
+ .reset_resume = uas_reset_resume,
+- .driver.shutdown = uas_shutdown,
++ .shutdown = uas_shutdown,
+ .id_table = uas_usb_ids,
+ };
--static bool hammer_has_usage(struct hid_device *hdev, unsigned int report_type,
-- unsigned application, unsigned usage)
--{
-- struct hid_report_enum *re = &hdev->report_enum[report_type];
-- struct hid_report *report;
-- int i, j;
--
-- list_for_each_entry(report, &re->report_list, list) {
-- if (report->application != application)
-- continue;
--
-- for (i = 0; i < report->maxfield; i++) {
-- struct hid_field *field = report->field[i];
--
-- for (j = 0; j < field->maxusage; j++)
-- if (field->usage[j].hid == usage)
-- return true;
-- }
-- }
--
-- return false;
--}
--
- static bool hammer_has_folded_event(struct hid_device *hdev)
- {
-- return hammer_has_usage(hdev, HID_INPUT_REPORT,
-+ return !!hid_find_field(hdev, HID_INPUT_REPORT,
- HID_GD_KEYBOARD, HID_USAGE_KBD_FOLDED);
- }
+diff --git a/include/drm/drm_format_helper.h b/include/drm/drm_format_helper.h
+index 428d81afe215..aa1604d92c1a 100644
+--- a/include/drm/drm_format_helper.h
++++ b/include/drm/drm_format_helper.h
+@@ -96,6 +96,9 @@ void drm_fb_xrgb8888_to_rgba5551(struct iosys_map *dst, const unsigned int *dst_
+ void drm_fb_xrgb8888_to_rgb888(struct iosys_map *dst, const unsigned int *dst_pitch,
+ const struct iosys_map *src, const struct drm_framebuffer *fb,
+ const struct drm_rect *clip, struct drm_format_conv_state *state);
++void drm_fb_xrgb8888_to_bgr888(struct iosys_map *dst, const unsigned int *dst_pitch,
++ const struct iosys_map *src, const struct drm_framebuffer *fb,
++ const struct drm_rect *clip, struct drm_format_conv_state *state);
+ void drm_fb_xrgb8888_to_argb8888(struct iosys_map *dst, const unsigned int *dst_pitch,
+ const struct iosys_map *src, const struct drm_framebuffer *fb,
+ const struct drm_rect *clip, struct drm_format_conv_state *state);
+diff --git a/include/linux/efi.h b/include/linux/efi.h
+index 418e555459da..3a6c04a9f9aa 100644
+--- a/include/linux/efi.h
++++ b/include/linux/efi.h
+@@ -74,10 +74,10 @@ typedef void *efi_handle_t;
+ */
+ typedef guid_t efi_guid_t __aligned(__alignof__(u32));
- static bool hammer_has_backlight_control(struct hid_device *hdev)
- {
-- return hammer_has_usage(hdev, HID_OUTPUT_REPORT,
-+ return !!hid_find_field(hdev, HID_OUTPUT_REPORT,
- HID_GD_KEYBOARD, HID_AD_BRIGHTNESS);
- }
+-#define EFI_GUID(a, b, c, d...) (efi_guid_t){ { \
++#define EFI_GUID(a, b, c, d...) ((efi_guid_t){ { \
+ (a) & 0xff, ((a) >> 8) & 0xff, ((a) >> 16) & 0xff, ((a) >> 24) & 0xff, \
+ (b) & 0xff, ((b) >> 8) & 0xff, \
+- (c) & 0xff, ((c) >> 8) & 0xff, d } }
++ (c) & 0xff, ((c) >> 8) & 0xff, d } })
+ /*
+ * Generic EFI table header
+@@ -385,6 +385,7 @@ void efi_native_runtime_setup(void);
+ #define EFI_MEMORY_ATTRIBUTES_TABLE_GUID EFI_GUID(0xdcfa911d, 0x26eb, 0x469f, 0xa2, 0x20, 0x38, 0xb7, 0xdc, 0x46, 0x12, 0x20)
+ #define EFI_CONSOLE_OUT_DEVICE_GUID EFI_GUID(0xd3b36f2c, 0xd551, 0x11d4, 0x9a, 0x46, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d)
+ #define APPLE_PROPERTIES_PROTOCOL_GUID EFI_GUID(0x91bd12fe, 0xf6c3, 0x44fb, 0xa5, 0xb7, 0x51, 0x22, 0xab, 0x30, 0x3a, 0xe0)
++#define APPLE_SET_OS_PROTOCOL_GUID EFI_GUID(0xc5c5da95, 0x7d5c, 0x45e6, 0xb2, 0xf1, 0x3f, 0xd5, 0x2b, 0xb1, 0x00, 0x77)
+ #define EFI_TCG2_PROTOCOL_GUID EFI_GUID(0x607f766c, 0x7455, 0x42be, 0x93, 0x0b, 0xe4, 0xd7, 0x6d, 0xb2, 0x72, 0x0f)
+ #define EFI_TCG2_FINAL_EVENTS_TABLE_GUID EFI_GUID(0x1e2ed096, 0x30e2, 0x4254, 0xbd, 0x89, 0x86, 0x3b, 0xbe, 0xf8, 0x23, 0x25)
+ #define EFI_LOAD_FILE_PROTOCOL_GUID EFI_GUID(0x56ec3091, 0x954c, 0x11d2, 0x8e, 0x3f, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b)
diff --git a/include/linux/hid.h b/include/linux/hid.h
-index 39e21e381..9520fdfdd 100644
+index 8e06d89698e6..6cdb5a451453 100644
--- a/include/linux/hid.h
+++ b/include/linux/hid.h
-@@ -913,6 +913,8 @@ extern void hidinput_report_event(struct hid_device *hid, struct hid_report *rep
+@@ -940,6 +940,8 @@ extern void hidinput_report_event(struct hid_device *hid, struct hid_report *rep
extern int hidinput_connect(struct hid_device *hid, unsigned int force);
extern void hidinput_disconnect(struct hid_device *);
@@ -6056,1065 +10562,32 @@ index 39e21e381..9520fdfdd 100644
int hid_set_field(struct hid_field *, unsigned, __s32);
int hid_input_report(struct hid_device *hid, enum hid_report_type type, u8 *data, u32 size,
int interrupt);
---
-2.42.0
-
-From 05cd738ce1c0e1a930a1dab02528fd9f1c702c38 Mon Sep 17 00:00:00 2001
-From: Kerem Karabay <kekrby@gmail.com>
-Date: Sun, 5 Mar 2023 18:52:43 +0300
-Subject: [PATCH 02/12] HID: hid-appletb-bl: add driver for the backlight of
- Apple Touch Bars
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-This commit adds a driver for the backlight of Apple Touch Bars on x86
-Macs. Note that currently only T2 Macs are supported.
-
-This driver is based on previous work done by Ronald Tschalär
-<ronald@innovation.ch>.
-
-Signed-off-by: Kerem Karabay <kekrby@gmail.com>
----
- drivers/hid/Kconfig | 10 ++
- drivers/hid/Makefile | 1 +
- drivers/hid/hid-appletb-bl.c | 193 +++++++++++++++++++++++++++++++++++
- drivers/hid/hid-quirks.c | 4 +-
- 5 files changed, 213 insertions(+), 1 deletion(-)
- create mode 100644 drivers/hid/hid-appletb-bl.c
-
-diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
-index e11c1c803..cf19a3b33 100644
---- a/drivers/hid/Kconfig
-+++ b/drivers/hid/Kconfig
-@@ -148,6 +148,16 @@ config HID_APPLEIR
-
- Say Y here if you want support for Apple infrared remote control.
-
-+config HID_APPLETB_BL
-+ tristate "Apple Touch Bar Backlight"
-+ depends on BACKLIGHT_CLASS_DEVICE
-+ help
-+ Say Y here if you want support for the backlight of Touch Bars on x86
-+ MacBook Pros.
-+
-+ To compile this driver as a module, choose M here: the
-+ module will be called hid-appletb-bl.
-+
- config HID_ASUS
- tristate "Asus"
- depends on USB_HID
-diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile
-index 7a9e16015..bc86e38b2 100644
---- a/drivers/hid/Makefile
-+++ b/drivers/hid/Makefile
-@@ -29,6 +29,7 @@ obj-$(CONFIG_HID_ALPS) += hid-alps.o
- obj-$(CONFIG_HID_ACRUX) += hid-axff.o
- obj-$(CONFIG_HID_APPLE) += hid-apple.o
- obj-$(CONFIG_HID_APPLEIR) += hid-appleir.o
-+obj-$(CONFIG_HID_APPLETB_BL) += hid-appletb-bl.o
- obj-$(CONFIG_HID_CREATIVE_SB0540) += hid-creative-sb0540.o
- obj-$(CONFIG_HID_ASUS) += hid-asus.o
- obj-$(CONFIG_HID_AUREAL) += hid-aureal.o
-diff --git a/drivers/hid/hid-appletb-bl.c b/drivers/hid/hid-appletb-bl.c
-new file mode 100644
-index 000000000..0c5e4b776
---- /dev/null
-+++ b/drivers/hid/hid-appletb-bl.c
-@@ -0,0 +1,193 @@
-+// SPDX-License-Identifier: GPL-2.0
-+/*
-+ * Apple Touch Bar Backlight Driver
-+ *
-+ * Copyright (c) 2017-2018 Ronald Tschalär
-+ * Copyright (c) 2022-2023 Kerem Karabay <kekrby@gmail.com>
-+ */
-+
-+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-+
-+#include <linux/hid.h>
-+#include <linux/backlight.h>
-+
-+#include "hid-ids.h"
-+
-+#define APPLETB_BL_ON 1
-+#define APPLETB_BL_DIM 3
-+#define APPLETB_BL_OFF 4
-+
-+#define HID_UP_APPLEVENDOR_TB_BL 0xff120000
-+
-+#define HID_VD_APPLE_TB_BRIGHTNESS 0xff120001
-+#define HID_USAGE_AUX1 0xff120020
-+#define HID_USAGE_BRIGHTNESS 0xff120021
-+
-+struct appletb_bl {
-+ struct hid_field *aux1_field, *brightness_field;
-+ struct backlight_device *bdev;
-+
-+ bool full_on;
-+};
-+
-+const u8 appletb_bl_brightness_map[] = {
-+ APPLETB_BL_OFF,
-+ APPLETB_BL_DIM,
-+ APPLETB_BL_ON
-+};
-+
-+static int appletb_bl_set_brightness(struct appletb_bl *bl, u8 brightness)
-+{
-+ struct hid_report *report = bl->brightness_field->report;
-+ struct hid_device *hdev = report->device;
-+ int ret;
-+
-+ ret = hid_set_field(bl->aux1_field, 0, 1);
-+ if (ret) {
-+ hid_err(hdev, "Failed to set auxiliary field (%pe)\n", ERR_PTR(ret));
-+ return ret;
-+ }
-+
-+ ret = hid_set_field(bl->brightness_field, 0, brightness);
-+ if (ret) {
-+ hid_err(hdev, "Failed to set brightness field (%pe)\n", ERR_PTR(ret));
-+ return ret;
-+ }
-+
-+ if (!bl->full_on) {
-+ ret = hid_hw_power(hdev, PM_HINT_FULLON);
-+ if (ret < 0) {
-+ hid_err(hdev, "Device didn't power on (%pe)\n", ERR_PTR(ret));
-+ return ret;
-+ }
-+
-+ bl->full_on = true;
-+ }
-+
-+ hid_hw_request(hdev, report, HID_REQ_SET_REPORT);
-+
-+ if (brightness == APPLETB_BL_OFF) {
-+ hid_hw_power(hdev, PM_HINT_NORMAL);
-+ bl->full_on = false;
-+ }
-+
-+ return 0;
-+}
-+
-+static int appletb_bl_update_status(struct backlight_device *bdev)
-+{
-+ struct appletb_bl *bl = bl_get_data(bdev);
-+ u16 brightness;
-+
-+ if (bdev->props.state & BL_CORE_SUSPENDED)
-+ brightness = 0;
-+ else
-+ brightness = backlight_get_brightness(bdev);
-+
-+ return appletb_bl_set_brightness(bl, appletb_bl_brightness_map[brightness]);
-+}
-+
-+static const struct backlight_ops appletb_bl_backlight_ops = {
-+ .options = BL_CORE_SUSPENDRESUME,
-+ .update_status = appletb_bl_update_status,
-+};
-+
-+static int appletb_bl_probe(struct hid_device *hdev, const struct hid_device_id *id)
-+{
-+ struct hid_field *aux1_field, *brightness_field;
-+ struct backlight_properties bl_props = { 0 };
-+ struct device *dev = &hdev->dev;
-+ struct appletb_bl *bl;
-+ int ret;
-+
-+ ret = hid_parse(hdev);
-+ if (ret)
-+ return dev_err_probe(dev, ret, "HID parse failed\n");
-+
-+ aux1_field = hid_find_field(hdev, HID_FEATURE_REPORT,
-+ HID_VD_APPLE_TB_BRIGHTNESS, HID_USAGE_AUX1);
-+
-+ brightness_field = hid_find_field(hdev, HID_FEATURE_REPORT,
-+ HID_VD_APPLE_TB_BRIGHTNESS, HID_USAGE_BRIGHTNESS);
-+
-+ if (!aux1_field || !brightness_field)
-+ return -ENODEV;
-+
-+ if (aux1_field->report != brightness_field->report)
-+ return dev_err_probe(dev, -ENODEV, "Encountered unexpected report structure\n");
-+
-+ bl = devm_kzalloc(dev, sizeof(*bl), GFP_KERNEL);
-+ if (!bl)
-+ return -ENOMEM;
-+
-+ ret = hid_hw_start(hdev, HID_CONNECT_DRIVER);
-+ if (ret)
-+ return dev_err_probe(dev, ret, "HID hardware start failed\n");
-+
-+ ret = hid_hw_open(hdev);
-+ if (ret) {
-+ dev_err_probe(dev, ret, "HID hardware open failed\n");
-+ goto stop_hw;
-+ }
-+
-+ bl->aux1_field = aux1_field;
-+ bl->brightness_field = brightness_field;
-+
-+ ret = appletb_bl_set_brightness(bl, APPLETB_BL_OFF);
-+ if (ret) {
-+ dev_err_probe(dev, ret, "Failed to set touch bar brightness to off\n");
-+ goto close_hw;
-+ }
-+
-+ bl_props.type = BACKLIGHT_RAW;
-+ bl_props.max_brightness = ARRAY_SIZE(appletb_bl_brightness_map) - 1;
-+
-+ bl->bdev = devm_backlight_device_register(dev, "appletb_backlight", dev, bl,
-+ &appletb_bl_backlight_ops, &bl_props);
-+ if (IS_ERR(bl->bdev)) {
-+ ret = PTR_ERR(bl->bdev);
-+ dev_err_probe(dev, ret, "Failed to register backlight device\n");
-+ goto close_hw;
-+ }
-+
-+ hid_set_drvdata(hdev, bl);
-+
-+ return 0;
-+
-+close_hw:
-+ hid_hw_close(hdev);
-+stop_hw:
-+ hid_hw_stop(hdev);
-+
-+ return ret;
-+}
-+
-+static void appletb_bl_remove(struct hid_device *hdev)
-+{
-+ struct appletb_bl *bl = hid_get_drvdata(hdev);
-+
-+ appletb_bl_set_brightness(bl, APPLETB_BL_OFF);
-+
-+ hid_hw_close(hdev);
-+ hid_hw_stop(hdev);
-+}
-+
-+static const struct hid_device_id appletb_bl_hid_ids[] = {
-+ /* MacBook Pro's 2018, 2019, with T2 chip: iBridge DFR Brightness */
-+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_TOUCHBAR_BACKLIGHT) },
-+ { }
-+};
-+MODULE_DEVICE_TABLE(hid, appletb_bl_hid_ids);
-+
-+static struct hid_driver appletb_bl_hid_driver = {
-+ .name = "hid-appletb-bl",
-+ .id_table = appletb_bl_hid_ids,
-+ .probe = appletb_bl_probe,
-+ .remove = appletb_bl_remove,
-+};
-+module_hid_driver(appletb_bl_hid_driver);
-+
-+MODULE_AUTHOR("Ronald Tschalär");
-+MODULE_AUTHOR("Kerem Karabay <kekrby@gmail.com>");
-+MODULE_DESCRIPTION("MacBookPro Touch Bar Backlight Driver");
-+MODULE_LICENSE("GPL");
-diff --git a/drivers/hid/hid-quirks.c b/drivers/hid/hid-quirks.c
-index 3983b4f28..82e7a80c9 100644
---- a/drivers/hid/hid-quirks.c
-+++ b/drivers/hid/hid-quirks.c
-@@ -325,7 +325,6 @@ static const struct hid_device_id hid_have_special_driver[] = {
- { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY) },
- { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_2021) },
- { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_FINGERPRINT_2021) },
-- { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_TOUCHBAR_BACKLIGHT) },
- { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_TOUCHBAR_DISPLAY) },
- #endif
- #if IS_ENABLED(CONFIG_HID_APPLEIR)
-@@ -335,6 +334,9 @@ static const struct hid_device_id hid_have_special_driver[] = {
- { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL4) },
- { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL5) },
- #endif
-+#if IS_ENABLED(CONFIG_HID_APPLETB_BL)
-+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_TOUCHBAR_BACKLIGHT) },
-+#endif
- #if IS_ENABLED(CONFIG_HID_ASUS)
- { HID_I2C_DEVICE(USB_VENDOR_ID_ASUSTEK, USB_DEVICE_ID_ASUSTEK_I2C_KEYBOARD) },
- { HID_I2C_DEVICE(USB_VENDOR_ID_ASUSTEK, USB_DEVICE_ID_ASUSTEK_I2C_TOUCHPAD) },
---
-2.42.0
-
-From 514b4f088b7ed916c634ca6f61de72c5f86268dd Mon Sep 17 00:00:00 2001
-From: Kerem Karabay <kekrby@gmail.com>
-Date: Sun, 5 Mar 2023 18:17:23 +0300
-Subject: [PATCH 03/12] HID: hid-appletb-kbd: add driver for the keyboard mode
- of Apple Touch Bars
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-The Touch Bars found on x86 Macs support two USB configurations: one
-where the device presents itself as a HID keyboard and can display
-predefined sets of keys, and one where the operating system has full
-control over what is displayed. This commit adds a driver for the
-display functionality of the first configuration.
-
-Note that currently only T2 Macs are supported.
-
-This driver is based on previous work done by Ronald Tschalär
-<ronald@innovation.ch>.
-
-Signed-off-by: Kerem Karabay <kekrby@gmail.com>
----
- .../ABI/testing/sysfs-driver-hid-appletb-kbd | 13 +
- drivers/hid/Kconfig | 11 +
- drivers/hid/Makefile | 1 +
- drivers/hid/hid-appletb-kbd.c | 289 ++++++++++++++++++
- drivers/hid/hid-quirks.c | 4 +-
- 5 files changed, 317 insertions(+), 1 deletion(-)
- create mode 100644 Documentation/ABI/testing/sysfs-driver-hid-appletb-kbd
- create mode 100644 drivers/hid/hid-appletb-kbd.c
-
-diff --git a/Documentation/ABI/testing/sysfs-driver-hid-appletb-kbd b/Documentation/ABI/testing/sysfs-driver-hid-appletb-kbd
-new file mode 100644
-index 000000000..2a19584d0
---- /dev/null
-+++ b/Documentation/ABI/testing/sysfs-driver-hid-appletb-kbd
-@@ -0,0 +1,13 @@
-+What: /sys/bus/hid/drivers/hid-appletb-kbd/<dev>/mode
-+Date: September, 2023
-+KernelVersion: 6.5
-+Contact: linux-input@vger.kernel.org
-+Description:
-+ The set of keys displayed on the Touch Bar.
-+ Valid values are:
-+ == =================
-+ 0 Escape key only
-+ 1 Function keys
-+ 2 Media/brightness keys
-+ 3 None
-+ == =================
-diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
-index cf19a3b33..852de13aa 100644
---- a/drivers/hid/Kconfig
-+++ b/drivers/hid/Kconfig
-@@ -158,6 +158,17 @@ config HID_APPLETB_BL
- To compile this driver as a module, choose M here: the
- module will be called hid-appletb-bl.
-
-+config HID_APPLETB_KBD
-+ tristate "Apple Touch Bar Keyboard Mode"
-+ depends on USB_HID
-+ help
-+ Say Y here if you want support for the keyboard mode (escape,
-+ function, media and brightness keys) of Touch Bars on x86 MacBook
-+ Pros.
-+
-+ To compile this driver as a module, choose M here: the
-+ module will be called hid-appletb-kbd.
-+
- config HID_ASUS
- tristate "Asus"
- depends on USB_HID
-diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile
-index bc86e38b2..5b60015fd 100644
---- a/drivers/hid/Makefile
-+++ b/drivers/hid/Makefile
-@@ -30,6 +30,7 @@ obj-$(CONFIG_HID_ACRUX) += hid-axff.o
- obj-$(CONFIG_HID_APPLE) += hid-apple.o
- obj-$(CONFIG_HID_APPLEIR) += hid-appleir.o
- obj-$(CONFIG_HID_APPLETB_BL) += hid-appletb-bl.o
-+obj-$(CONFIG_HID_APPLETB_KBD) += hid-appletb-kbd.o
- obj-$(CONFIG_HID_CREATIVE_SB0540) += hid-creative-sb0540.o
- obj-$(CONFIG_HID_ASUS) += hid-asus.o
- obj-$(CONFIG_HID_AUREAL) += hid-aureal.o
-diff --git a/drivers/hid/hid-appletb-kbd.c b/drivers/hid/hid-appletb-kbd.c
-new file mode 100644
-index 000000000..bc004c408
---- /dev/null
-+++ b/drivers/hid/hid-appletb-kbd.c
-@@ -0,0 +1,289 @@
-+// SPDX-License-Identifier: GPL-2.0
-+/*
-+ * Apple Touch Bar Keyboard Mode Driver
-+ *
-+ * Copyright (c) 2017-2018 Ronald Tschalär
-+ * Copyright (c) 2022-2023 Kerem Karabay <kekrby@gmail.com>
-+ */
-+
-+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-+
-+#include <linux/hid.h>
-+#include <linux/usb.h>
-+#include <linux/input.h>
-+#include <linux/sysfs.h>
-+#include <linux/bitops.h>
-+#include <linux/module.h>
-+#include <linux/string.h>
-+#include <linux/input/sparse-keymap.h>
-+
-+#include "hid-ids.h"
-+
-+#define APPLETB_KBD_MODE_ESC 0
-+#define APPLETB_KBD_MODE_FN 1
-+#define APPLETB_KBD_MODE_SPCL 2
-+#define APPLETB_KBD_MODE_OFF 3
-+#define APPLETB_KBD_MODE_MAX APPLETB_KBD_MODE_OFF
-+
-+#define HID_USAGE_MODE 0x00ff0004
-+
-+struct appletb_kbd {
-+ struct hid_field *mode_field;
-+
-+ u8 saved_mode;
-+ u8 current_mode;
-+};
-+
-+static const struct key_entry appletb_kbd_keymap[] = {
-+ { KE_KEY, KEY_ESC, { KEY_ESC } },
-+ { KE_KEY, KEY_F1, { KEY_BRIGHTNESSDOWN } },
-+ { KE_KEY, KEY_F2, { KEY_BRIGHTNESSUP } },
-+ { KE_KEY, KEY_F3, { KEY_RESERVED } },
-+ { KE_KEY, KEY_F4, { KEY_RESERVED } },
-+ { KE_KEY, KEY_F5, { KEY_KBDILLUMDOWN } },
-+ { KE_KEY, KEY_F6, { KEY_KBDILLUMUP } },
-+ { KE_KEY, KEY_F7, { KEY_PREVIOUSSONG } },
-+ { KE_KEY, KEY_F8, { KEY_PLAYPAUSE } },
-+ { KE_KEY, KEY_F9, { KEY_NEXTSONG } },
-+ { KE_KEY, KEY_F10, { KEY_MUTE } },
-+ { KE_KEY, KEY_F11, { KEY_VOLUMEDOWN } },
-+ { KE_KEY, KEY_F12, { KEY_VOLUMEUP } },
-+ { KE_END, 0 }
-+};
-+
-+static int appletb_kbd_set_mode(struct appletb_kbd *kbd, u8 mode)
-+{
-+ struct hid_report *report = kbd->mode_field->report;
-+ struct hid_device *hdev = report->device;
-+ int ret;
-+
-+ ret = hid_hw_power(hdev, PM_HINT_FULLON);
-+ if (ret) {
-+ hid_err(hdev, "Device didn't resume (%pe)\n", ERR_PTR(ret));
-+ return ret;
-+ }
-+
-+ ret = hid_set_field(kbd->mode_field, 0, mode);
-+ if (ret) {
-+ hid_err(hdev, "Failed to set mode field to %u (%pe)\n", mode, ERR_PTR(ret));
-+ goto power_normal;
-+ }
-+
-+ hid_hw_request(hdev, report, HID_REQ_SET_REPORT);
-+
-+ kbd->current_mode = mode;
-+
-+power_normal:
-+ hid_hw_power(hdev, PM_HINT_NORMAL);
-+
-+ return ret;
-+}
-+
-+static ssize_t mode_show(struct device *dev,
-+ struct device_attribute *attr, char *buf)
-+{
-+ struct appletb_kbd *kbd = dev_get_drvdata(dev);
-+
-+ return sysfs_emit(buf, "%d\n", kbd->current_mode);
-+}
-+
-+static ssize_t mode_store(struct device *dev,
-+ struct device_attribute *attr,
-+ const char *buf, size_t size)
-+{
-+ struct appletb_kbd *kbd = dev_get_drvdata(dev);
-+ u8 mode;
-+ int ret;
-+
-+ ret = kstrtou8(buf, 0, &mode);
-+ if (ret)
-+ return ret;
-+
-+ if (mode > APPLETB_KBD_MODE_MAX)
-+ return -EINVAL;
-+
-+ ret = appletb_kbd_set_mode(kbd, mode);
-+
-+ return ret < 0 ? ret : size;
-+}
-+static DEVICE_ATTR_RW(mode);
-+
-+struct attribute *appletb_kbd_attrs[] = {
-+ &dev_attr_mode.attr,
-+ NULL
-+};
-+ATTRIBUTE_GROUPS(appletb_kbd);
-+
-+static int appletb_tb_key_to_slot(unsigned int code)
-+{
-+ switch (code) {
-+ case KEY_ESC:
-+ return 0;
-+ case KEY_F1 ... KEY_F10:
-+ return code - KEY_F1 + 1;
-+ case KEY_F11 ... KEY_F12:
-+ return code - KEY_F11 + 11;
-+
-+ default:
-+ return -EINVAL;
-+ }
-+}
-+
-+static int appletb_kbd_hid_event(struct hid_device *hdev, struct hid_field *field,
-+ struct hid_usage *usage, __s32 value)
-+{
-+ struct appletb_kbd *kbd = hid_get_drvdata(hdev);
-+ struct key_entry *translation;
-+ struct input_dev *input;
-+ int slot;
-+
-+ if ((usage->hid & HID_USAGE_PAGE) != HID_UP_KEYBOARD || usage->type != EV_KEY)
-+ return 0;
-+
-+ input = field->hidinput->input;
-+
-+ /*
-+ * Skip non-touch-bar keys.
-+ *
-+ * Either the touch bar itself or usbhid generate a slew of key-down
-+ * events for all the meta keys. None of which we're at all interested
-+ * in.
-+ */
-+ slot = appletb_tb_key_to_slot(usage->code);
-+ if (slot < 0)
-+ return 0;
-+
-+ translation = sparse_keymap_entry_from_scancode(input, usage->code);
-+
-+ if (translation && kbd->current_mode == APPLETB_KBD_MODE_SPCL) {
-+ input_event(input, usage->type, translation->keycode, value);
-+
-+ return 1;
-+ }
-+
-+ return kbd->current_mode == APPLETB_KBD_MODE_OFF;
-+}
-+
-+static int appletb_kbd_input_configured(struct hid_device *hdev, struct hid_input *hidinput)
-+{
-+ struct input_dev *input = hidinput->input;
-+
-+ /*
-+ * Clear various input capabilities that are blindly set by the hid
-+ * driver (usbkbd.c)
-+ */
-+ memset(input->evbit, 0, sizeof(input->evbit));
-+ memset(input->keybit, 0, sizeof(input->keybit));
-+ memset(input->ledbit, 0, sizeof(input->ledbit));
-+
-+ __set_bit(EV_REP, input->evbit);
-+
-+ return sparse_keymap_setup(input, appletb_kbd_keymap, NULL);
-+}
-+
-+static int appletb_kbd_probe(struct hid_device *hdev, const struct hid_device_id *id)
-+{
-+ struct appletb_kbd *kbd;
-+ struct device *dev = &hdev->dev;
-+ struct hid_field *mode_field;
-+ int ret;
-+
-+ ret = hid_parse(hdev);
-+ if (ret)
-+ return dev_err_probe(dev, ret, "HID parse failed\n");
-+
-+ mode_field = hid_find_field(hdev, HID_OUTPUT_REPORT,
-+ HID_GD_KEYBOARD, HID_USAGE_MODE);
-+ if (!mode_field)
-+ return -ENODEV;
-+
-+ kbd = devm_kzalloc(dev, sizeof(*kbd), GFP_KERNEL);
-+ if (!kbd)
-+ return -ENOMEM;
-+
-+ kbd->mode_field = mode_field;
-+
-+ ret = hid_hw_start(hdev, HID_CONNECT_HIDINPUT);
-+ if (ret)
-+ return dev_err_probe(dev, ret, "HID hw start failed\n");
-+
-+ ret = hid_hw_open(hdev);
-+ if (ret) {
-+ dev_err_probe(dev, ret, "HID hw open failed\n");
-+ goto stop_hw;
-+ }
-+
-+ ret = appletb_kbd_set_mode(kbd, APPLETB_KBD_MODE_OFF);
-+ if (ret) {
-+ dev_err_probe(dev, ret, "Failed to set touchbar mode\n");
-+ goto close_hw;
-+ }
-+
-+ hid_set_drvdata(hdev, kbd);
-+
-+ return 0;
-+
-+close_hw:
-+ hid_hw_close(hdev);
-+stop_hw:
-+ hid_hw_stop(hdev);
-+ return ret;
-+}
-+
-+static void appletb_kbd_remove(struct hid_device *hdev)
-+{
-+ struct appletb_kbd *kbd = hid_get_drvdata(hdev);
-+
-+ appletb_kbd_set_mode(kbd, APPLETB_KBD_MODE_OFF);
-+
-+ hid_hw_close(hdev);
-+ hid_hw_stop(hdev);
-+}
-+
-+#ifdef CONFIG_PM
-+static int appletb_kbd_suspend(struct hid_device *hdev, pm_message_t msg)
-+{
-+ struct appletb_kbd *kbd = hid_get_drvdata(hdev);
-+
-+ kbd->saved_mode = kbd->current_mode;
-+ appletb_kbd_set_mode(kbd, APPLETB_KBD_MODE_OFF);
-+
-+ return 0;
-+}
-+
-+static int appletb_kbd_reset_resume(struct hid_device *hdev)
-+{
-+ struct appletb_kbd *kbd = hid_get_drvdata(hdev);
-+
-+ appletb_kbd_set_mode(kbd, kbd->saved_mode);
-+
-+ return 0;
-+}
-+#endif
-+
-+static const struct hid_device_id appletb_kbd_hid_ids[] = {
-+ /* MacBook Pro's 2018, 2019, with T2 chip: iBridge Display */
-+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_TOUCHBAR_DISPLAY) },
-+ { }
-+};
-+MODULE_DEVICE_TABLE(hid, appletb_kbd_hid_ids);
-+
-+static struct hid_driver appletb_kbd_hid_driver = {
-+ .name = "hid-appletb-kbd",
-+ .id_table = appletb_kbd_hid_ids,
-+ .probe = appletb_kbd_probe,
-+ .remove = appletb_kbd_remove,
-+ .event = appletb_kbd_hid_event,
-+ .input_configured = appletb_kbd_input_configured,
-+#ifdef CONFIG_PM
-+ .suspend = appletb_kbd_suspend,
-+ .reset_resume = appletb_kbd_reset_resume,
-+#endif
-+ .driver.dev_groups = appletb_kbd_groups,
-+};
-+module_hid_driver(appletb_kbd_hid_driver);
-+
-+MODULE_AUTHOR("Ronald Tschalär");
-+MODULE_AUTHOR("Kerem Karabay <kekrby@gmail.com>");
-+MODULE_DESCRIPTION("MacBookPro Touch Bar Keyboard Mode Driver");
-+MODULE_LICENSE("GPL");
-diff --git a/drivers/hid/hid-quirks.c b/drivers/hid/hid-quirks.c
-index 82e7a80c9..82be9dfaf 100644
---- a/drivers/hid/hid-quirks.c
-+++ b/drivers/hid/hid-quirks.c
-@@ -325,7 +325,6 @@ static const struct hid_device_id hid_have_special_driver[] = {
- { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY) },
- { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_2021) },
- { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_FINGERPRINT_2021) },
-- { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_TOUCHBAR_DISPLAY) },
- #endif
- #if IS_ENABLED(CONFIG_HID_APPLEIR)
- { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL) },
-@@ -337,6 +336,9 @@ static const struct hid_device_id hid_have_special_driver[] = {
- #if IS_ENABLED(CONFIG_HID_APPLETB_BL)
- { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_TOUCHBAR_BACKLIGHT) },
- #endif
-+#if IS_ENABLED(CONFIG_HID_APPLETB_KBD)
-+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_TOUCHBAR_DISPLAY) },
-+#endif
- #if IS_ENABLED(CONFIG_HID_ASUS)
- { HID_I2C_DEVICE(USB_VENDOR_ID_ASUSTEK, USB_DEVICE_ID_ASUSTEK_I2C_KEYBOARD) },
- { HID_I2C_DEVICE(USB_VENDOR_ID_ASUSTEK, USB_DEVICE_ID_ASUSTEK_I2C_TOUCHPAD) },
---
-2.42.0
-
-From 2f9be28549307b4ac51e8d66bf3b8d5e0621466d Mon Sep 17 00:00:00 2001
-From: Kerem Karabay <kekrby@gmail.com>
-Date: Wed, 19 Jul 2023 19:37:14 +0300
-Subject: [PATCH 04/12] HID: multitouch: support getting the contact ID from
- HID_DG_TRANSDUCER_INDEX fields
-
-This is needed to support Apple Touch Bars, where the contact ID is
-contained in fields with the HID_DG_TRANSDUCER_INDEX usage.
-
-Signed-off-by: Kerem Karabay <kekrby@gmail.com>
----
- drivers/hid/hid-multitouch.c | 5 ++++-
- 1 file changed, 4 insertions(+), 1 deletion(-)
-
-diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c
-index e31be0cb8..902a59928 100644
---- a/drivers/hid/hid-multitouch.c
-+++ b/drivers/hid/hid-multitouch.c
-@@ -636,7 +636,9 @@ static struct mt_report_data *mt_allocate_report_data(struct mt_device *td,
-
- if (field->logical == HID_DG_FINGER || td->hdev->group != HID_GROUP_MULTITOUCH_WIN_8) {
- for (n = 0; n < field->report_count; n++) {
-- if (field->usage[n].hid == HID_DG_CONTACTID) {
-+ unsigned int hid = field->usage[n].hid;
-+
-+ if (hid == HID_DG_CONTACTID || hid == HID_DG_TRANSDUCER_INDEX) {
- rdata->is_mt_collection = true;
- break;
- }
-@@ -815,6 +817,7 @@ static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi,
- MT_STORE_FIELD(tip_state);
- return 1;
- case HID_DG_CONTACTID:
-+ case HID_DG_TRANSDUCER_INDEX:
- MT_STORE_FIELD(contactid);
- app->touches_by_report++;
- return 1;
---
-2.42.0
-
-From 6162d328fe7b2cf5a3ee8c29bdb229e9528c7a6c Mon Sep 17 00:00:00 2001
-From: Kerem Karabay <kekrby@gmail.com>
-Date: Wed, 19 Jul 2023 19:44:10 +0300
-Subject: [PATCH 05/12] HID: multitouch: support getting the tip state from
- HID_DG_TOUCH fields
-
-This is necessary on Apple Touch Bars, where the tip state is contained
-in fields with the HID_DG_TOUCH usage. This feature is gated by a quirk
-in order to prevent breaking other devices, see commit c2ef8f21ea8f
-("HID: multitouch: add support for trackpads").
-
-Signed-off-by: Kerem Karabay <kekrby@gmail.com>
----
- drivers/hid/hid-multitouch.c | 14 ++++++++++----
- 1 file changed, 10 insertions(+), 4 deletions(-)
-
-diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c
-index 902a59928..dd5509eeb 100644
---- a/drivers/hid/hid-multitouch.c
-+++ b/drivers/hid/hid-multitouch.c
-@@ -72,6 +72,7 @@
- #define MT_QUIRK_FORCE_MULTI_INPUT BIT(20)
- #define MT_QUIRK_DISABLE_WAKEUP BIT(21)
- #define MT_QUIRK_ORIENTATION_INVERT BIT(22)
-+#define MT_QUIRK_TOUCH_IS_TIPSTATE BIT(25)
-
- #define MT_INPUTMODE_TOUCHSCREEN 0x02
- #define MT_INPUTMODE_TOUCHPAD 0x03
-@@ -810,6 +811,15 @@ static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi,
-
- MT_STORE_FIELD(confidence_state);
- return 1;
-+ case HID_DG_TOUCH:
-+ /*
-+ * Legacy devices use TIPSWITCH and not TOUCH.
-+ * Let's just ignore this field unless the quirk is set.
-+ */
-+ if (!(cls->quirks & MT_QUIRK_TOUCH_IS_TIPSTATE))
-+ return -1;
-+
-+ fallthrough;
- case HID_DG_TIPSWITCH:
- if (field->application != HID_GD_SYSTEM_MULTIAXIS)
- input_set_capability(hi->input,
-@@ -873,10 +883,6 @@ static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi,
- case HID_DG_CONTACTMAX:
- /* contact max are global to the report */
- return -1;
-- case HID_DG_TOUCH:
-- /* Legacy devices use TIPSWITCH and not TOUCH.
-- * Let's just ignore this field. */
-- return -1;
- }
- /* let hid-input decide for the others */
- return 0;
---
-2.42.0
-
-From e923c6e1a5a508e341851ae020cdb3e7333ccd18 Mon Sep 17 00:00:00 2001
-From: Kerem Karabay <kekrby@gmail.com>
-Date: Wed, 19 Jul 2023 19:26:57 +0300
-Subject: [PATCH 06/12] HID: multitouch: take cls->maxcontacts into account for
- devices without a HID_DG_CONTACTMAX field too
-
-This is needed for Apple Touch Bars, where no HID_DG_CONTACTMAX field is
-present and the maximum contact count is greater than the default.
-
-Signed-off-by: Kerem Karabay <kekrby@gmail.com>
----
- drivers/hid/hid-multitouch.c | 7 ++++---
- 1 file changed, 4 insertions(+), 3 deletions(-)
-
-diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c
-index dd5509eeb..624c1d3cc 100644
---- a/drivers/hid/hid-multitouch.c
-+++ b/drivers/hid/hid-multitouch.c
-@@ -491,9 +491,6 @@ static void mt_feature_mapping(struct hid_device *hdev,
- if (!td->maxcontacts &&
- field->logical_maximum <= MT_MAX_MAXCONTACT)
- td->maxcontacts = field->logical_maximum;
-- if (td->mtclass.maxcontacts)
-- /* check if the maxcontacts is given by the class */
-- td->maxcontacts = td->mtclass.maxcontacts;
-
- break;
- case HID_DG_BUTTONTYPE:
-@@ -1310,6 +1307,10 @@ static int mt_touch_input_configured(struct hid_device *hdev,
- struct input_dev *input = hi->input;
- int ret;
-
-+ /* check if the maxcontacts is given by the class */
-+ if (cls->maxcontacts)
-+ td->maxcontacts = cls->maxcontacts;
-+
- if (!td->maxcontacts)
- td->maxcontacts = MT_DEFAULT_MAXCONTACT;
-
---
-2.42.0
-
-From b9f7232d2696b91ae98fadd7b14c531aa8edceb5 Mon Sep 17 00:00:00 2001
-From: Kerem Karabay <kekrby@gmail.com>
-Date: Wed, 19 Jul 2023 19:39:53 +0300
-Subject: [PATCH 07/12] HID: multitouch: allow specifying if a device is direct
- in a class
-
-Currently the driver determines the device type based on the
-application, but this value is not reliable on Apple Touch Bars, where
-the application is HID_DG_TOUCHPAD even though the devices are direct,
-so allow setting it in classes.
-
-Signed-off-by: Kerem Karabay <kekrby@gmail.com>
----
- drivers/hid/hid-multitouch.c | 8 ++++++--
- 1 file changed, 6 insertions(+), 2 deletions(-)
-
-diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c
-index 624c1d3cc..f98fb36ff 100644
---- a/drivers/hid/hid-multitouch.c
-+++ b/drivers/hid/hid-multitouch.c
-@@ -147,6 +147,7 @@ struct mt_class {
- __s32 sn_height; /* Signal/noise ratio for height events */
- __s32 sn_pressure; /* Signal/noise ratio for pressure events */
- __u8 maxcontacts;
-+ bool is_direct; /* true for touchscreens */
- bool is_indirect; /* true for touchpads */
- bool export_all_inputs; /* do not ignore mouse, keyboards, etc... */
- };
-@@ -564,13 +565,13 @@ static struct mt_application *mt_allocate_application(struct mt_device *td,
- mt_application->application = application;
- INIT_LIST_HEAD(&mt_application->mt_usages);
-
-- if (application == HID_DG_TOUCHSCREEN)
-+ if (application == HID_DG_TOUCHSCREEN && !td->mtclass.is_indirect)
- mt_application->mt_flags |= INPUT_MT_DIRECT;
-
- /*
- * Model touchscreens providing buttons as touchpads.
- */
-- if (application == HID_DG_TOUCHPAD) {
-+ if (application == HID_DG_TOUCHPAD && !td->mtclass.is_direct) {
- mt_application->mt_flags |= INPUT_MT_POINTER;
- td->inputmode_value = MT_INPUTMODE_TOUCHPAD;
- }
-@@ -1318,6 +1319,9 @@ static int mt_touch_input_configured(struct hid_device *hdev,
- if (td->serial_maybe)
- mt_post_parse_default_settings(td, app);
-
-+ if (cls->is_direct)
-+ app->mt_flags |= INPUT_MT_DIRECT;
-+
- if (cls->is_indirect)
- app->mt_flags |= INPUT_MT_POINTER;
-
---
-2.42.0
-
-From a74de0b6f2e1b79d54e84dbeab1b310232275d6c Mon Sep 17 00:00:00 2001
-From: Kerem Karabay <kekrby@gmail.com>
-Date: Wed, 19 Jul 2023 19:46:02 +0300
-Subject: [PATCH 08/12] HID: multitouch: add device ID for Apple Touch Bars
-
-Note that this is device ID is for T2 Macs. Testing on T1 Macs would be
-appreciated.
-
-Signed-off-by: Kerem Karabay <kekrby@gmail.com>
----
- drivers/hid/Kconfig | 1 +
- drivers/hid/hid-multitouch.c | 26 ++++++++++++++++++++++----
- 2 files changed, 23 insertions(+), 4 deletions(-)
-
-diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
-index 852de13aa..4e238df87 100644
---- a/drivers/hid/Kconfig
-+++ b/drivers/hid/Kconfig
-@@ -737,6 +737,7 @@ config HID_MULTITOUCH
- Say Y here if you have one of the following devices:
- - 3M PCT touch screens
- - ActionStar dual touch panels
-+ - Touch Bars on x86 MacBook Pros
- - Atmel panels
- - Cando dual touch panels
- - Chunghwa panels
-diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c
-index f98fb36ff..f881b19db 100644
---- a/drivers/hid/hid-multitouch.c
-+++ b/drivers/hid/hid-multitouch.c
-@@ -212,6 +212,7 @@
- #define MT_CLS_GOOGLE 0x0111
- #define MT_CLS_RAZER_BLADE_STEALTH 0x0112
- #define MT_CLS_SMART_TECH 0x0113
-+#define MT_CLS_APPLE_TOUCHBAR 0x0115
-
- #define MT_DEFAULT_MAXCONTACT 10
- #define MT_MAX_MAXCONTACT 250
-@@ -396,6 +396,13 @@
- MT_QUIRK_CONTACT_CNT_ACCURATE |
- MT_QUIRK_SEPARATE_APP_REPORT,
- },
-+ { .name = MT_CLS_APPLE_TOUCHBAR,
-+ .quirks = MT_QUIRK_HOVERING |
-+ MT_QUIRK_TOUCH_IS_TIPSTATE |
-+ MT_QUIRK_SLOT_IS_CONTACTID_MINUS_ONE,
-+ .is_direct = true,
-+ .maxcontacts = 11,
-+ },
- { }
- };
-
-@@ -1755,6 +1763,15 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
- }
- }
-
-+ ret = hid_parse(hdev);
-+ if (ret != 0)
-+ return ret;
-+
-+ if (mtclass->name == MT_CLS_APPLE_TOUCHBAR &&
-+ !hid_find_field(hdev, HID_INPUT_REPORT,
-+ HID_DG_TOUCHPAD, HID_DG_TRANSDUCER_INDEX))
-+ return -ENODEV;
-+
- td = devm_kzalloc(&hdev->dev, sizeof(struct mt_device), GFP_KERNEL);
- if (!td) {
- dev_err(&hdev->dev, "cannot allocate multitouch data\n");
-@@ -1780,10 +1780,6 @@
-
- timer_setup(&td->release_timer, mt_expired_timeout, 0);
-
-- ret = hid_parse(hdev);
-- if (ret != 0)
-- return ret;
--
- if (mtclass->quirks & MT_QUIRK_FIX_CONST_CONTACT_ID)
- mt_fix_const_fields(hdev, HID_DG_CONTACTID);
-
-@@ -2229,6 +2229,11 @@
- MT_USB_DEVICE(USB_VENDOR_ID_XIROKU,
- USB_DEVICE_ID_XIROKU_CSR2) },
-
-+ /* Apple Touch Bars */
-+ { .driver_data = MT_CLS_APPLE_TOUCHBAR,
-+ HID_USB_DEVICE(USB_VENDOR_ID_APPLE,
-+ USB_DEVICE_ID_APPLE_TOUCHBAR_DISPLAY) },
-+
- /* Google MT devices */
- { .driver_data = MT_CLS_GOOGLE,
- HID_DEVICE(HID_BUS_ANY, HID_GROUP_ANY, USB_VENDOR_ID_GOOGLE,
---
-2.42.0
-
-From f6ab7e4580962c9d82e7dc40dd074d47b2bce034 Mon Sep 17 00:00:00 2001
-From: Hector Martin <marcan@marcan.st>
-Date: Tue, 1 Feb 2022 00:40:51 +0900
-Subject: [PATCH 09/12] lib/vsprintf: Add support for generic FOURCCs by
- extending %p4cc
-
-%p4cc is designed for DRM/V4L2 FOURCCs with their specific quirks, but
-it's useful to be able to print generic 4-character codes formatted as
-an integer. Extend it to add format specifiers for printing generic
-32-bit FOURCCs with various endian semantics:
-
-%p4ch Host-endian
-%p4cl Little-endian
-%p4cb Big-endian
-%p4cr Reverse-endian
-
-The endianness determines how bytes are interpreted as a u32, and the
-FOURCC is then always printed MSByte-first (this is the opposite of
-V4L/DRM FOURCCs). This covers most practical cases, e.g. %p4cr would
-allow printing LSByte-first FOURCCs stored in host endian order
-(other than the hex form being in character order, not the integer
-value).
-
-Signed-off-by: Hector Martin <marcan@marcan.st>
-Signed-off-by: Kerem Karabay <kekrby@gmail.com>
----
- Documentation/core-api/printk-formats.rst | 32 ++++++++++++++++++++
- lib/test_printf.c | 20 +++++++++----
- lib/vsprintf.c | 36 +++++++++++++++++++----
- scripts/checkpatch.pl | 2 +-
- 4 files changed, 77 insertions(+), 13 deletions(-)
-
-diff --git a/Documentation/core-api/printk-formats.rst b/Documentation/core-api/printk-formats.rst
-index dfe7e75a7..0ccef63e6 100644
---- a/Documentation/core-api/printk-formats.rst
-+++ b/Documentation/core-api/printk-formats.rst
-@@ -631,6 +631,38 @@ Examples::
- %p4cc Y10 little-endian (0x20303159)
- %p4cc NV12 big-endian (0xb231564e)
+diff --git a/include/linux/usb.h b/include/linux/usb.h
+index 1913a13833f2..832997a9da0a 100644
+--- a/include/linux/usb.h
++++ b/include/linux/usb.h
+@@ -1171,6 +1171,7 @@ extern ssize_t usb_show_dynids(struct usb_dynids *dynids, char *buf);
+ * post_reset method is called.
+ * @post_reset: Called by usb_reset_device() after the device
+ * has been reset
++ * @shutdown: Called at shut-down time to quiesce the device.
+ * @id_table: USB drivers use ID table to support hotplugging.
+ * Export this with MODULE_DEVICE_TABLE(usb,...). This must be set
+ * or your driver's probe function will never get called.
+@@ -1222,6 +1223,8 @@ struct usb_driver {
+ int (*pre_reset)(struct usb_interface *intf);
+ int (*post_reset)(struct usb_interface *intf);
-+Generic FourCC code
-+-------------------
-+
-+::
-+ %p4c[hnbl] gP00 (0x67503030)
-+
-+Print a generic FourCC code, as both ASCII characters and its numerical
-+value as hexadecimal.
-+
-+The additional ``h``, ``r``, ``b``, and ``l`` specifiers are used to specify
-+host, reversed, big or little endian order data respectively. Host endian
-+order means the data is interpreted as a 32-bit integer and the most
-+significant byte is printed first; that is, the character code as printed
-+matches the byte order stored in memory on big-endian systems, and is reversed
-+on little-endian systems.
-+
-+Passed by reference.
-+
-+Examples for a little-endian machine, given &(u32)0x67503030::
-+
-+ %p4ch gP00 (0x67503030)
-+ %p4cl gP00 (0x67503030)
-+ %p4cb 00Pg (0x30305067)
-+ %p4cr 00Pg (0x30305067)
-+
-+Examples for a big-endian machine, given &(u32)0x67503030::
-+
-+ %p4ch gP00 (0x67503030)
-+ %p4cl 00Pg (0x30305067)
-+ %p4cb gP00 (0x67503030)
-+ %p4cr 00Pg (0x30305067)
++ void (*shutdown)(struct usb_interface *intf);
+
- Rust
- ----
+ const struct usb_device_id *id_table;
+ const struct attribute_group **dev_groups;
diff --git a/lib/test_printf.c b/lib/test_printf.c
-index 7677ebccf..2355be36f 100644
+index 69b6a5e177f2..a318bb72a165 100644
--- a/lib/test_printf.c
+++ b/lib/test_printf.c
-@@ -746,18 +746,26 @@ static void __init fwnode_pointer(void)
+@@ -745,18 +745,26 @@ static void __init fwnode_pointer(void)
static void __init fourcc_pointer(void)
{
struct {
@@ -7148,10 +10621,10 @@ index 7677ebccf..2355be36f 100644
static void __init
diff --git a/lib/vsprintf.c b/lib/vsprintf.c
-index 40f560959..bd9af783c 100644
+index cdd4e2314bfc..4feaea1815fa 100644
--- a/lib/vsprintf.c
+++ b/lib/vsprintf.c
-@@ -1758,27 +1758,50 @@ char *fourcc_string(char *buf, char *end, const u32 *fourcc,
+@@ -1760,27 +1760,50 @@ char *fourcc_string(char *buf, char *end, const u32 *fourcc,
char output[sizeof("0123 little-endian (0x01234567)")];
char *p = output;
unsigned int i;
@@ -7208,7 +10681,7 @@ index 40f560959..bd9af783c 100644
*p++ = ' ';
*p++ = '(';
-@@ -2348,6 +2371,7 @@ char *rust_fmt_argument(char *buf, char *end, void *ptr);
+@@ -2355,6 +2378,7 @@ char *rust_fmt_argument(char *buf, char *end, void *ptr);
* read the documentation (path below) first.
* - 'NF' For a netdev_features_t
* - '4cc' V4L2 or DRM FourCC code, with endianness and raw numerical value.
@@ -7217,10 +10690,10 @@ index 40f560959..bd9af783c 100644
* a certain separator (' ' by default):
* C colon
diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl
-index 880fde13d..f080e33a4 100755
+index 2b812210b412..4c3a8cc6ef15 100755
--- a/scripts/checkpatch.pl
+++ b/scripts/checkpatch.pl
-@@ -6906,7 +6906,7 @@ sub process {
+@@ -6909,7 +6909,7 @@ sub process {
($extension eq "f" &&
defined $qualifier && $qualifier !~ /^w/) ||
($extension eq "4" &&
@@ -7230,4618 +10703,5 @@ index 880fde13d..f080e33a4 100755
last;
}
--
-2.42.0
-
-From f893444f7c842f97f3707897ba29f2c8dd77c8df Mon Sep 17 00:00:00 2001
-From: Kerem Karabay <kekrby@gmail.com>
-Date: Mon, 7 Aug 2023 20:29:27 +0300
-Subject: [PATCH 10/12] USB: core: add 'shutdown' callback to usb_driver
-
-This simplifies running code on shutdown for USB drivers.
-
-Signed-off-by: Kerem Karabay <kekrby@gmail.com>
----
- drivers/usb/core/driver.c | 14 ++++++++++++++
- drivers/usb/storage/uas.c | 5 ++---
- include/linux/usb.h | 3 +++
- 3 files changed, 19 insertions(+), 3 deletions(-)
+2.46.0.rc1
-diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c
-index f58a0299f..dc0f86376 100644
---- a/drivers/usb/core/driver.c
-+++ b/drivers/usb/core/driver.c
-@@ -514,6 +514,19 @@ static int usb_unbind_interface(struct device *dev)
- return 0;
- }
-
-+static void usb_shutdown_interface(struct device *dev)
-+{
-+ struct usb_interface *intf = to_usb_interface(dev);
-+ struct usb_driver *driver;
-+
-+ if (!dev->driver)
-+ return;
-+
-+ driver = to_usb_driver(dev->driver);
-+ if (driver->shutdown)
-+ driver->shutdown(intf);
-+}
-+
- /**
- * usb_driver_claim_interface - bind a driver to an interface
- * @driver: the driver to be bound
-@@ -1053,6 +1066,7 @@ int usb_register_driver(struct usb_driver *new_driver, struct module *owner,
- new_driver->driver.bus = &usb_bus_type;
- new_driver->driver.probe = usb_probe_interface;
- new_driver->driver.remove = usb_unbind_interface;
-+ new_driver->driver.shutdown = usb_shutdown_interface;
- new_driver->driver.owner = owner;
- new_driver->driver.mod_name = mod_name;
- new_driver->driver.dev_groups = new_driver->dev_groups;
-diff --git a/drivers/usb/storage/uas.c b/drivers/usb/storage/uas.c
-index 2583ee981..591fa0379 100644
---- a/drivers/usb/storage/uas.c
-+++ b/drivers/usb/storage/uas.c
-@@ -1221,9 +1221,8 @@ static void uas_disconnect(struct usb_interface *intf)
- * hang on reboot when the device is still in uas mode. Note the reset is
- * necessary as some devices won't revert to usb-storage mode without it.
- */
--static void uas_shutdown(struct device *dev)
-+static void uas_shutdown(struct usb_interface *intf)
- {
-- struct usb_interface *intf = to_usb_interface(dev);
- struct usb_device *udev = interface_to_usbdev(intf);
- struct Scsi_Host *shost = usb_get_intfdata(intf);
- struct uas_dev_info *devinfo = (struct uas_dev_info *)shost->hostdata;
-@@ -1246,7 +1245,7 @@ static struct usb_driver uas_driver = {
- .suspend = uas_suspend,
- .resume = uas_resume,
- .reset_resume = uas_reset_resume,
-- .driver.shutdown = uas_shutdown,
-+ .shutdown = uas_shutdown,
- .id_table = uas_usb_ids,
- };
-
-diff --git a/include/linux/usb.h b/include/linux/usb.h
-index 25f8e62a3..5f3ae2186 100644
---- a/include/linux/usb.h
-+++ b/include/linux/usb.h
-@@ -1194,6 +1194,7 @@ struct usbdrv_wrap {
- * post_reset method is called.
- * @post_reset: Called by usb_reset_device() after the device
- * has been reset
-+ * @shutdown: Called at shut-down time to quiesce the device.
- * @id_table: USB drivers use ID table to support hotplugging.
- * Export this with MODULE_DEVICE_TABLE(usb,...). This must be set
- * or your driver's probe function will never get called.
-@@ -1245,6 +1246,8 @@ struct usb_driver {
- int (*pre_reset)(struct usb_interface *intf);
- int (*post_reset)(struct usb_interface *intf);
-
-+ void (*shutdown)(struct usb_interface *intf);
-+
- const struct usb_device_id *id_table;
- const struct attribute_group **dev_groups;
-
---
-2.42.0
-
-From 337d6f6e34daaa786a0fb70d0dbd553288cd5ecd Mon Sep 17 00:00:00 2001
-From: Kerem Karabay <kekrby@gmail.com>
-Date: Fri, 4 Aug 2023 17:49:25 +0300
-Subject: [PATCH 11/12] drm/format-helper: add helper for BGR888 to XRGB8888
- conversion
-
-Add XRGB8888 emulation helper for devices that only support BGR888.
-
-Signed-off-by: Kerem Karabay <kekrby@gmail.com>
----
- drivers/gpu/drm/drm_format_helper.c | 53 ++++++++++++++
- .../gpu/drm/tests/drm_format_helper_test.c | 69 +++++++++++++++++++
- include/drm/drm_format_helper.h | 3 +
- 3 files changed, 125 insertions(+)
-
-diff --git a/drivers/gpu/drm/drm_format_helper.c b/drivers/gpu/drm/drm_format_helper.c
-index b1be458ed4dda5..24836384554a47 100644
---- a/drivers/gpu/drm/drm_format_helper.c
-+++ b/drivers/gpu/drm/drm_format_helper.c
-@@ -702,6 +702,58 @@ void drm_fb_xrgb8888_to_rgb888(struct iosys_map *dst, const unsigned int *dst_pi
- }
- EXPORT_SYMBOL(drm_fb_xrgb8888_to_rgb888);
-
-+static void drm_fb_xrgb8888_to_bgr888_line(void *dbuf, const void *sbuf, unsigned int pixels)
-+{
-+ u8 *dbuf8 = dbuf;
-+ const __le32 *sbuf32 = sbuf;
-+ unsigned int x;
-+ u32 pix;
-+
-+ for (x = 0; x < pixels; x++) {
-+ pix = le32_to_cpu(sbuf32[x]);
-+ /* write red-green-blue to output in little endianness */
-+ *dbuf8++ = (pix & 0x00FF0000) >> 16;
-+ *dbuf8++ = (pix & 0x0000FF00) >> 8;
-+ *dbuf8++ = (pix & 0x000000FF) >> 0;
-+ }
-+}
-+
-+/**
-+ * drm_fb_xrgb8888_to_bgr888 - Convert XRGB8888 to BGR888 clip buffer
-+ * @dst: Array of BGR888 destination buffers
-+ * @dst_pitch: Array of numbers of bytes between the start of two consecutive scanlines
-+ * within @dst; can be NULL if scanlines are stored next to each other.
-+ * @src: Array of XRGB8888 source buffers
-+ * @fb: DRM framebuffer
-+ * @clip: Clip rectangle area to copy
-+ * @state: Transform and conversion state
-+ *
-+ * This function copies parts of a framebuffer to display memory and converts the
-+ * color format during the process. Destination and framebuffer formats must match. The
-+ * parameters @dst, @dst_pitch and @src refer to arrays. Each array must have at
-+ * least as many entries as there are planes in @fb's format. Each entry stores the
-+ * value for the format's respective color plane at the same index.
-+ *
-+ * This function does not apply clipping on @dst (i.e. the destination is at the
-+ * top-left corner).
-+ *
-+ * Drivers can use this function for BGR888 devices that don't natively
-+ * support XRGB8888.
-+ */
-+void drm_fb_xrgb8888_to_bgr888(struct iosys_map *dst, const unsigned int *dst_pitch,
-+ const struct iosys_map *src, const struct drm_framebuffer *fb,
-+ const struct drm_rect *clip,
-+ struct drm_format_conv_state *state)
-+{
-+ static const u8 dst_pixsize[DRM_FORMAT_MAX_PLANES] = {
-+ 3,
-+ };
-+
-+ drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false,
-+ state, drm_fb_xrgb8888_to_bgr888_line);
-+}
-+EXPORT_SYMBOL(drm_fb_xrgb8888_to_bgr888);
-+
- static void drm_fb_xrgb8888_to_argb8888_line(void *dbuf, const void *sbuf, unsigned int pixels)
- {
- __le32 *dbuf32 = dbuf;
-@@ -1035,6 +1087,9 @@ int drm_fb_blit(struct iosys_map *dst, const unsigned int *dst_pitch, uint32_t d
- } else if (dst_format == DRM_FORMAT_RGB888) {
- drm_fb_xrgb8888_to_rgb888(dst, dst_pitch, src, fb, clip, state);
- return 0;
-+ } else if (dst_format == DRM_FORMAT_BGR888) {
-+ drm_fb_xrgb8888_to_bgr888(dst, dst_pitch, src, fb, clip, state);
-+ return 0;
- } else if (dst_format == DRM_FORMAT_ARGB8888) {
- drm_fb_xrgb8888_to_argb8888(dst, dst_pitch, src, fb, clip, state);
- return 0;
-diff --git a/drivers/gpu/drm/tests/drm_format_helper_test.c b/drivers/gpu/drm/tests/drm_format_helper_test.c
-index 474bb7a1c..dff7fabd9 100644
---- a/drivers/gpu/drm/tests/drm_format_helper_test.c
-+++ b/drivers/gpu/drm/tests/drm_format_helper_test.c
-@@ -52,6 +52,11 @@ struct convert_to_rgb888_result {
- const u8 expected[TEST_BUF_SIZE];
- };
-
-+struct convert_to_bgr888_result {
-+ unsigned int dst_pitch;
-+ const u8 expected[TEST_BUF_SIZE];
-+};
-+
- struct convert_to_argb8888_result {
- unsigned int dst_pitch;
- const u32 expected[TEST_BUF_SIZE];
-@@ -84,6 +89,7 @@ struct convert_xrgb8888_case {
- struct convert_to_argb1555_result argb1555_result;
- struct convert_to_rgba5551_result rgba5551_result;
- struct convert_to_rgb888_result rgb888_result;
-+ struct convert_to_bgr888_result bgr888_result;
- struct convert_to_argb8888_result argb8888_result;
- struct convert_to_xrgb2101010_result xrgb2101010_result;
- struct convert_to_argb2101010_result argb2101010_result;
-@@ -125,6 +131,10 @@ static struct convert_xrgb8888_case convert_xrgb8888_cases[] = {
- .dst_pitch = TEST_USE_DEFAULT_PITCH,
- .expected = { 0x00, 0x00, 0xFF },
- },
-+ .bgr888_result = {
-+ .dst_pitch = TEST_USE_DEFAULT_PITCH,
-+ .expected = { 0xFF, 0x00, 0x00 },
-+ },
- .argb8888_result = {
- .dst_pitch = TEST_USE_DEFAULT_PITCH,
- .expected = { 0xFFFF0000 },
-@@ -179,6 +189,10 @@ static struct convert_xrgb8888_case convert_xrgb8888_cases[] = {
- .dst_pitch = TEST_USE_DEFAULT_PITCH,
- .expected = { 0x00, 0x00, 0xFF },
- },
-+ .bgr888_result = {
-+ .dst_pitch = TEST_USE_DEFAULT_PITCH,
-+ .expected = { 0xFF, 0x00, 0x00 },
-+ },
- .argb8888_result = {
- .dst_pitch = TEST_USE_DEFAULT_PITCH,
- .expected = { 0xFFFF0000 },
-@@ -280,6 +294,15 @@ static struct convert_xrgb8888_case convert_xrgb8888_cases[] = {
- 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
- },
- },
-+ .bgr888_result = {
-+ .dst_pitch = TEST_USE_DEFAULT_PITCH,
-+ .expected = {
-+ 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00,
-+ 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00,
-+ 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF,
-+ 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF,
-+ },
-+ },
- .argb8888_result = {
- .dst_pitch = TEST_USE_DEFAULT_PITCH,
- .expected = {
-@@ -391,6 +414,17 @@ static struct convert_xrgb8888_case convert_xrgb8888_cases[] = {
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- },
- },
-+ .bgr888_result = {
-+ .dst_pitch = 15,
-+ .expected = {
-+ 0x0E, 0x44, 0x9C, 0x11, 0x4D, 0x05, 0xA8, 0xF3, 0x03,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x6C, 0xF0, 0x73, 0x0E, 0x44, 0x9C, 0x11, 0x4D, 0x05,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0xA8, 0x03, 0x03, 0x6C, 0xF0, 0x73, 0x0E, 0x44, 0x9C,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ },
-+ },
- .argb8888_result = {
- .dst_pitch = 20,
- .expected = {
-diff --git a/include/drm/drm_format_helper.h b/include/drm/drm_format_helper.h
-index 291deb094..7fc553318 100644
---- a/include/drm/drm_format_helper.h
-+++ b/include/drm/drm_format_helper.h
-@@ -42,6 +42,9 @@ void drm_fb_xrgb8888_to_rgba5551(struct iosys_map *dst, const unsigned int *dst_
- void drm_fb_xrgb8888_to_rgb888(struct iosys_map *dst, const unsigned int *dst_pitch,
- const struct iosys_map *src, const struct drm_framebuffer *fb,
- const struct drm_rect *clip, struct drm_format_conv_state *state);
-+void drm_fb_xrgb8888_to_bgr888(struct iosys_map *dst, const unsigned int *dst_pitch,
-+ const struct iosys_map *src, const struct drm_framebuffer *fb,
-+ const struct drm_rect *clip, struct drm_format_conv_state *state);
- void drm_fb_xrgb8888_to_argb8888(struct iosys_map *dst, const unsigned int *dst_pitch,
- const struct iosys_map *src, const struct drm_framebuffer *fb,
- const struct drm_rect *clip, struct drm_format_conv_state *state);
---
-2.42.0
-
-From 1f0b6c21c4d56f5be74c4d7d0665525862e307c3 Mon Sep 17 00:00:00 2001
-From: Kerem Karabay <kekrby@gmail.com>
-Date: Sat, 6 May 2023 17:30:09 +0300
-Subject: [PATCH 12/12] drm/tiny: add driver for Apple Touch Bars in x86 Macs
-
-The Touch Bars found on x86 Macs support two USB configurations: one
-where the device presents itself as a HID keyboard and can display
-predefined sets of keys, and one where the operating system has full
-control over what is displayed. This commit adds support for the display
-functionality of the second configuration.
-
-Note that this driver has only been tested on T2 Macs, and only includes
-the USB device ID for these devices. Testing on T1 Macs would be
-appreciated.
-
-Credit goes to @imbushuo on GitHub for reverse engineering most of the
-protocol.
-
-Signed-off-by: Kerem Karabay <kekrby@gmail.com>
----
- drivers/gpu/drm/tiny/Kconfig | 12 +
- drivers/gpu/drm/tiny/Makefile | 1 +
- drivers/gpu/drm/tiny/appletbdrm.c | 624 ++++++++++++++++++++++++++++++
- 4 files changed, 643 insertions(+)
- create mode 100644 drivers/gpu/drm/tiny/appletbdrm.c
-
-diff --git a/drivers/gpu/drm/tiny/Kconfig b/drivers/gpu/drm/tiny/Kconfig
-index f6889f649..559a97bce 100644
---- a/drivers/gpu/drm/tiny/Kconfig
-+++ b/drivers/gpu/drm/tiny/Kconfig
-@@ -1,5 +1,17 @@
- # SPDX-License-Identifier: GPL-2.0-only
-
-+config DRM_APPLETBDRM
-+ tristate "DRM support for Apple Touch Bars"
-+ depends on DRM && USB && MMU
-+ select DRM_KMS_HELPER
-+ select DRM_GEM_SHMEM_HELPER
-+ help
-+ Say Y here if you want support for the display of Touch Bars on x86
-+ MacBook Pros.
-+
-+ To compile this driver as a module, choose M here: the
-+ module will be called appletbdrm.
-+
- config DRM_ARCPGU
- tristate "ARC PGU"
- depends on DRM && OF
-diff --git a/drivers/gpu/drm/tiny/Makefile b/drivers/gpu/drm/tiny/Makefile
-index 76dde89a0..9a1b412e7 100644
---- a/drivers/gpu/drm/tiny/Makefile
-+++ b/drivers/gpu/drm/tiny/Makefile
-@@ -1,5 +1,6 @@
- # SPDX-License-Identifier: GPL-2.0-only
-
-+obj-$(CONFIG_DRM_APPLETBDRM) += appletbdrm.o
- obj-$(CONFIG_DRM_ARCPGU) += arcpgu.o
- obj-$(CONFIG_DRM_BOCHS) += bochs.o
- obj-$(CONFIG_DRM_CIRRUS_QEMU) += cirrus.o
-diff --git a/drivers/gpu/drm/tiny/appletbdrm.c b/drivers/gpu/drm/tiny/appletbdrm.c
-new file mode 100644
-index 000000000..33a99436b
---- /dev/null
-+++ b/drivers/gpu/drm/tiny/appletbdrm.c
-@@ -0,0 +1,624 @@
-+// SPDX-License-Identifier: GPL-2.0
-+/*
-+ * Apple Touch Bar DRM Driver
-+ *
-+ * Copyright (c) 2023 Kerem Karabay <kekrby@gmail.com>
-+ */
-+
-+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-+
-+#include <asm/unaligned.h>
-+
-+#include <linux/usb.h>
-+#include <linux/module.h>
-+
-+#include <drm/drm_drv.h>
-+#include <drm/drm_fourcc.h>
-+#include <drm/drm_probe_helper.h>
-+#include <drm/drm_atomic_helper.h>
-+#include <drm/drm_damage_helper.h>
-+#include <drm/drm_format_helper.h>
-+#include <drm/drm_gem_shmem_helper.h>
-+#include <drm/drm_gem_atomic_helper.h>
-+#include <drm/drm_simple_kms_helper.h>
-+#include <drm/drm_gem_framebuffer_helper.h>
-+
-+#define _APPLETBDRM_FOURCC(s) (((s)[0] << 24) | ((s)[1] << 16) | ((s)[2] << 8) | (s)[3])
-+#define APPLETBDRM_FOURCC(s) _APPLETBDRM_FOURCC(#s)
-+
-+#define APPLETBDRM_PIXEL_FORMAT APPLETBDRM_FOURCC(RGBA) /* The actual format is BGR888 */
-+#define APPLETBDRM_BITS_PER_PIXEL 24
-+
-+#define APPLETBDRM_MSG_CLEAR_DISPLAY APPLETBDRM_FOURCC(CLRD)
-+#define APPLETBDRM_MSG_GET_INFORMATION APPLETBDRM_FOURCC(GINF)
-+#define APPLETBDRM_MSG_UPDATE_COMPLETE APPLETBDRM_FOURCC(UDCL)
-+#define APPLETBDRM_MSG_SIGNAL_READINESS APPLETBDRM_FOURCC(REDY)
-+
-+#define APPLETBDRM_BULK_MSG_TIMEOUT 1000
-+
-+#define drm_to_adev(_drm) container_of(_drm, struct appletbdrm_device, drm)
-+#define adev_to_udev(adev) interface_to_usbdev(to_usb_interface(adev->dev))
-+
-+struct appletbdrm_device {
-+ struct device *dev;
-+
-+ u8 in_ep;
-+ u8 out_ep;
-+
-+ u32 width;
-+ u32 height;
-+
-+ struct drm_device drm;
-+ struct drm_display_mode mode;
-+ struct drm_connector connector;
-+ struct drm_simple_display_pipe pipe;
-+
-+ bool readiness_signal_received;
-+};
-+
-+struct appletbdrm_request_header {
-+ __le16 unk_00;
-+ __le16 unk_02;
-+ __le32 unk_04;
-+ __le32 unk_08;
-+ __le32 size;
-+} __packed;
-+
-+struct appletbdrm_response_header {
-+ u8 unk_00[16];
-+ u32 msg;
-+} __packed;
-+
-+struct appletbdrm_simple_request {
-+ struct appletbdrm_request_header header;
-+ u32 msg;
-+ u8 unk_14[8];
-+ __le32 size;
-+} __packed;
-+
-+struct appletbdrm_information {
-+ struct appletbdrm_response_header header;
-+ u8 unk_14[12];
-+ __le32 width;
-+ __le32 height;
-+ u8 bits_per_pixel;
-+ __le32 bytes_per_row;
-+ __le32 orientation;
-+ __le32 bitmap_info;
-+ u32 pixel_format;
-+ __le32 width_inches; /* floating point */
-+ __le32 height_inches; /* floating point */
-+} __packed;
-+
-+struct appletbdrm_frame {
-+ __le16 begin_x;
-+ __le16 begin_y;
-+ __le16 width;
-+ __le16 height;
-+ __le32 buf_size;
-+ u8 buf[];
-+} __packed;
-+
-+struct appletbdrm_fb_request_footer {
-+ u8 unk_00[12];
-+ __le32 unk_0c;
-+ u8 unk_10[12];
-+ __le32 unk_1c;
-+ __le64 timestamp;
-+ u8 unk_28[12];
-+ __le32 unk_34;
-+ u8 unk_38[20];
-+ __le32 unk_4c;
-+} __packed;
-+
-+struct appletbdrm_fb_request {
-+ struct appletbdrm_request_header header;
-+ __le16 unk_10;
-+ u8 msg_id;
-+ u8 unk_13[29];
-+ /*
-+ * Contents of `data`:
-+ * - struct appletbdrm_frame frames[];
-+ * - struct appletbdrm_fb_request_footer footer;
-+ * - padding to make the total size a multiple of 16
-+ */
-+ u8 data[];
-+} __packed;
-+
-+struct appletbdrm_fb_request_response {
-+ struct appletbdrm_response_header header;
-+ u8 unk_14[12];
-+ __le64 timestamp;
-+} __packed;
-+
-+static int appletbdrm_send_request(struct appletbdrm_device *adev,
-+ struct appletbdrm_request_header *request, size_t size)
-+{
-+ struct usb_device *udev = adev_to_udev(adev);
-+ struct drm_device *drm = &adev->drm;
-+ int ret, actual_size;
-+
-+ ret = usb_bulk_msg(udev, usb_sndbulkpipe(udev, adev->out_ep),
-+ request, size, &actual_size, APPLETBDRM_BULK_MSG_TIMEOUT);
-+ if (ret) {
-+ drm_err(drm, "Failed to send message (%pe)\n", ERR_PTR(ret));
-+ return ret;
-+ }
-+
-+ if (actual_size != size) {
-+ drm_err(drm, "Actual size (%d) doesn't match expected size (%lu)\n",
-+ actual_size, size);
-+ return -EIO;
-+ }
-+
-+ return ret;
-+}
-+
-+static int appletbdrm_read_response(struct appletbdrm_device *adev,
-+ struct appletbdrm_response_header *response,
-+ size_t size, u32 expected_response)
-+{
-+ struct usb_device *udev = adev_to_udev(adev);
-+ struct drm_device *drm = &adev->drm;
-+ int ret, actual_size;
-+
-+retry:
-+ ret = usb_bulk_msg(udev, usb_rcvbulkpipe(udev, adev->in_ep),
-+ response, size, &actual_size, APPLETBDRM_BULK_MSG_TIMEOUT);
-+ if (ret) {
-+ drm_err(drm, "Failed to read response (%pe)\n", ERR_PTR(ret));
-+ return ret;
-+ }
-+
-+ /*
-+ * The device responds to the first request sent in a particular
-+ * timeframe after the USB device configuration is set with a readiness
-+ * signal, in which case the response should be read again
-+ */
-+ if (response->msg == APPLETBDRM_MSG_SIGNAL_READINESS) {
-+ if (!adev->readiness_signal_received) {
-+ adev->readiness_signal_received = true;
-+ goto retry;
-+ }
-+
-+ drm_err(drm, "Encountered unexpected readiness signal\n");
-+ return -EIO;
-+ }
-+
-+ if (actual_size != size) {
-+ drm_err(drm, "Actual size (%d) doesn't match expected size (%lu)\n",
-+ actual_size, size);
-+ return -EIO;
-+ }
-+
-+ if (response->msg != expected_response) {
-+ drm_err(drm, "Unexpected response from device (expected %p4ch found %p4ch)\n",
-+ &expected_response, &response->msg);
-+ return -EIO;
-+ }
-+
-+ return 0;
-+}
-+
-+static int appletbdrm_send_msg(struct appletbdrm_device *adev, u32 msg)
-+{
-+ struct appletbdrm_simple_request *request;
-+ int ret;
-+
-+ request = kzalloc(sizeof(*request), GFP_KERNEL);
-+ if (!request)
-+ return -ENOMEM;
-+
-+ request->header.unk_00 = cpu_to_le16(2);
-+ request->header.unk_02 = cpu_to_le16(0x1512);
-+ request->header.size = cpu_to_le32(sizeof(*request) - sizeof(request->header));
-+ request->msg = msg;
-+ request->size = request->header.size;
-+
-+ ret = appletbdrm_send_request(adev, &request->header, sizeof(*request));
-+
-+ kfree(request);
-+
-+ return ret;
-+}
-+
-+static int appletbdrm_clear_display(struct appletbdrm_device *adev)
-+{
-+ return appletbdrm_send_msg(adev, APPLETBDRM_MSG_CLEAR_DISPLAY);
-+}
-+
-+static int appletbdrm_signal_readiness(struct appletbdrm_device *adev)
-+{
-+ return appletbdrm_send_msg(adev, APPLETBDRM_MSG_SIGNAL_READINESS);
-+}
-+
-+static int appletbdrm_get_information(struct appletbdrm_device *adev)
-+{
-+ struct appletbdrm_information *info;
-+ struct drm_device *drm = &adev->drm;
-+ u8 bits_per_pixel;
-+ u32 pixel_format;
-+ int ret;
-+
-+ info = kzalloc(sizeof(*info), GFP_KERNEL);
-+ if (!info)
-+ return -ENOMEM;
-+
-+ ret = appletbdrm_send_msg(adev, APPLETBDRM_MSG_GET_INFORMATION);
-+ if (ret)
-+ return ret;
-+
-+ ret = appletbdrm_read_response(adev, &info->header, sizeof(*info),
-+ APPLETBDRM_MSG_GET_INFORMATION);
-+ if (ret)
-+ goto free_info;
-+
-+ bits_per_pixel = info->bits_per_pixel;
-+ pixel_format = get_unaligned(&info->pixel_format);
-+
-+ adev->width = get_unaligned_le32(&info->width);
-+ adev->height = get_unaligned_le32(&info->height);
-+
-+ if (bits_per_pixel != APPLETBDRM_BITS_PER_PIXEL) {
-+ drm_err(drm, "Encountered unexpected bits per pixel value (%d)\n", bits_per_pixel);
-+ ret = -EINVAL;
-+ goto free_info;
-+ }
-+
-+ if (pixel_format != APPLETBDRM_PIXEL_FORMAT) {
-+ drm_err(drm, "Encountered unknown pixel format (%p4ch)\n", &pixel_format);
-+ ret = -EINVAL;
-+ goto free_info;
-+ }
-+
-+free_info:
-+ kfree(info);
-+
-+ return ret;
-+}
-+
-+static u32 rect_size(struct drm_rect *rect)
-+{
-+ return drm_rect_width(rect) * drm_rect_height(rect) * (APPLETBDRM_BITS_PER_PIXEL / 8);
-+}
-+
-+static int appletbdrm_flush_damage(struct appletbdrm_device *adev,
-+ struct drm_plane_state *old_state,
-+ struct drm_plane_state *state)
-+{
-+ struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(state);
-+ struct appletbdrm_fb_request_response *response;
-+ struct appletbdrm_fb_request_footer *footer;
-+ struct drm_atomic_helper_damage_iter iter;
-+ struct drm_framebuffer *fb = state->fb;
-+ struct appletbdrm_fb_request *request;
-+ struct drm_device *drm = &adev->drm;
-+ struct appletbdrm_frame *frame;
-+ u64 timestamp = ktime_get_ns();
-+ struct drm_rect damage;
-+ size_t frames_size = 0;
-+ size_t request_size;
-+ int ret;
-+
-+ drm_atomic_helper_damage_iter_init(&iter, old_state, state);
-+ drm_atomic_for_each_plane_damage(&iter, &damage) {
-+ frames_size += struct_size(frame, buf, rect_size(&damage));
-+ }
-+
-+ if (!frames_size)
-+ return 0;
-+
-+ request_size = ALIGN(sizeof(*request) + frames_size + sizeof(*footer), 16);
-+
-+ request = kzalloc(request_size, GFP_KERNEL);
-+ if (!request)
-+ return -ENOMEM;
-+
-+ response = kzalloc(sizeof(*response), GFP_KERNEL);
-+ if (!response) {
-+ ret = -ENOMEM;
-+ goto free_request;
-+ }
-+
-+ ret = drm_gem_fb_begin_cpu_access(fb, DMA_FROM_DEVICE);
-+ if (ret) {
-+ drm_err(drm, "Failed to start CPU framebuffer access (%pe)\n", ERR_PTR(ret));
-+ goto free_response;
-+ }
-+
-+ request->header.unk_00 = cpu_to_le16(2);
-+ request->header.unk_02 = cpu_to_le16(0x12);
-+ request->header.unk_04 = cpu_to_le32(9);
-+ request->header.size = cpu_to_le32(request_size - sizeof(request->header));
-+ request->unk_10 = cpu_to_le16(1);
-+ request->msg_id = timestamp & 0xff;
-+
-+ frame = (struct appletbdrm_frame *)request->data;
-+
-+ drm_atomic_helper_damage_iter_init(&iter, old_state, state);
-+ drm_atomic_for_each_plane_damage(&iter, &damage) {
-+ struct iosys_map dst = IOSYS_MAP_INIT_VADDR(frame->buf);
-+ u32 buf_size = rect_size(&damage);
-+
-+ /*
-+ * The coordinates need to be translated to the coordinate
-+ * system the device expects, see the comment in
-+ * appletbdrm_setup_mode_config
-+ */
-+ frame->begin_x = cpu_to_le16(damage.y1);
-+ frame->begin_y = cpu_to_le16(adev->height - damage.x2);
-+ frame->width = cpu_to_le16(drm_rect_height(&damage));
-+ frame->height = cpu_to_le16(drm_rect_width(&damage));
-+ frame->buf_size = cpu_to_le32(buf_size);
-+
-+ ret = drm_fb_blit(&dst, NULL, DRM_FORMAT_BGR888,
-+ &shadow_plane_state->data[0], fb, &damage, &shadow_plane_state->fmtcnv_state);
-+ if (ret) {
-+ drm_err(drm, "Failed to copy damage clip (%pe)\n", ERR_PTR(ret));
-+ goto end_fb_cpu_access;
-+ }
-+
-+ frame = (void *)frame + struct_size(frame, buf, buf_size);
-+ }
-+
-+ footer = (struct appletbdrm_fb_request_footer *)&request->data[frames_size];
-+
-+ footer->unk_0c = cpu_to_le32(0xfffe);
-+ footer->unk_1c = cpu_to_le32(0x80001);
-+ footer->unk_34 = cpu_to_le32(0x80002);
-+ footer->unk_4c = cpu_to_le32(0xffff);
-+ footer->timestamp = cpu_to_le64(timestamp);
-+
-+ ret = appletbdrm_send_request(adev, &request->header, request_size);
-+ if (ret)
-+ goto end_fb_cpu_access;
-+
-+ ret = appletbdrm_read_response(adev, &response->header, sizeof(*response),
-+ APPLETBDRM_MSG_UPDATE_COMPLETE);
-+ if (ret)
-+ goto end_fb_cpu_access;
-+
-+ if (response->timestamp != footer->timestamp) {
-+ drm_err(drm, "Response timestamp (%llu) doesn't match request timestamp (%llu)\n",
-+ le64_to_cpu(response->timestamp), timestamp);
-+ goto end_fb_cpu_access;
-+ }
-+
-+end_fb_cpu_access:
-+ drm_gem_fb_end_cpu_access(fb, DMA_FROM_DEVICE);
-+free_response:
-+ kfree(response);
-+free_request:
-+ kfree(request);
-+
-+ return ret;
-+}
-+
-+static int appletbdrm_connector_helper_get_modes(struct drm_connector *connector)
-+{
-+ struct appletbdrm_device *adev = drm_to_adev(connector->dev);
-+
-+ return drm_connector_helper_get_modes_fixed(connector, &adev->mode);
-+}
-+
-+static enum drm_mode_status appletbdrm_pipe_mode_valid(struct drm_simple_display_pipe *pipe,
-+ const struct drm_display_mode *mode)
-+{
-+ struct drm_crtc *crtc = &pipe->crtc;
-+ struct appletbdrm_device *adev = drm_to_adev(crtc->dev);
-+
-+ return drm_crtc_helper_mode_valid_fixed(crtc, mode, &adev->mode);
-+}
-+
-+static void appletbdrm_pipe_disable(struct drm_simple_display_pipe *pipe)
-+{
-+ struct appletbdrm_device *adev = drm_to_adev(pipe->crtc.dev);
-+ int idx;
-+
-+ if (!drm_dev_enter(&adev->drm, &idx))
-+ return;
-+
-+ appletbdrm_clear_display(adev);
-+
-+ drm_dev_exit(idx);
-+}
-+
-+static void appletbdrm_pipe_update(struct drm_simple_display_pipe *pipe,
-+ struct drm_plane_state *old_state)
-+{
-+ struct drm_crtc *crtc = &pipe->crtc;
-+ struct appletbdrm_device *adev = drm_to_adev(crtc->dev);
-+ int idx;
-+
-+ if (!crtc->state->active || !drm_dev_enter(&adev->drm, &idx))
-+ return;
-+
-+ appletbdrm_flush_damage(adev, old_state, pipe->plane.state);
-+
-+ drm_dev_exit(idx);
-+}
-+
-+static const u32 appletbdrm_formats[] = {
-+ DRM_FORMAT_BGR888,
-+ DRM_FORMAT_XRGB8888, /* emulated */
-+};
-+
-+static const struct drm_mode_config_funcs appletbdrm_mode_config_funcs = {
-+ .fb_create = drm_gem_fb_create_with_dirty,
-+ .atomic_check = drm_atomic_helper_check,
-+ .atomic_commit = drm_atomic_helper_commit,
-+};
-+
-+static const struct drm_connector_funcs appletbdrm_connector_funcs = {
-+ .reset = drm_atomic_helper_connector_reset,
-+ .destroy = drm_connector_cleanup,
-+ .fill_modes = drm_helper_probe_single_connector_modes,
-+ .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
-+ .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
-+};
-+
-+static const struct drm_connector_helper_funcs appletbdrm_connector_helper_funcs = {
-+ .get_modes = appletbdrm_connector_helper_get_modes,
-+};
-+
-+static const struct drm_simple_display_pipe_funcs appletbdrm_pipe_funcs = {
-+ DRM_GEM_SIMPLE_DISPLAY_PIPE_SHADOW_PLANE_FUNCS,
-+ .update = appletbdrm_pipe_update,
-+ .disable = appletbdrm_pipe_disable,
-+ .mode_valid = appletbdrm_pipe_mode_valid,
-+};
-+
-+DEFINE_DRM_GEM_FOPS(appletbdrm_drm_fops);
-+
-+static const struct drm_driver appletbdrm_drm_driver = {
-+ DRM_GEM_SHMEM_DRIVER_OPS,
-+ .name = "appletbdrm",
-+ .desc = "Apple Touch Bar DRM Driver",
-+ .date = "20230910",
-+ .major = 1,
-+ .minor = 0,
-+ .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_ATOMIC,
-+ .fops = &appletbdrm_drm_fops,
-+};
-+
-+static int appletbdrm_setup_mode_config(struct appletbdrm_device *adev)
-+{
-+ struct drm_connector *connector = &adev->connector;
-+ struct drm_device *drm = &adev->drm;
-+ struct device *dev = adev->dev;
-+ int ret;
-+
-+ ret = drmm_mode_config_init(drm);
-+ if (ret)
-+ return dev_err_probe(dev, ret, "Failed to initialize mode configuration\n");
-+
-+ /*
-+ * The coordinate system used by the device is different from the
-+ * coordinate system of the framebuffer in that the x and y axes are
-+ * swapped, and that the y axis is inverted; so what the device reports
-+ * as the height is actually the width of the framebuffer and vice
-+ * versa
-+ */
-+ drm->mode_config.min_width = 0;
-+ drm->mode_config.min_height = 0;
-+ drm->mode_config.max_width = max(adev->height, DRM_SHADOW_PLANE_MAX_WIDTH);
-+ drm->mode_config.max_height = max(adev->width, DRM_SHADOW_PLANE_MAX_HEIGHT);
-+ drm->mode_config.preferred_depth = APPLETBDRM_BITS_PER_PIXEL;
-+ drm->mode_config.funcs = &appletbdrm_mode_config_funcs;
-+
-+ adev->mode = (struct drm_display_mode) {
-+ DRM_MODE_INIT(60, adev->height, adev->width,
-+ DRM_MODE_RES_MM(adev->height, 218),
-+ DRM_MODE_RES_MM(adev->width, 218))
-+ };
-+
-+ ret = drm_connector_init(drm, connector,
-+ &appletbdrm_connector_funcs, DRM_MODE_CONNECTOR_USB);
-+ if (ret)
-+ return dev_err_probe(dev, ret, "Failed to initialize connector\n");
-+
-+ drm_connector_helper_add(connector, &appletbdrm_connector_helper_funcs);
-+
-+ ret = drm_connector_set_panel_orientation(connector,
-+ DRM_MODE_PANEL_ORIENTATION_RIGHT_UP);
-+ if (ret)
-+ return dev_err_probe(dev, ret, "Failed to set panel orientation\n");
-+
-+ connector->display_info.non_desktop = true;
-+ ret = drm_object_property_set_value(&connector->base,
-+ drm->mode_config.non_desktop_property, true);
-+ if (ret)
-+ return dev_err_probe(dev, ret, "Failed to set non-desktop property\n");
-+
-+ ret = drm_simple_display_pipe_init(drm, &adev->pipe, &appletbdrm_pipe_funcs,
-+ appletbdrm_formats, ARRAY_SIZE(appletbdrm_formats),
-+ NULL, &adev->connector);
-+ if (ret)
-+ return dev_err_probe(dev, ret, "Failed to initialize simple display pipe\n");
-+
-+ drm_plane_enable_fb_damage_clips(&adev->pipe.plane);
-+
-+ drm_mode_config_reset(drm);
-+
-+ ret = drm_dev_register(drm, 0);
-+ if (ret)
-+ return dev_err_probe(dev, ret, "Failed to register DRM device\n");
-+
-+ return 0;
-+}
-+
-+static int appletbdrm_probe(struct usb_interface *intf,
-+ const struct usb_device_id *id)
-+{
-+ struct usb_endpoint_descriptor *bulk_in, *bulk_out;
-+ struct device *dev = &intf->dev;
-+ struct appletbdrm_device *adev;
-+ int ret;
-+
-+ ret = usb_find_common_endpoints(intf->cur_altsetting, &bulk_in, &bulk_out, NULL, NULL);
-+ if (ret)
-+ return dev_err_probe(dev, ret, "Failed to find bulk endpoints\n");
-+
-+ adev = devm_drm_dev_alloc(dev, &appletbdrm_drm_driver, struct appletbdrm_device, drm);
-+ if (IS_ERR(adev))
-+ return PTR_ERR(adev);
-+
-+ adev->dev = dev;
-+ adev->in_ep = bulk_in->bEndpointAddress;
-+ adev->out_ep = bulk_out->bEndpointAddress;
-+
-+ usb_set_intfdata(intf, adev);
-+
-+ ret = appletbdrm_get_information(adev);
-+ if (ret)
-+ return dev_err_probe(dev, ret, "Failed to get display information\n");
-+
-+ ret = appletbdrm_signal_readiness(adev);
-+ if (ret)
-+ return dev_err_probe(dev, ret, "Failed to signal readiness\n");
-+
-+ ret = appletbdrm_clear_display(adev);
-+ if (ret)
-+ return dev_err_probe(dev, ret, "Failed to clear display\n");
-+
-+ return appletbdrm_setup_mode_config(adev);
-+}
-+
-+static void appletbdrm_disconnect(struct usb_interface *intf)
-+{
-+ struct appletbdrm_device *adev = usb_get_intfdata(intf);
-+ struct drm_device *drm = &adev->drm;
-+
-+ drm_dev_unplug(drm);
-+ drm_atomic_helper_shutdown(drm);
-+}
-+
-+static void appletbdrm_shutdown(struct usb_interface *intf)
-+{
-+ struct appletbdrm_device *adev = usb_get_intfdata(intf);
-+
-+ /*
-+ * The framebuffer needs to be cleared on shutdown since its content
-+ * persists across boots
-+ */
-+ drm_atomic_helper_shutdown(&adev->drm);
-+}
-+
-+static const struct usb_device_id appletbdrm_usb_id_table[] = {
-+ { USB_DEVICE_INTERFACE_CLASS(0x05ac, 0x8302, USB_CLASS_AUDIO_VIDEO) },
-+ {}
-+};
-+MODULE_DEVICE_TABLE(usb, appletbdrm_usb_id_table);
-+
-+static struct usb_driver appletbdrm_usb_driver = {
-+ .name = "appletbdrm",
-+ .probe = appletbdrm_probe,
-+ .disconnect = appletbdrm_disconnect,
-+ .shutdown = appletbdrm_shutdown,
-+ .id_table = appletbdrm_usb_id_table,
-+};
-+module_usb_driver(appletbdrm_usb_driver);
-+
-+MODULE_AUTHOR("Kerem Karabay <kekrby@gmail.com>");
-+MODULE_DESCRIPTION("Apple Touch Bar DRM Driver");
-+MODULE_LICENSE("GPL");
---
-2.42.0
-
-From e34c6d09241ba826a6e9b2b0e50e306b273b7bda Mon Sep 17 00:00:00 2001
-From: Orlando Chamberlain <orlandoch.dev@gmail.com>
-Date: Thu, 16 Feb 2023 12:32:34 +1100
-Subject: [PATCH 5/8] Documentation: leds: standardise keyboard backlight led
- names
-
-Advice use of either "input*:*:kbd_backlight" or ":*:kbd_backlight". We
-don't want people using vendor or product name (e.g. "smc", "apple",
-"asus") as this information is available from sysfs anyway, and it made the
-folder names inconsistent.
-
-Signed-off-by: Orlando Chamberlain <orlandoch.dev@gmail.com>
----
- Documentation/leds/well-known-leds.txt | 8 ++++++++
- 1 file changed, 8 insertions(+)
-
-diff --git a/Documentation/leds/well-known-leds.txt b/Documentation/leds/well-known-leds.txt
-index 2160382c86be..4e5429fce4d8 100644
---- a/Documentation/leds/well-known-leds.txt
-+++ b/Documentation/leds/well-known-leds.txt
-@@ -44,6 +44,14 @@ Legacy: "lp5523:kb{1,2,3,4,5,6}" (Nokia N900)
-
- Frontlight/backlight of main keyboard.
-
-+Good: ":*:kbd_backlight"
-+Good: "input*:*:kbd_backlight"
-+Legacy: "*:*:kbd_backlight"
-+
-+Many drivers have the vendor or product name as the first field of the led name,
-+this makes names inconsistent and is redundant as that information is already in
-+sysfs.
-+
- Legacy: "button-backlight" (Motorola Droid 4)
-
- Some phones have touch buttons below screen; it is different from main
---
-2.39.1
-
-From c124f5401040d02abd6d349979be29acd1e88545 Mon Sep 17 00:00:00 2001
-From: Orlando Chamberlain <orlandoch.dev@gmail.com>
-Date: Fri, 10 Feb 2023 23:14:31 +1100
-Subject: [PATCH 6/8] HID: hid-apple-magic-backlight: Add driver for keyboard
- backlight on internal Magic Keyboards
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-This driver adds support for the keyboard backlight on Intel T2 Macs
-with internal Magic Keyboards (MacBookPro16,x and MacBookAir9,1)
-
-Co-developed-by: Kerem Karabay <kekrby@gmail.com>
-Signed-off-by: Kerem Karabay <kekrby@gmail.com>
-Signed-off-by: Orlando Chamberlain <orlandoch.dev@gmail.com>
-Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com>
-Reviewed-by: Thomas Weißschuh <linux@weissschuh.net>
----
- drivers/hid/Kconfig | 13 +++
- drivers/hid/Makefile | 1 +
- drivers/hid/hid-apple-magic-backlight.c | 120 ++++++++++++++++++++++++
- 4 files changed, 140 insertions(+)
- create mode 100644 drivers/hid/hid-apple-magic-backlight.c
-
-diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
-index 4e238df87..83fbab6d4 100644
---- a/drivers/hid/Kconfig
-+++ b/drivers/hid/Kconfig
-@@ -169,6 +169,19 @@ config HID_APPLETB_KBD
- To compile this driver as a module, choose M here: the
- module will be called hid-appletb-kbd.
-
-+config HID_APPLE_MAGIC_BACKLIGHT
-+ tristate "Apple Magic Keyboard Backlight"
-+ depends on USB_HID
-+ depends on LEDS_CLASS
-+ depends on NEW_LEDS
-+ help
-+ Say Y here if you want support for the keyboard backlight on Macs with
-+ the magic keyboard (MacBookPro16,x and MacBookAir9,1). Note that this
-+ driver is not for external magic keyboards.
-+
-+ To compile this driver as a module, choose M here: the
-+ module will be called hid-apple-magic-backlight.
-+
- config HID_ASUS
- tristate "Asus"
- depends on USB_HID
-diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile
-index 5b60015fd..581f5e720 100644
---- a/drivers/hid/Makefile
-+++ b/drivers/hid/Makefile
-@@ -31,6 +31,7 @@ obj-$(CONFIG_HID_APPLE) += hid-apple.o
- obj-$(CONFIG_HID_APPLEIR) += hid-appleir.o
- obj-$(CONFIG_HID_APPLETB_BL) += hid-appletb-bl.o
- obj-$(CONFIG_HID_APPLETB_KBD) += hid-appletb-kbd.o
-+obj-$(CONFIG_HID_APPLE_MAGIC_BACKLIGHT) += hid-apple-magic-backlight.o
- obj-$(CONFIG_HID_CREATIVE_SB0540) += hid-creative-sb0540.o
- obj-$(CONFIG_HID_ASUS) += hid-asus.o
- obj-$(CONFIG_HID_AUREAL) += hid-aureal.o
-diff --git a/drivers/hid/hid-apple-magic-backlight.c b/drivers/hid/hid-apple-magic-backlight.c
-new file mode 100644
-index 000000000..f0fc02ff3
---- /dev/null
-+++ b/drivers/hid/hid-apple-magic-backlight.c
-@@ -0,0 +1,120 @@
-+// SPDX-License-Identifier: GPL-2.0
-+/*
-+ * Apple Magic Keyboard Backlight Driver
-+ *
-+ * For Intel Macs with internal Magic Keyboard (MacBookPro16,1-4 and MacBookAir9,1)
-+ *
-+ * Copyright (c) 2022 Kerem Karabay <kekrby@gmail.com>
-+ * Copyright (c) 2023 Orlando Chamberlain <orlandoch.dev@gmail.com>
-+ */
-+
-+#include <linux/hid.h>
-+#include <linux/leds.h>
-+#include <linux/device.h>
-+#include <linux/errno.h>
-+#include <dt-bindings/leds/common.h>
-+
-+#include "hid-ids.h"
-+
-+#define HID_USAGE_MAGIC_BL 0xff00000f
-+
-+#define APPLE_MAGIC_REPORT_ID_POWER 3
-+#define APPLE_MAGIC_REPORT_ID_BRIGHTNESS 1
-+
-+struct apple_magic_backlight {
-+ struct led_classdev cdev;
-+ struct hid_report *brightness;
-+ struct hid_report *power;
-+};
-+
-+static void apple_magic_backlight_report_set(struct hid_report *rep, s32 value, u8 rate)
-+{
-+ rep->field[0]->value[0] = value;
-+ rep->field[1]->value[0] = 0x5e; /* Mimic Windows */
-+ rep->field[1]->value[0] |= rate << 8;
-+
-+ hid_hw_request(rep->device, rep, HID_REQ_SET_REPORT);
-+}
-+
-+static void apple_magic_backlight_set(struct apple_magic_backlight *backlight,
-+ int brightness, char rate)
-+{
-+ apple_magic_backlight_report_set(backlight->power, brightness ? 1 : 0, rate);
-+ if (brightness)
-+ apple_magic_backlight_report_set(backlight->brightness, brightness, rate);
-+}
-+
-+static int apple_magic_backlight_led_set(struct led_classdev *led_cdev,
-+ enum led_brightness brightness)
-+{
-+ struct apple_magic_backlight *backlight = container_of(led_cdev,
-+ struct apple_magic_backlight, cdev);
-+
-+ apple_magic_backlight_set(backlight, brightness, 1);
-+ return 0;
-+}
-+
-+static int apple_magic_backlight_probe(struct hid_device *hdev,
-+ const struct hid_device_id *id)
-+{
-+ struct apple_magic_backlight *backlight;
-+ int rc;
-+
-+ rc = hid_parse(hdev);
-+ if (rc)
-+ return rc;
-+
-+ /*
-+ * Ensure this usb endpoint is for the keyboard backlight, not touchbar
-+ * backlight.
-+ */
-+ if (hdev->collection[0].usage != HID_USAGE_MAGIC_BL)
-+ return -ENODEV;
-+
-+ backlight = devm_kzalloc(&hdev->dev, sizeof(*backlight), GFP_KERNEL);
-+ if (!backlight)
-+ return -ENOMEM;
-+
-+ rc = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
-+ if (rc)
-+ return rc;
-+
-+ backlight->brightness = hid_register_report(hdev, HID_FEATURE_REPORT,
-+ APPLE_MAGIC_REPORT_ID_BRIGHTNESS, 0);
-+ backlight->power = hid_register_report(hdev, HID_FEATURE_REPORT,
-+ APPLE_MAGIC_REPORT_ID_POWER, 0);
-+
-+ if (!backlight->brightness || !backlight->power) {
-+ rc = -ENODEV;
-+ goto hw_stop;
-+ }
-+
-+ backlight->cdev.name = ":white:" LED_FUNCTION_KBD_BACKLIGHT;
-+ backlight->cdev.max_brightness = backlight->brightness->field[0]->logical_maximum;
-+ backlight->cdev.brightness_set_blocking = apple_magic_backlight_led_set;
-+
-+ apple_magic_backlight_set(backlight, 0, 0);
-+
-+ return devm_led_classdev_register(&hdev->dev, &backlight->cdev);
-+
-+hw_stop:
-+ hid_hw_stop(hdev);
-+ return rc;
-+}
-+
-+static const struct hid_device_id apple_magic_backlight_hid_ids[] = {
-+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_TOUCHBAR_BACKLIGHT) },
-+ { }
-+};
-+MODULE_DEVICE_TABLE(hid, apple_magic_backlight_hid_ids);
-+
-+static struct hid_driver apple_magic_backlight_hid_driver = {
-+ .name = "hid-apple-magic-backlight",
-+ .id_table = apple_magic_backlight_hid_ids,
-+ .probe = apple_magic_backlight_probe,
-+};
-+module_hid_driver(apple_magic_backlight_hid_driver);
-+
-+MODULE_DESCRIPTION("MacBook Magic Keyboard Backlight");
-+MODULE_AUTHOR("Orlando Chamberlain <orlandoch.dev@gmail.com>");
-+MODULE_LICENSE("GPL");
---
-2.39.2
-
-From 12c7a3306a631a651464ef56318a218dc4cdb157 Mon Sep 17 00:00:00 2001
-From: Orlando Chamberlain <orlandoch.dev@gmail.com>
-Date: Sat, 18 Feb 2023 23:05:05 +1100
-Subject: [PATCH 8/9] i915: 4 lane quirk for mbp15,1
-
-Needed to use iGPU when dGPU was boot GPU
-
-Patch written by Kerem Karabay <kekrby@gmail.com>
----
- drivers/gpu/drm/i915/display/intel_ddi.c | 3 +++
- drivers/gpu/drm/i915/display/intel_quirks.c | 15 +++++++++++++++
- drivers/gpu/drm/i915/display/intel_quirks.h | 1 +
- 3 files changed, 19 insertions(+)
-
-diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c
-index 0f1ec2a98cc8..1ec67390f623 100644
---- a/drivers/gpu/drm/i915/display/intel_ddi.c
-+++ b/drivers/gpu/drm/i915/display/intel_ddi.c
-@@ -4097,6 +4097,9 @@ static bool intel_ddi_a_force_4_lanes(struct intel_digital_port *dig_port)
- if (dig_port->saved_port_bits & DDI_A_4_LANES)
- return false;
-
-+ if (intel_has_quirk(dev_priv, QUIRK_DDI_A_FORCE_4_LANES))
-+ return true;
-+
- /* Broxton/Geminilake: Bspec says that DDI_A_4_LANES is the only
- * supported configuration
- */
-diff --git a/drivers/gpu/drm/i915/display/intel_quirks.c b/drivers/gpu/drm/i915/display/intel_quirks.c
-index 6e48d3bcdfec..a8c55e165b46 100644
---- a/drivers/gpu/drm/i915/display/intel_quirks.c
-+++ b/drivers/gpu/drm/i915/display/intel_quirks.c
-@@ -59,6 +59,18 @@ static void quirk_increase_ddi_disabled_time(struct drm_i915_private *i915)
- drm_info(&i915->drm, "Applying Increase DDI Disabled quirk\n");
- }
-
-+/*
-+ * In some cases, the firmware might not set the lane count to 4 (for example,
-+ * when booting in some dual GPU Macs with the dGPU as the default GPU), this
-+ * quirk is used to force it as otherwise it might not be possible to compute a
-+ * valid link configuration.
-+ */
-+static void quirk_ddi_a_force_4_lanes(struct drm_i915_private *i915)
-+{
-+ intel_set_quirk(i915, QUIRK_DDI_A_FORCE_4_LANES);
-+ drm_info(&i915->drm, "Applying DDI A Forced 4 Lanes quirk\n");
-+}
-+
- static void quirk_no_pps_backlight_power_hook(struct drm_i915_private *i915)
- {
- intel_set_quirk(i915, QUIRK_NO_PPS_BACKLIGHT_POWER_HOOK);
-@@ -199,6 +211,9 @@ static struct intel_quirk intel_quirks[] = {
- { 0x3184, 0x1019, 0xa94d, quirk_increase_ddi_disabled_time },
- /* HP Notebook - 14-r206nv */
- { 0x0f31, 0x103c, 0x220f, quirk_invert_brightness },
-+
-+ /* Apple MacBookPro15,1 */
-+ { 0x3e9b, 0x106b, 0x0176, quirk_ddi_a_force_4_lanes },
- };
-
- void intel_init_quirks(struct drm_i915_private *i915)
-diff --git a/drivers/gpu/drm/i915/display/intel_quirks.h b/drivers/gpu/drm/i915/display/intel_quirks.h
-index 10a4d163149f..78aacf1f6f5c 100644
---- a/drivers/gpu/drm/i915/display/intel_quirks.h
-+++ b/drivers/gpu/drm/i915/display/intel_quirks.h
-@@ -17,6 +17,7 @@ enum intel_quirk_id {
- QUIRK_INVERT_BRIGHTNESS,
- QUIRK_LVDS_SSC_DISABLE,
- QUIRK_NO_PPS_BACKLIGHT_POWER_HOOK,
-+ QUIRK_DDI_A_FORCE_4_LANES,
- };
-
- void intel_init_quirks(struct drm_i915_private *i915);
---
-2.39.1
-
-From bd8e785c74e22978648ced004552eb9c137f1eb6 Mon Sep 17 00:00:00 2001
-From: Orlando Chamberlain <orlandoch.dev@gmail.com>
-Date: Fri, 10 Feb 2023 22:45:00 +1100
-Subject: [PATCH 9/9] apple-gmux: allow switching to igpu at probe
-
-This means user don't need to set the gpu-power-prefs efivar to use the
-igpu while runtime switching isn't working, so macOS will be unaffected.
-
-This isn't really upstreamable, what we want upstream is the ability to
-switch at runtime (so both gpus need to be able to probe the eDP panel).
-
-Based off of work by Kerem Karabay <kekrby@gmail.com>
----
- drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c | 3 +++
- drivers/gpu/vga/vga_switcheroo.c | 7 +------
- drivers/pci/vgaarb.c | 1 +
- drivers/platform/x86/apple-gmux.c | 18 ++++++++++++++++++
- 4 files changed, 23 insertions(+), 6 deletions(-)
-
-diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
-index 81edf66dbea8..8f3daf28665b 100644
---- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
-+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
-@@ -2051,6 +2051,9 @@ static int amdgpu_pci_probe(struct pci_dev *pdev,
- int ret, retry = 0, i;
- bool supports_atomic = false;
-
-+ if (vga_switcheroo_client_probe_defer(pdev))
-+ return -EPROBE_DEFER;
-+
- /* skip devices which are owned by radeon */
- for (i = 0; i < ARRAY_SIZE(amdgpu_unsupported_pciidlist); i++) {
- if (amdgpu_unsupported_pciidlist[i] == pdev->device)
-diff --git a/drivers/gpu/vga/vga_switcheroo.c b/drivers/gpu/vga/vga_switcheroo.c
-index 365e6ddbe90f..cf357cd3389d 100644
---- a/drivers/gpu/vga/vga_switcheroo.c
-+++ b/drivers/gpu/vga/vga_switcheroo.c
-@@ -438,12 +438,7 @@ find_active_client(struct list_head *head)
- bool vga_switcheroo_client_probe_defer(struct pci_dev *pdev)
- {
- if ((pdev->class >> 16) == PCI_BASE_CLASS_DISPLAY) {
-- /*
-- * apple-gmux is needed on pre-retina MacBook Pro
-- * to probe the panel if pdev is the inactive GPU.
-- */
-- if (apple_gmux_present() && pdev != vga_default_device() &&
-- !vgasr_priv.handler_flags)
-+ if (apple_gmux_present() && !vgasr_priv.handler_flags)
- return true;
- }
-
-diff --git a/drivers/pci/vgaarb.c b/drivers/pci/vgaarb.c
-index 5e6b1eb54c64..1f11701d37d1 100644
---- a/drivers/pci/vgaarb.c
-+++ b/drivers/pci/vgaarb.c
-@@ -143,6 +143,7 @@ void vga_set_default_device(struct pci_dev *pdev)
- pci_dev_put(vga_default);
- vga_default = pci_dev_get(pdev);
- }
-+EXPORT_SYMBOL_GPL(vga_set_default_device);
-
- /**
- * vga_remove_vgacon - deactivate VGA console
-diff --git a/drivers/platform/x86/apple-gmux.c b/drivers/platform/x86/apple-gmux.c
-index 1417e230edbd..e69785af8e1d 100644
---- a/drivers/platform/x86/apple-gmux.c
-+++ b/drivers/platform/x86/apple-gmux.c
-@@ -21,6 +21,7 @@
- #include <linux/delay.h>
- #include <linux/pci.h>
- #include <linux/vga_switcheroo.h>
-+#include <linux/vgaarb.h>
- #include <linux/debugfs.h>
- #include <acpi/video.h>
- #include <asm/io.h>
-@@ -107,6 +108,10 @@ struct apple_gmux_config {
-
- # define MMIO_GMUX_MAX_BRIGHTNESS 0xffff
-
-+static bool force_igd;
-+module_param(force_igd, bool, 0);
-+MODULE_PARM_DESC(force_idg, "Switch gpu to igd on module load. Make sure that you have apple-set-os set up and the iGPU is in `lspci -s 00:02.0`. (default: false) (bool)");
-+
- static u8 gmux_pio_read8(struct apple_gmux_data *gmux_data, int port)
- {
- return inb(gmux_data->iostart + port);
-@@ -945,6 +950,19 @@ static int gmux_probe(struct pnp_dev *pnp, const struct pnp_device_id *id)
- gmux_enable_interrupts(gmux_data);
- gmux_read_switch_state(gmux_data);
-
-+ if (force_igd) {
-+ struct pci_dev *pdev;
-+
-+ pdev = pci_get_domain_bus_and_slot(0, 0, PCI_DEVFN(2, 0));
-+ if (pdev) {
-+ pr_info("Switching to IGD");
-+ gmux_switchto(VGA_SWITCHEROO_IGD);
-+ vga_set_default_device(pdev);
-+ } else {
-+ pr_err("force_idg is true, but couldn't find iGPU at 00:02.0! Is apple-set-os working?");
-+ }
-+ }
-+
- /*
- * Retina MacBook Pros cannot switch the panel's AUX separately
- * and need eDP pre-calibration. They are distinguishable from
---
-2.43.0
-
-From 6adb501c697cd0e3246e75237ee8e43eb5a92cc3 Mon Sep 17 00:00:00 2001
-From: Kerem Karabay <kekrby@gmail.com>
-Date: Thu, 23 Nov 2023 18:58:51 +0530
-Subject: [PATCH] efi: libstub: add support for the apple_set_os protocol
-
-On dual GPU EFI Macs, the EFI stub needs to report that it is booting
-macOS in order to prevent the firmware from disabling the iGPU.
-
-See also this patch for GRUB by Andreas Heider <andreas@heider.io>:
-https://lists.gnu.org/archive/html/grub-devel/2013-12/msg00442.html
----
- .../admin-guide/kernel-parameters.txt | 2 ++
- .../firmware/efi/libstub/efi-stub-helper.c | 3 +++
- drivers/firmware/efi/libstub/efistub.h | 14 ++++++++++
- drivers/firmware/efi/libstub/x86-stub.c | 27 +++++++++++++++++++
- include/linux/efi.h | 1 +
- 5 files changed, 47 insertions(+)
-
-diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
-index 41644336e..cbd4697a5 100644
---- a/Documentation/admin-guide/kernel-parameters.txt
-+++ b/Documentation/admin-guide/kernel-parameters.txt
-@@ -399,6 +399,8 @@
- useful so that a dump capture kernel won't be
- shot down by NMI
-
-+ apple_set_os [KNL] Report that macOS is being booted to the firmware
-+
- autoconf= [IPV6]
- See Documentation/networking/ipv6.rst.
-
-diff --git a/drivers/firmware/efi/libstub/efi-stub-helper.c b/drivers/firmware/efi/libstub/efi-stub-helper.c
-index bfa30625f..3d99acc1a 100644
---- a/drivers/firmware/efi/libstub/efi-stub-helper.c
-+++ b/drivers/firmware/efi/libstub/efi-stub-helper.c
-@@ -19,6 +19,7 @@
- bool efi_nochunk;
- bool efi_nokaslr = !IS_ENABLED(CONFIG_RANDOMIZE_BASE);
- bool efi_novamap;
-+bool efi_apple_set_os;
-
- static bool efi_noinitrd;
- static bool efi_nosoftreserve;
-@@ -75,6 +76,8 @@
- efi_loglevel = CONSOLE_LOGLEVEL_QUIET;
- } else if (!strcmp(param, "noinitrd")) {
- efi_noinitrd = true;
-+ } else if (!strcmp(param, "apple_set_os")) {
-+ efi_apple_set_os = true;
- } else if (IS_ENABLED(CONFIG_X86_64) && !strcmp(param, "no5lvl")) {
- efi_no5lvl = true;
- } else if (IS_ENABLED(CONFIG_ARCH_HAS_MEM_ENCRYPT) &&
-diff --git a/drivers/firmware/efi/libstub/efistub.h b/drivers/firmware/efi/libstub/efistub.h
-index 212687c30..21b414d09 100644
---- a/drivers/firmware/efi/libstub/efistub.h
-+++ b/drivers/firmware/efi/libstub/efistub.h
-@@ -39,6 +39,7 @@
- extern int efi_loglevel;
- extern int efi_mem_encrypt;
- extern bool efi_novamap;
-+extern bool efi_apple_set_os;
- extern const efi_system_table_t *efi_system_table;
-
- typedef union efi_dxe_services_table efi_dxe_services_table_t;
-@@ -825,6 +826,19 @@ union apple_properties_protocol {
- } mixed_mode;
- };
-
-+typedef struct apple_set_os_protocol apple_set_os_protocol_t;
-+
-+struct apple_set_os_protocol {
-+ u64 version;
-+ efi_status_t (__efiapi *set_os_version) (const char *);
-+ efi_status_t (__efiapi *set_os_vendor) (const char *);
-+ struct {
-+ u32 version;
-+ u32 set_os_version;
-+ u32 set_os_vendor;
-+ } mixed_mode;
-+};
-+
- typedef u32 efi_tcg2_event_log_format;
-
- #define INITRD_EVENT_TAG_ID 0x8F3B22ECU
-diff --git a/drivers/firmware/efi/libstub/x86-stub.c b/drivers/firmware/efi/libstub/x86-stub.c
-index 70b325a2f..2131f8543 100644
---- a/drivers/firmware/efi/libstub/x86-stub.c
-+++ b/drivers/firmware/efi/libstub/x86-stub.c
-@@ -223,6 +223,30 @@ static void retrieve_apple_device_properties(struct boot_params *boot_params)
- }
- }
-
-+static void apple_set_os(void)
-+{
-+ efi_guid_t guid = APPLE_SET_OS_PROTOCOL_GUID;
-+ apple_set_os_protocol_t *set_os;
-+ efi_status_t status;
-+
-+ status = efi_bs_call(locate_protocol, &guid, NULL, (void **)&set_os);
-+ if (status != EFI_SUCCESS)
-+ return;
-+
-+ if (efi_table_attr(set_os, version) >= 2) {
-+ status = efi_fn_call(set_os, set_os_vendor, "Apple Inc.");
-+ if (status != EFI_SUCCESS)
-+ efi_err("Failed to set OS vendor via apple_set_os\n");
-+ }
-+
-+ /* The version being set doesn't seem to matter */
-+ if (efi_table_attr(set_os, version) > 0) {
-+ status = efi_fn_call(set_os, set_os_version, "Mac OS X 10.9");
-+ if (status != EFI_SUCCESS)
-+ efi_err("Failed to set OS version via apple_set_os\n");
-+ }
-+}
-+
- efi_status_t efi_adjust_memory_range_protection(unsigned long start,
- unsigned long size)
- {
-@@ -321,6 +345,9 @@ static void setup_quirks(struct boot_params *boot_params)
- if (IS_ENABLED(CONFIG_APPLE_PROPERTIES) &&
- !memcmp(efistub_fw_vendor(), apple, sizeof(apple)))
- retrieve_apple_device_properties(boot_params);
-+
-+ if (efi_apple_set_os)
-+ apple_set_os();
- }
-
- /*
-diff --git a/include/linux/efi.h b/include/linux/efi.h
-index 80b21d1c6..f1e58e027 100644
---- a/include/linux/efi.h
-+++ b/include/linux/efi.h
-@@ -387,6 +387,7 @@
- #define EFI_MEMORY_ATTRIBUTES_TABLE_GUID EFI_GUID(0xdcfa911d, 0x26eb, 0x469f, 0xa2, 0x20, 0x38, 0xb7, 0xdc, 0x46, 0x12, 0x20)
- #define EFI_CONSOLE_OUT_DEVICE_GUID EFI_GUID(0xd3b36f2c, 0xd551, 0x11d4, 0x9a, 0x46, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d)
- #define APPLE_PROPERTIES_PROTOCOL_GUID EFI_GUID(0x91bd12fe, 0xf6c3, 0x44fb, 0xa5, 0xb7, 0x51, 0x22, 0xab, 0x30, 0x3a, 0xe0)
-+#define APPLE_SET_OS_PROTOCOL_GUID EFI_GUID(0xc5c5da95, 0x7d5c, 0x45e6, 0xb2, 0xf1, 0x3f, 0xd5, 0x2b, 0xb1, 0x00, 0x77)
- #define EFI_TCG2_PROTOCOL_GUID EFI_GUID(0x607f766c, 0x7455, 0x42be, 0x93, 0x0b, 0xe4, 0xd7, 0x6d, 0xb2, 0x72, 0x0f)
- #define EFI_TCG2_FINAL_EVENTS_TABLE_GUID EFI_GUID(0x1e2ed096, 0x30e2, 0x4254, 0xbd, 0x89, 0x86, 0x3b, 0xbe, 0xf8, 0x23, 0x25)
- #define EFI_LOAD_FILE_PROTOCOL_GUID EFI_GUID(0x56ec3091, 0x954c, 0x11d2, 0x8e, 0x3f, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b)
---
-2.34.1
-
-From 09dd6c563cd73d72e917de07e8d59358c41e051d Mon Sep 17 00:00:00 2001
-From: Paul Pawlowski <paul@mrarm.io>
-Date: Sun, 17 Nov 2019 23:12:55 +0100
-Subject: [PATCH 1/6] applesmc: convert static structures to drvdata
-
-All static data structures have been moved to an applesmc_device struct,
-which is then associated with the platform device.
-This change is intended to ease the migration to an acpi_device, where
-static data would preferably be avoided.
-
-Signed-off-by: Aun-Ali Zaidi <admin@kodeit.net>
----
- drivers/hwmon/applesmc.c | 540 +++++++++++++++++++++++----------------
- 1 file changed, 319 insertions(+), 221 deletions(-)
-
-diff --git a/drivers/hwmon/applesmc.c b/drivers/hwmon/applesmc.c
-index 79b498f816fe..62211b590a61 100644
---- a/drivers/hwmon/applesmc.c
-+++ b/drivers/hwmon/applesmc.c
-@@ -6,6 +6,7 @@
- *
- * Copyright (C) 2007 Nicolas Boichat <nicolas@boichat.ch>
- * Copyright (C) 2010 Henrik Rydberg <rydberg@euromail.se>
-+ * Copyright (C) 2019 Paul Pawlowski <paul@mrarm.io>
- *
- * Based on hdaps.c driver:
- * Copyright (C) 2005 Robert Love <rml@novell.com>
-@@ -119,7 +120,7 @@ struct applesmc_entry {
- };
-
- /* Register lookup and registers common to all SMCs */
--static struct applesmc_registers {
-+struct applesmc_registers {
- struct mutex mutex; /* register read/write mutex */
- unsigned int key_count; /* number of SMC registers */
- unsigned int fan_count; /* number of fans */
-@@ -133,26 +134,32 @@ static struct applesmc_registers {
- bool init_complete; /* true when fully initialized */
- struct applesmc_entry *cache; /* cached key entries */
- const char **index; /* temperature key index */
--} smcreg = {
-- .mutex = __MUTEX_INITIALIZER(smcreg.mutex),
- };
-
--static const int debug;
--static struct platform_device *pdev;
--static s16 rest_x;
--static s16 rest_y;
--static u8 backlight_state[2];
-+struct applesmc_device {
-+ struct platform_device *dev;
-+ struct applesmc_registers reg;
-
--static struct device *hwmon_dev;
--static struct input_dev *applesmc_idev;
-+ s16 rest_x;
-+ s16 rest_y;
-
--/*
-- * Last index written to key_at_index sysfs file, and value to use for all other
-- * key_at_index_* sysfs files.
-- */
--static unsigned int key_at_index;
-+ u8 backlight_state[2];
-+
-+ struct device *hwmon_dev;
-+ struct input_dev *idev;
-+
-+ /*
-+ * Last index written to key_at_index sysfs file, and value to use for all other
-+ * key_at_index_* sysfs files.
-+ */
-+ unsigned int key_at_index;
-+
-+ struct workqueue_struct *backlight_wq;
-+ struct work_struct backlight_work;
-+ struct led_classdev backlight_dev;
-+};
-
--static struct workqueue_struct *applesmc_led_wq;
-+static const int debug;
-
- /*
- * Wait for specific status bits with a mask on the SMC.
-@@ -338,36 +345,37 @@ static int read_register_count(unsigned int *count)
- * All functions below are concurrency safe - callers should NOT hold lock.
- */
-
--static int applesmc_read_entry(const struct applesmc_entry *entry,
-- u8 *buf, u8 len)
-+static int applesmc_read_entry(struct applesmc_device *smc,
-+ const struct applesmc_entry *entry, u8 *buf, u8 len)
- {
- int ret;
-
- if (entry->len != len)
- return -EINVAL;
-- mutex_lock(&smcreg.mutex);
-+ mutex_lock(&smc->reg.mutex);
- ret = read_smc(APPLESMC_READ_CMD, entry->key, buf, len);
-- mutex_unlock(&smcreg.mutex);
-+ mutex_unlock(&smc->reg.mutex);
-
- return ret;
- }
-
--static int applesmc_write_entry(const struct applesmc_entry *entry,
-- const u8 *buf, u8 len)
-+static int applesmc_write_entry(struct applesmc_device *smc,
-+ const struct applesmc_entry *entry, const u8 *buf, u8 len)
- {
- int ret;
-
- if (entry->len != len)
- return -EINVAL;
-- mutex_lock(&smcreg.mutex);
-+ mutex_lock(&smc->reg.mutex);
- ret = write_smc(APPLESMC_WRITE_CMD, entry->key, buf, len);
-- mutex_unlock(&smcreg.mutex);
-+ mutex_unlock(&smc->reg.mutex);
- return ret;
- }
-
--static const struct applesmc_entry *applesmc_get_entry_by_index(int index)
-+static const struct applesmc_entry *applesmc_get_entry_by_index(
-+ struct applesmc_device *smc, int index)
- {
-- struct applesmc_entry *cache = &smcreg.cache[index];
-+ struct applesmc_entry *cache = &smc->reg.cache[index];
- u8 key[4], info[6];
- __be32 be;
- int ret = 0;
-@@ -375,7 +383,7 @@ static const struct applesmc_entry *applesmc_get_entry_by_index(int index)
- if (cache->valid)
- return cache;
-
-- mutex_lock(&smcreg.mutex);
-+ mutex_lock(&smc->reg.mutex);
-
- if (cache->valid)
- goto out;
-@@ -394,20 +402,21 @@ static const struct applesmc_entry *applesmc_get_entry_by_index(int index)
- cache->valid = true;
-
- out:
-- mutex_unlock(&smcreg.mutex);
-+ mutex_unlock(&smc->reg.mutex);
- if (ret)
- return ERR_PTR(ret);
- return cache;
- }
-
--static int applesmc_get_lower_bound(unsigned int *lo, const char *key)
-+static int applesmc_get_lower_bound(struct applesmc_device *smc,
-+ unsigned int *lo, const char *key)
- {
-- int begin = 0, end = smcreg.key_count;
-+ int begin = 0, end = smc->reg.key_count;
- const struct applesmc_entry *entry;
-
- while (begin != end) {
- int middle = begin + (end - begin) / 2;
-- entry = applesmc_get_entry_by_index(middle);
-+ entry = applesmc_get_entry_by_index(smc, middle);
- if (IS_ERR(entry)) {
- *lo = 0;
- return PTR_ERR(entry);
-@@ -422,16 +431,17 @@ static int applesmc_get_lower_bound(unsigned int *lo, const char *key)
- return 0;
- }
-
--static int applesmc_get_upper_bound(unsigned int *hi, const char *key)
-+static int applesmc_get_upper_bound(struct applesmc_device *smc,
-+ unsigned int *hi, const char *key)
- {
-- int begin = 0, end = smcreg.key_count;
-+ int begin = 0, end = smc->reg.key_count;
- const struct applesmc_entry *entry;
-
- while (begin != end) {
- int middle = begin + (end - begin) / 2;
-- entry = applesmc_get_entry_by_index(middle);
-+ entry = applesmc_get_entry_by_index(smc, middle);
- if (IS_ERR(entry)) {
-- *hi = smcreg.key_count;
-+ *hi = smc->reg.key_count;
- return PTR_ERR(entry);
- }
- if (strcmp(key, entry->key) < 0)
-@@ -444,50 +454,54 @@ static int applesmc_get_upper_bound(unsigned int *hi, const char *key)
- return 0;
- }
-
--static const struct applesmc_entry *applesmc_get_entry_by_key(const char *key)
-+static const struct applesmc_entry *applesmc_get_entry_by_key(
-+ struct applesmc_device *smc, const char *key)
- {
- int begin, end;
- int ret;
-
-- ret = applesmc_get_lower_bound(&begin, key);
-+ ret = applesmc_get_lower_bound(smc, &begin, key);
- if (ret)
- return ERR_PTR(ret);
-- ret = applesmc_get_upper_bound(&end, key);
-+ ret = applesmc_get_upper_bound(smc, &end, key);
- if (ret)
- return ERR_PTR(ret);
- if (end - begin != 1)
- return ERR_PTR(-EINVAL);
-
-- return applesmc_get_entry_by_index(begin);
-+ return applesmc_get_entry_by_index(smc, begin);
- }
-
--static int applesmc_read_key(const char *key, u8 *buffer, u8 len)
-+static int applesmc_read_key(struct applesmc_device *smc,
-+ const char *key, u8 *buffer, u8 len)
- {
- const struct applesmc_entry *entry;
-
-- entry = applesmc_get_entry_by_key(key);
-+ entry = applesmc_get_entry_by_key(smc, key);
- if (IS_ERR(entry))
- return PTR_ERR(entry);
-
-- return applesmc_read_entry(entry, buffer, len);
-+ return applesmc_read_entry(smc, entry, buffer, len);
- }
-
--static int applesmc_write_key(const char *key, const u8 *buffer, u8 len)
-+static int applesmc_write_key(struct applesmc_device *smc,
-+ const char *key, const u8 *buffer, u8 len)
- {
- const struct applesmc_entry *entry;
-
-- entry = applesmc_get_entry_by_key(key);
-+ entry = applesmc_get_entry_by_key(smc, key);
- if (IS_ERR(entry))
- return PTR_ERR(entry);
-
-- return applesmc_write_entry(entry, buffer, len);
-+ return applesmc_write_entry(smc, entry, buffer, len);
- }
-
--static int applesmc_has_key(const char *key, bool *value)
-+static int applesmc_has_key(struct applesmc_device *smc,
-+ const char *key, bool *value)
- {
- const struct applesmc_entry *entry;
-
-- entry = applesmc_get_entry_by_key(key);
-+ entry = applesmc_get_entry_by_key(smc, key);
- if (IS_ERR(entry) && PTR_ERR(entry) != -EINVAL)
- return PTR_ERR(entry);
-
-@@ -498,12 +512,13 @@ static int applesmc_has_key(const char *key, bool *value)
- /*
- * applesmc_read_s16 - Read 16-bit signed big endian register
- */
--static int applesmc_read_s16(const char *key, s16 *value)
-+static int applesmc_read_s16(struct applesmc_device *smc,
-+ const char *key, s16 *value)
- {
- u8 buffer[2];
- int ret;
-
-- ret = applesmc_read_key(key, buffer, 2);
-+ ret = applesmc_read_key(smc, key, buffer, 2);
- if (ret)
- return ret;
-
-@@ -514,28 +529,29 @@ static int applesmc_read_s16(const char *key, s16 *value)
- /*
- * applesmc_device_init - initialize the accelerometer. Can sleep.
- */
--static void applesmc_device_init(void)
-+static void applesmc_device_init(struct applesmc_device *smc)
- {
- int total;
- u8 buffer[2];
-
-- if (!smcreg.has_accelerometer)
-+ if (!smc->reg.has_accelerometer)
- return;
-
- for (total = INIT_TIMEOUT_MSECS; total > 0; total -= INIT_WAIT_MSECS) {
-- if (!applesmc_read_key(MOTION_SENSOR_KEY, buffer, 2) &&
-+ if (!applesmc_read_key(smc, MOTION_SENSOR_KEY, buffer, 2) &&
- (buffer[0] != 0x00 || buffer[1] != 0x00))
- return;
- buffer[0] = 0xe0;
- buffer[1] = 0x00;
-- applesmc_write_key(MOTION_SENSOR_KEY, buffer, 2);
-+ applesmc_write_key(smc, MOTION_SENSOR_KEY, buffer, 2);
- msleep(INIT_WAIT_MSECS);
- }
-
- pr_warn("failed to init the device\n");
- }
-
--static int applesmc_init_index(struct applesmc_registers *s)
-+static int applesmc_init_index(struct applesmc_device *smc,
-+ struct applesmc_registers *s)
- {
- const struct applesmc_entry *entry;
- unsigned int i;
-@@ -548,7 +564,7 @@ static int applesmc_init_index(struct applesmc_registers *s)
- return -ENOMEM;
-
- for (i = s->temp_begin; i < s->temp_end; i++) {
-- entry = applesmc_get_entry_by_index(i);
-+ entry = applesmc_get_entry_by_index(smc, i);
- if (IS_ERR(entry))
- continue;
- if (strcmp(entry->type, TEMP_SENSOR_TYPE))
-@@ -562,9 +578,9 @@ static int applesmc_init_index(struct applesmc_registers *s)
- /*
- * applesmc_init_smcreg_try - Try to initialize register cache. Idempotent.
- */
--static int applesmc_init_smcreg_try(void)
-+static int applesmc_init_smcreg_try(struct applesmc_device *smc)
- {
-- struct applesmc_registers *s = &smcreg;
-+ struct applesmc_registers *s = &smc->reg;
- bool left_light_sensor = false, right_light_sensor = false;
- unsigned int count;
- u8 tmp[1];
-@@ -590,35 +606,35 @@ static int applesmc_init_smcreg_try(void)
- if (!s->cache)
- return -ENOMEM;
-
-- ret = applesmc_read_key(FANS_COUNT, tmp, 1);
-+ ret = applesmc_read_key(smc, FANS_COUNT, tmp, 1);
- if (ret)
- return ret;
- s->fan_count = tmp[0];
- if (s->fan_count > 10)
- s->fan_count = 10;
-
-- ret = applesmc_get_lower_bound(&s->temp_begin, "T");
-+ ret = applesmc_get_lower_bound(smc, &s->temp_begin, "T");
- if (ret)
- return ret;
-- ret = applesmc_get_lower_bound(&s->temp_end, "U");
-+ ret = applesmc_get_lower_bound(smc, &s->temp_end, "U");
- if (ret)
- return ret;
- s->temp_count = s->temp_end - s->temp_begin;
-
-- ret = applesmc_init_index(s);
-+ ret = applesmc_init_index(smc, s);
- if (ret)
- return ret;
-
-- ret = applesmc_has_key(LIGHT_SENSOR_LEFT_KEY, &left_light_sensor);
-+ ret = applesmc_has_key(smc, LIGHT_SENSOR_LEFT_KEY, &left_light_sensor);
- if (ret)
- return ret;
-- ret = applesmc_has_key(LIGHT_SENSOR_RIGHT_KEY, &right_light_sensor);
-+ ret = applesmc_has_key(smc, LIGHT_SENSOR_RIGHT_KEY, &right_light_sensor);
- if (ret)
- return ret;
-- ret = applesmc_has_key(MOTION_SENSOR_KEY, &s->has_accelerometer);
-+ ret = applesmc_has_key(smc, MOTION_SENSOR_KEY, &s->has_accelerometer);
- if (ret)
- return ret;
-- ret = applesmc_has_key(BACKLIGHT_KEY, &s->has_key_backlight);
-+ ret = applesmc_has_key(smc, BACKLIGHT_KEY, &s->has_key_backlight);
- if (ret)
- return ret;
-
-@@ -634,13 +650,13 @@ static int applesmc_init_smcreg_try(void)
- return 0;
- }
-
--static void applesmc_destroy_smcreg(void)
-+static void applesmc_destroy_smcreg(struct applesmc_device *smc)
- {
-- kfree(smcreg.index);
-- smcreg.index = NULL;
-- kfree(smcreg.cache);
-- smcreg.cache = NULL;
-- smcreg.init_complete = false;
-+ kfree(smc->reg.index);
-+ smc->reg.index = NULL;
-+ kfree(smc->reg.cache);
-+ smc->reg.cache = NULL;
-+ smc->reg.init_complete = false;
- }
-
- /*
-@@ -649,12 +665,12 @@ static void applesmc_destroy_smcreg(void)
- * Retries until initialization is successful, or the operation times out.
- *
- */
--static int applesmc_init_smcreg(void)
-+static int applesmc_init_smcreg(struct applesmc_device *smc)
- {
- int ms, ret;
-
- for (ms = 0; ms < INIT_TIMEOUT_MSECS; ms += INIT_WAIT_MSECS) {
-- ret = applesmc_init_smcreg_try();
-+ ret = applesmc_init_smcreg_try(smc);
- if (!ret) {
- if (ms)
- pr_info("init_smcreg() took %d ms\n", ms);
-@@ -663,21 +679,58 @@ static int applesmc_init_smcreg(void)
- msleep(INIT_WAIT_MSECS);
- }
-
-- applesmc_destroy_smcreg();
-+ applesmc_destroy_smcreg(smc);
-
- return ret;
- }
-
- /* Device model stuff */
-+static int applesmc_create_modules(struct applesmc_device *smc);
-+static void applesmc_destroy_modules(struct applesmc_device *smc);
- static int applesmc_probe(struct platform_device *dev)
- {
-+ struct applesmc_device *smc;
- int ret;
-
-- ret = applesmc_init_smcreg();
-+ smc = kzalloc(sizeof(struct applesmc_device), GFP_KERNEL);
-+ if (!smc)
-+ return -ENOMEM;
-+ smc->dev = dev;
-+ mutex_init(&smc->reg.mutex);
-+
-+ platform_set_drvdata(dev, smc);
-+
-+ ret = applesmc_init_smcreg(smc);
- if (ret)
-- return ret;
-+ goto out_mem;
-+
-+ applesmc_device_init(smc);
-+
-+ ret = applesmc_create_modules(smc);
-+ if (ret)
-+ goto out_reg;
-+
-+ return 0;
-+
-+out_reg:
-+ applesmc_destroy_smcreg(smc);
-+out_mem:
-+ platform_set_drvdata(dev, NULL);
-+ mutex_destroy(&smc->reg.mutex);
-+ kfree(smc);
-
-- applesmc_device_init();
-+ return ret;
-+}
-+
-+static int applesmc_remove(struct platform_device *dev)
-+{
-+ struct applesmc_device *smc = platform_get_drvdata(dev);
-+
-+ applesmc_destroy_modules(smc);
-+ applesmc_destroy_smcreg(smc);
-+
-+ mutex_destroy(&smc->reg.mutex);
-+ kfree(smc);
-
- return 0;
- }
-@@ -685,15 +738,21 @@ static int applesmc_probe(struct platform_device *dev)
- /* Synchronize device with memorized backlight state */
- static int applesmc_pm_resume(struct device *dev)
- {
-- if (smcreg.has_key_backlight)
-- applesmc_write_key(BACKLIGHT_KEY, backlight_state, 2);
-+ struct applesmc_device *smc = dev_get_drvdata(dev);
-+
-+ if (smc->reg.has_key_backlight)
-+ applesmc_write_key(smc, BACKLIGHT_KEY, smc->backlight_state, 2);
-+
- return 0;
- }
-
- /* Reinitialize device on resume from hibernation */
- static int applesmc_pm_restore(struct device *dev)
- {
-- applesmc_device_init();
-+ struct applesmc_device *smc = dev_get_drvdata(dev);
-+
-+ applesmc_device_init(smc);
-+
- return applesmc_pm_resume(dev);
- }
-
-@@ -704,6 +763,7 @@ static const struct dev_pm_ops applesmc_pm_ops = {
-
- static struct platform_driver applesmc_driver = {
- .probe = applesmc_probe,
-+ .remove = applesmc_remove,
- .driver = {
- .name = "applesmc",
- .pm = &applesmc_pm_ops,
-@@ -714,25 +774,26 @@ static struct platform_driver applesmc_driver = {
- * applesmc_calibrate - Set our "resting" values. Callers must
- * hold applesmc_lock.
- */
--static void applesmc_calibrate(void)
-+static void applesmc_calibrate(struct applesmc_device *smc)
- {
-- applesmc_read_s16(MOTION_SENSOR_X_KEY, &rest_x);
-- applesmc_read_s16(MOTION_SENSOR_Y_KEY, &rest_y);
-- rest_x = -rest_x;
-+ applesmc_read_s16(smc, MOTION_SENSOR_X_KEY, &smc->rest_x);
-+ applesmc_read_s16(smc, MOTION_SENSOR_Y_KEY, &smc->rest_y);
-+ smc->rest_x = -smc->rest_x;
- }
-
- static void applesmc_idev_poll(struct input_dev *idev)
- {
-+ struct applesmc_device *smc = dev_get_drvdata(&idev->dev);
- s16 x, y;
-
-- if (applesmc_read_s16(MOTION_SENSOR_X_KEY, &x))
-+ if (applesmc_read_s16(smc, MOTION_SENSOR_X_KEY, &x))
- return;
-- if (applesmc_read_s16(MOTION_SENSOR_Y_KEY, &y))
-+ if (applesmc_read_s16(smc, MOTION_SENSOR_Y_KEY, &y))
- return;
-
- x = -x;
-- input_report_abs(idev, ABS_X, x - rest_x);
-- input_report_abs(idev, ABS_Y, y - rest_y);
-+ input_report_abs(idev, ABS_X, x - smc->rest_x);
-+ input_report_abs(idev, ABS_Y, y - smc->rest_y);
- input_sync(idev);
- }
-
-@@ -747,16 +808,17 @@ static ssize_t applesmc_name_show(struct device *dev,
- static ssize_t applesmc_position_show(struct device *dev,
- struct device_attribute *attr, char *buf)
- {
-+ struct applesmc_device *smc = dev_get_drvdata(dev);
- int ret;
- s16 x, y, z;
-
-- ret = applesmc_read_s16(MOTION_SENSOR_X_KEY, &x);
-+ ret = applesmc_read_s16(smc, MOTION_SENSOR_X_KEY, &x);
- if (ret)
- goto out;
-- ret = applesmc_read_s16(MOTION_SENSOR_Y_KEY, &y);
-+ ret = applesmc_read_s16(smc, MOTION_SENSOR_Y_KEY, &y);
- if (ret)
- goto out;
-- ret = applesmc_read_s16(MOTION_SENSOR_Z_KEY, &z);
-+ ret = applesmc_read_s16(smc, MOTION_SENSOR_Z_KEY, &z);
- if (ret)
- goto out;
-
-@@ -770,6 +832,7 @@ static ssize_t applesmc_position_show(struct device *dev,
- static ssize_t applesmc_light_show(struct device *dev,
- struct device_attribute *attr, char *sysfsbuf)
- {
-+ struct applesmc_device *smc = dev_get_drvdata(dev);
- const struct applesmc_entry *entry;
- static int data_length;
- int ret;
-@@ -777,7 +840,7 @@ static ssize_t applesmc_light_show(struct device *dev,
- u8 buffer[10];
-
- if (!data_length) {
-- entry = applesmc_get_entry_by_key(LIGHT_SENSOR_LEFT_KEY);
-+ entry = applesmc_get_entry_by_key(smc, LIGHT_SENSOR_LEFT_KEY);
- if (IS_ERR(entry))
- return PTR_ERR(entry);
- if (entry->len > 10)
-@@ -786,7 +849,7 @@ static ssize_t applesmc_light_show(struct device *dev,
- pr_info("light sensor data length set to %d\n", data_length);
- }
-
-- ret = applesmc_read_key(LIGHT_SENSOR_LEFT_KEY, buffer, data_length);
-+ ret = applesmc_read_key(smc, LIGHT_SENSOR_LEFT_KEY, buffer, data_length);
- if (ret)
- goto out;
- /* newer macbooks report a single 10-bit bigendian value */
-@@ -796,7 +859,7 @@ static ssize_t applesmc_light_show(struct device *dev,
- }
- left = buffer[2];
-
-- ret = applesmc_read_key(LIGHT_SENSOR_RIGHT_KEY, buffer, data_length);
-+ ret = applesmc_read_key(smc, LIGHT_SENSOR_RIGHT_KEY, buffer, data_length);
- if (ret)
- goto out;
- right = buffer[2];
-@@ -812,7 +875,8 @@ static ssize_t applesmc_light_show(struct device *dev,
- static ssize_t applesmc_show_sensor_label(struct device *dev,
- struct device_attribute *devattr, char *sysfsbuf)
- {
-- const char *key = smcreg.index[to_index(devattr)];
-+ struct applesmc_device *smc = dev_get_drvdata(dev);
-+ const char *key = smc->reg.index[to_index(devattr)];
-
- return sysfs_emit(sysfsbuf, "%s\n", key);
- }
-@@ -821,12 +885,13 @@ static ssize_t applesmc_show_sensor_label(struct device *dev,
- static ssize_t applesmc_show_temperature(struct device *dev,
- struct device_attribute *devattr, char *sysfsbuf)
- {
-- const char *key = smcreg.index[to_index(devattr)];
-+ struct applesmc_device *smc = dev_get_drvdata(dev);
-+ const char *key = smc->reg.index[to_index(devattr)];
- int ret;
- s16 value;
- int temp;
-
-- ret = applesmc_read_s16(key, &value);
-+ ret = applesmc_read_s16(smc, key, &value);
- if (ret)
- return ret;
-
-@@ -838,6 +903,7 @@ static ssize_t applesmc_show_temperature(struct device *dev,
- static ssize_t applesmc_show_fan_speed(struct device *dev,
- struct device_attribute *attr, char *sysfsbuf)
- {
-+ struct applesmc_device *smc = dev_get_drvdata(dev);
- int ret;
- unsigned int speed = 0;
- char newkey[5];
-@@ -846,7 +912,7 @@ static ssize_t applesmc_show_fan_speed(struct device *dev,
- scnprintf(newkey, sizeof(newkey), fan_speed_fmt[to_option(attr)],
- to_index(attr));
-
-- ret = applesmc_read_key(newkey, buffer, 2);
-+ ret = applesmc_read_key(smc, newkey, buffer, 2);
- if (ret)
- return ret;
-
-@@ -858,6 +924,7 @@ static ssize_t applesmc_store_fan_speed(struct device *dev,
- struct device_attribute *attr,
- const char *sysfsbuf, size_t count)
- {
-+ struct applesmc_device *smc = dev_get_drvdata(dev);
- int ret;
- unsigned long speed;
- char newkey[5];
-@@ -871,7 +938,7 @@ static ssize_t applesmc_store_fan_speed(struct device *dev,
-
- buffer[0] = (speed >> 6) & 0xff;
- buffer[1] = (speed << 2) & 0xff;
-- ret = applesmc_write_key(newkey, buffer, 2);
-+ ret = applesmc_write_key(smc, newkey, buffer, 2);
-
- if (ret)
- return ret;
-@@ -882,11 +949,12 @@ static ssize_t applesmc_store_fan_speed(struct device *dev,
- static ssize_t applesmc_show_fan_manual(struct device *dev,
- struct device_attribute *attr, char *sysfsbuf)
- {
-+ struct applesmc_device *smc = dev_get_drvdata(dev);
- int ret;
- u16 manual = 0;
- u8 buffer[2];
-
-- ret = applesmc_read_key(FANS_MANUAL, buffer, 2);
-+ ret = applesmc_read_key(smc, FANS_MANUAL, buffer, 2);
- if (ret)
- return ret;
-
-@@ -898,6 +966,7 @@ static ssize_t applesmc_store_fan_manual(struct device *dev,
- struct device_attribute *attr,
- const char *sysfsbuf, size_t count)
- {
-+ struct applesmc_device *smc = dev_get_drvdata(dev);
- int ret;
- u8 buffer[2];
- unsigned long input;
-@@ -906,7 +975,7 @@ static ssize_t applesmc_store_fan_manual(struct device *dev,
- if (kstrtoul(sysfsbuf, 10, &input) < 0)
- return -EINVAL;
-
-- ret = applesmc_read_key(FANS_MANUAL, buffer, 2);
-+ ret = applesmc_read_key(smc, FANS_MANUAL, buffer, 2);
- if (ret)
- goto out;
-
-@@ -920,7 +989,7 @@ static ssize_t applesmc_store_fan_manual(struct device *dev,
- buffer[0] = (val >> 8) & 0xFF;
- buffer[1] = val & 0xFF;
-
-- ret = applesmc_write_key(FANS_MANUAL, buffer, 2);
-+ ret = applesmc_write_key(smc, FANS_MANUAL, buffer, 2);
-
- out:
- if (ret)
-@@ -932,13 +1001,14 @@ static ssize_t applesmc_store_fan_manual(struct device *dev,
- static ssize_t applesmc_show_fan_position(struct device *dev,
- struct device_attribute *attr, char *sysfsbuf)
- {
-+ struct applesmc_device *smc = dev_get_drvdata(dev);
- int ret;
- char newkey[5];
- u8 buffer[17];
-
- scnprintf(newkey, sizeof(newkey), FAN_ID_FMT, to_index(attr));
-
-- ret = applesmc_read_key(newkey, buffer, 16);
-+ ret = applesmc_read_key(smc, newkey, buffer, 16);
- buffer[16] = 0;
-
- if (ret)
-@@ -950,30 +1020,36 @@ static ssize_t applesmc_show_fan_position(struct device *dev,
- static ssize_t applesmc_calibrate_show(struct device *dev,
- struct device_attribute *attr, char *sysfsbuf)
- {
-- return sysfs_emit(sysfsbuf, "(%d,%d)\n", rest_x, rest_y);
-+ struct applesmc_device *smc = dev_get_drvdata(dev);
-+
-+ return sysfs_emit(sysfsbuf, "(%d,%d)\n", smc->rest_x, smc->rest_y);
- }
-
- static ssize_t applesmc_calibrate_store(struct device *dev,
- struct device_attribute *attr, const char *sysfsbuf, size_t count)
- {
-- applesmc_calibrate();
-+ struct applesmc_device *smc = dev_get_drvdata(dev);
-+
-+ applesmc_calibrate(smc);
-
- return count;
- }
-
- static void applesmc_backlight_set(struct work_struct *work)
- {
-- applesmc_write_key(BACKLIGHT_KEY, backlight_state, 2);
-+ struct applesmc_device *smc = container_of(work, struct applesmc_device, backlight_work);
-+
-+ applesmc_write_key(smc, BACKLIGHT_KEY, smc->backlight_state, 2);
- }
--static DECLARE_WORK(backlight_work, &applesmc_backlight_set);
-
- static void applesmc_brightness_set(struct led_classdev *led_cdev,
- enum led_brightness value)
- {
-+ struct applesmc_device *smc = dev_get_drvdata(led_cdev->dev);
- int ret;
-
-- backlight_state[0] = value;
-- ret = queue_work(applesmc_led_wq, &backlight_work);
-+ smc->backlight_state[0] = value;
-+ ret = queue_work(smc->backlight_wq, &smc->backlight_work);
-
- if (debug && (!ret))
- dev_dbg(led_cdev->dev, "work was already on the queue.\n");
-@@ -982,11 +1058,12 @@ static void applesmc_brightness_set(struct led_classdev *led_cdev,
- static ssize_t applesmc_key_count_show(struct device *dev,
- struct device_attribute *attr, char *sysfsbuf)
- {
-+ struct applesmc_device *smc = dev_get_drvdata(dev);
- int ret;
- u8 buffer[4];
- u32 count;
-
-- ret = applesmc_read_key(KEY_COUNT_KEY, buffer, 4);
-+ ret = applesmc_read_key(smc, KEY_COUNT_KEY, buffer, 4);
- if (ret)
- return ret;
-
-@@ -998,13 +1075,14 @@ static ssize_t applesmc_key_count_show(struct device *dev,
- static ssize_t applesmc_key_at_index_read_show(struct device *dev,
- struct device_attribute *attr, char *sysfsbuf)
- {
-+ struct applesmc_device *smc = dev_get_drvdata(dev);
- const struct applesmc_entry *entry;
- int ret;
-
-- entry = applesmc_get_entry_by_index(key_at_index);
-+ entry = applesmc_get_entry_by_index(smc, smc->key_at_index);
- if (IS_ERR(entry))
- return PTR_ERR(entry);
-- ret = applesmc_read_entry(entry, sysfsbuf, entry->len);
-+ ret = applesmc_read_entry(smc, entry, sysfsbuf, entry->len);
- if (ret)
- return ret;
-
-@@ -1014,9 +1092,10 @@ static ssize_t applesmc_key_at_index_read_show(struct device *dev,
- static ssize_t applesmc_key_at_index_data_length_show(struct device *dev,
- struct device_attribute *attr, char *sysfsbuf)
- {
-+ struct applesmc_device *smc = dev_get_drvdata(dev);
- const struct applesmc_entry *entry;
-
-- entry = applesmc_get_entry_by_index(key_at_index);
-+ entry = applesmc_get_entry_by_index(smc, smc->key_at_index);
- if (IS_ERR(entry))
- return PTR_ERR(entry);
-
-@@ -1026,9 +1105,10 @@ static ssize_t applesmc_key_at_index_data_length_show(struct device *dev,
- static ssize_t applesmc_key_at_index_type_show(struct device *dev,
- struct device_attribute *attr, char *sysfsbuf)
- {
-+ struct applesmc_device *smc = dev_get_drvdata(dev);
- const struct applesmc_entry *entry;
-
-- entry = applesmc_get_entry_by_index(key_at_index);
-+ entry = applesmc_get_entry_by_index(smc, smc->key_at_index);
- if (IS_ERR(entry))
- return PTR_ERR(entry);
-
-@@ -1038,9 +1118,10 @@ static ssize_t applesmc_key_at_index_type_show(struct device *dev,
- static ssize_t applesmc_key_at_index_name_show(struct device *dev,
- struct device_attribute *attr, char *sysfsbuf)
- {
-+ struct applesmc_device *smc = dev_get_drvdata(dev);
- const struct applesmc_entry *entry;
-
-- entry = applesmc_get_entry_by_index(key_at_index);
-+ entry = applesmc_get_entry_by_index(smc, smc->key_at_index);
- if (IS_ERR(entry))
- return PTR_ERR(entry);
-
-@@ -1050,28 +1131,25 @@ static ssize_t applesmc_key_at_index_name_show(struct device *dev,
- static ssize_t applesmc_key_at_index_show(struct device *dev,
- struct device_attribute *attr, char *sysfsbuf)
- {
-- return sysfs_emit(sysfsbuf, "%d\n", key_at_index);
-+ struct applesmc_device *smc = dev_get_drvdata(dev);
-+
-+ return sysfs_emit(sysfsbuf, "%d\n", smc->key_at_index);
- }
-
- static ssize_t applesmc_key_at_index_store(struct device *dev,
- struct device_attribute *attr, const char *sysfsbuf, size_t count)
- {
-+ struct applesmc_device *smc = dev_get_drvdata(dev);
- unsigned long newkey;
-
- if (kstrtoul(sysfsbuf, 10, &newkey) < 0
-- || newkey >= smcreg.key_count)
-+ || newkey >= smc->reg.key_count)
- return -EINVAL;
-
-- key_at_index = newkey;
-+ smc->key_at_index = newkey;
- return count;
- }
-
--static struct led_classdev applesmc_backlight = {
-- .name = "smc::kbd_backlight",
-- .default_trigger = "nand-disk",
-- .brightness_set = applesmc_brightness_set,
--};
--
- static struct applesmc_node_group info_group[] = {
- { "name", applesmc_name_show },
- { "key_count", applesmc_key_count_show },
-@@ -1116,14 +1194,15 @@ static struct applesmc_node_group temp_group[] = {
- /*
- * applesmc_destroy_nodes - remove files and free associated memory
- */
--static void applesmc_destroy_nodes(struct applesmc_node_group *groups)
-+static void applesmc_destroy_nodes(struct applesmc_device *smc,
-+ struct applesmc_node_group *groups)
- {
- struct applesmc_node_group *grp;
- struct applesmc_dev_attr *node;
-
- for (grp = groups; grp->nodes; grp++) {
- for (node = grp->nodes; node->sda.dev_attr.attr.name; node++)
-- sysfs_remove_file(&pdev->dev.kobj,
-+ sysfs_remove_file(&smc->dev->dev.kobj,
- &node->sda.dev_attr.attr);
- kfree(grp->nodes);
- grp->nodes = NULL;
-@@ -1133,7 +1212,8 @@ static void applesmc_destroy_nodes(struct applesmc_node_group *groups)
- /*
- * applesmc_create_nodes - create a two-dimensional group of sysfs files
- */
--static int applesmc_create_nodes(struct applesmc_node_group *groups, int num)
-+static int applesmc_create_nodes(struct applesmc_device *smc,
-+ struct applesmc_node_group *groups, int num)
- {
- struct applesmc_node_group *grp;
- struct applesmc_dev_attr *node;
-@@ -1157,7 +1237,7 @@ static int applesmc_create_nodes(struct applesmc_node_group *groups, int num)
- sysfs_attr_init(attr);
- attr->name = node->name;
- attr->mode = 0444 | (grp->store ? 0200 : 0);
-- ret = sysfs_create_file(&pdev->dev.kobj, attr);
-+ ret = sysfs_create_file(&smc->dev->dev.kobj, attr);
- if (ret) {
- attr->name = NULL;
- goto out;
-@@ -1167,57 +1247,57 @@ static int applesmc_create_nodes(struct applesmc_node_group *groups, int num)
-
- return 0;
- out:
-- applesmc_destroy_nodes(groups);
-+ applesmc_destroy_nodes(smc, groups);
- return ret;
- }
-
- /* Create accelerometer resources */
--static int applesmc_create_accelerometer(void)
-+static int applesmc_create_accelerometer(struct applesmc_device *smc)
- {
- int ret;
-
-- if (!smcreg.has_accelerometer)
-+ if (!smc->reg.has_accelerometer)
- return 0;
-
-- ret = applesmc_create_nodes(accelerometer_group, 1);
-+ ret = applesmc_create_nodes(smc, accelerometer_group, 1);
- if (ret)
- goto out;
-
-- applesmc_idev = input_allocate_device();
-- if (!applesmc_idev) {
-+ smc->idev = input_allocate_device();
-+ if (!smc->idev) {
- ret = -ENOMEM;
- goto out_sysfs;
- }
-
- /* initial calibrate for the input device */
-- applesmc_calibrate();
-+ applesmc_calibrate(smc);
-
- /* initialize the input device */
-- applesmc_idev->name = "applesmc";
-- applesmc_idev->id.bustype = BUS_HOST;
-- applesmc_idev->dev.parent = &pdev->dev;
-- input_set_abs_params(applesmc_idev, ABS_X,
-+ smc->idev->name = "applesmc";
-+ smc->idev->id.bustype = BUS_HOST;
-+ smc->idev->dev.parent = &smc->dev->dev;
-+ input_set_abs_params(smc->idev, ABS_X,
- -256, 256, APPLESMC_INPUT_FUZZ, APPLESMC_INPUT_FLAT);
-- input_set_abs_params(applesmc_idev, ABS_Y,
-+ input_set_abs_params(smc->idev, ABS_Y,
- -256, 256, APPLESMC_INPUT_FUZZ, APPLESMC_INPUT_FLAT);
-
-- ret = input_setup_polling(applesmc_idev, applesmc_idev_poll);
-+ ret = input_setup_polling(smc->idev, applesmc_idev_poll);
- if (ret)
- goto out_idev;
-
-- input_set_poll_interval(applesmc_idev, APPLESMC_POLL_INTERVAL);
-+ input_set_poll_interval(smc->idev, APPLESMC_POLL_INTERVAL);
-
-- ret = input_register_device(applesmc_idev);
-+ ret = input_register_device(smc->idev);
- if (ret)
- goto out_idev;
-
- return 0;
-
- out_idev:
-- input_free_device(applesmc_idev);
-+ input_free_device(smc->idev);
-
- out_sysfs:
-- applesmc_destroy_nodes(accelerometer_group);
-+ applesmc_destroy_nodes(smc, accelerometer_group);
-
- out:
- pr_warn("driver init failed (ret=%d)!\n", ret);
-@@ -1225,44 +1305,55 @@ static int applesmc_create_accelerometer(void)
- }
-
- /* Release all resources used by the accelerometer */
--static void applesmc_release_accelerometer(void)
-+static void applesmc_release_accelerometer(struct applesmc_device *smc)
- {
-- if (!smcreg.has_accelerometer)
-+ if (!smc->reg.has_accelerometer)
- return;
-- input_unregister_device(applesmc_idev);
-- applesmc_destroy_nodes(accelerometer_group);
-+ input_unregister_device(smc->idev);
-+ applesmc_destroy_nodes(smc, accelerometer_group);
- }
-
--static int applesmc_create_light_sensor(void)
-+static int applesmc_create_light_sensor(struct applesmc_device *smc)
- {
-- if (!smcreg.num_light_sensors)
-+ if (!smc->reg.num_light_sensors)
- return 0;
-- return applesmc_create_nodes(light_sensor_group, 1);
-+ return applesmc_create_nodes(smc, light_sensor_group, 1);
- }
-
--static void applesmc_release_light_sensor(void)
-+static void applesmc_release_light_sensor(struct applesmc_device *smc)
- {
-- if (!smcreg.num_light_sensors)
-+ if (!smc->reg.num_light_sensors)
- return;
-- applesmc_destroy_nodes(light_sensor_group);
-+ applesmc_destroy_nodes(smc, light_sensor_group);
- }
-
--static int applesmc_create_key_backlight(void)
-+static int applesmc_create_key_backlight(struct applesmc_device *smc)
- {
-- if (!smcreg.has_key_backlight)
-+ int ret;
-+
-+ if (!smc->reg.has_key_backlight)
- return 0;
-- applesmc_led_wq = create_singlethread_workqueue("applesmc-led");
-- if (!applesmc_led_wq)
-+ smc->backlight_wq = create_singlethread_workqueue("applesmc-led");
-+ if (!smc->backlight_wq)
- return -ENOMEM;
-- return led_classdev_register(&pdev->dev, &applesmc_backlight);
-+
-+ INIT_WORK(&smc->backlight_work, applesmc_backlight_set);
-+ smc->backlight_dev.name = "smc::kbd_backlight";
-+ smc->backlight_dev.default_trigger = "nand-disk";
-+ smc->backlight_dev.brightness_set = applesmc_brightness_set;
-+ ret = led_classdev_register(&smc->dev->dev, &smc->backlight_dev);
-+ if (ret)
-+ destroy_workqueue(smc->backlight_wq);
-+
-+ return ret;
- }
-
--static void applesmc_release_key_backlight(void)
-+static void applesmc_release_key_backlight(struct applesmc_device *smc)
- {
-- if (!smcreg.has_key_backlight)
-+ if (!smc->reg.has_key_backlight)
- return;
-- led_classdev_unregister(&applesmc_backlight);
-- destroy_workqueue(applesmc_led_wq);
-+ led_classdev_unregister(&smc->backlight_dev);
-+ destroy_workqueue(smc->backlight_wq);
- }
-
- static int applesmc_dmi_match(const struct dmi_system_id *id)
-@@ -1302,86 +1393,100 @@ static const struct dmi_system_id applesmc_whitelist[] __initconst = {
- { .ident = NULL }
- };
-
--static int __init applesmc_init(void)
-+static int applesmc_create_modules(struct applesmc_device *smc)
- {
- int ret;
-
-- if (!dmi_check_system(applesmc_whitelist)) {
-- pr_warn("supported laptop not found!\n");
-- ret = -ENODEV;
-- goto out;
-- }
--
-- if (!request_region(APPLESMC_DATA_PORT, APPLESMC_NR_PORTS,
-- "applesmc")) {
-- ret = -ENXIO;
-- goto out;
-- }
--
-- ret = platform_driver_register(&applesmc_driver);
-- if (ret)
-- goto out_region;
--
-- pdev = platform_device_register_simple("applesmc", APPLESMC_DATA_PORT,
-- NULL, 0);
-- if (IS_ERR(pdev)) {
-- ret = PTR_ERR(pdev);
-- goto out_driver;
-- }
--
-- /* create register cache */
-- ret = applesmc_init_smcreg();
-- if (ret)
-- goto out_device;
--
-- ret = applesmc_create_nodes(info_group, 1);
-+ ret = applesmc_create_nodes(smc, info_group, 1);
- if (ret)
-- goto out_smcreg;
-+ goto out;
-
-- ret = applesmc_create_nodes(fan_group, smcreg.fan_count);
-+ ret = applesmc_create_nodes(smc, fan_group, smc->reg.fan_count);
- if (ret)
- goto out_info;
-
-- ret = applesmc_create_nodes(temp_group, smcreg.index_count);
-+ ret = applesmc_create_nodes(smc, temp_group, smc->reg.index_count);
- if (ret)
- goto out_fans;
-
-- ret = applesmc_create_accelerometer();
-+ ret = applesmc_create_accelerometer(smc);
- if (ret)
- goto out_temperature;
-
-- ret = applesmc_create_light_sensor();
-+ ret = applesmc_create_light_sensor(smc);
- if (ret)
- goto out_accelerometer;
-
-- ret = applesmc_create_key_backlight();
-+ ret = applesmc_create_key_backlight(smc);
- if (ret)
- goto out_light_sysfs;
-
-- hwmon_dev = hwmon_device_register(&pdev->dev);
-- if (IS_ERR(hwmon_dev)) {
-- ret = PTR_ERR(hwmon_dev);
-+ smc->hwmon_dev = hwmon_device_register(&smc->dev->dev);
-+ if (IS_ERR(smc->hwmon_dev)) {
-+ ret = PTR_ERR(smc->hwmon_dev);
- goto out_light_ledclass;
- }
-
- return 0;
-
- out_light_ledclass:
-- applesmc_release_key_backlight();
-+ applesmc_release_key_backlight(smc);
- out_light_sysfs:
-- applesmc_release_light_sensor();
-+ applesmc_release_light_sensor(smc);
- out_accelerometer:
-- applesmc_release_accelerometer();
-+ applesmc_release_accelerometer(smc);
- out_temperature:
-- applesmc_destroy_nodes(temp_group);
-+ applesmc_destroy_nodes(smc, temp_group);
- out_fans:
-- applesmc_destroy_nodes(fan_group);
-+ applesmc_destroy_nodes(smc, fan_group);
- out_info:
-- applesmc_destroy_nodes(info_group);
--out_smcreg:
-- applesmc_destroy_smcreg();
--out_device:
-- platform_device_unregister(pdev);
-+ applesmc_destroy_nodes(smc, info_group);
-+out:
-+ return ret;
-+}
-+
-+static void applesmc_destroy_modules(struct applesmc_device *smc)
-+{
-+ hwmon_device_unregister(smc->hwmon_dev);
-+ applesmc_release_key_backlight(smc);
-+ applesmc_release_light_sensor(smc);
-+ applesmc_release_accelerometer(smc);
-+ applesmc_destroy_nodes(smc, temp_group);
-+ applesmc_destroy_nodes(smc, fan_group);
-+ applesmc_destroy_nodes(smc, info_group);
-+}
-+
-+static struct platform_device *pdev;
-+
-+static int __init applesmc_init(void)
-+{
-+ int ret;
-+
-+ if (!dmi_check_system(applesmc_whitelist)) {
-+ pr_warn("supported laptop not found!\n");
-+ ret = -ENODEV;
-+ goto out;
-+ }
-+
-+ if (!request_region(APPLESMC_DATA_PORT, APPLESMC_NR_PORTS,
-+ "applesmc")) {
-+ ret = -ENXIO;
-+ goto out;
-+ }
-+
-+ ret = platform_driver_register(&applesmc_driver);
-+ if (ret)
-+ goto out_region;
-+
-+ pdev = platform_device_register_simple("applesmc", APPLESMC_DATA_PORT,
-+ NULL, 0);
-+ if (IS_ERR(pdev)) {
-+ ret = PTR_ERR(pdev);
-+ goto out_driver;
-+ }
-+
-+ return 0;
-+
- out_driver:
- platform_driver_unregister(&applesmc_driver);
- out_region:
-@@ -1393,14 +1498,6 @@ static int __init applesmc_init(void)
-
- static void __exit applesmc_exit(void)
- {
-- hwmon_device_unregister(hwmon_dev);
-- applesmc_release_key_backlight();
-- applesmc_release_light_sensor();
-- applesmc_release_accelerometer();
-- applesmc_destroy_nodes(temp_group);
-- applesmc_destroy_nodes(fan_group);
-- applesmc_destroy_nodes(info_group);
-- applesmc_destroy_smcreg();
- platform_device_unregister(pdev);
- platform_driver_unregister(&applesmc_driver);
- release_region(APPLESMC_DATA_PORT, APPLESMC_NR_PORTS);
-@@ -1410,6 +1507,7 @@ module_init(applesmc_init);
- module_exit(applesmc_exit);
-
- MODULE_AUTHOR("Nicolas Boichat");
-+MODULE_AUTHOR("Paul Pawlowski");
- MODULE_DESCRIPTION("Apple SMC");
- MODULE_LICENSE("GPL v2");
- MODULE_DEVICE_TABLE(dmi, applesmc_whitelist);
---
-2.30.0
-
-From 713e78b8dbb8adb92d4ee09ea11e726b05577689 Mon Sep 17 00:00:00 2001
-From: Paul Pawlowski <paul@mrarm.io>
-Date: Sun, 17 Nov 2019 23:11:56 +0100
-Subject: [PATCH 2/6] applesmc: make io port base addr dynamic
-
-This change makes the port base runtime configurable.
-The reason why this change is made is so that when we switch to an
-acpi_device we can resolve the port base addr from ACPI.
-
-This change is not strictly required for T2 support - the base
-address is still 0x300 on T2 Macs.
-
-Signed-off-by: Aun-Ali Zaidi <admin@kodeit.net>
----
- drivers/hwmon/applesmc.c | 91 +++++++++++++++++++++-------------------
- 1 file changed, 49 insertions(+), 42 deletions(-)
-
-diff --git a/drivers/hwmon/applesmc.c b/drivers/hwmon/applesmc.c
-index 62211b590a61..39ed0bb21365 100644
---- a/drivers/hwmon/applesmc.c
-+++ b/drivers/hwmon/applesmc.c
-@@ -35,10 +35,11 @@
- #include <linux/err.h>
- #include <linux/bits.h>
-
-+#define APPLESMC_PORT_BASE 0x300
- /* data port used by Apple SMC */
--#define APPLESMC_DATA_PORT 0x300
-+#define APPLESMC_DATA_PORT 0
- /* command/status port used by Apple SMC */
--#define APPLESMC_CMD_PORT 0x304
-+#define APPLESMC_CMD_PORT 4
-
- #define APPLESMC_NR_PORTS 32 /* 0x300-0x31f */
-
-@@ -140,6 +141,8 @@ struct applesmc_device {
- struct platform_device *dev;
- struct applesmc_registers reg;
-
-+ u16 port_base;
-+
- s16 rest_x;
- s16 rest_y;
-
-@@ -169,7 +172,7 @@ static const int debug;
- * run out past 500ms.
- */
-
--static int wait_status(u8 val, u8 mask)
-+static int wait_status(struct applesmc_device *smc, u8 val, u8 mask)
- {
- u8 status;
- int us;
-@@ -177,7 +180,7 @@ static int wait_status(u8 val, u8 mask)
-
- us = APPLESMC_MIN_WAIT;
- for (i = 0; i < 24 ; i++) {
-- status = inb(APPLESMC_CMD_PORT);
-+ status = inb(smc->port_base + APPLESMC_CMD_PORT);
- if ((status & mask) == val)
- return 0;
- usleep_range(us, us * 2);
-@@ -189,11 +192,11 @@ static int wait_status(u8 val, u8 mask)
-
- /* send_byte - Write to SMC data port. Callers must hold applesmc_lock. */
-
--static int send_byte(u8 cmd, u16 port)
-+static int send_byte(struct applesmc_device *smc, u8 cmd, u16 port)
- {
- int status;
-
-- status = wait_status(0, SMC_STATUS_IB_CLOSED);
-+ status = wait_status(smc, 0, SMC_STATUS_IB_CLOSED);
- if (status)
- return status;
- /*
-@@ -202,24 +205,24 @@ static int send_byte(u8 cmd, u16 port)
- * this extra read may not happen if status returns both
- * simultaneously and this would appear to be required.
- */
-- status = wait_status(SMC_STATUS_BUSY, SMC_STATUS_BUSY);
-+ status = wait_status(smc, SMC_STATUS_BUSY, SMC_STATUS_BUSY);
- if (status)
- return status;
-
-- outb(cmd, port);
-+ outb(cmd, smc->port_base + port);
- return 0;
- }
-
- /* send_command - Write a command to the SMC. Callers must hold applesmc_lock. */
-
--static int send_command(u8 cmd)
-+static int send_command(struct applesmc_device *smc, u8 cmd)
- {
- int ret;
-
-- ret = wait_status(0, SMC_STATUS_IB_CLOSED);
-+ ret = wait_status(smc, 0, SMC_STATUS_IB_CLOSED);
- if (ret)
- return ret;
-- outb(cmd, APPLESMC_CMD_PORT);
-+ outb(cmd, smc->port_base + APPLESMC_CMD_PORT);
- return 0;
- }
-
-@@ -229,108 +232,112 @@ static int send_command(u8 cmd)
- * If busy is stuck high after the command then the SMC is jammed.
- */
-
--static int smc_sane(void)
-+static int smc_sane(struct applesmc_device *smc)
- {
- int ret;
-
-- ret = wait_status(0, SMC_STATUS_BUSY);
-+ ret = wait_status(smc, 0, SMC_STATUS_BUSY);
- if (!ret)
- return ret;
-- ret = send_command(APPLESMC_READ_CMD);
-+ ret = send_command(smc, APPLESMC_READ_CMD);
- if (ret)
- return ret;
-- return wait_status(0, SMC_STATUS_BUSY);
-+ return wait_status(smc, 0, SMC_STATUS_BUSY);
- }
-
--static int send_argument(const char *key)
-+static int send_argument(struct applesmc_device *smc, const char *key)
- {
- int i;
-
- for (i = 0; i < 4; i++)
-- if (send_byte(key[i], APPLESMC_DATA_PORT))
-+ if (send_byte(smc, key[i], APPLESMC_DATA_PORT))
- return -EIO;
- return 0;
- }
-
--static int read_smc(u8 cmd, const char *key, u8 *buffer, u8 len)
-+static int read_smc(struct applesmc_device *smc, u8 cmd, const char *key,
-+ u8 *buffer, u8 len)
- {
- u8 status, data = 0;
- int i;
- int ret;
-
-- ret = smc_sane();
-+ ret = smc_sane(smc);
- if (ret)
- return ret;
-
-- if (send_command(cmd) || send_argument(key)) {
-+ if (send_command(smc, cmd) || send_argument(smc, key)) {
- pr_warn("%.4s: read arg fail\n", key);
- return -EIO;
- }
-
- /* This has no effect on newer (2012) SMCs */
-- if (send_byte(len, APPLESMC_DATA_PORT)) {
-+ if (send_byte(smc, len, APPLESMC_DATA_PORT)) {
- pr_warn("%.4s: read len fail\n", key);
- return -EIO;
- }
-
- for (i = 0; i < len; i++) {
-- if (wait_status(SMC_STATUS_AWAITING_DATA | SMC_STATUS_BUSY,
-+ if (wait_status(smc,
-+ SMC_STATUS_AWAITING_DATA | SMC_STATUS_BUSY,
- SMC_STATUS_AWAITING_DATA | SMC_STATUS_BUSY)) {
- pr_warn("%.4s: read data[%d] fail\n", key, i);
- return -EIO;
- }
-- buffer[i] = inb(APPLESMC_DATA_PORT);
-+ buffer[i] = inb(smc->port_base + APPLESMC_DATA_PORT);
- }
-
- /* Read the data port until bit0 is cleared */
- for (i = 0; i < 16; i++) {
- udelay(APPLESMC_MIN_WAIT);
-- status = inb(APPLESMC_CMD_PORT);
-+ status = inb(smc->port_base + APPLESMC_CMD_PORT);
- if (!(status & SMC_STATUS_AWAITING_DATA))
- break;
-- data = inb(APPLESMC_DATA_PORT);
-+ data = inb(smc->port_base + APPLESMC_DATA_PORT);
- }
- if (i)
- pr_warn("flushed %d bytes, last value is: %d\n", i, data);
-
-- return wait_status(0, SMC_STATUS_BUSY);
-+ return wait_status(smc, 0, SMC_STATUS_BUSY);
- }
-
--static int write_smc(u8 cmd, const char *key, const u8 *buffer, u8 len)
-+static int write_smc(struct applesmc_device *smc, u8 cmd, const char *key,
-+ const u8 *buffer, u8 len)
- {
- int i;
- int ret;
-
-- ret = smc_sane();
-+ ret = smc_sane(smc);
- if (ret)
- return ret;
-
-- if (send_command(cmd) || send_argument(key)) {
-+ if (send_command(smc, cmd) || send_argument(smc, key)) {
- pr_warn("%s: write arg fail\n", key);
- return -EIO;
- }
-
-- if (send_byte(len, APPLESMC_DATA_PORT)) {
-+ if (send_byte(smc, len, APPLESMC_DATA_PORT)) {
- pr_warn("%.4s: write len fail\n", key);
- return -EIO;
- }
-
- for (i = 0; i < len; i++) {
-- if (send_byte(buffer[i], APPLESMC_DATA_PORT)) {
-+ if (send_byte(smc, buffer[i], APPLESMC_DATA_PORT)) {
- pr_warn("%s: write data fail\n", key);
- return -EIO;
- }
- }
-
-- return wait_status(0, SMC_STATUS_BUSY);
-+ return wait_status(smc, 0, SMC_STATUS_BUSY);
- }
-
--static int read_register_count(unsigned int *count)
-+static int read_register_count(struct applesmc_device *smc,
-+ unsigned int *count)
- {
- __be32 be;
- int ret;
-
-- ret = read_smc(APPLESMC_READ_CMD, KEY_COUNT_KEY, (u8 *)&be, 4);
-+ ret = read_smc(smc, APPLESMC_READ_CMD, KEY_COUNT_KEY, (u8 *)&be, 4);
- if (ret)
- return ret;
-
-@@ -353,7 +360,7 @@ static int applesmc_read_entry(struct applesmc_device *smc,
- if (entry->len != len)
- return -EINVAL;
- mutex_lock(&smc->reg.mutex);
-- ret = read_smc(APPLESMC_READ_CMD, entry->key, buf, len);
-+ ret = read_smc(smc, APPLESMC_READ_CMD, entry->key, buf, len);
- mutex_unlock(&smc->reg.mutex);
-
- return ret;
-@@ -367,7 +374,7 @@ static int applesmc_write_entry(struct applesmc_device *smc,
- if (entry->len != len)
- return -EINVAL;
- mutex_lock(&smc->reg.mutex);
-- ret = write_smc(APPLESMC_WRITE_CMD, entry->key, buf, len);
-+ ret = write_smc(smc, APPLESMC_WRITE_CMD, entry->key, buf, len);
- mutex_unlock(&smc->reg.mutex);
- return ret;
- }
-@@ -388,10 +395,10 @@ static const struct applesmc_entry *applesmc_get_entry_by_index(
- if (cache->valid)
- goto out;
- be = cpu_to_be32(index);
-- ret = read_smc(APPLESMC_GET_KEY_BY_INDEX_CMD, (u8 *)&be, key, 4);
-+ ret = read_smc(smc, APPLESMC_GET_KEY_BY_INDEX_CMD, (u8 *)&be, key, 4);
- if (ret)
- goto out;
-- ret = read_smc(APPLESMC_GET_KEY_TYPE_CMD, key, info, 6);
-+ ret = read_smc(smc, APPLESMC_GET_KEY_TYPE_CMD, key, info, 6);
- if (ret)
- goto out;
-
-@@ -589,7 +596,7 @@ static int applesmc_init_smcreg_try(struct applesmc_device *smc)
- if (s->init_complete)
- return 0;
-
-- ret = read_register_count(&count);
-+ ret = read_register_count(smc, &count);
- if (ret)
- return ret;
-
-@@ -1468,7 +1475,7 @@ static int __init applesmc_init(void)
- goto out;
- }
-
-- if (!request_region(APPLESMC_DATA_PORT, APPLESMC_NR_PORTS,
-+ if (!request_region(APPLESMC_PORT_BASE, APPLESMC_NR_PORTS,
- "applesmc")) {
- ret = -ENXIO;
- goto out;
-@@ -1490,7 +1497,7 @@ static int __init applesmc_init(void)
- out_driver:
- platform_driver_unregister(&applesmc_driver);
- out_region:
-- release_region(APPLESMC_DATA_PORT, APPLESMC_NR_PORTS);
-+ release_region(APPLESMC_PORT_BASE, APPLESMC_NR_PORTS);
- out:
- pr_warn("driver init failed (ret=%d)!\n", ret);
- return ret;
-@@ -1500,7 +1507,7 @@ static void __exit applesmc_exit(void)
- {
- platform_device_unregister(pdev);
- platform_driver_unregister(&applesmc_driver);
-- release_region(APPLESMC_DATA_PORT, APPLESMC_NR_PORTS);
-+ release_region(APPLESMC_PORT_BASE, APPLESMC_NR_PORTS);
- }
-
- module_init(applesmc_init);
---
-2.30.0
-
-From ee3d4bf4a01bc94553bde2ae3e806a63a13faa12 Mon Sep 17 00:00:00 2001
-From: Paul Pawlowski <paul@mrarm.io>
-Date: Sun, 17 Nov 2019 23:12:08 +0100
-Subject: [PATCH 3/6] applesmc: switch to acpi_device (from platform)
-
-This change makes the change from platform_device
-to acpi_device. The rationale for this change is
-that on T2 Macs, an additional FixedMemory32
-region is needed for device operation, and it can
-be easily resolved via ACPI tables (this will be
-done in another commit).
-
-Additionally, on older Macs, the OS X driver also
-looks for the specified ACPI device to resolve
-its memory regions, and therefore this change
-should not result in any incompatibilities.
-
-Signed-off-by: Aun-Ali Zaidi <admin@kodeit.net>
----
- drivers/hwmon/applesmc.c | 125 ++++++++++++++++++++++++++-------------
- 1 file changed, 85 insertions(+), 40 deletions(-)
-
-diff --git a/drivers/hwmon/applesmc.c b/drivers/hwmon/applesmc.c
-index 39ed0bb21365..bdaaf696f7b6 100644
---- a/drivers/hwmon/applesmc.c
-+++ b/drivers/hwmon/applesmc.c
-@@ -19,7 +19,7 @@
- #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
- #include <linux/delay.h>
--#include <linux/platform_device.h>
-+#include <linux/acpi.h>
- #include <linux/input.h>
- #include <linux/kernel.h>
- #include <linux/slab.h>
-@@ -35,7 +35,6 @@
- #include <linux/err.h>
- #include <linux/bits.h>
-
--#define APPLESMC_PORT_BASE 0x300
- /* data port used by Apple SMC */
- #define APPLESMC_DATA_PORT 0
- /* command/status port used by Apple SMC */
-@@ -138,9 +137,10 @@ struct applesmc_registers {
- };
-
- struct applesmc_device {
-- struct platform_device *dev;
-+ struct acpi_device *dev;
- struct applesmc_registers reg;
-
-+ bool port_base_set;
- u16 port_base;
-
- s16 rest_x;
-@@ -692,9 +692,13 @@ static int applesmc_init_smcreg(struct applesmc_device *smc)
- }
-
- /* Device model stuff */
-+
-+static int applesmc_init_resources(struct applesmc_device *smc);
-+static void applesmc_free_resources(struct applesmc_device *smc);
- static int applesmc_create_modules(struct applesmc_device *smc);
- static void applesmc_destroy_modules(struct applesmc_device *smc);
--static int applesmc_probe(struct platform_device *dev)
-+
-+static int applesmc_add(struct acpi_device *dev)
- {
- struct applesmc_device *smc;
- int ret;
-@@ -705,12 +709,16 @@ static int applesmc_probe(struct platform_device *dev)
- smc->dev = dev;
- mutex_init(&smc->reg.mutex);
-
-- platform_set_drvdata(dev, smc);
-+ dev_set_drvdata(&dev->dev, smc);
-
-- ret = applesmc_init_smcreg(smc);
-+ ret = applesmc_init_resources(smc);
- if (ret)
- goto out_mem;
-
-+ ret = applesmc_init_smcreg(smc);
-+ if (ret)
-+ goto out_res;
-+
- applesmc_device_init(smc);
-
- ret = applesmc_create_modules(smc);
-@@ -721,20 +729,23 @@ static int applesmc_probe(struct platform_device *dev)
-
- out_reg:
- applesmc_destroy_smcreg(smc);
-+out_res:
-+ applesmc_free_resources(smc);
- out_mem:
-- platform_set_drvdata(dev, NULL);
-+ dev_set_drvdata(&dev->dev, NULL);
- mutex_destroy(&smc->reg.mutex);
- kfree(smc);
-
- return ret;
- }
-
--static int applesmc_remove(struct platform_device *dev)
-+static int applesmc_remove(struct acpi_device *dev)
- {
-- struct applesmc_device *smc = platform_get_drvdata(dev);
-+ struct applesmc_device *smc = dev_get_drvdata(&dev->dev);
-
- applesmc_destroy_modules(smc);
- applesmc_destroy_smcreg(smc);
-+ applesmc_free_resources(smc);
-
- mutex_destroy(&smc->reg.mutex);
- kfree(smc);
-@@ -742,6 +753,52 @@ static int applesmc_remove(struct platform_device *dev)
- return 0;
- }
-
-+static acpi_status applesmc_walk_resources(struct acpi_resource *res,
-+ void *data)
-+{
-+ struct applesmc_device *smc = data;
-+
-+ switch (res->type) {
-+ case ACPI_RESOURCE_TYPE_IO:
-+ if (!smc->port_base_set) {
-+ if (res->data.io.address_length < APPLESMC_NR_PORTS)
-+ return AE_ERROR;
-+ smc->port_base = res->data.io.minimum;
-+ smc->port_base_set = true;
-+ }
-+ return AE_OK;
-+
-+ case ACPI_RESOURCE_TYPE_END_TAG:
-+ if (smc->port_base_set)
-+ return AE_OK;
-+ else
-+ return AE_NOT_FOUND;
-+
-+ default:
-+ return AE_OK;
-+ }
-+}
-+
-+static int applesmc_init_resources(struct applesmc_device *smc)
-+{
-+ int ret;
-+
-+ ret = acpi_walk_resources(smc->dev->handle, METHOD_NAME__CRS,
-+ applesmc_walk_resources, smc);
-+ if (ACPI_FAILURE(ret))
-+ return -ENXIO;
-+
-+ if (!request_region(smc->port_base, APPLESMC_NR_PORTS, "applesmc"))
-+ return -ENXIO;
-+
-+ return 0;
-+}
-+
-+static void applesmc_free_resources(struct applesmc_device *smc)
-+{
-+ release_region(smc->port_base, APPLESMC_NR_PORTS);
-+}
-+
- /* Synchronize device with memorized backlight state */
- static int applesmc_pm_resume(struct device *dev)
- {
-@@ -763,18 +820,28 @@ static int applesmc_pm_restore(struct device *dev)
- return applesmc_pm_resume(dev);
- }
-
-+static const struct acpi_device_id applesmc_ids[] = {
-+ {"APP0001", 0},
-+ {"", 0},
-+};
-+
- static const struct dev_pm_ops applesmc_pm_ops = {
- .resume = applesmc_pm_resume,
- .restore = applesmc_pm_restore,
- };
-
--static struct platform_driver applesmc_driver = {
-- .probe = applesmc_probe,
-- .remove = applesmc_remove,
-- .driver = {
-- .name = "applesmc",
-- .pm = &applesmc_pm_ops,
-+static struct acpi_driver applesmc_driver = {
-+ .name = "applesmc",
-+ .class = "applesmc",
-+ .ids = applesmc_ids,
-+ .ops = {
-+ .add = applesmc_add,
-+ .remove = applesmc_remove
- },
-+ .drv = {
-+ .pm = &applesmc_pm_ops
-+ },
-+ .owner = THIS_MODULE
- };
-
- /*
-@@ -1262,7 +1329,6 @@ static int applesmc_create_nodes(struct applesmc_device *smc,
- static int applesmc_create_accelerometer(struct applesmc_device *smc)
- {
- int ret;
--
- if (!smc->reg.has_accelerometer)
- return 0;
-
-@@ -1463,8 +1529,6 @@ static void applesmc_destroy_modules(struct applesmc_device *smc)
- applesmc_destroy_nodes(smc, info_group);
- }
-
--static struct platform_device *pdev;
--
- static int __init applesmc_init(void)
- {
- int ret;
-@@ -1475,29 +1539,12 @@ static int __init applesmc_init(void)
- goto out;
- }
-
-- if (!request_region(APPLESMC_PORT_BASE, APPLESMC_NR_PORTS,
-- "applesmc")) {
-- ret = -ENXIO;
-- goto out;
-- }
--
-- ret = platform_driver_register(&applesmc_driver);
-+ ret = acpi_bus_register_driver(&applesmc_driver);
- if (ret)
-- goto out_region;
--
-- pdev = platform_device_register_simple("applesmc", APPLESMC_DATA_PORT,
-- NULL, 0);
-- if (IS_ERR(pdev)) {
-- ret = PTR_ERR(pdev);
-- goto out_driver;
-- }
-+ goto out;
-
- return 0;
-
--out_driver:
-- platform_driver_unregister(&applesmc_driver);
--out_region:
-- release_region(APPLESMC_PORT_BASE, APPLESMC_NR_PORTS);
- out:
- pr_warn("driver init failed (ret=%d)!\n", ret);
- return ret;
-@@ -1505,9 +1552,7 @@ static int __init applesmc_init(void)
-
- static void __exit applesmc_exit(void)
- {
-- platform_device_unregister(pdev);
-- platform_driver_unregister(&applesmc_driver);
-- release_region(APPLESMC_PORT_BASE, APPLESMC_NR_PORTS);
-+ acpi_bus_unregister_driver(&applesmc_driver);
- }
-
- module_init(applesmc_init);
---
-2.30.0
-
-From 43df89a1377782788760808d8ea4bcf0730effbb Mon Sep 17 00:00:00 2001
-From: Paul Pawlowski <paul@mrarm.io>
-Date: Sun, 17 Nov 2019 23:12:14 +0100
-Subject: [PATCH 4/6] applesmc: key interface wrappers
-
-This change replaces the read_smc and write_smc
-methods with wrappers, additionally removing the
-command id parameter from them (and introducing
-get_smc_key_by_index and get_smc_key_info).
-
-This is done as to allow simple implementation
-replacement on T2 Macs. The newly introduced
-methods mentioned in the previous paragraph need
-special handling on T2 and as such had to be
-separated.
-
-Signed-off-by: Aun-Ali Zaidi <admin@kodeit.net>
----
- drivers/hwmon/applesmc.c | 119 ++++++++++++++++++++++++++-------------
- 1 file changed, 79 insertions(+), 40 deletions(-)
-
-diff --git a/drivers/hwmon/applesmc.c b/drivers/hwmon/applesmc.c
-index bdaaf696f7b6..3017d8ca2c79 100644
---- a/drivers/hwmon/applesmc.c
-+++ b/drivers/hwmon/applesmc.c
-@@ -172,7 +172,7 @@ static const int debug;
- * run out past 500ms.
- */
-
--static int wait_status(struct applesmc_device *smc, u8 val, u8 mask)
-+static int port_wait_status(struct applesmc_device *smc, u8 val, u8 mask)
- {
- u8 status;
- int us;
-@@ -190,13 +190,13 @@ static int wait_status(struct applesmc_device *smc, u8 val, u8 mask)
- return -EIO;
- }
-
--/* send_byte - Write to SMC data port. Callers must hold applesmc_lock. */
-+/* port_send_byte - Write to SMC data port. Callers must hold applesmc_lock. */
-
--static int send_byte(struct applesmc_device *smc, u8 cmd, u16 port)
-+static int port_send_byte(struct applesmc_device *smc, u8 cmd, u16 port)
- {
- int status;
-
-- status = wait_status(smc, 0, SMC_STATUS_IB_CLOSED);
-+ status = port_wait_status(smc, 0, SMC_STATUS_IB_CLOSED);
- if (status)
- return status;
- /*
-@@ -205,7 +205,7 @@ static int send_byte(struct applesmc_device *smc, u8 cmd, u16 port)
- * this extra read may not happen if status returns both
- * simultaneously and this would appear to be required.
- */
-- status = wait_status(smc, SMC_STATUS_BUSY, SMC_STATUS_BUSY);
-+ status = port_wait_status(smc, SMC_STATUS_BUSY, SMC_STATUS_BUSY);
- if (status)
- return status;
-
-@@ -213,15 +213,16 @@ static int send_byte(struct applesmc_device *smc, u8 cmd, u16 port)
- return 0;
- }
-
--/* send_command - Write a command to the SMC. Callers must hold applesmc_lock. */
-+/* port_send_command - Write a command to the SMC. Callers must hold applesmc_lock. */
-
--static int send_command(struct applesmc_device *smc, u8 cmd)
-+static int port_send_command(struct applesmc_device *smc, u8 cmd)
- {
- int ret;
-
-- ret = wait_status(smc, 0, SMC_STATUS_IB_CLOSED);
-+ ret = port_wait_status(smc, 0, SMC_STATUS_IB_CLOSED);
- if (ret)
- return ret;
-+
- outb(cmd, smc->port_base + APPLESMC_CMD_PORT);
- return 0;
- }
-@@ -232,53 +233,53 @@ static int send_command(struct applesmc_device *smc, u8 cmd)
- * If busy is stuck high after the command then the SMC is jammed.
- */
-
--static int smc_sane(struct applesmc_device *smc)
-+static int port_smc_sane(struct applesmc_device *smc)
- {
- int ret;
-
-- ret = wait_status(smc, 0, SMC_STATUS_BUSY);
-+ ret = port_wait_status(smc, 0, SMC_STATUS_BUSY);
- if (!ret)
- return ret;
-- ret = send_command(smc, APPLESMC_READ_CMD);
-+ ret = port_send_command(smc, APPLESMC_READ_CMD);
- if (ret)
- return ret;
-- return wait_status(smc, 0, SMC_STATUS_BUSY);
-+ return port_wait_status(smc, 0, SMC_STATUS_BUSY);
- }
-
--static int send_argument(struct applesmc_device *smc, const char *key)
-+static int port_send_argument(struct applesmc_device *smc, const char *key)
- {
- int i;
-
- for (i = 0; i < 4; i++)
-- if (send_byte(smc, key[i], APPLESMC_DATA_PORT))
-+ if (port_send_byte(smc, key[i], APPLESMC_DATA_PORT))
- return -EIO;
- return 0;
- }
-
--static int read_smc(struct applesmc_device *smc, u8 cmd, const char *key,
-+static int port_read_smc(struct applesmc_device *smc, u8 cmd, const char *key,
- u8 *buffer, u8 len)
- {
- u8 status, data = 0;
- int i;
- int ret;
-
-- ret = smc_sane(smc);
-+ ret = port_smc_sane(smc);
- if (ret)
- return ret;
-
-- if (send_command(smc, cmd) || send_argument(smc, key)) {
-+ if (port_send_command(smc, cmd) || port_send_argument(smc, key)) {
- pr_warn("%.4s: read arg fail\n", key);
- return -EIO;
- }
-
- /* This has no effect on newer (2012) SMCs */
-- if (send_byte(smc, len, APPLESMC_DATA_PORT)) {
-+ if (port_send_byte(smc, len, APPLESMC_DATA_PORT)) {
- pr_warn("%.4s: read len fail\n", key);
- return -EIO;
- }
-
- for (i = 0; i < len; i++) {
-- if (wait_status(smc,
-+ if (port_wait_status(smc,
- SMC_STATUS_AWAITING_DATA | SMC_STATUS_BUSY,
- SMC_STATUS_AWAITING_DATA | SMC_STATUS_BUSY)) {
- pr_warn("%.4s: read data[%d] fail\n", key, i);
-@@ -298,37 +299,80 @@ static int read_smc(struct applesmc_device *smc, u8 cmd, const char *key,
- if (i)
- pr_warn("flushed %d bytes, last value is: %d\n", i, data);
-
-- return wait_status(smc, 0, SMC_STATUS_BUSY);
-+ return port_wait_status(smc, 0, SMC_STATUS_BUSY);
- }
-
--static int write_smc(struct applesmc_device *smc, u8 cmd, const char *key,
-+static int port_write_smc(struct applesmc_device *smc, u8 cmd, const char *key,
- const u8 *buffer, u8 len)
- {
- int i;
- int ret;
-
-- ret = smc_sane(smc);
-+ ret = port_smc_sane(smc);
- if (ret)
- return ret;
-
-- if (send_command(smc, cmd) || send_argument(smc, key)) {
-+ if (port_send_command(smc, cmd) || port_send_argument(smc, key)) {
- pr_warn("%s: write arg fail\n", key);
- return -EIO;
- }
-
-- if (send_byte(smc, len, APPLESMC_DATA_PORT)) {
-+ if (port_send_byte(smc, len, APPLESMC_DATA_PORT)) {
- pr_warn("%.4s: write len fail\n", key);
- return -EIO;
- }
-
- for (i = 0; i < len; i++) {
-- if (send_byte(smc, buffer[i], APPLESMC_DATA_PORT)) {
-+ if (port_send_byte(smc, buffer[i], APPLESMC_DATA_PORT)) {
- pr_warn("%s: write data fail\n", key);
- return -EIO;
- }
- }
-
-- return wait_status(smc, 0, SMC_STATUS_BUSY);
-+ return port_wait_status(smc, 0, SMC_STATUS_BUSY);
-+}
-+
-+static int port_get_smc_key_info(struct applesmc_device *smc,
-+ const char *key, struct applesmc_entry *info)
-+{
-+ int ret;
-+ u8 raw[6];
-+
-+ ret = port_read_smc(smc, APPLESMC_GET_KEY_TYPE_CMD, key, raw, 6);
-+ if (ret)
-+ return ret;
-+ info->len = raw[0];
-+ memcpy(info->type, &raw[1], 4);
-+ info->flags = raw[5];
-+ return 0;
-+}
-+
-+static int read_smc(struct applesmc_device *smc, const char *key,
-+ u8 *buffer, u8 len)
-+{
-+ return port_read_smc(smc, APPLESMC_READ_CMD, key, buffer, len);
-+}
-+
-+static int write_smc(struct applesmc_device *smc, const char *key,
-+ const u8 *buffer, u8 len)
-+{
-+ return port_write_smc(smc, APPLESMC_WRITE_CMD, key, buffer, len);
-+}
-+
-+static int get_smc_key_by_index(struct applesmc_device *smc,
-+ unsigned int index, char *key)
-+{
-+ __be32 be;
-+
-+ be = cpu_to_be32(index);
-+ return port_read_smc(smc, APPLESMC_GET_KEY_BY_INDEX_CMD,
-+ (const char *) &be, (u8 *) key, 4);
-+}
-+
-+static int get_smc_key_info(struct applesmc_device *smc, const char *key,
-+ struct applesmc_entry *info)
-+{
-+ return port_get_smc_key_info(smc, key, info);
- }
-
- static int read_register_count(struct applesmc_device *smc,
-@@ -337,8 +381,8 @@ static int read_register_count(struct applesmc_device *smc,
- __be32 be;
- int ret;
-
-- ret = read_smc(smc, APPLESMC_READ_CMD, KEY_COUNT_KEY, (u8 *)&be, 4);
-- if (ret)
-+ ret = read_smc(smc, KEY_COUNT_KEY, (u8 *)&be, 4);
-+ if (ret < 0)
- return ret;
-
- *count = be32_to_cpu(be);
-@@ -360,7 +404,7 @@ static int applesmc_read_entry(struct applesmc_device *smc,
- if (entry->len != len)
- return -EINVAL;
- mutex_lock(&smc->reg.mutex);
-- ret = read_smc(smc, APPLESMC_READ_CMD, entry->key, buf, len);
-+ ret = read_smc(smc, entry->key, buf, len);
- mutex_unlock(&smc->reg.mutex);
-
- return ret;
-@@ -374,7 +418,7 @@ static int applesmc_write_entry(struct applesmc_device *smc,
- if (entry->len != len)
- return -EINVAL;
- mutex_lock(&smc->reg.mutex);
-- ret = write_smc(smc, APPLESMC_WRITE_CMD, entry->key, buf, len);
-+ ret = write_smc(smc, entry->key, buf, len);
- mutex_unlock(&smc->reg.mutex);
- return ret;
- }
-@@ -383,8 +427,7 @@ static const struct applesmc_entry *applesmc_get_entry_by_index(
- struct applesmc_device *smc, int index)
- {
- struct applesmc_entry *cache = &smc->reg.cache[index];
-- u8 key[4], info[6];
-- __be32 be;
-+ char key[4];
- int ret = 0;
-
- if (cache->valid)
-@@ -394,18 +437,14 @@ static const struct applesmc_entry *applesmc_get_entry_by_index(
-
- if (cache->valid)
- goto out;
-- be = cpu_to_be32(index);
-- ret = read_smc(smc, APPLESMC_GET_KEY_BY_INDEX_CMD, (u8 *)&be, key, 4);
-+ ret = get_smc_key_by_index(smc, index, key);
- if (ret)
- goto out;
-- ret = read_smc(smc, APPLESMC_GET_KEY_TYPE_CMD, key, info, 6);
-+ memcpy(cache->key, key, 4);
-+
-+ ret = get_smc_key_info(smc, key, cache);
- if (ret)
- goto out;
--
-- memcpy(cache->key, key, 4);
-- cache->len = info[0];
-- memcpy(cache->type, &info[1], 4);
-- cache->flags = info[5];
- cache->valid = true;
-
- out:
---
-2.30.0
-
-From 799e7a54c62a36007f7874c58d7dac87c9651759 Mon Sep 17 00:00:00 2001
-From: Aun-Ali Zaidi <admin@kodeit.net>
-Date: Sun, 17 Nov 2019 23:12:16 +0100
-Subject: [PATCH 5/6] applesmc: basic mmio interface implementation
-
-This change introduces a basic MMIO-based
-interface implementation required to communicate
-with the SMC on T2 Macs. The MMIO interface is
-enabled only when it's supported on the running
-system.
-
-The MMIO interface replaces legacy port-based SMC
-key reads, writes and metadata requests (getting
-key by index and getting key info).
-
-(Based on patch by @mcmrarm)
-
-Signed-off-by: Aun-Ali Zaidi <admin@kodeit.net>
----
- drivers/hwmon/applesmc.c | 237 ++++++++++++++++++++++++++++++++++++++-
- 1 file changed, 231 insertions(+), 6 deletions(-)
-
-diff --git a/drivers/hwmon/applesmc.c b/drivers/hwmon/applesmc.c
-index 3017d8ca2c79..2d23bb9ad9dd 100644
---- a/drivers/hwmon/applesmc.c
-+++ b/drivers/hwmon/applesmc.c
-@@ -42,6 +42,18 @@
-
- #define APPLESMC_NR_PORTS 32 /* 0x300-0x31f */
-
-+#define APPLESMC_IOMEM_KEY_DATA 0
-+#define APPLESMC_IOMEM_KEY_STATUS 0x4005
-+#define APPLESMC_IOMEM_KEY_NAME 0x78
-+#define APPLESMC_IOMEM_KEY_DATA_LEN 0x7D
-+#define APPLESMC_IOMEM_KEY_SMC_ID 0x7E
-+#define APPLESMC_IOMEM_KEY_CMD 0x7F
-+#define APPLESMC_IOMEM_MIN_SIZE 0x4006
-+
-+#define APPLESMC_IOMEM_KEY_TYPE_CODE 0
-+#define APPLESMC_IOMEM_KEY_TYPE_DATA_LEN 5
-+#define APPLESMC_IOMEM_KEY_TYPE_FLAGS 6
-+
- #define APPLESMC_MAX_DATA_LENGTH 32
-
- /* Apple SMC status bits */
-@@ -138,10 +150,13 @@ struct applesmc_registers {
-
- struct applesmc_device {
- struct acpi_device *dev;
-+ struct device *ldev;
- struct applesmc_registers reg;
-
-- bool port_base_set;
-+ bool port_base_set, iomem_base_set;
- u16 port_base;
-+ u8 *__iomem iomem_base;
-+ u32 iomem_base_addr, iomem_base_size;
-
- s16 rest_x;
- s16 rest_y;
-@@ -347,16 +362,156 @@ static int port_get_smc_key_info(struct applesmc_device *smc,
- return 0;
- }
-
-+
-+/*
-+ * MMIO based communication.
-+ * TODO: Use updated mechanism for cmd timeout/retry
-+ */
-+
-+static void iomem_clear_status(struct applesmc_device *smc)
-+{
-+ if (ioread8(smc->iomem_base + APPLESMC_IOMEM_KEY_STATUS))
-+ iowrite8(0, smc->iomem_base + APPLESMC_IOMEM_KEY_STATUS);
-+}
-+
-+static int iomem_wait_read(struct applesmc_device *smc)
-+{
-+ u8 status;
-+ int us;
-+ int i;
-+
-+ us = APPLESMC_MIN_WAIT;
-+ for (i = 0; i < 24 ; i++) {
-+ status = ioread8(smc->iomem_base + APPLESMC_IOMEM_KEY_STATUS);
-+ if (status & 0x20)
-+ return 0;
-+ usleep_range(us, us * 2);
-+ if (i > 9)
-+ us <<= 1;
-+ }
-+
-+ dev_warn(smc->ldev, "%s... timeout\n", __func__);
-+ return -EIO;
-+}
-+
-+static int iomem_read_smc(struct applesmc_device *smc, u8 cmd, const char *key,
-+ u8 *buffer, u8 len)
-+{
-+ u8 err, remote_len;
-+ u32 key_int = *((u32 *) key);
-+
-+ iomem_clear_status(smc);
-+ iowrite32(key_int, smc->iomem_base + APPLESMC_IOMEM_KEY_NAME);
-+ iowrite32(0, smc->iomem_base + APPLESMC_IOMEM_KEY_SMC_ID);
-+ iowrite32(cmd, smc->iomem_base + APPLESMC_IOMEM_KEY_CMD);
-+
-+ if (iomem_wait_read(smc))
-+ return -EIO;
-+
-+ err = ioread8(smc->iomem_base + APPLESMC_IOMEM_KEY_CMD);
-+ if (err != 0) {
-+ dev_warn(smc->ldev, "read_smc_mmio(%x %8x/%.4s) failed: %u\n",
-+ cmd, key_int, key, err);
-+ return -EIO;
-+ }
-+
-+ if (cmd == APPLESMC_READ_CMD) {
-+ remote_len = ioread8(smc->iomem_base + APPLESMC_IOMEM_KEY_DATA_LEN);
-+ if (remote_len != len) {
-+ dev_warn(smc->ldev,
-+ "read_smc_mmio(%x %8x/%.4s) failed: buffer length mismatch (remote = %u, requested = %u)\n",
-+ cmd, key_int, key, remote_len, len);
-+ return -EINVAL;
-+ }
-+ } else {
-+ remote_len = len;
-+ }
-+
-+ memcpy_fromio(buffer, smc->iomem_base + APPLESMC_IOMEM_KEY_DATA,
-+ remote_len);
-+
-+ dev_dbg(smc->ldev, "read_smc_mmio(%x %8x/%.4s): buflen=%u reslen=%u\n",
-+ cmd, key_int, key, len, remote_len);
-+ print_hex_dump_bytes("read_smc_mmio(): ", DUMP_PREFIX_NONE, buffer, remote_len);
-+ return 0;
-+}
-+
-+static int iomem_get_smc_key_type(struct applesmc_device *smc, const char *key,
-+ struct applesmc_entry *e)
-+{
-+ u8 err;
-+ u8 cmd = APPLESMC_GET_KEY_TYPE_CMD;
-+ u32 key_int = *((u32 *) key);
-+
-+ iomem_clear_status(smc);
-+ iowrite32(key_int, smc->iomem_base + APPLESMC_IOMEM_KEY_NAME);
-+ iowrite32(0, smc->iomem_base + APPLESMC_IOMEM_KEY_SMC_ID);
-+ iowrite32(cmd, smc->iomem_base + APPLESMC_IOMEM_KEY_CMD);
-+
-+ if (iomem_wait_read(smc))
-+ return -EIO;
-+
-+ err = ioread8(smc->iomem_base + APPLESMC_IOMEM_KEY_CMD);
-+ if (err != 0) {
-+ dev_warn(smc->ldev, "get_smc_key_type_mmio(%.4s) failed: %u\n", key, err);
-+ return -EIO;
-+ }
-+
-+ e->len = ioread8(smc->iomem_base + APPLESMC_IOMEM_KEY_TYPE_DATA_LEN);
-+ *((uint32_t *) e->type) = ioread32(
-+ smc->iomem_base + APPLESMC_IOMEM_KEY_TYPE_CODE);
-+ e->flags = ioread8(smc->iomem_base + APPLESMC_IOMEM_KEY_TYPE_FLAGS);
-+
-+ dev_dbg(smc->ldev, "get_smc_key_type_mmio(%.4s): len=%u type=%.4s flags=%x\n",
-+ key, e->len, e->type, e->flags);
-+ return 0;
-+}
-+
-+static int iomem_write_smc(struct applesmc_device *smc, u8 cmd, const char *key,
-+ const u8 *buffer, u8 len)
-+{
-+ u8 err;
-+ u32 key_int = *((u32 *) key);
-+
-+ iomem_clear_status(smc);
-+ iowrite32(key_int, smc->iomem_base + APPLESMC_IOMEM_KEY_NAME);
-+ memcpy_toio(smc->iomem_base + APPLESMC_IOMEM_KEY_DATA, buffer, len);
-+ iowrite32(len, smc->iomem_base + APPLESMC_IOMEM_KEY_DATA_LEN);
-+ iowrite32(0, smc->iomem_base + APPLESMC_IOMEM_KEY_SMC_ID);
-+ iowrite32(cmd, smc->iomem_base + APPLESMC_IOMEM_KEY_CMD);
-+
-+ if (iomem_wait_read(smc))
-+ return -EIO;
-+
-+ err = ioread8(smc->iomem_base + APPLESMC_IOMEM_KEY_CMD);
-+ if (err != 0) {
-+ dev_warn(smc->ldev, "write_smc_mmio(%x %.4s) failed: %u\n", cmd, key, err);
-+ print_hex_dump_bytes("write_smc_mmio(): ", DUMP_PREFIX_NONE, buffer, len);
-+ return -EIO;
-+ }
-+
-+ dev_dbg(smc->ldev, "write_smc_mmio(%x %.4s): buflen=%u\n", cmd, key, len);
-+ print_hex_dump_bytes("write_smc_mmio(): ", DUMP_PREFIX_NONE, buffer, len);
-+ return 0;
-+}
-+
-+
- static int read_smc(struct applesmc_device *smc, const char *key,
- u8 *buffer, u8 len)
- {
-- return port_read_smc(smc, APPLESMC_READ_CMD, key, buffer, len);
-+ if (smc->iomem_base_set)
-+ return iomem_read_smc(smc, APPLESMC_READ_CMD, key, buffer, len);
-+ else
-+ return port_read_smc(smc, APPLESMC_READ_CMD, key, buffer, len);
- }
-
- static int write_smc(struct applesmc_device *smc, const char *key,
- const u8 *buffer, u8 len)
- {
-- return port_write_smc(smc, APPLESMC_WRITE_CMD, key, buffer, len);
-+ if (smc->iomem_base_set)
-+ return iomem_write_smc(smc, APPLESMC_WRITE_CMD, key, buffer, len);
-+ else
-+ return port_write_smc(smc, APPLESMC_WRITE_CMD, key, buffer, len);
- }
-
- static int get_smc_key_by_index(struct applesmc_device *smc,
-@@ -365,14 +520,21 @@ static int get_smc_key_by_index(struct applesmc_device *smc,
- __be32 be;
-
- be = cpu_to_be32(index);
-- return port_read_smc(smc, APPLESMC_GET_KEY_BY_INDEX_CMD,
-- (const char *) &be, (u8 *) key, 4);
-+ if (smc->iomem_base_set)
-+ return iomem_read_smc(smc, APPLESMC_GET_KEY_BY_INDEX_CMD,
-+ (const char *) &be, (u8 *) key, 4);
-+ else
-+ return port_read_smc(smc, APPLESMC_GET_KEY_BY_INDEX_CMD,
-+ (const char *) &be, (u8 *) key, 4);
- }
-
- static int get_smc_key_info(struct applesmc_device *smc, const char *key,
- struct applesmc_entry *info)
- {
-- return port_get_smc_key_info(smc, key, info);
-+ if (smc->iomem_base_set)
-+ return iomem_get_smc_key_type(smc, key, info);
-+ else
-+ return port_get_smc_key_info(smc, key, info);
- }
-
- static int read_register_count(struct applesmc_device *smc,
-@@ -746,6 +908,7 @@ static int applesmc_add(struct acpi_device *dev)
- if (!smc)
- return -ENOMEM;
- smc->dev = dev;
-+ smc->ldev = &dev->dev;
- mutex_init(&smc->reg.mutex);
-
- dev_set_drvdata(&dev->dev, smc);
-@@ -807,6 +970,20 @@ static acpi_status applesmc_walk_resources(struct acpi_resource *res,
- }
- return AE_OK;
-
-+ case ACPI_RESOURCE_TYPE_FIXED_MEMORY32:
-+ if (!smc->iomem_base_set) {
-+ if (res->data.fixed_memory32.address_length <
-+ APPLESMC_IOMEM_MIN_SIZE) {
-+ dev_warn(smc->ldev, "found iomem but it's too small: %u\n",
-+ res->data.fixed_memory32.address_length);
-+ return AE_OK;
-+ }
-+ smc->iomem_base_addr = res->data.fixed_memory32.address;
-+ smc->iomem_base_size = res->data.fixed_memory32.address_length;
-+ smc->iomem_base_set = true;
-+ }
-+ return AE_OK;
-+
- case ACPI_RESOURCE_TYPE_END_TAG:
- if (smc->port_base_set)
- return AE_OK;
-@@ -818,6 +995,8 @@ static acpi_status applesmc_walk_resources(struct acpi_resource *res,
- }
- }
-
-+static int applesmc_try_enable_iomem(struct applesmc_device *smc);
-+
- static int applesmc_init_resources(struct applesmc_device *smc)
- {
- int ret;
-@@ -830,11 +1009,57 @@ static int applesmc_init_resources(struct applesmc_device *smc)
- if (!request_region(smc->port_base, APPLESMC_NR_PORTS, "applesmc"))
- return -ENXIO;
-
-+ if (smc->iomem_base_set) {
-+ if (applesmc_try_enable_iomem(smc))
-+ smc->iomem_base_set = false;
-+ }
-+
- return 0;
- }
-
-+static int applesmc_try_enable_iomem(struct applesmc_device *smc)
-+{
-+ u8 test_val, ldkn_version;
-+
-+ dev_dbg(smc->ldev, "Trying to enable iomem based communication\n");
-+ smc->iomem_base = ioremap(smc->iomem_base_addr, smc->iomem_base_size);
-+ if (!smc->iomem_base)
-+ goto out;
-+
-+ /* Apple's driver does this check for some reason */
-+ test_val = ioread8(smc->iomem_base + APPLESMC_IOMEM_KEY_STATUS);
-+ if (test_val == 0xff) {
-+ dev_warn(smc->ldev,
-+ "iomem enable failed: initial status is 0xff (is %x)\n",
-+ test_val);
-+ goto out_iomem;
-+ }
-+
-+ if (read_smc(smc, "LDKN", &ldkn_version, 1)) {
-+ dev_warn(smc->ldev, "iomem enable failed: ldkn read failed\n");
-+ goto out_iomem;
-+ }
-+
-+ if (ldkn_version < 2) {
-+ dev_warn(smc->ldev,
-+ "iomem enable failed: ldkn version %u is less than minimum (2)\n",
-+ ldkn_version);
-+ goto out_iomem;
-+ }
-+
-+ return 0;
-+
-+out_iomem:
-+ iounmap(smc->iomem_base);
-+
-+out:
-+ return -ENXIO;
-+}
-+
- static void applesmc_free_resources(struct applesmc_device *smc)
- {
-+ if (smc->iomem_base_set)
-+ iounmap(smc->iomem_base);
- release_region(smc->port_base, APPLESMC_NR_PORTS);
- }
-
---
-2.30.0
-
-From 4e63e9b77422aae8e7411ddc7a8458c2585c86df Mon Sep 17 00:00:00 2001
-From: Paul Pawlowski <paul@mrarm.io>
-Date: Sun, 17 Nov 2019 23:12:18 +0100
-Subject: [PATCH 6/6] applesmc: fan support on T2 Macs
-
-T2 Macs changed the fan values from shorts to
-floats, and changed the fan manual override
-setting from a bitmask to a per-fan boolean
-named F0Md (thanks to @kleuter for mentioning
-it).
-
-A minimal soft-float implementation has been
-written for convert floats to integers (and vice
-versa).
-
-Signed-off-by: Aun-Ali Zaidi <admin@kodeit.net>
----
- drivers/hwmon/applesmc.c | 119 +++++++++++++++++++++++++++++++++------
- 1 file changed, 102 insertions(+), 17 deletions(-)
-
-diff --git a/drivers/hwmon/applesmc.c b/drivers/hwmon/applesmc.c
-index 2d23bb9ad9dd..0938227be612 100644
---- a/drivers/hwmon/applesmc.c
-+++ b/drivers/hwmon/applesmc.c
-@@ -87,6 +87,7 @@
- #define FAN_ID_FMT "F%dID" /* r-o char[16] */
-
- #define TEMP_SENSOR_TYPE "sp78"
-+#define FLOAT_TYPE "flt "
-
- /* List of keys used to read/write fan speeds */
- static const char *const fan_speed_fmt[] = {
-@@ -96,6 +97,7 @@ static const char *const fan_speed_fmt[] = {
- "F%dSf", /* safe speed - not all models */
- "F%dTg", /* target speed (manual: rw) */
- };
-+#define FAN_MANUAL_FMT "F%dMd"
-
- #define INIT_TIMEOUT_MSECS 5000 /* wait up to 5s for device init ... */
- #define INIT_WAIT_MSECS 50 /* ... in 50ms increments */
-@@ -734,6 +736,42 @@ static int applesmc_read_s16(struct applesmc_device *smc,
- return 0;
- }
-
-+/**
-+ * applesmc_float_to_u32 - Retrieve the integral part of a float.
-+ * This is needed because Apple made fans use float values in the T2.
-+ * The fractional point is not significantly useful though, and the integral
-+ * part can be easily extracted.
-+ */
-+static inline u32 applesmc_float_to_u32(u32 d)
-+{
-+ u8 sign = (u8) ((d >> 31) & 1);
-+ s32 exp = (s32) ((d >> 23) & 0xff) - 0x7f;
-+ u32 fr = d & ((1u << 23) - 1);
-+
-+ if (sign || exp < 0)
-+ return 0;
-+
-+ return (u32) ((1u << exp) + (fr >> (23 - exp)));
-+}
-+
-+/**
-+ * applesmc_u32_to_float - Convert an u32 into a float.
-+ * See applesmc_float_to_u32 for a rationale.
-+ */
-+static inline u32 applesmc_u32_to_float(u32 d)
-+{
-+ u32 dc = d, bc = 0, exp;
-+
-+ if (!d)
-+ return 0;
-+
-+ while (dc >>= 1)
-+ ++bc;
-+ exp = 0x7f + bc;
-+
-+ return (u32) ((exp << 23) |
-+ ((d << (23 - (exp - 0x7f))) & ((1u << 23) - 1)));
-+}
- /*
- * applesmc_device_init - initialize the accelerometer. Can sleep.
- */
-@@ -1242,6 +1280,7 @@ static ssize_t applesmc_show_fan_speed(struct device *dev,
- struct device_attribute *attr, char *sysfsbuf)
- {
- struct applesmc_device *smc = dev_get_drvdata(dev);
-+ const struct applesmc_entry *entry;
- int ret;
- unsigned int speed = 0;
- char newkey[5];
-@@ -1250,11 +1289,21 @@ static ssize_t applesmc_show_fan_speed(struct device *dev,
- scnprintf(newkey, sizeof(newkey), fan_speed_fmt[to_option(attr)],
- to_index(attr));
-
-- ret = applesmc_read_key(smc, newkey, buffer, 2);
-+ entry = applesmc_get_entry_by_key(smc, newkey);
-+ if (IS_ERR(entry))
-+ return PTR_ERR(entry);
-+
-+ if (!strcmp(entry->type, FLOAT_TYPE)) {
-+ ret = applesmc_read_entry(smc, entry, (u8 *) &speed, 4);
-+ speed = applesmc_float_to_u32(speed);
-+ } else {
-+ ret = applesmc_read_entry(smc, entry, buffer, 2);
-+ speed = ((buffer[0] << 8 | buffer[1]) >> 2);
-+ }
-+
- if (ret)
- return ret;
-
-- speed = ((buffer[0] << 8 | buffer[1]) >> 2);
- return sysfs_emit(sysfsbuf, "%u\n", speed);
- }
-
-@@ -1263,6 +1312,7 @@ static ssize_t applesmc_store_fan_speed(struct device *dev,
- const char *sysfsbuf, size_t count)
- {
- struct applesmc_device *smc = dev_get_drvdata(dev);
-+ const struct applesmc_entry *entry;
- int ret;
- unsigned long speed;
- char newkey[5];
-@@ -1274,9 +1324,18 @@ static ssize_t applesmc_store_fan_speed(struct device *dev,
- scnprintf(newkey, sizeof(newkey), fan_speed_fmt[to_option(attr)],
- to_index(attr));
-
-- buffer[0] = (speed >> 6) & 0xff;
-- buffer[1] = (speed << 2) & 0xff;
-- ret = applesmc_write_key(smc, newkey, buffer, 2);
-+ entry = applesmc_get_entry_by_key(smc, newkey);
-+ if (IS_ERR(entry))
-+ return PTR_ERR(entry);
-+
-+ if (!strcmp(entry->type, FLOAT_TYPE)) {
-+ speed = applesmc_u32_to_float(speed);
-+ ret = applesmc_write_entry(smc, entry, (u8 *) &speed, 4);
-+ } else {
-+ buffer[0] = (speed >> 6) & 0xff;
-+ buffer[1] = (speed << 2) & 0xff;
-+ ret = applesmc_write_key(smc, newkey, buffer, 2);
-+ }
-
- if (ret)
- return ret;
-@@ -1291,12 +1350,26 @@ static ssize_t applesmc_show_fan_manual(struct device *dev,
- int ret;
- u16 manual = 0;
- u8 buffer[2];
-+ char newkey[5];
-+ bool has_newkey = false;
-+
-+ scnprintf(newkey, sizeof(newkey), FAN_MANUAL_FMT, to_index(attr));
-+
-+ ret = applesmc_has_key(smc, newkey, &has_newkey);
-+ if (ret)
-+ return ret;
-+
-+ if (has_newkey) {
-+ ret = applesmc_read_key(smc, newkey, buffer, 1);
-+ manual = buffer[0];
-+ } else {
-+ ret = applesmc_read_key(smc, FANS_MANUAL, buffer, 2);
-+ manual = ((buffer[0] << 8 | buffer[1]) >> to_index(attr)) & 0x01;
-+ }
-
-- ret = applesmc_read_key(smc, FANS_MANUAL, buffer, 2);
- if (ret)
- return ret;
-
-- manual = ((buffer[0] << 8 | buffer[1]) >> to_index(attr)) & 0x01;
- return sysfs_emit(sysfsbuf, "%d\n", manual);
- }
-
-@@ -1307,27 +1380,39 @@ static ssize_t applesmc_store_fan_manual(struct device *dev,
- struct applesmc_device *smc = dev_get_drvdata(dev);
- int ret;
- u8 buffer[2];
-+ char newkey[5];
-+ bool has_newkey = false;
- unsigned long input;
- u16 val;
-
- if (kstrtoul(sysfsbuf, 10, &input) < 0)
- return -EINVAL;
-
-- ret = applesmc_read_key(smc, FANS_MANUAL, buffer, 2);
-+ scnprintf(newkey, sizeof(newkey), FAN_MANUAL_FMT, to_index(attr));
-+
-+ ret = applesmc_has_key(smc, newkey, &has_newkey);
- if (ret)
-- goto out;
-+ return ret;
-
-- val = (buffer[0] << 8 | buffer[1]);
-+ if (has_newkey) {
-+ buffer[0] = input & 1;
-+ ret = applesmc_write_key(smc, newkey, buffer, 1);
-+ } else {
-+ ret = applesmc_read_key(smc, FANS_MANUAL, buffer, 2);
-+ val = (buffer[0] << 8 | buffer[1]);
-+ if (ret)
-+ goto out;
-
-- if (input)
-- val = val | (0x01 << to_index(attr));
-- else
-- val = val & ~(0x01 << to_index(attr));
-+ if (input)
-+ val = val | (0x01 << to_index(attr));
-+ else
-+ val = val & ~(0x01 << to_index(attr));
-
-- buffer[0] = (val >> 8) & 0xFF;
-- buffer[1] = val & 0xFF;
-+ buffer[0] = (val >> 8) & 0xFF;
-+ buffer[1] = val & 0xFF;
-
-- ret = applesmc_write_key(smc, FANS_MANUAL, buffer, 2);
-+ ret = applesmc_write_key(smc, FANS_MANUAL, buffer, 2);
-+ }
-
- out:
- if (ret)
---
-2.30.0
-
-From 58868e6f356229eab48cfdee1603011653a19c79 Mon Sep 17 00:00:00 2001
-From: Orlando Chamberlain <redecorating@protonmail.com>
-Date: Sun, 9 Oct 2022 15:59:01 +0530
-Subject: [PATCH] applesmc: Add iMacPro to applesmc_whitelist
-
-The iMacPro1,1 is the only iMacPro released before the line was
-discontinued. Add it to the applesmc_whitelist.
-
-Signed-off-by: Orlando Chamberlain <redecorating@protonmail.com>
----
- drivers/hwmon/applesmc.c | 4 ++++
- 1 file changed, 4 insertions(+)
-
-diff --git a/drivers/hwmon/applesmc.c b/drivers/hwmon/applesmc.c
-index 8b3f73fcb..493f95bb0 100644
---- a/drivers/hwmon/applesmc.c
-+++ b/drivers/hwmon/applesmc.c
-@@ -1804,6 +1804,10 @@ static const struct dmi_system_id applesmc_whitelist[] __initconst = {
- DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
- DMI_MATCH(DMI_PRODUCT_NAME, "Macmini") },
- },
-+ { applesmc_dmi_match, "Apple iMacPro", {
-+ DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
-+ DMI_MATCH(DMI_PRODUCT_NAME, "iMacPro") },
-+ },
- { applesmc_dmi_match, "Apple MacPro", {
- DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
- DMI_MATCH(DMI_PRODUCT_NAME, "MacPro") },
---
-2.34.1
-
-From e52b0fad357b6203691942831715fce4f26d66e2 Mon Sep 17 00:00:00 2001
-From: Orlando Chamberlain <orlandoch.dev@gmail.com>
-Date: Tue, 24 Jan 2023 15:46:48 +1100
-Subject: [PATCH 1/1] applesmc: make applesmc_remove void
-
-for linux6.2 compatibility
----
- drivers/hwmon/applesmc.c | 4 ++--
- 1 file changed, 2 insertions(+), 2 deletions(-)
-
-diff --git a/drivers/hwmon/applesmc.c b/drivers/hwmon/applesmc.c
-index d071130ff68d..12be9269a314 100644
---- a/drivers/hwmon/applesmc.c
-+++ b/drivers/hwmon/applesmc.c
-@@ -979,7 +979,7 @@ static int applesmc_add(struct acpi_device *dev)
- return ret;
- }
-
--static int applesmc_remove(struct acpi_device *dev)
-+static void applesmc_remove(struct acpi_device *dev)
- {
- struct applesmc_device *smc = dev_get_drvdata(&dev->dev);
-
-@@ -990,7 +990,7 @@ static int applesmc_remove(struct acpi_device *dev)
- mutex_destroy(&smc->reg.mutex);
- kfree(smc);
-
-- return 0;
-+ return;
- }
-
- static acpi_status applesmc_walk_resources(struct acpi_resource *res,
---
-2.39.1
-
-From 38786c7979c8ece013b5b7d5cb07dc2aa40198be Mon Sep 17 00:00:00 2001
-From: Orlando Chamberlain <orlandoch.dev@gmail.com>
-Date: Mon, 30 Jan 2023 18:42:21 +1100
-Subject: [PATCH 1/1] applesmc: battery charge limiter
-
----
- drivers/hwmon/applesmc.c | 42 +++++++++++++++++++++++++++++++++++++++-
- 1 file changed, 41 insertions(+), 1 deletion(-)
-
-diff --git a/drivers/hwmon/applesmc.c b/drivers/hwmon/applesmc.c
-index 12be9269a314..bc1eec74cfef 100644
---- a/drivers/hwmon/applesmc.c
-+++ b/drivers/hwmon/applesmc.c
-@@ -1478,6 +1478,35 @@ static void applesmc_brightness_set(struct led_classdev *led_cdev,
- dev_dbg(led_cdev->dev, "work was already on the queue.\n");
- }
-
-+static ssize_t applesmc_BCLM_store(struct device *dev,
-+ struct device_attribute *attr, char *sysfsbuf, size_t count)
-+{
-+ struct applesmc_device *smc = dev_get_drvdata(dev);
-+ u8 val;
-+
-+ if (kstrtou8(sysfsbuf, 10, &val) < 0)
-+ return -EINVAL;
-+
-+ if (val < 0 || val > 100)
-+ return -EINVAL;
-+
-+ if (applesmc_write_key(smc, "BCLM", &val, 1))
-+ return -ENODEV;
-+ return count;
-+}
-+
-+static ssize_t applesmc_BCLM_show(struct device *dev,
-+ struct device_attribute *attr, char *sysfsbuf)
-+{
-+ struct applesmc_device *smc = dev_get_drvdata(dev);
-+ u8 val;
-+
-+ if (applesmc_read_key(smc, "BCLM", &val, 1))
-+ return -ENODEV;
-+
-+ return sysfs_emit(sysfsbuf, "%d\n", val);
-+}
-+
- static ssize_t applesmc_key_count_show(struct device *dev,
- struct device_attribute *attr, char *sysfsbuf)
- {
-@@ -1612,6 +1641,11 @@ static struct applesmc_node_group temp_group[] = {
- { }
- };
-
-+static struct applesmc_node_group BCLM_group[] = {
-+ { "battery_charge_limit", applesmc_BCLM_show, applesmc_BCLM_store },
-+ { }
-+};
-+
- /* Module stuff */
-
- /*
-@@ -1830,10 +1864,13 @@ static int applesmc_create_modules(struct applesmc_device *smc)
- ret = applesmc_create_nodes(smc, info_group, 1);
- if (ret)
- goto out;
-+ ret = applesmc_create_nodes(smc, BCLM_group, 1);
-+ if (ret)
-+ goto out_info;
-
- ret = applesmc_create_nodes(smc, fan_group, smc->reg.fan_count);
- if (ret)
-- goto out_info;
-+ goto out_bclm;
-
- ret = applesmc_create_nodes(smc, temp_group, smc->reg.index_count);
- if (ret)
-@@ -1869,6 +1906,8 @@ static int applesmc_create_modules(struct applesmc_device *smc)
- applesmc_destroy_nodes(smc, temp_group);
- out_fans:
- applesmc_destroy_nodes(smc, fan_group);
-+out_bclm:
-+ applesmc_destroy_nodes(smc, BCLM_group);
- out_info:
- applesmc_destroy_nodes(smc, info_group);
- out:
-@@ -1883,6 +1922,7 @@ static void applesmc_destroy_modules(struct applesmc_device *smc)
- applesmc_release_accelerometer(smc);
- applesmc_destroy_nodes(smc, temp_group);
- applesmc_destroy_nodes(smc, fan_group);
-+ applesmc_destroy_nodes(smc, BCLM_group);
- applesmc_destroy_nodes(smc, info_group);
- }
-
---
-2.39.1
-
-From 327e6e1d0f6e8db68c124dff4d6a326b381ccedb Mon Sep 17 00:00:00 2001
-From: Aun-Ali Zaidi <admin@kodeit.net>
-Date: Wed, 23 Mar 2022 17:12:21 +0530
-Subject: [PATCH] Input: bcm5974 - Add support for the T2 Macs
-
----
- drivers/input/mouse/bcm5974.c | 138 ++++++++++++++++++++++++++++++++++
- 1 file changed, 138 insertions(+)
-
-diff --git a/drivers/input/mouse/bcm5974.c b/drivers/input/mouse/bcm5974.c
-index 59a14505b..88f17f21a 100644
---- a/drivers/input/mouse/bcm5974.c
-+++ b/drivers/input/mouse/bcm5974.c
-@@ -83,6 +83,24 @@
- #define USB_DEVICE_ID_APPLE_WELLSPRING9_ISO 0x0273
- #define USB_DEVICE_ID_APPLE_WELLSPRING9_JIS 0x0274
-
-+/* T2-Attached Devices */
-+/* MacbookAir8,1 (2018) */
-+#define USB_DEVICE_ID_APPLE_WELLSPRINGT2_J140K 0x027a
-+/* MacbookPro15,2 (2018) */
-+#define USB_DEVICE_ID_APPLE_WELLSPRINGT2_J132 0x027b
-+/* MacbookPro15,1 (2018) */
-+#define USB_DEVICE_ID_APPLE_WELLSPRINGT2_J680 0x027c
-+/* MacbookPro15,4 (2019) */
-+#define USB_DEVICE_ID_APPLE_WELLSPRINGT2_J213 0x027d
-+/* MacbookPro16,2 (2020) */
-+#define USB_DEVICE_ID_APPLE_WELLSPRINGT2_J214K 0x027e
-+/* MacbookPro16,3 (2020) */
-+#define USB_DEVICE_ID_APPLE_WELLSPRINGT2_J223 0x027f
-+/* MacbookAir9,1 (2020) */
-+#define USB_DEVICE_ID_APPLE_WELLSPRINGT2_J230K 0x0280
-+/* MacbookPro16,1 (2019)*/
-+#define USB_DEVICE_ID_APPLE_WELLSPRINGT2_J152F 0x0340
-+
- #define BCM5974_DEVICE(prod) { \
- .match_flags = (USB_DEVICE_ID_MATCH_DEVICE | \
- USB_DEVICE_ID_MATCH_INT_CLASS | \
-@@ -147,6 +165,22 @@ static const struct usb_device_id bcm5974_table[] = {
- BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING9_ANSI),
- BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING9_ISO),
- BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING9_JIS),
-+ /* MacbookAir8,1 */
-+ BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRINGT2_J140K),
-+ /* MacbookPro15,2 */
-+ BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRINGT2_J132),
-+ /* MacbookPro15,1 */
-+ BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRINGT2_J680),
-+ /* MacbookPro15,4 */
-+ BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRINGT2_J213),
-+ /* MacbookPro16,2 */
-+ BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRINGT2_J214K),
-+ /* MacbookPro16,3 */
-+ BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRINGT2_J223),
-+ /* MacbookAir9,1 */
-+ BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRINGT2_J230K),
-+ /* MacbookPro16,1 */
-+ BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRINGT2_J152F),
- /* Terminating entry */
- {}
- };
-@@ -483,6 +517,110 @@ static const struct bcm5974_config bcm5974_config_table[] = {
- { SN_COORD, -203, 6803 },
- { SN_ORIENT, -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION }
- },
-+ {
-+ USB_DEVICE_ID_APPLE_WELLSPRINGT2_J140K,
-+ 0,
-+ 0,
-+ HAS_INTEGRATED_BUTTON,
-+ 0, sizeof(struct bt_data),
-+ 0x83, DATAFORMAT(TYPE4),
-+ { SN_PRESSURE, 0, 300 },
-+ { SN_WIDTH, 0, 2048 },
-+ { SN_COORD, -6243, 6749 },
-+ { SN_COORD, -170, 7685 },
-+ { SN_ORIENT, -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION }
-+ },
-+ {
-+ USB_DEVICE_ID_APPLE_WELLSPRINGT2_J132,
-+ 0,
-+ 0,
-+ HAS_INTEGRATED_BUTTON,
-+ 0, sizeof(struct bt_data),
-+ 0x83, DATAFORMAT(TYPE4),
-+ { SN_PRESSURE, 0, 300 },
-+ { SN_WIDTH, 0, 2048 },
-+ { SN_COORD, -6243, 6749 },
-+ { SN_COORD, -170, 7685 },
-+ { SN_ORIENT, -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION }
-+ },
-+ {
-+ USB_DEVICE_ID_APPLE_WELLSPRINGT2_J680,
-+ 0,
-+ 0,
-+ HAS_INTEGRATED_BUTTON,
-+ 0, sizeof(struct bt_data),
-+ 0x83, DATAFORMAT(TYPE4),
-+ { SN_PRESSURE, 0, 300 },
-+ { SN_WIDTH, 0, 2048 },
-+ { SN_COORD, -7456, 7976 },
-+ { SN_COORD, -1768, 7685 },
-+ { SN_ORIENT, -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION }
-+ },
-+ {
-+ USB_DEVICE_ID_APPLE_WELLSPRINGT2_J213,
-+ 0,
-+ 0,
-+ HAS_INTEGRATED_BUTTON,
-+ 0, sizeof(struct bt_data),
-+ 0x83, DATAFORMAT(TYPE4),
-+ { SN_PRESSURE, 0, 300 },
-+ { SN_WIDTH, 0, 2048 },
-+ { SN_COORD, -6243, 6749 },
-+ { SN_COORD, -170, 7685 },
-+ { SN_ORIENT, -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION }
-+ },
-+ {
-+ USB_DEVICE_ID_APPLE_WELLSPRINGT2_J214K,
-+ 0,
-+ 0,
-+ HAS_INTEGRATED_BUTTON,
-+ 0, sizeof(struct bt_data),
-+ 0x83, DATAFORMAT(TYPE4),
-+ { SN_PRESSURE, 0, 300 },
-+ { SN_WIDTH, 0, 2048 },
-+ { SN_COORD, -7823, 8329 },
-+ { SN_COORD, -370, 7925 },
-+ { SN_ORIENT, -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION }
-+ },
-+ {
-+ USB_DEVICE_ID_APPLE_WELLSPRINGT2_J223,
-+ 0,
-+ 0,
-+ HAS_INTEGRATED_BUTTON,
-+ 0, sizeof(struct bt_data),
-+ 0x83, DATAFORMAT(TYPE4),
-+ { SN_PRESSURE, 0, 300 },
-+ { SN_WIDTH, 0, 2048 },
-+ { SN_COORD, -6243, 6749 },
-+ { SN_COORD, -170, 7685 },
-+ { SN_ORIENT, -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION }
-+ },
-+ {
-+ USB_DEVICE_ID_APPLE_WELLSPRINGT2_J230K,
-+ 0,
-+ 0,
-+ HAS_INTEGRATED_BUTTON,
-+ 0, sizeof(struct bt_data),
-+ 0x83, DATAFORMAT(TYPE4),
-+ { SN_PRESSURE, 0, 300 },
-+ { SN_WIDTH, 0, 2048 },
-+ { SN_COORD, -6243, 6749 },
-+ { SN_COORD, -170, 7685 },
-+ { SN_ORIENT, -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION }
-+ },
-+ {
-+ USB_DEVICE_ID_APPLE_WELLSPRINGT2_J152F,
-+ 0,
-+ 0,
-+ HAS_INTEGRATED_BUTTON,
-+ 0, sizeof(struct bt_data),
-+ 0x83, DATAFORMAT(TYPE4),
-+ { SN_PRESSURE, 0, 300 },
-+ { SN_WIDTH, 0, 2048 },
-+ { SN_COORD, -8916, 9918 },
-+ { SN_COORD, -1934, 9835 },
-+ { SN_ORIENT, -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION }
-+ },
- {}
- };
-
---
-2.25.1
-
-From: Ashish Arora <ashisharora.linux@outlook.com>
-Subject: Re: [PATCH] drm/i915: Discard large BIOS framebuffers causing display corruption.
-Date: Sat, 08 Jan 2022 21:43:18 +1100
-
-On certain 4k panels, the BIOS framebuffer is larger than what panel
-requires causing display corruption. Introduce a check for the same.
-
-Signed-off-by: Ashish Arora <ashisharora.linux@outlook.com>
----
- drivers/gpu/drm/i915/display/intel_fbdev.c | 6 +++---
- 1 file changed, 3 insertions(+), 3 deletions(-)
-
-diff --git a/drivers/gpu/drm/i915/display/intel_fbdev.c b/drivers/gpu/drm/i915/display/intel_fbdev.c
-index 112aa04..8fb8bcc 100644
---- a/drivers/gpu/drm/i915/display/intel_fbdev.c
-+++ b/drivers/gpu/drm/i915/display/intel_fbdev.c
-@@ -217,10 +217,10 @@ static int intelfb_create(struct drm_fb_helper *helper,
- return ret;
-
- if (intel_fb &&
-- (sizes->fb_width > intel_fb->base.width ||
-- sizes->fb_height > intel_fb->base.height)) {
-+ (sizes->fb_width != intel_fb->base.width ||
-+ sizes->fb_height != intel_fb->base.height)) {
- drm_dbg_kms(&dev_priv->drm,
-- "BIOS fb too small (%dx%d), we require (%dx%d),"
-+ "BIOS fb not valid (%dx%d), we require (%dx%d),"
- " releasing it\n",
- intel_fb->base.width, intel_fb->base.height,
- sizes->fb_width, sizes->fb_height);
---
-1.8.3.1
-
-From 3d4a4a3d62815f90fc65a827a3e2de96c4571350 Mon Sep 17 00:00:00 2001
-From: Orlando Chamberlain <orlandoch.dev@gmail.com>
-Date: Mon, 20 Nov 2023 10:32:23 +1100
-Subject: [PATCH 1/1] acpi video: force native for some T2 macbooks
-
-The intel backlight is needed for these.
-
-MacBookPro15,2/4 or MacBookPro16,3 or MacBookAir8,1/2 might also need
-this so I'm not going to be submitting this upstream yet
-
-mbp16,3 was reported not to have this issue for 6.5.8 at least.
----
- drivers/acpi/video_detect.c | 16 ++++++++++++++++
- 1 file changed, 16 insertions(+)
-
-diff --git a/drivers/acpi/video_detect.c b/drivers/acpi/video_detect.c
-index 442396f6ed1f..baf7264d7b94 100644
---- a/drivers/acpi/video_detect.c
-+++ b/drivers/acpi/video_detect.c
-@@ -513,6 +513,14 @@ static const struct dmi_system_id video_detect_dmi_table[] = {
- DMI_MATCH(DMI_PRODUCT_NAME, "iMac12,2"),
- },
- },
-+ {
-+ .callback = video_detect_force_native,
-+ /* Apple MacBook Air 9,1 */
-+ .matches = {
-+ DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
-+ DMI_MATCH(DMI_PRODUCT_NAME, "MacBookAir9,1"),
-+ },
-+ },
- {
- /* https://bugzilla.redhat.com/show_bug.cgi?id=1217249 */
- .callback = video_detect_force_native,
-@@ -522,6 +530,14 @@ static const struct dmi_system_id video_detect_dmi_table[] = {
- DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro12,1"),
- },
- },
-+ {
-+ .callback = video_detect_force_native,
-+ /* Apple MacBook Pro 16,2 */
-+ .matches = {
-+ DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
-+ DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro16,2"),
-+ },
-+ },
- {
- .callback = video_detect_force_native,
- /* Dell Inspiron N4010 */
---
-2.42.1