diff options
Diffstat (limited to 'SOURCES/t2linux.patch')
-rw-r--r-- | SOURCES/t2linux.patch | 10690 |
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 = ¶ms->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, ++ ¶ms->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, ¶ms->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, ¶ms->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 |