aboutsummaryrefslogtreecommitdiff
path: root/SOURCES/t2linux.patch
diff options
context:
space:
mode:
authorJan200101 <sentrycraft123@gmail.com>2024-10-05 23:55:37 +0200
committerJan200101 <sentrycraft123@gmail.com>2024-10-05 23:55:37 +0200
commitbfc36f8fbe1fe4b58215e39b503569ef48ffec79 (patch)
treee18aa589e7fa4c65747ef5689965e36f1fe4cdff /SOURCES/t2linux.patch
parentac5b7561796db2077970c2430557cfb10ddd5187 (diff)
downloadkernel-fsync-bfc36f8fbe1fe4b58215e39b503569ef48ffec79.tar.gz
kernel-fsync-bfc36f8fbe1fe4b58215e39b503569ef48ffec79.zip
kernel 6.10.12
Diffstat (limited to 'SOURCES/t2linux.patch')
-rw-r--r--SOURCES/t2linux.patch10707
1 files changed, 0 insertions, 10707 deletions
diff --git a/SOURCES/t2linux.patch b/SOURCES/t2linux.patch
deleted file mode 100644
index 46faa57..0000000
--- a/SOURCES/t2linux.patch
+++ /dev/null
@@ -1,10707 +0,0 @@
-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>
----
- .../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
- create mode 100644 drivers/staging/apple-bce/audio/audio.c
- create mode 100644 drivers/staging/apple-bce/audio/audio.h
- create mode 100644 drivers/staging/apple-bce/audio/description.h
- create mode 100644 drivers/staging/apple-bce/audio/pcm.c
- create mode 100644 drivers/staging/apple-bce/audio/pcm.h
- create mode 100644 drivers/staging/apple-bce/audio/protocol.c
- create mode 100644 drivers/staging/apple-bce/audio/protocol.h
- create mode 100644 drivers/staging/apple-bce/audio/protocol_bce.c
- create mode 100644 drivers/staging/apple-bce/audio/protocol_bce.h
- create mode 100644 drivers/staging/apple-bce/mailbox.c
- create mode 100644 drivers/staging/apple-bce/mailbox.h
- create mode 100644 drivers/staging/apple-bce/queue.c
- create mode 100644 drivers/staging/apple-bce/queue.h
- create mode 100644 drivers/staging/apple-bce/queue_dma.c
- create mode 100644 drivers/staging/apple-bce/queue_dma.h
- create mode 100644 drivers/staging/apple-bce/vhci/command.h
- create mode 100644 drivers/staging/apple-bce/vhci/queue.c
- create mode 100644 drivers/staging/apple-bce/vhci/queue.h
- create mode 100644 drivers/staging/apple-bce/vhci/transfer.c
- create mode 100644 drivers/staging/apple-bce/vhci/transfer.h
- create mode 100644 drivers/staging/apple-bce/vhci/vhci.c
- create mode 100644 drivers/staging/apple-bce/vhci/vhci.h
-
-diff --git a/Documentation/ABI/testing/sysfs-driver-hid-appletb-kbd b/Documentation/ABI/testing/sysfs-driver-hid-appletb-kbd
-new file mode 100644
-index 000000000000..2a19584d091e
---- /dev/null
-+++ b/Documentation/ABI/testing/sysfs-driver-hid-appletb-kbd
-@@ -0,0 +1,13 @@
-+What: /sys/bus/hid/drivers/hid-appletb-kbd/<dev>/mode
-+Date: September, 2023
-+KernelVersion: 6.5
-+Contact: linux-input@vger.kernel.org
-+Description:
-+ The set of keys displayed on the Touch Bar.
-+ Valid values are:
-+ == =================
-+ 0 Escape key only
-+ 1 Function keys
-+ 2 Media/brightness keys
-+ 3 None
-+ == =================
-diff --git a/Documentation/core-api/printk-formats.rst b/Documentation/core-api/printk-formats.rst
-index 4451ef501936..c726a846f752 100644
---- a/Documentation/core-api/printk-formats.rst
-+++ b/Documentation/core-api/printk-formats.rst
-@@ -632,6 +632,38 @@ Examples::
- %p4cc Y10 little-endian (0x20303159)
- %p4cc NV12 big-endian (0xb231564e)
-
-+Generic FourCC code
-+-------------------
-+
-+::
-+ %p4c[hnbl] gP00 (0x67503030)
-+
-+Print a generic FourCC code, as both ASCII characters and its numerical
-+value as hexadecimal.
-+
-+The additional ``h``, ``r``, ``b``, and ``l`` specifiers are used to specify
-+host, reversed, big or little endian order data respectively. Host endian
-+order means the data is interpreted as a 32-bit integer and the most
-+significant byte is printed first; that is, the character code as printed
-+matches the byte order stored in memory on big-endian systems, and is reversed
-+on little-endian systems.
-+
-+Passed by reference.
-+
-+Examples for a little-endian machine, given &(u32)0x67503030::
-+
-+ %p4ch gP00 (0x67503030)
-+ %p4cl gP00 (0x67503030)
-+ %p4cb 00Pg (0x30305067)
-+ %p4cr 00Pg (0x30305067)
-+
-+Examples for a big-endian machine, given &(u32)0x67503030::
-+
-+ %p4ch gP00 (0x67503030)
-+ %p4cl 00Pg (0x30305067)
-+ %p4cb gP00 (0x67503030)
-+ %p4cr 00Pg (0x30305067)
-+
- Rust
- ----
-
-diff --git a/MAINTAINERS b/MAINTAINERS
-index 4112729fc23a..064156d69e75 100644
---- a/MAINTAINERS
-+++ b/MAINTAINERS
-@@ -6728,6 +6728,12 @@ S: Supported
- T: git https://gitlab.freedesktop.org/drm/misc/kernel.git
- F: drivers/gpu/drm/sun4i/sun8i*
-
-+DRM DRIVER FOR APPLE TOUCH BARS
-+M: Kerem Karabay <kekrby@gmail.com>
-+L: dri-devel@lists.freedesktop.org
-+S: Maintained
-+F: drivers/gpu/drm/tiny/appletbdrm.c
-+
- DRM DRIVER FOR ARM PL111 CLCD
- S: Orphan
- T: git https://gitlab.freedesktop.org/drm/misc/kernel.git
-@@ -9733,6 +9739,12 @@ F: include/linux/pm.h
- F: include/linux/suspend.h
- F: kernel/power/
-
-+HID APPLE TOUCH BAR DRIVERS
-+M: Kerem Karabay <kekrby@gmail.com>
-+L: linux-input@vger.kernel.org
-+S: Maintained
-+F: drivers/hid/hid-appletb-*
-+
- HID CORE LAYER
- M: Jiri Kosina <jikos@kernel.org>
- M: Benjamin Tissoires <bentiss@kernel.org>
-diff --git a/drivers/acpi/video_detect.c b/drivers/acpi/video_detect.c
-index 2cc3821b2b16..c11cbe5b6eaa 100644
---- a/drivers/acpi/video_detect.c
-+++ b/drivers/acpi/video_detect.c
-@@ -539,6 +539,14 @@ static const struct dmi_system_id video_detect_dmi_table[] = {
- DMI_MATCH(DMI_PRODUCT_NAME, "iMac12,2"),
- },
- },
-+ {
-+ .callback = video_detect_force_native,
-+ /* Apple MacBook Air 9,1 */
-+ .matches = {
-+ DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
-+ DMI_MATCH(DMI_PRODUCT_NAME, "MacBookAir9,1"),
-+ },
-+ },
- {
- /* https://bugzilla.redhat.com/show_bug.cgi?id=1217249 */
- .callback = video_detect_force_native,
-@@ -548,6 +556,14 @@ static const struct dmi_system_id video_detect_dmi_table[] = {
- DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro12,1"),
- },
- },
-+ {
-+ .callback = video_detect_force_native,
-+ /* Apple MacBook Pro 16,2 */
-+ .matches = {
-+ DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
-+ DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro16,2"),
-+ },
-+ },
- {
- .callback = video_detect_force_native,
- /* Dell Inspiron N4010 */
-diff --git a/drivers/firmware/efi/libstub/Makefile b/drivers/firmware/efi/libstub/Makefile
-index 06f0428a723c..1f32d6cf98d6 100644
---- a/drivers/firmware/efi/libstub/Makefile
-+++ b/drivers/firmware/efi/libstub/Makefile
-@@ -76,7 +76,7 @@ lib-$(CONFIG_EFI_GENERIC_STUB) += efi-stub.o string.o intrinsics.o systable.o \
-
- lib-$(CONFIG_ARM) += arm32-stub.o
- lib-$(CONFIG_ARM64) += kaslr.o arm64.o arm64-stub.o smbios.o
--lib-$(CONFIG_X86) += x86-stub.o
-+lib-$(CONFIG_X86) += x86-stub.o smbios.o
- lib-$(CONFIG_X86_64) += x86-5lvl.o
- lib-$(CONFIG_RISCV) += kaslr.o riscv.o riscv-stub.o
- lib-$(CONFIG_LOONGARCH) += loongarch.o loongarch-stub.o
-diff --git a/drivers/firmware/efi/libstub/arm64.c b/drivers/firmware/efi/libstub/arm64.c
-index 446e35eaf3d9..e57cd3de0a00 100644
---- a/drivers/firmware/efi/libstub/arm64.c
-+++ b/drivers/firmware/efi/libstub/arm64.c
-@@ -39,8 +39,7 @@ static bool system_needs_vamap(void)
- static char const emag[] = "eMAG";
-
- default:
-- version = efi_get_smbios_string(&record->header, 4,
-- processor_version);
-+ version = efi_get_smbios_string(record, processor_version);
- if (!version || (strncmp(version, altra, sizeof(altra) - 1) &&
- strncmp(version, emag, sizeof(emag) - 1)))
- break;
-diff --git a/drivers/firmware/efi/libstub/efistub.h b/drivers/firmware/efi/libstub/efistub.h
-index 27abb4ce0291..d33ccbc4a2c6 100644
---- a/drivers/firmware/efi/libstub/efistub.h
-+++ b/drivers/firmware/efi/libstub/efistub.h
-@@ -1204,14 +1204,13 @@ struct efi_smbios_type4_record {
- u16 thread_enabled;
- };
-
--#define efi_get_smbios_string(__record, __type, __name) ({ \
-- int off = offsetof(struct efi_smbios_type ## __type ## _record, \
-- __name); \
-- __efi_get_smbios_string((__record), __type, off); \
-+#define efi_get_smbios_string(__record, __field) ({ \
-+ __typeof__(__record) __rec = __record; \
-+ __efi_get_smbios_string(&__rec->header, &__rec->__field); \
- })
-
- const u8 *__efi_get_smbios_string(const struct efi_smbios_record *record,
-- u8 type, int offset);
-+ const u8 *offset);
-
- void efi_remap_image(unsigned long image_base, unsigned alloc_size,
- unsigned long code_size);
-diff --git a/drivers/firmware/efi/libstub/smbios.c b/drivers/firmware/efi/libstub/smbios.c
-index c217de2cc8d5..f31410d7e7e1 100644
---- a/drivers/firmware/efi/libstub/smbios.c
-+++ b/drivers/firmware/efi/libstub/smbios.c
-@@ -6,20 +6,31 @@
-
- #include "efistub.h"
-
--typedef struct efi_smbios_protocol efi_smbios_protocol_t;
--
--struct efi_smbios_protocol {
-- efi_status_t (__efiapi *add)(efi_smbios_protocol_t *, efi_handle_t,
-- u16 *, struct efi_smbios_record *);
-- efi_status_t (__efiapi *update_string)(efi_smbios_protocol_t *, u16 *,
-- unsigned long *, u8 *);
-- efi_status_t (__efiapi *remove)(efi_smbios_protocol_t *, u16);
-- efi_status_t (__efiapi *get_next)(efi_smbios_protocol_t *, u16 *, u8 *,
-- struct efi_smbios_record **,
-- efi_handle_t *);
--
-- u8 major_version;
-- u8 minor_version;
-+typedef union efi_smbios_protocol efi_smbios_protocol_t;
-+
-+union efi_smbios_protocol {
-+ struct {
-+ efi_status_t (__efiapi *add)(efi_smbios_protocol_t *, efi_handle_t,
-+ u16 *, struct efi_smbios_record *);
-+ efi_status_t (__efiapi *update_string)(efi_smbios_protocol_t *, u16 *,
-+ unsigned long *, u8 *);
-+ efi_status_t (__efiapi *remove)(efi_smbios_protocol_t *, u16);
-+ efi_status_t (__efiapi *get_next)(efi_smbios_protocol_t *, u16 *, u8 *,
-+ struct efi_smbios_record **,
-+ efi_handle_t *);
-+
-+ u8 major_version;
-+ u8 minor_version;
-+ };
-+ struct {
-+ u32 add;
-+ u32 update_string;
-+ u32 remove;
-+ u32 get_next;
-+
-+ u8 major_version;
-+ u8 minor_version;
-+ } mixed_mode;
- };
-
- const struct efi_smbios_record *efi_get_smbios_record(u8 type)
-@@ -38,7 +49,7 @@ const struct efi_smbios_record *efi_get_smbios_record(u8 type)
- }
-
- const u8 *__efi_get_smbios_string(const struct efi_smbios_record *record,
-- u8 type, int offset)
-+ const u8 *offset)
- {
- const u8 *strtable;
-
-@@ -46,7 +57,7 @@ const u8 *__efi_get_smbios_string(const struct efi_smbios_record *record,
- return NULL;
-
- strtable = (u8 *)record + record->length;
-- for (int i = 1; i < ((u8 *)record)[offset]; i++) {
-+ for (int i = 1; i < *offset; i++) {
- int len = strlen(strtable);
-
- if (!len)
-diff --git a/drivers/firmware/efi/libstub/x86-stub.c b/drivers/firmware/efi/libstub/x86-stub.c
-index 99d39eda5134..0a2342c0bc16 100644
---- a/drivers/firmware/efi/libstub/x86-stub.c
-+++ b/drivers/firmware/efi/libstub/x86-stub.c
-@@ -225,6 +225,68 @@ static void retrieve_apple_device_properties(struct boot_params *boot_params)
- }
- }
-
-+static bool apple_match_product_name(void)
-+{
-+ static const char type1_product_matches[][15] = {
-+ "MacBookPro11,3",
-+ "MacBookPro11,5",
-+ "MacBookPro13,3",
-+ "MacBookPro14,3",
-+ "MacBookPro15,1",
-+ "MacBookPro15,3",
-+ "MacBookPro16,1",
-+ "MacBookPro16,4",
-+ };
-+ const struct efi_smbios_type1_record *record;
-+ const u8 *product;
-+
-+ record = (struct efi_smbios_type1_record *)efi_get_smbios_record(1);
-+ if (!record)
-+ return false;
-+
-+ product = efi_get_smbios_string(record, product_name);
-+ if (!product)
-+ return false;
-+
-+ for (int i = 0; i < ARRAY_SIZE(type1_product_matches); i++) {
-+ if (!strcmp(product, type1_product_matches[i]))
-+ return true;
-+ }
-+
-+ return false;
-+}
-+
-+static void apple_set_os(void)
-+{
-+ struct {
-+ unsigned long version;
-+ efi_status_t (__efiapi *set_os_version)(const char *);
-+ efi_status_t (__efiapi *set_os_vendor)(const char *);
-+ } *set_os;
-+ efi_status_t status;
-+
-+ if (!efi_is_64bit() || !apple_match_product_name())
-+ return;
-+
-+ status = efi_bs_call(locate_protocol, &APPLE_SET_OS_PROTOCOL_GUID, NULL,
-+ (void **)&set_os);
-+ if (status != EFI_SUCCESS)
-+ return;
-+
-+ if (set_os->version >= 2) {
-+ status = set_os->set_os_vendor("Apple Inc.");
-+ if (status != EFI_SUCCESS)
-+ efi_err("Failed to set OS vendor via apple_set_os\n");
-+ }
-+
-+ if (set_os->version > 0) {
-+ /* The version being set doesn't seem to matter */
-+ status = set_os->set_os_version("Mac OS X 10.9");
-+ if (status != EFI_SUCCESS)
-+ efi_err("Failed to set OS version via apple_set_os\n");
-+ }
-+}
-+
- efi_status_t efi_adjust_memory_range_protection(unsigned long start,
- unsigned long size)
- {
-@@ -335,9 +397,12 @@ static const efi_char16_t apple[] = L"Apple";
-
- static void setup_quirks(struct boot_params *boot_params)
- {
-- if (IS_ENABLED(CONFIG_APPLE_PROPERTIES) &&
-- !memcmp(efistub_fw_vendor(), apple, sizeof(apple)))
-- retrieve_apple_device_properties(boot_params);
-+ if (!memcmp(efistub_fw_vendor(), apple, sizeof(apple))) {
-+ if (IS_ENABLED(CONFIG_APPLE_PROPERTIES))
-+ retrieve_apple_device_properties(boot_params);
-+
-+ apple_set_os();
-+ }
- }
-
- /*
-diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
-index bb0b636d0d75..a05ed98da785 100644
---- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
-+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
-@@ -2211,6 +2211,9 @@ static int amdgpu_pci_probe(struct pci_dev *pdev,
- int ret, retry = 0, i;
- bool supports_atomic = false;
-
-+ if (vga_switcheroo_client_probe_defer(pdev))
-+ return -EPROBE_DEFER;
-+
- /* skip devices which are owned by radeon */
- for (i = 0; i < ARRAY_SIZE(amdgpu_unsupported_pciidlist); i++) {
- if (amdgpu_unsupported_pciidlist[i] == pdev->device)
-diff --git a/drivers/gpu/drm/drm_format_helper.c b/drivers/gpu/drm/drm_format_helper.c
-index b1be458ed4dd..28c0e76a1e88 100644
---- a/drivers/gpu/drm/drm_format_helper.c
-+++ b/drivers/gpu/drm/drm_format_helper.c
-@@ -702,6 +702,57 @@ void drm_fb_xrgb8888_to_rgb888(struct iosys_map *dst, const unsigned int *dst_pi
- }
- EXPORT_SYMBOL(drm_fb_xrgb8888_to_rgb888);
-
-+static void drm_fb_xrgb8888_to_bgr888_line(void *dbuf, const void *sbuf, unsigned int pixels)
-+{
-+ u8 *dbuf8 = dbuf;
-+ const __le32 *sbuf32 = sbuf;
-+ unsigned int x;
-+ u32 pix;
-+
-+ for (x = 0; x < pixels; x++) {
-+ pix = le32_to_cpu(sbuf32[x]);
-+ /* write red-green-blue to output in little endianness */
-+ *dbuf8++ = (pix & 0x00FF0000) >> 16;
-+ *dbuf8++ = (pix & 0x0000FF00) >> 8;
-+ *dbuf8++ = (pix & 0x000000FF) >> 0;
-+ }
-+}
-+
-+/**
-+ * drm_fb_xrgb8888_to_bgr888 - Convert XRGB8888 to BGR888 clip buffer
-+ * @dst: Array of BGR888 destination buffers
-+ * @dst_pitch: Array of numbers of bytes between the start of two consecutive scanlines
-+ * within @dst; can be NULL if scanlines are stored next to each other.
-+ * @src: Array of XRGB8888 source buffers
-+ * @fb: DRM framebuffer
-+ * @clip: Clip rectangle area to copy
-+ * @state: Transform and conversion state
-+ *
-+ * This function copies parts of a framebuffer to display memory and converts the
-+ * color format during the process. Destination and framebuffer formats must match. The
-+ * parameters @dst, @dst_pitch and @src refer to arrays. Each array must have at
-+ * least as many entries as there are planes in @fb's format. Each entry stores the
-+ * value for the format's respective color plane at the same index.
-+ *
-+ * This function does not apply clipping on @dst (i.e. the destination is at the
-+ * top-left corner).
-+ *
-+ * Drivers can use this function for BGR888 devices that don't natively
-+ * support XRGB8888.
-+ */
-+void drm_fb_xrgb8888_to_bgr888(struct iosys_map *dst, const unsigned int *dst_pitch,
-+ const struct iosys_map *src, const struct drm_framebuffer *fb,
-+ const struct drm_rect *clip, struct drm_format_conv_state *state)
-+{
-+ static const u8 dst_pixsize[DRM_FORMAT_MAX_PLANES] = {
-+ 3,
-+ };
-+
-+ drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false, state,
-+ drm_fb_xrgb8888_to_bgr888_line);
-+}
-+EXPORT_SYMBOL(drm_fb_xrgb8888_to_bgr888);
-+
- static void drm_fb_xrgb8888_to_argb8888_line(void *dbuf, const void *sbuf, unsigned int pixels)
- {
- __le32 *dbuf32 = dbuf;
-@@ -1035,6 +1086,9 @@ int drm_fb_blit(struct iosys_map *dst, const unsigned int *dst_pitch, uint32_t d
- } else if (dst_format == DRM_FORMAT_RGB888) {
- drm_fb_xrgb8888_to_rgb888(dst, dst_pitch, src, fb, clip, state);
- return 0;
-+ } else if (dst_format == DRM_FORMAT_BGR888) {
-+ drm_fb_xrgb8888_to_bgr888(dst, dst_pitch, src, fb, clip, state);
-+ return 0;
- } else if (dst_format == DRM_FORMAT_ARGB8888) {
- drm_fb_xrgb8888_to_argb8888(dst, dst_pitch, src, fb, clip, state);
- return 0;
-diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c
-index 6bff169fa8d4..8d80ae00b838 100644
---- a/drivers/gpu/drm/i915/display/intel_ddi.c
-+++ b/drivers/gpu/drm/i915/display/intel_ddi.c
-@@ -4648,6 +4648,7 @@ intel_ddi_init_hdmi_connector(struct intel_digital_port *dig_port)
-
- static bool intel_ddi_a_force_4_lanes(struct intel_digital_port *dig_port)
- {
-+ struct intel_display *display = to_intel_display(dig_port);
- struct drm_i915_private *dev_priv = to_i915(dig_port->base.base.dev);
-
- if (dig_port->base.port != PORT_A)
-@@ -4656,6 +4657,9 @@ static bool intel_ddi_a_force_4_lanes(struct intel_digital_port *dig_port)
- if (dig_port->saved_port_bits & DDI_A_4_LANES)
- return false;
-
-+ if (intel_has_quirk(display, QUIRK_DDI_A_FORCE_4_LANES))
-+ return true;
-+
- /* Broxton/Geminilake: Bspec says that DDI_A_4_LANES is the only
- * supported configuration
- */
-diff --git a/drivers/gpu/drm/i915/display/intel_fbdev.c b/drivers/gpu/drm/i915/display/intel_fbdev.c
-index bda702c2cab8..1647e141ae78 100644
---- a/drivers/gpu/drm/i915/display/intel_fbdev.c
-+++ b/drivers/gpu/drm/i915/display/intel_fbdev.c
-@@ -196,10 +196,10 @@ static int intelfb_create(struct drm_fb_helper *helper,
- return ret;
-
- if (intel_fb &&
-- (sizes->fb_width > intel_fb->base.width ||
-- sizes->fb_height > intel_fb->base.height)) {
-+ (sizes->fb_width != intel_fb->base.width ||
-+ sizes->fb_height != intel_fb->base.height)) {
- drm_dbg_kms(&dev_priv->drm,
-- "BIOS fb too small (%dx%d), we require (%dx%d),"
-+ "BIOS fb not valid (%dx%d), we require (%dx%d),"
- " releasing it\n",
- intel_fb->base.width, intel_fb->base.height,
- sizes->fb_width, sizes->fb_height);
-diff --git a/drivers/gpu/drm/i915/display/intel_quirks.c b/drivers/gpu/drm/i915/display/intel_quirks.c
-index 14d5fefc9c5b..727639b8f6a6 100644
---- a/drivers/gpu/drm/i915/display/intel_quirks.c
-+++ b/drivers/gpu/drm/i915/display/intel_quirks.c
-@@ -59,6 +59,18 @@ static void quirk_increase_ddi_disabled_time(struct intel_display *display)
- drm_info(display->drm, "Applying Increase DDI Disabled quirk\n");
- }
-
-+/*
-+ * In some cases, the firmware might not set the lane count to 4 (for example,
-+ * when booting in some dual GPU Macs with the dGPU as the default GPU), this
-+ * quirk is used to force it as otherwise it might not be possible to compute a
-+ * valid link configuration.
-+ */
-+static void quirk_ddi_a_force_4_lanes(struct intel_display *display)
-+{
-+ intel_set_quirk(display, QUIRK_DDI_A_FORCE_4_LANES);
-+ drm_info(display->drm, "Applying DDI A Forced 4 Lanes quirk\n");
-+}
-+
- static void quirk_no_pps_backlight_power_hook(struct intel_display *display)
- {
- intel_set_quirk(display, QUIRK_NO_PPS_BACKLIGHT_POWER_HOOK);
-@@ -201,6 +213,9 @@ static struct intel_quirk intel_quirks[] = {
- { 0x3184, 0x1019, 0xa94d, quirk_increase_ddi_disabled_time },
- /* HP Notebook - 14-r206nv */
- { 0x0f31, 0x103c, 0x220f, quirk_invert_brightness },
-+
-+ /* Apple MacBookPro15,1 */
-+ { 0x3e9b, 0x106b, 0x0176, quirk_ddi_a_force_4_lanes },
- };
-
- void intel_init_quirks(struct intel_display *display)
-diff --git a/drivers/gpu/drm/i915/display/intel_quirks.h b/drivers/gpu/drm/i915/display/intel_quirks.h
-index 151c8f4ae576..46e7feba88f4 100644
---- a/drivers/gpu/drm/i915/display/intel_quirks.h
-+++ b/drivers/gpu/drm/i915/display/intel_quirks.h
-@@ -17,6 +17,7 @@ enum intel_quirk_id {
- QUIRK_INVERT_BRIGHTNESS,
- QUIRK_LVDS_SSC_DISABLE,
- QUIRK_NO_PPS_BACKLIGHT_POWER_HOOK,
-+ QUIRK_DDI_A_FORCE_4_LANES,
- };
-
- void intel_init_quirks(struct intel_display *display);
-diff --git a/drivers/gpu/drm/tests/drm_format_helper_test.c b/drivers/gpu/drm/tests/drm_format_helper_test.c
-index 08992636ec05..35cd3405d045 100644
---- a/drivers/gpu/drm/tests/drm_format_helper_test.c
-+++ b/drivers/gpu/drm/tests/drm_format_helper_test.c
-@@ -60,6 +60,11 @@ struct convert_to_rgb888_result {
- const u8 expected[TEST_BUF_SIZE];
- };
-
-+struct convert_to_bgr888_result {
-+ unsigned int dst_pitch;
-+ const u8 expected[TEST_BUF_SIZE];
-+};
-+
- struct convert_to_argb8888_result {
- unsigned int dst_pitch;
- const u32 expected[TEST_BUF_SIZE];
-@@ -107,6 +112,7 @@ struct convert_xrgb8888_case {
- struct convert_to_argb1555_result argb1555_result;
- struct convert_to_rgba5551_result rgba5551_result;
- struct convert_to_rgb888_result rgb888_result;
-+ struct convert_to_bgr888_result bgr888_result;
- struct convert_to_argb8888_result argb8888_result;
- struct convert_to_xrgb2101010_result xrgb2101010_result;
- struct convert_to_argb2101010_result argb2101010_result;
-@@ -151,6 +157,10 @@ static struct convert_xrgb8888_case convert_xrgb8888_cases[] = {
- .dst_pitch = TEST_USE_DEFAULT_PITCH,
- .expected = { 0x00, 0x00, 0xFF },
- },
-+ .bgr888_result = {
-+ .dst_pitch = TEST_USE_DEFAULT_PITCH,
-+ .expected = { 0xFF, 0x00, 0x00 },
-+ },
- .argb8888_result = {
- .dst_pitch = TEST_USE_DEFAULT_PITCH,
- .expected = { 0xFFFF0000 },
-@@ -217,6 +227,10 @@ static struct convert_xrgb8888_case convert_xrgb8888_cases[] = {
- .dst_pitch = TEST_USE_DEFAULT_PITCH,
- .expected = { 0x00, 0x00, 0xFF },
- },
-+ .bgr888_result = {
-+ .dst_pitch = TEST_USE_DEFAULT_PITCH,
-+ .expected = { 0xFF, 0x00, 0x00 },
-+ },
- .argb8888_result = {
- .dst_pitch = TEST_USE_DEFAULT_PITCH,
- .expected = { 0xFFFF0000 },
-@@ -330,6 +344,15 @@ static struct convert_xrgb8888_case convert_xrgb8888_cases[] = {
- 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
- },
- },
-+ .bgr888_result = {
-+ .dst_pitch = TEST_USE_DEFAULT_PITCH,
-+ .expected = {
-+ 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00,
-+ 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00,
-+ 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF,
-+ 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF,
-+ },
-+ },
- .argb8888_result = {
- .dst_pitch = TEST_USE_DEFAULT_PITCH,
- .expected = {
-@@ -468,6 +491,17 @@ static struct convert_xrgb8888_case convert_xrgb8888_cases[] = {
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- },
- },
-+ .bgr888_result = {
-+ .dst_pitch = 15,
-+ .expected = {
-+ 0x0E, 0x44, 0x9C, 0x11, 0x4D, 0x05, 0xA8, 0xF3, 0x03,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x6C, 0xF0, 0x73, 0x0E, 0x44, 0x9C, 0x11, 0x4D, 0x05,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0xA8, 0x03, 0x03, 0x6C, 0xF0, 0x73, 0x0E, 0x44, 0x9C,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ },
-+ },
- .argb8888_result = {
- .dst_pitch = 20,
- .expected = {
-@@ -914,6 +948,52 @@ static void drm_test_fb_xrgb8888_to_rgb888(struct kunit *test)
- KUNIT_EXPECT_MEMEQ(test, buf, result->expected, dst_size);
- }
-
-+static void drm_test_fb_xrgb8888_to_bgr888(struct kunit *test)
-+{
-+ const struct convert_xrgb8888_case *params = test->param_value;
-+ const struct convert_to_bgr888_result *result = &params->bgr888_result;
-+ size_t dst_size;
-+ u8 *buf = NULL;
-+ __le32 *xrgb8888 = NULL;
-+ struct iosys_map dst, src;
-+
-+ struct drm_framebuffer fb = {
-+ .format = drm_format_info(DRM_FORMAT_XRGB8888),
-+ .pitches = { params->pitch, 0, 0 },
-+ };
-+
-+ dst_size = conversion_buf_size(DRM_FORMAT_BGR888, result->dst_pitch,
-+ &params->clip, 0);
-+ KUNIT_ASSERT_GT(test, dst_size, 0);
-+
-+ buf = kunit_kzalloc(test, dst_size, GFP_KERNEL);
-+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, buf);
-+ iosys_map_set_vaddr(&dst, buf);
-+
-+ xrgb8888 = cpubuf_to_le32(test, params->xrgb8888, TEST_BUF_SIZE);
-+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, xrgb8888);
-+ iosys_map_set_vaddr(&src, xrgb8888);
-+
-+ /*
-+ * BGR888 expected results are already in little-endian
-+ * order, so there's no need to convert the test output.
-+ */
-+ drm_fb_xrgb8888_to_bgr888(&dst, &result->dst_pitch, &src, &fb, &params->clip,
-+ &fmtcnv_state);
-+ KUNIT_EXPECT_MEMEQ(test, buf, result->expected, dst_size);
-+
-+ buf = dst.vaddr; /* restore original value of buf */
-+ memset(buf, 0, dst_size);
-+
-+ int blit_result = 0;
-+
-+ blit_result = drm_fb_blit(&dst, &result->dst_pitch, DRM_FORMAT_BGR888, &src, &fb, &params->clip,
-+ &fmtcnv_state);
-+
-+ KUNIT_EXPECT_FALSE(test, blit_result);
-+ KUNIT_EXPECT_MEMEQ(test, buf, result->expected, dst_size);
-+}
-+
- static void drm_test_fb_xrgb8888_to_argb8888(struct kunit *test)
- {
- const struct convert_xrgb8888_case *params = test->param_value;
-@@ -1851,6 +1931,7 @@ static struct kunit_case drm_format_helper_test_cases[] = {
- KUNIT_CASE_PARAM(drm_test_fb_xrgb8888_to_argb1555, convert_xrgb8888_gen_params),
- KUNIT_CASE_PARAM(drm_test_fb_xrgb8888_to_rgba5551, convert_xrgb8888_gen_params),
- KUNIT_CASE_PARAM(drm_test_fb_xrgb8888_to_rgb888, convert_xrgb8888_gen_params),
-+ KUNIT_CASE_PARAM(drm_test_fb_xrgb8888_to_bgr888, convert_xrgb8888_gen_params),
- KUNIT_CASE_PARAM(drm_test_fb_xrgb8888_to_argb8888, convert_xrgb8888_gen_params),
- KUNIT_CASE_PARAM(drm_test_fb_xrgb8888_to_xrgb2101010, convert_xrgb8888_gen_params),
- KUNIT_CASE_PARAM(drm_test_fb_xrgb8888_to_argb2101010, convert_xrgb8888_gen_params),
-diff --git a/drivers/gpu/drm/tiny/Kconfig b/drivers/gpu/drm/tiny/Kconfig
-index f6889f649bc1..559a97bce12c 100644
---- a/drivers/gpu/drm/tiny/Kconfig
-+++ b/drivers/gpu/drm/tiny/Kconfig
-@@ -1,5 +1,17 @@
- # SPDX-License-Identifier: GPL-2.0-only
-
-+config DRM_APPLETBDRM
-+ tristate "DRM support for Apple Touch Bars"
-+ depends on DRM && USB && MMU
-+ select DRM_KMS_HELPER
-+ select DRM_GEM_SHMEM_HELPER
-+ help
-+ Say Y here if you want support for the display of Touch Bars on x86
-+ MacBook Pros.
-+
-+ To compile this driver as a module, choose M here: the
-+ module will be called appletbdrm.
-+
- config DRM_ARCPGU
- tristate "ARC PGU"
- depends on DRM && OF
-diff --git a/drivers/gpu/drm/tiny/Makefile b/drivers/gpu/drm/tiny/Makefile
-index 76dde89a044b..9a1b412e764a 100644
---- a/drivers/gpu/drm/tiny/Makefile
-+++ b/drivers/gpu/drm/tiny/Makefile
-@@ -1,5 +1,6 @@
- # SPDX-License-Identifier: GPL-2.0-only
-
-+obj-$(CONFIG_DRM_APPLETBDRM) += appletbdrm.o
- obj-$(CONFIG_DRM_ARCPGU) += arcpgu.o
- obj-$(CONFIG_DRM_BOCHS) += bochs.o
- obj-$(CONFIG_DRM_CIRRUS_QEMU) += cirrus.o
-diff --git a/drivers/gpu/drm/tiny/appletbdrm.c b/drivers/gpu/drm/tiny/appletbdrm.c
-new file mode 100644
-index 000000000000..b9440ce0064e
---- /dev/null
-+++ b/drivers/gpu/drm/tiny/appletbdrm.c
-@@ -0,0 +1,624 @@
-+// SPDX-License-Identifier: GPL-2.0
-+/*
-+ * Apple Touch Bar DRM Driver
-+ *
-+ * Copyright (c) 2023 Kerem Karabay <kekrby@gmail.com>
-+ */
-+
-+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-+
-+#include <asm/unaligned.h>
-+
-+#include <linux/usb.h>
-+#include <linux/module.h>
-+
-+#include <drm/drm_drv.h>
-+#include <drm/drm_fourcc.h>
-+#include <drm/drm_probe_helper.h>
-+#include <drm/drm_atomic_helper.h>
-+#include <drm/drm_damage_helper.h>
-+#include <drm/drm_format_helper.h>
-+#include <drm/drm_gem_shmem_helper.h>
-+#include <drm/drm_gem_atomic_helper.h>
-+#include <drm/drm_simple_kms_helper.h>
-+#include <drm/drm_gem_framebuffer_helper.h>
-+
-+#define _APPLETBDRM_FOURCC(s) (((s)[0] << 24) | ((s)[1] << 16) | ((s)[2] << 8) | (s)[3])
-+#define APPLETBDRM_FOURCC(s) _APPLETBDRM_FOURCC(#s)
-+
-+#define APPLETBDRM_PIXEL_FORMAT APPLETBDRM_FOURCC(RGBA) /* The actual format is BGR888 */
-+#define APPLETBDRM_BITS_PER_PIXEL 24
-+
-+#define APPLETBDRM_MSG_CLEAR_DISPLAY APPLETBDRM_FOURCC(CLRD)
-+#define APPLETBDRM_MSG_GET_INFORMATION APPLETBDRM_FOURCC(GINF)
-+#define APPLETBDRM_MSG_UPDATE_COMPLETE APPLETBDRM_FOURCC(UDCL)
-+#define APPLETBDRM_MSG_SIGNAL_READINESS APPLETBDRM_FOURCC(REDY)
-+
-+#define APPLETBDRM_BULK_MSG_TIMEOUT 1000
-+
-+#define drm_to_adev(_drm) container_of(_drm, struct appletbdrm_device, drm)
-+#define adev_to_udev(adev) interface_to_usbdev(to_usb_interface(adev->dev))
-+
-+struct appletbdrm_device {
-+ struct device *dev;
-+
-+ u8 in_ep;
-+ u8 out_ep;
-+
-+ u32 width;
-+ u32 height;
-+
-+ struct drm_device drm;
-+ struct drm_display_mode mode;
-+ struct drm_connector connector;
-+ struct drm_simple_display_pipe pipe;
-+
-+ bool readiness_signal_received;
-+};
-+
-+struct appletbdrm_request_header {
-+ __le16 unk_00;
-+ __le16 unk_02;
-+ __le32 unk_04;
-+ __le32 unk_08;
-+ __le32 size;
-+} __packed;
-+
-+struct appletbdrm_response_header {
-+ u8 unk_00[16];
-+ u32 msg;
-+} __packed;
-+
-+struct appletbdrm_simple_request {
-+ struct appletbdrm_request_header header;
-+ u32 msg;
-+ u8 unk_14[8];
-+ __le32 size;
-+} __packed;
-+
-+struct appletbdrm_information {
-+ struct appletbdrm_response_header header;
-+ u8 unk_14[12];
-+ __le32 width;
-+ __le32 height;
-+ u8 bits_per_pixel;
-+ __le32 bytes_per_row;
-+ __le32 orientation;
-+ __le32 bitmap_info;
-+ u32 pixel_format;
-+ __le32 width_inches; /* floating point */
-+ __le32 height_inches; /* floating point */
-+} __packed;
-+
-+struct appletbdrm_frame {
-+ __le16 begin_x;
-+ __le16 begin_y;
-+ __le16 width;
-+ __le16 height;
-+ __le32 buf_size;
-+ u8 buf[];
-+} __packed;
-+
-+struct appletbdrm_fb_request_footer {
-+ u8 unk_00[12];
-+ __le32 unk_0c;
-+ u8 unk_10[12];
-+ __le32 unk_1c;
-+ __le64 timestamp;
-+ u8 unk_28[12];
-+ __le32 unk_34;
-+ u8 unk_38[20];
-+ __le32 unk_4c;
-+} __packed;
-+
-+struct appletbdrm_fb_request {
-+ struct appletbdrm_request_header header;
-+ __le16 unk_10;
-+ u8 msg_id;
-+ u8 unk_13[29];
-+ /*
-+ * Contents of `data`:
-+ * - struct appletbdrm_frame frames[];
-+ * - struct appletbdrm_fb_request_footer footer;
-+ * - padding to make the total size a multiple of 16
-+ */
-+ u8 data[];
-+} __packed;
-+
-+struct appletbdrm_fb_request_response {
-+ struct appletbdrm_response_header header;
-+ u8 unk_14[12];
-+ __le64 timestamp;
-+} __packed;
-+
-+static int appletbdrm_send_request(struct appletbdrm_device *adev,
-+ struct appletbdrm_request_header *request, size_t size)
-+{
-+ struct usb_device *udev = adev_to_udev(adev);
-+ struct drm_device *drm = &adev->drm;
-+ int ret, actual_size;
-+
-+ ret = usb_bulk_msg(udev, usb_sndbulkpipe(udev, adev->out_ep),
-+ request, size, &actual_size, APPLETBDRM_BULK_MSG_TIMEOUT);
-+ if (ret) {
-+ drm_err(drm, "Failed to send message (%pe)\n", ERR_PTR(ret));
-+ return ret;
-+ }
-+
-+ if (actual_size != size) {
-+ drm_err(drm, "Actual size (%d) doesn't match expected size (%lu)\n",
-+ actual_size, size);
-+ return -EIO;
-+ }
-+
-+ return ret;
-+}
-+
-+static int appletbdrm_read_response(struct appletbdrm_device *adev,
-+ struct appletbdrm_response_header *response,
-+ size_t size, u32 expected_response)
-+{
-+ struct usb_device *udev = adev_to_udev(adev);
-+ struct drm_device *drm = &adev->drm;
-+ int ret, actual_size;
-+
-+retry:
-+ ret = usb_bulk_msg(udev, usb_rcvbulkpipe(udev, adev->in_ep),
-+ response, size, &actual_size, APPLETBDRM_BULK_MSG_TIMEOUT);
-+ if (ret) {
-+ drm_err(drm, "Failed to read response (%pe)\n", ERR_PTR(ret));
-+ return ret;
-+ }
-+
-+ /*
-+ * The device responds to the first request sent in a particular
-+ * timeframe after the USB device configuration is set with a readiness
-+ * signal, in which case the response should be read again
-+ */
-+ if (response->msg == APPLETBDRM_MSG_SIGNAL_READINESS) {
-+ if (!adev->readiness_signal_received) {
-+ adev->readiness_signal_received = true;
-+ goto retry;
-+ }
-+
-+ drm_err(drm, "Encountered unexpected readiness signal\n");
-+ return -EIO;
-+ }
-+
-+ if (actual_size != size) {
-+ drm_err(drm, "Actual size (%d) doesn't match expected size (%lu)\n",
-+ actual_size, size);
-+ return -EIO;
-+ }
-+
-+ if (response->msg != expected_response) {
-+ drm_err(drm, "Unexpected response from device (expected %p4ch found %p4ch)\n",
-+ &expected_response, &response->msg);
-+ return -EIO;
-+ }
-+
-+ return 0;
-+}
-+
-+static int appletbdrm_send_msg(struct appletbdrm_device *adev, u32 msg)
-+{
-+ struct appletbdrm_simple_request *request;
-+ int ret;
-+
-+ request = kzalloc(sizeof(*request), GFP_KERNEL);
-+ if (!request)
-+ return -ENOMEM;
-+
-+ request->header.unk_00 = cpu_to_le16(2);
-+ request->header.unk_02 = cpu_to_le16(0x1512);
-+ request->header.size = cpu_to_le32(sizeof(*request) - sizeof(request->header));
-+ request->msg = msg;
-+ request->size = request->header.size;
-+
-+ ret = appletbdrm_send_request(adev, &request->header, sizeof(*request));
-+
-+ kfree(request);
-+
-+ return ret;
-+}
-+
-+static int appletbdrm_clear_display(struct appletbdrm_device *adev)
-+{
-+ return appletbdrm_send_msg(adev, APPLETBDRM_MSG_CLEAR_DISPLAY);
-+}
-+
-+static int appletbdrm_signal_readiness(struct appletbdrm_device *adev)
-+{
-+ return appletbdrm_send_msg(adev, APPLETBDRM_MSG_SIGNAL_READINESS);
-+}
-+
-+static int appletbdrm_get_information(struct appletbdrm_device *adev)
-+{
-+ struct appletbdrm_information *info;
-+ struct drm_device *drm = &adev->drm;
-+ u8 bits_per_pixel;
-+ u32 pixel_format;
-+ int ret;
-+
-+ info = kzalloc(sizeof(*info), GFP_KERNEL);
-+ if (!info)
-+ return -ENOMEM;
-+
-+ ret = appletbdrm_send_msg(adev, APPLETBDRM_MSG_GET_INFORMATION);
-+ if (ret)
-+ return ret;
-+
-+ ret = appletbdrm_read_response(adev, &info->header, sizeof(*info),
-+ APPLETBDRM_MSG_GET_INFORMATION);
-+ if (ret)
-+ goto free_info;
-+
-+ bits_per_pixel = info->bits_per_pixel;
-+ pixel_format = get_unaligned(&info->pixel_format);
-+
-+ adev->width = get_unaligned_le32(&info->width);
-+ adev->height = get_unaligned_le32(&info->height);
-+
-+ if (bits_per_pixel != APPLETBDRM_BITS_PER_PIXEL) {
-+ drm_err(drm, "Encountered unexpected bits per pixel value (%d)\n", bits_per_pixel);
-+ ret = -EINVAL;
-+ goto free_info;
-+ }
-+
-+ if (pixel_format != APPLETBDRM_PIXEL_FORMAT) {
-+ drm_err(drm, "Encountered unknown pixel format (%p4ch)\n", &pixel_format);
-+ ret = -EINVAL;
-+ goto free_info;
-+ }
-+
-+free_info:
-+ kfree(info);
-+
-+ return ret;
-+}
-+
-+static u32 rect_size(struct drm_rect *rect)
-+{
-+ return drm_rect_width(rect) * drm_rect_height(rect) * (APPLETBDRM_BITS_PER_PIXEL / 8);
-+}
-+
-+static int appletbdrm_flush_damage(struct appletbdrm_device *adev,
-+ struct drm_plane_state *old_state,
-+ struct drm_plane_state *state)
-+{
-+ struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(state);
-+ struct appletbdrm_fb_request_response *response;
-+ struct appletbdrm_fb_request_footer *footer;
-+ struct drm_atomic_helper_damage_iter iter;
-+ struct drm_framebuffer *fb = state->fb;
-+ struct appletbdrm_fb_request *request;
-+ struct drm_device *drm = &adev->drm;
-+ struct appletbdrm_frame *frame;
-+ u64 timestamp = ktime_get_ns();
-+ struct drm_rect damage;
-+ size_t frames_size = 0;
-+ size_t request_size;
-+ int ret;
-+
-+ drm_atomic_helper_damage_iter_init(&iter, old_state, state);
-+ drm_atomic_for_each_plane_damage(&iter, &damage) {
-+ frames_size += struct_size(frame, buf, rect_size(&damage));
-+ }
-+
-+ if (!frames_size)
-+ return 0;
-+
-+ request_size = ALIGN(sizeof(*request) + frames_size + sizeof(*footer), 16);
-+
-+ request = kzalloc(request_size, GFP_KERNEL);
-+ if (!request)
-+ return -ENOMEM;
-+
-+ response = kzalloc(sizeof(*response), GFP_KERNEL);
-+ if (!response) {
-+ ret = -ENOMEM;
-+ goto free_request;
-+ }
-+
-+ ret = drm_gem_fb_begin_cpu_access(fb, DMA_FROM_DEVICE);
-+ if (ret) {
-+ drm_err(drm, "Failed to start CPU framebuffer access (%pe)\n", ERR_PTR(ret));
-+ goto free_response;
-+ }
-+
-+ request->header.unk_00 = cpu_to_le16(2);
-+ request->header.unk_02 = cpu_to_le16(0x12);
-+ request->header.unk_04 = cpu_to_le32(9);
-+ request->header.size = cpu_to_le32(request_size - sizeof(request->header));
-+ request->unk_10 = cpu_to_le16(1);
-+ request->msg_id = timestamp & 0xff;
-+
-+ frame = (struct appletbdrm_frame *)request->data;
-+
-+ drm_atomic_helper_damage_iter_init(&iter, old_state, state);
-+ drm_atomic_for_each_plane_damage(&iter, &damage) {
-+ struct iosys_map dst = IOSYS_MAP_INIT_VADDR(frame->buf);
-+ u32 buf_size = rect_size(&damage);
-+
-+ /*
-+ * The coordinates need to be translated to the coordinate
-+ * system the device expects, see the comment in
-+ * appletbdrm_setup_mode_config
-+ */
-+ frame->begin_x = cpu_to_le16(damage.y1);
-+ frame->begin_y = cpu_to_le16(adev->height - damage.x2);
-+ frame->width = cpu_to_le16(drm_rect_height(&damage));
-+ frame->height = cpu_to_le16(drm_rect_width(&damage));
-+ frame->buf_size = cpu_to_le32(buf_size);
-+
-+ ret = drm_fb_blit(&dst, NULL, DRM_FORMAT_BGR888,
-+ &shadow_plane_state->data[0], fb, &damage, &shadow_plane_state->fmtcnv_state);
-+ if (ret) {
-+ drm_err(drm, "Failed to copy damage clip (%pe)\n", ERR_PTR(ret));
-+ goto end_fb_cpu_access;
-+ }
-+
-+ frame = (void *)frame + struct_size(frame, buf, buf_size);
-+ }
-+
-+ footer = (struct appletbdrm_fb_request_footer *)&request->data[frames_size];
-+
-+ footer->unk_0c = cpu_to_le32(0xfffe);
-+ footer->unk_1c = cpu_to_le32(0x80001);
-+ footer->unk_34 = cpu_to_le32(0x80002);
-+ footer->unk_4c = cpu_to_le32(0xffff);
-+ footer->timestamp = cpu_to_le64(timestamp);
-+
-+ ret = appletbdrm_send_request(adev, &request->header, request_size);
-+ if (ret)
-+ goto end_fb_cpu_access;
-+
-+ ret = appletbdrm_read_response(adev, &response->header, sizeof(*response),
-+ APPLETBDRM_MSG_UPDATE_COMPLETE);
-+ if (ret)
-+ goto end_fb_cpu_access;
-+
-+ if (response->timestamp != footer->timestamp) {
-+ drm_err(drm, "Response timestamp (%llu) doesn't match request timestamp (%llu)\n",
-+ le64_to_cpu(response->timestamp), timestamp);
-+ goto end_fb_cpu_access;
-+ }
-+
-+end_fb_cpu_access:
-+ drm_gem_fb_end_cpu_access(fb, DMA_FROM_DEVICE);
-+free_response:
-+ kfree(response);
-+free_request:
-+ kfree(request);
-+
-+ return ret;
-+}
-+
-+static int appletbdrm_connector_helper_get_modes(struct drm_connector *connector)
-+{
-+ struct appletbdrm_device *adev = drm_to_adev(connector->dev);
-+
-+ return drm_connector_helper_get_modes_fixed(connector, &adev->mode);
-+}
-+
-+static enum drm_mode_status appletbdrm_pipe_mode_valid(struct drm_simple_display_pipe *pipe,
-+ const struct drm_display_mode *mode)
-+{
-+ struct drm_crtc *crtc = &pipe->crtc;
-+ struct appletbdrm_device *adev = drm_to_adev(crtc->dev);
-+
-+ return drm_crtc_helper_mode_valid_fixed(crtc, mode, &adev->mode);
-+}
-+
-+static void appletbdrm_pipe_disable(struct drm_simple_display_pipe *pipe)
-+{
-+ struct appletbdrm_device *adev = drm_to_adev(pipe->crtc.dev);
-+ int idx;
-+
-+ if (!drm_dev_enter(&adev->drm, &idx))
-+ return;
-+
-+ appletbdrm_clear_display(adev);
-+
-+ drm_dev_exit(idx);
-+}
-+
-+static void appletbdrm_pipe_update(struct drm_simple_display_pipe *pipe,
-+ struct drm_plane_state *old_state)
-+{
-+ struct drm_crtc *crtc = &pipe->crtc;
-+ struct appletbdrm_device *adev = drm_to_adev(crtc->dev);
-+ int idx;
-+
-+ if (!crtc->state->active || !drm_dev_enter(&adev->drm, &idx))
-+ return;
-+
-+ appletbdrm_flush_damage(adev, old_state, pipe->plane.state);
-+
-+ drm_dev_exit(idx);
-+}
-+
-+static const u32 appletbdrm_formats[] = {
-+ DRM_FORMAT_BGR888,
-+ DRM_FORMAT_XRGB8888, /* emulated */
-+};
-+
-+static const struct drm_mode_config_funcs appletbdrm_mode_config_funcs = {
-+ .fb_create = drm_gem_fb_create_with_dirty,
-+ .atomic_check = drm_atomic_helper_check,
-+ .atomic_commit = drm_atomic_helper_commit,
-+};
-+
-+static const struct drm_connector_funcs appletbdrm_connector_funcs = {
-+ .reset = drm_atomic_helper_connector_reset,
-+ .destroy = drm_connector_cleanup,
-+ .fill_modes = drm_helper_probe_single_connector_modes,
-+ .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
-+ .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
-+};
-+
-+static const struct drm_connector_helper_funcs appletbdrm_connector_helper_funcs = {
-+ .get_modes = appletbdrm_connector_helper_get_modes,
-+};
-+
-+static const struct drm_simple_display_pipe_funcs appletbdrm_pipe_funcs = {
-+ DRM_GEM_SIMPLE_DISPLAY_PIPE_SHADOW_PLANE_FUNCS,
-+ .update = appletbdrm_pipe_update,
-+ .disable = appletbdrm_pipe_disable,
-+ .mode_valid = appletbdrm_pipe_mode_valid,
-+};
-+
-+DEFINE_DRM_GEM_FOPS(appletbdrm_drm_fops);
-+
-+static const struct drm_driver appletbdrm_drm_driver = {
-+ DRM_GEM_SHMEM_DRIVER_OPS,
-+ .name = "appletbdrm",
-+ .desc = "Apple Touch Bar DRM Driver",
-+ .date = "20230910",
-+ .major = 1,
-+ .minor = 0,
-+ .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_ATOMIC,
-+ .fops = &appletbdrm_drm_fops,
-+};
-+
-+static int appletbdrm_setup_mode_config(struct appletbdrm_device *adev)
-+{
-+ struct drm_connector *connector = &adev->connector;
-+ struct drm_device *drm = &adev->drm;
-+ struct device *dev = adev->dev;
-+ int ret;
-+
-+ ret = drmm_mode_config_init(drm);
-+ if (ret)
-+ return dev_err_probe(dev, ret, "Failed to initialize mode configuration\n");
-+
-+ /*
-+ * The coordinate system used by the device is different from the
-+ * coordinate system of the framebuffer in that the x and y axes are
-+ * swapped, and that the y axis is inverted; so what the device reports
-+ * as the height is actually the width of the framebuffer and vice
-+ * versa
-+ */
-+ drm->mode_config.min_width = 0;
-+ drm->mode_config.min_height = 0;
-+ drm->mode_config.max_width = max(adev->height, DRM_SHADOW_PLANE_MAX_WIDTH);
-+ drm->mode_config.max_height = max(adev->width, DRM_SHADOW_PLANE_MAX_HEIGHT);
-+ drm->mode_config.preferred_depth = APPLETBDRM_BITS_PER_PIXEL;
-+ drm->mode_config.funcs = &appletbdrm_mode_config_funcs;
-+
-+ adev->mode = (struct drm_display_mode) {
-+ DRM_MODE_INIT(60, adev->height, adev->width,
-+ DRM_MODE_RES_MM(adev->height, 218),
-+ DRM_MODE_RES_MM(adev->width, 218))
-+ };
-+
-+ ret = drm_connector_init(drm, connector,
-+ &appletbdrm_connector_funcs, DRM_MODE_CONNECTOR_USB);
-+ if (ret)
-+ return dev_err_probe(dev, ret, "Failed to initialize connector\n");
-+
-+ drm_connector_helper_add(connector, &appletbdrm_connector_helper_funcs);
-+
-+ ret = drm_connector_set_panel_orientation(connector,
-+ DRM_MODE_PANEL_ORIENTATION_RIGHT_UP);
-+ if (ret)
-+ return dev_err_probe(dev, ret, "Failed to set panel orientation\n");
-+
-+ connector->display_info.non_desktop = true;
-+ ret = drm_object_property_set_value(&connector->base,
-+ drm->mode_config.non_desktop_property, true);
-+ if (ret)
-+ return dev_err_probe(dev, ret, "Failed to set non-desktop property\n");
-+
-+ ret = drm_simple_display_pipe_init(drm, &adev->pipe, &appletbdrm_pipe_funcs,
-+ appletbdrm_formats, ARRAY_SIZE(appletbdrm_formats),
-+ NULL, &adev->connector);
-+ if (ret)
-+ return dev_err_probe(dev, ret, "Failed to initialize simple display pipe\n");
-+
-+ drm_plane_enable_fb_damage_clips(&adev->pipe.plane);
-+
-+ drm_mode_config_reset(drm);
-+
-+ ret = drm_dev_register(drm, 0);
-+ if (ret)
-+ return dev_err_probe(dev, ret, "Failed to register DRM device\n");
-+
-+ return 0;
-+}
-+
-+static int appletbdrm_probe(struct usb_interface *intf,
-+ const struct usb_device_id *id)
-+{
-+ struct usb_endpoint_descriptor *bulk_in, *bulk_out;
-+ struct device *dev = &intf->dev;
-+ struct appletbdrm_device *adev;
-+ int ret;
-+
-+ ret = usb_find_common_endpoints(intf->cur_altsetting, &bulk_in, &bulk_out, NULL, NULL);
-+ if (ret)
-+ return dev_err_probe(dev, ret, "Failed to find bulk endpoints\n");
-+
-+ adev = devm_drm_dev_alloc(dev, &appletbdrm_drm_driver, struct appletbdrm_device, drm);
-+ if (IS_ERR(adev))
-+ return PTR_ERR(adev);
-+
-+ adev->dev = dev;
-+ adev->in_ep = bulk_in->bEndpointAddress;
-+ adev->out_ep = bulk_out->bEndpointAddress;
-+
-+ usb_set_intfdata(intf, adev);
-+
-+ ret = appletbdrm_get_information(adev);
-+ if (ret)
-+ return dev_err_probe(dev, ret, "Failed to get display information\n");
-+
-+ ret = appletbdrm_signal_readiness(adev);
-+ if (ret)
-+ return dev_err_probe(dev, ret, "Failed to signal readiness\n");
-+
-+ ret = appletbdrm_clear_display(adev);
-+ if (ret)
-+ return dev_err_probe(dev, ret, "Failed to clear display\n");
-+
-+ return appletbdrm_setup_mode_config(adev);
-+}
-+
-+static void appletbdrm_disconnect(struct usb_interface *intf)
-+{
-+ struct appletbdrm_device *adev = usb_get_intfdata(intf);
-+ struct drm_device *drm = &adev->drm;
-+
-+ drm_dev_unplug(drm);
-+ drm_atomic_helper_shutdown(drm);
-+}
-+
-+static void appletbdrm_shutdown(struct usb_interface *intf)
-+{
-+ struct appletbdrm_device *adev = usb_get_intfdata(intf);
-+
-+ /*
-+ * The framebuffer needs to be cleared on shutdown since its content
-+ * persists across boots
-+ */
-+ drm_atomic_helper_shutdown(&adev->drm);
-+}
-+
-+static const struct usb_device_id appletbdrm_usb_id_table[] = {
-+ { USB_DEVICE_INTERFACE_CLASS(0x05ac, 0x8302, USB_CLASS_AUDIO_VIDEO) },
-+ {}
-+};
-+MODULE_DEVICE_TABLE(usb, appletbdrm_usb_id_table);
-+
-+static struct usb_driver appletbdrm_usb_driver = {
-+ .name = "appletbdrm",
-+ .probe = appletbdrm_probe,
-+ .disconnect = appletbdrm_disconnect,
-+ .shutdown = appletbdrm_shutdown,
-+ .id_table = appletbdrm_usb_id_table,
-+};
-+module_usb_driver(appletbdrm_usb_driver);
-+
-+MODULE_AUTHOR("Kerem Karabay <kekrby@gmail.com>");
-+MODULE_DESCRIPTION("Apple Touch Bar DRM Driver");
-+MODULE_LICENSE("GPL");
-diff --git a/drivers/gpu/vga/vga_switcheroo.c b/drivers/gpu/vga/vga_switcheroo.c
-index 365e6ddbe90f..cf357cd3389d 100644
---- a/drivers/gpu/vga/vga_switcheroo.c
-+++ b/drivers/gpu/vga/vga_switcheroo.c
-@@ -438,12 +438,7 @@ find_active_client(struct list_head *head)
- bool vga_switcheroo_client_probe_defer(struct pci_dev *pdev)
- {
- if ((pdev->class >> 16) == PCI_BASE_CLASS_DISPLAY) {
-- /*
-- * apple-gmux is needed on pre-retina MacBook Pro
-- * to probe the panel if pdev is the inactive GPU.
-- */
-- if (apple_gmux_present() && pdev != vga_default_device() &&
-- !vgasr_priv.handler_flags)
-+ if (apple_gmux_present() && !vgasr_priv.handler_flags)
- return true;
- }
-
-diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
-index 08446c89eff6..35ef5d4ef068 100644
---- a/drivers/hid/Kconfig
-+++ b/drivers/hid/Kconfig
-@@ -148,6 +148,27 @@ config HID_APPLEIR
-
- Say Y here if you want support for Apple infrared remote control.
-
-+config HID_APPLETB_BL
-+ tristate "Apple Touch Bar Backlight"
-+ depends on BACKLIGHT_CLASS_DEVICE
-+ help
-+ Say Y here if you want support for the backlight of Touch Bars on x86
-+ MacBook Pros.
-+
-+ To compile this driver as a module, choose M here: the
-+ module will be called hid-appletb-bl.
-+
-+config HID_APPLETB_KBD
-+ tristate "Apple Touch Bar Keyboard Mode"
-+ depends on USB_HID
-+ help
-+ Say Y here if you want support for the keyboard mode (escape,
-+ function, media and brightness keys) of Touch Bars on x86 MacBook
-+ Pros.
-+
-+ To compile this driver as a module, choose M here: the
-+ module will be called hid-appletb-kbd.
-+
- config HID_ASUS
- tristate "Asus"
- depends on USB_HID
-@@ -723,6 +744,7 @@ config HID_MULTITOUCH
- Say Y here if you have one of the following devices:
- - 3M PCT touch screens
- - ActionStar dual touch panels
-+ - Touch Bars on x86 MacBook Pros
- - Atmel panels
- - Cando dual touch panels
- - Chunghwa panels
-diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile
-index ce71b53ea6c5..fecec1d61393 100644
---- a/drivers/hid/Makefile
-+++ b/drivers/hid/Makefile
-@@ -29,6 +29,8 @@
- obj-$(CONFIG_HID_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_ASUS_ALLY) += hid-asus-ally.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 000000000000..8cfbd3f64af6
---- /dev/null
-+++ b/drivers/staging/apple-bce/Makefile
-@@ -0,0 +1,28 @@
-+modname := apple-bce
-+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
-+
-+MY_CFLAGS += -DWITHOUT_NVME_PATCH
-+#MY_CFLAGS += -g -DDEBUG
-+ccflags-y += ${MY_CFLAGS}
-+CC += ${MY_CFLAGS}
-+
-+KVERSION := $(KERNELRELEASE)
-+ifeq ($(origin KERNELRELEASE), undefined)
-+KVERSION := $(shell uname -r)
-+endif
-+
-+KDIR := /lib/modules/$(KVERSION)/build
-+PWD := $(shell pwd)
-+
-+.PHONY: all
-+
-+all:
-+ $(MAKE) -C $(KDIR) M=$(PWD) modules
-+
-+clean:
-+ $(MAKE) -C $(KDIR) M=$(PWD) clean
-+
-+install:
-+ $(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 000000000000..4fd2415d7028
---- /dev/null
-+++ b/drivers/staging/apple-bce/apple_bce.c
-@@ -0,0 +1,445 @@
-+#include "apple_bce.h"
-+#include <linux/module.h>
-+#include <linux/crc32.h>
-+#include "audio/audio.h"
-+#include <linux/version.h>
-+
-+static dev_t bce_chrdev;
-+static struct class *bce_class;
-+
-+struct apple_bce_device *global_bce;
-+
-+static int bce_create_command_queues(struct apple_bce_device *bce);
-+static void bce_free_command_queues(struct apple_bce_device *bce);
-+static irqreturn_t bce_handle_mb_irq(int irq, void *dev);
-+static irqreturn_t bce_handle_dma_irq(int irq, void *dev);
-+static int bce_fw_version_handshake(struct apple_bce_device *bce);
-+static int bce_register_command_queue(struct apple_bce_device *bce, struct bce_queue_memcfg *cfg, int is_sq);
-+
-+static int apple_bce_probe(struct pci_dev *dev, const struct pci_device_id *id)
-+{
-+ struct apple_bce_device *bce = NULL;
-+ int status = 0;
-+ int nvec;
-+
-+ pr_info("apple-bce: capturing our device\n");
-+
-+ if (pci_enable_device(dev))
-+ return -ENODEV;
-+ if (pci_request_regions(dev, "apple-bce")) {
-+ status = -ENODEV;
-+ goto fail;
-+ }
-+ pci_set_master(dev);
-+ nvec = pci_alloc_irq_vectors(dev, 1, 8, PCI_IRQ_MSI);
-+ if (nvec < 5) {
-+ status = -EINVAL;
-+ goto fail;
-+ }
-+
-+ bce = kzalloc(sizeof(struct apple_bce_device), GFP_KERNEL);
-+ if (!bce) {
-+ status = -ENOMEM;
-+ goto fail;
-+ }
-+
-+ bce->pci = dev;
-+ pci_set_drvdata(dev, bce);
-+
-+ bce->devt = bce_chrdev;
-+ bce->dev = device_create(bce_class, &dev->dev, bce->devt, NULL, "apple-bce");
-+ if (IS_ERR_OR_NULL(bce->dev)) {
-+ status = PTR_ERR(bce_class);
-+ goto fail;
-+ }
-+
-+ bce->reg_mem_mb = pci_iomap(dev, 4, 0);
-+ bce->reg_mem_dma = pci_iomap(dev, 2, 0);
-+
-+ if (IS_ERR_OR_NULL(bce->reg_mem_mb) || IS_ERR_OR_NULL(bce->reg_mem_dma)) {
-+ dev_warn(&dev->dev, "apple-bce: Failed to pci_iomap required regions\n");
-+ goto fail;
-+ }
-+
-+ bce_mailbox_init(&bce->mbox, bce->reg_mem_mb);
-+ bce_timestamp_init(&bce->timestamp, bce->reg_mem_mb);
-+
-+ spin_lock_init(&bce->queues_lock);
-+ ida_init(&bce->queue_ida);
-+
-+ if ((status = pci_request_irq(dev, 0, bce_handle_mb_irq, NULL, dev, "bce_mbox")))
-+ goto fail;
-+ if ((status = pci_request_irq(dev, 4, NULL, bce_handle_dma_irq, dev, "bce_dma")))
-+ goto fail_interrupt_0;
-+
-+ if ((status = dma_set_mask_and_coherent(&dev->dev, DMA_BIT_MASK(37)))) {
-+ dev_warn(&dev->dev, "dma: Setting mask failed\n");
-+ goto fail_interrupt;
-+ }
-+
-+ /* Gets the function 0's interface. This is needed because Apple only accepts DMA on our function if function 0
-+ is a bus master, so we need to work around this. */
-+ bce->pci0 = pci_get_slot(dev->bus, PCI_DEVFN(PCI_SLOT(dev->devfn), 0));
-+#ifndef WITHOUT_NVME_PATCH
-+ if ((status = pci_enable_device_mem(bce->pci0))) {
-+ dev_warn(&dev->dev, "apple-bce: failed to enable function 0\n");
-+ goto fail_dev0;
-+ }
-+#endif
-+ pci_set_master(bce->pci0);
-+
-+ bce_timestamp_start(&bce->timestamp, true);
-+
-+ if ((status = bce_fw_version_handshake(bce)))
-+ goto fail_ts;
-+ pr_info("apple-bce: handshake done\n");
-+
-+ if ((status = bce_create_command_queues(bce))) {
-+ pr_info("apple-bce: Creating command queues failed\n");
-+ goto fail_ts;
-+ }
-+
-+ global_bce = bce;
-+
-+ bce_vhci_create(bce, &bce->vhci);
-+
-+ return 0;
-+
-+fail_ts:
-+ bce_timestamp_stop(&bce->timestamp);
-+#ifndef WITHOUT_NVME_PATCH
-+ pci_disable_device(bce->pci0);
-+fail_dev0:
-+#endif
-+ pci_dev_put(bce->pci0);
-+fail_interrupt:
-+ pci_free_irq(dev, 4, dev);
-+fail_interrupt_0:
-+ pci_free_irq(dev, 0, dev);
-+fail:
-+ if (bce && bce->dev) {
-+ device_destroy(bce_class, bce->devt);
-+
-+ if (!IS_ERR_OR_NULL(bce->reg_mem_mb))
-+ pci_iounmap(dev, bce->reg_mem_mb);
-+ if (!IS_ERR_OR_NULL(bce->reg_mem_dma))
-+ pci_iounmap(dev, bce->reg_mem_dma);
-+
-+ kfree(bce);
-+ }
-+
-+ pci_free_irq_vectors(dev);
-+ pci_release_regions(dev);
-+ pci_disable_device(dev);
-+
-+ if (!status)
-+ status = -EINVAL;
-+ return status;
-+}
-+
-+static int bce_create_command_queues(struct apple_bce_device *bce)
-+{
-+ int status;
-+ struct bce_queue_memcfg *cfg;
-+
-+ bce->cmd_cq = bce_alloc_cq(bce, 0, 0x20);
-+ bce->cmd_cmdq = bce_alloc_cmdq(bce, 1, 0x20);
-+ if (bce->cmd_cq == NULL || bce->cmd_cmdq == NULL) {
-+ status = -ENOMEM;
-+ goto err;
-+ }
-+ bce->queues[0] = (struct bce_queue *) bce->cmd_cq;
-+ bce->queues[1] = (struct bce_queue *) bce->cmd_cmdq->sq;
-+
-+ cfg = kzalloc(sizeof(struct bce_queue_memcfg), GFP_KERNEL);
-+ if (!cfg) {
-+ status = -ENOMEM;
-+ goto err;
-+ }
-+ bce_get_cq_memcfg(bce->cmd_cq, cfg);
-+ if ((status = bce_register_command_queue(bce, cfg, false)))
-+ goto err;
-+ bce_get_sq_memcfg(bce->cmd_cmdq->sq, bce->cmd_cq, cfg);
-+ if ((status = bce_register_command_queue(bce, cfg, true)))
-+ goto err;
-+ kfree(cfg);
-+
-+ return 0;
-+
-+err:
-+ if (bce->cmd_cq)
-+ bce_free_cq(bce, bce->cmd_cq);
-+ if (bce->cmd_cmdq)
-+ bce_free_cmdq(bce, bce->cmd_cmdq);
-+ return status;
-+}
-+
-+static void bce_free_command_queues(struct apple_bce_device *bce)
-+{
-+ bce_free_cq(bce, bce->cmd_cq);
-+ bce_free_cmdq(bce, bce->cmd_cmdq);
-+ bce->cmd_cq = NULL;
-+ bce->queues[0] = NULL;
-+}
-+
-+static irqreturn_t bce_handle_mb_irq(int irq, void *dev)
-+{
-+ struct apple_bce_device *bce = pci_get_drvdata(dev);
-+ bce_mailbox_handle_interrupt(&bce->mbox);
-+ return IRQ_HANDLED;
-+}
-+
-+static irqreturn_t bce_handle_dma_irq(int irq, void *dev)
-+{
-+ int i;
-+ struct apple_bce_device *bce = pci_get_drvdata(dev);
-+ spin_lock(&bce->queues_lock);
-+ for (i = 0; i < BCE_MAX_QUEUE_COUNT; i++)
-+ if (bce->queues[i] && bce->queues[i]->type == BCE_QUEUE_CQ)
-+ bce_handle_cq_completions(bce, (struct bce_queue_cq *) bce->queues[i]);
-+ spin_unlock(&bce->queues_lock);
-+ return IRQ_HANDLED;
-+}
-+
-+static int bce_fw_version_handshake(struct apple_bce_device *bce)
-+{
-+ u64 result;
-+ int status;
-+
-+ if ((status = bce_mailbox_send(&bce->mbox, BCE_MB_MSG(BCE_MB_SET_FW_PROTOCOL_VERSION, BC_PROTOCOL_VERSION),
-+ &result)))
-+ return status;
-+ if (BCE_MB_TYPE(result) != BCE_MB_SET_FW_PROTOCOL_VERSION ||
-+ BCE_MB_VALUE(result) != BC_PROTOCOL_VERSION) {
-+ pr_err("apple-bce: FW version handshake failed %x:%llx\n", BCE_MB_TYPE(result), BCE_MB_VALUE(result));
-+ return -EINVAL;
-+ }
-+ return 0;
-+}
-+
-+static int bce_register_command_queue(struct apple_bce_device *bce, struct bce_queue_memcfg *cfg, int is_sq)
-+{
-+ int status;
-+ int cmd_type;
-+ u64 result;
-+ // OS X uses an bidirectional direction, but that's not really needed
-+ dma_addr_t a = dma_map_single(&bce->pci->dev, cfg, sizeof(struct bce_queue_memcfg), DMA_TO_DEVICE);
-+ if (dma_mapping_error(&bce->pci->dev, a))
-+ return -ENOMEM;
-+ cmd_type = is_sq ? BCE_MB_REGISTER_COMMAND_SQ : BCE_MB_REGISTER_COMMAND_CQ;
-+ status = bce_mailbox_send(&bce->mbox, BCE_MB_MSG(cmd_type, a), &result);
-+ dma_unmap_single(&bce->pci->dev, a, sizeof(struct bce_queue_memcfg), DMA_TO_DEVICE);
-+ if (status)
-+ return status;
-+ if (BCE_MB_TYPE(result) != BCE_MB_REGISTER_COMMAND_QUEUE_REPLY)
-+ return -EINVAL;
-+ return 0;
-+}
-+
-+static void apple_bce_remove(struct pci_dev *dev)
-+{
-+ struct apple_bce_device *bce = pci_get_drvdata(dev);
-+ bce->is_being_removed = true;
-+
-+ bce_vhci_destroy(&bce->vhci);
-+
-+ bce_timestamp_stop(&bce->timestamp);
-+#ifndef WITHOUT_NVME_PATCH
-+ pci_disable_device(bce->pci0);
-+#endif
-+ pci_dev_put(bce->pci0);
-+ pci_free_irq(dev, 0, dev);
-+ pci_free_irq(dev, 4, dev);
-+ bce_free_command_queues(bce);
-+ pci_iounmap(dev, bce->reg_mem_mb);
-+ pci_iounmap(dev, bce->reg_mem_dma);
-+ device_destroy(bce_class, bce->devt);
-+ pci_free_irq_vectors(dev);
-+ pci_release_regions(dev);
-+ pci_disable_device(dev);
-+ kfree(bce);
-+}
-+
-+static int bce_save_state_and_sleep(struct apple_bce_device *bce)
-+{
-+ int attempt, status = 0;
-+ u64 resp;
-+ dma_addr_t dma_addr;
-+ void *dma_ptr = NULL;
-+ size_t size = max(PAGE_SIZE, 4096UL);
-+
-+ for (attempt = 0; attempt < 5; ++attempt) {
-+ pr_debug("apple-bce: suspend: attempt %i, buffer size %li\n", attempt, size);
-+ dma_ptr = dma_alloc_coherent(&bce->pci->dev, size, &dma_addr, GFP_KERNEL);
-+ if (!dma_ptr) {
-+ pr_err("apple-bce: suspend failed (data alloc failed)\n");
-+ break;
-+ }
-+ BUG_ON((dma_addr % 4096) != 0);
-+ status = bce_mailbox_send(&bce->mbox,
-+ BCE_MB_MSG(BCE_MB_SAVE_STATE_AND_SLEEP, (dma_addr & ~(4096LLU - 1)) | (size / 4096)), &resp);
-+ if (status) {
-+ pr_err("apple-bce: suspend failed (mailbox send)\n");
-+ break;
-+ }
-+ if (BCE_MB_TYPE(resp) == BCE_MB_SAVE_RESTORE_STATE_COMPLETE) {
-+ bce->saved_data_dma_addr = dma_addr;
-+ bce->saved_data_dma_ptr = dma_ptr;
-+ bce->saved_data_dma_size = size;
-+ return 0;
-+ } else if (BCE_MB_TYPE(resp) == BCE_MB_SAVE_STATE_AND_SLEEP_FAILURE) {
-+ dma_free_coherent(&bce->pci->dev, size, dma_ptr, dma_addr);
-+ /* The 0x10ff magic value was extracted from Apple's driver */
-+ size = (BCE_MB_VALUE(resp) + 0x10ff) & ~(4096LLU - 1);
-+ pr_debug("apple-bce: suspend: device requested a larger buffer (%li)\n", size);
-+ continue;
-+ } else {
-+ pr_err("apple-bce: suspend failed (invalid device response)\n");
-+ status = -EINVAL;
-+ break;
-+ }
-+ }
-+ if (dma_ptr)
-+ dma_free_coherent(&bce->pci->dev, size, dma_ptr, dma_addr);
-+ if (!status)
-+ return bce_mailbox_send(&bce->mbox, BCE_MB_MSG(BCE_MB_SLEEP_NO_STATE, 0), &resp);
-+ return status;
-+}
-+
-+static int bce_restore_state_and_wake(struct apple_bce_device *bce)
-+{
-+ int status;
-+ u64 resp;
-+ if (!bce->saved_data_dma_ptr) {
-+ if ((status = bce_mailbox_send(&bce->mbox, BCE_MB_MSG(BCE_MB_RESTORE_NO_STATE, 0), &resp))) {
-+ pr_err("apple-bce: resume with no state failed (mailbox send)\n");
-+ return status;
-+ }
-+ if (BCE_MB_TYPE(resp) != BCE_MB_RESTORE_NO_STATE) {
-+ pr_err("apple-bce: resume with no state failed (invalid device response)\n");
-+ return -EINVAL;
-+ }
-+ return 0;
-+ }
-+
-+ if ((status = bce_mailbox_send(&bce->mbox, BCE_MB_MSG(BCE_MB_RESTORE_STATE_AND_WAKE,
-+ (bce->saved_data_dma_addr & ~(4096LLU - 1)) | (bce->saved_data_dma_size / 4096)), &resp))) {
-+ pr_err("apple-bce: resume with state failed (mailbox send)\n");
-+ goto finish_with_state;
-+ }
-+ if (BCE_MB_TYPE(resp) != BCE_MB_SAVE_RESTORE_STATE_COMPLETE) {
-+ pr_err("apple-bce: resume with state failed (invalid device response)\n");
-+ status = -EINVAL;
-+ goto finish_with_state;
-+ }
-+
-+finish_with_state:
-+ dma_free_coherent(&bce->pci->dev, bce->saved_data_dma_size, bce->saved_data_dma_ptr, bce->saved_data_dma_addr);
-+ bce->saved_data_dma_ptr = NULL;
-+ return status;
-+}
-+
-+static int apple_bce_suspend(struct device *dev)
-+{
-+ struct apple_bce_device *bce = pci_get_drvdata(to_pci_dev(dev));
-+ int status;
-+
-+ bce_timestamp_stop(&bce->timestamp);
-+
-+ if ((status = bce_save_state_and_sleep(bce)))
-+ return status;
-+
-+ return 0;
-+}
-+
-+static int apple_bce_resume(struct device *dev)
-+{
-+ struct apple_bce_device *bce = pci_get_drvdata(to_pci_dev(dev));
-+ int status;
-+
-+ pci_set_master(bce->pci);
-+ pci_set_master(bce->pci0);
-+
-+ if ((status = bce_restore_state_and_wake(bce)))
-+ return status;
-+
-+ bce_timestamp_start(&bce->timestamp, false);
-+
-+ return 0;
-+}
-+
-+static struct pci_device_id apple_bce_ids[ ] = {
-+ { PCI_DEVICE(PCI_VENDOR_ID_APPLE, 0x1801) },
-+ { 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
-+};
-+struct pci_driver apple_bce_pci_driver = {
-+ .name = "apple-bce",
-+ .id_table = apple_bce_ids,
-+ .probe = apple_bce_probe,
-+ .remove = apple_bce_remove,
-+ .driver = {
-+ .pm = &apple_bce_pci_driver_pm
-+ }
-+};
-+
-+
-+static int __init apple_bce_module_init(void)
-+{
-+ int result;
-+ if ((result = alloc_chrdev_region(&bce_chrdev, 0, 1, "apple-bce")))
-+ goto fail_chrdev;
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(6,4,0)
-+ bce_class = class_create(THIS_MODULE, "apple-bce");
-+#else
-+ bce_class = class_create("apple-bce");
-+#endif
-+ if (IS_ERR(bce_class)) {
-+ result = PTR_ERR(bce_class);
-+ goto fail_class;
-+ }
-+ if ((result = bce_vhci_module_init())) {
-+ pr_err("apple-bce: bce-vhci init failed");
-+ goto fail_class;
-+ }
-+
-+ result = pci_register_driver(&apple_bce_pci_driver);
-+ if (result)
-+ goto fail_drv;
-+
-+ aaudio_module_init();
-+
-+ return 0;
-+
-+fail_drv:
-+ pci_unregister_driver(&apple_bce_pci_driver);
-+fail_class:
-+ class_destroy(bce_class);
-+fail_chrdev:
-+ unregister_chrdev_region(bce_chrdev, 1);
-+ if (!result)
-+ result = -EINVAL;
-+ return result;
-+}
-+static void __exit apple_bce_module_exit(void)
-+{
-+ pci_unregister_driver(&apple_bce_pci_driver);
-+
-+ aaudio_module_exit();
-+ bce_vhci_module_exit();
-+ class_destroy(bce_class);
-+ unregister_chrdev_region(bce_chrdev, 1);
-+}
-+
-+MODULE_LICENSE("GPL");
-+MODULE_AUTHOR("MrARM");
-+MODULE_DESCRIPTION("Apple BCE Driver");
-+MODULE_VERSION("0.01");
-+module_init(apple_bce_module_init);
-+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 000000000000..f13ab8d5742e
---- /dev/null
-+++ b/drivers/staging/apple-bce/apple_bce.h
-@@ -0,0 +1,38 @@
-+#pragma once
-+
-+#include <linux/pci.h>
-+#include <linux/spinlock.h>
-+#include "mailbox.h"
-+#include "queue.h"
-+#include "vhci/vhci.h"
-+
-+#define BC_PROTOCOL_VERSION 0x20001
-+#define BCE_MAX_QUEUE_COUNT 0x100
-+
-+#define BCE_QUEUE_USER_MIN 2
-+#define BCE_QUEUE_USER_MAX (BCE_MAX_QUEUE_COUNT - 1)
-+
-+struct apple_bce_device {
-+ struct pci_dev *pci, *pci0;
-+ dev_t devt;
-+ struct device *dev;
-+ void __iomem *reg_mem_mb;
-+ void __iomem *reg_mem_dma;
-+ struct bce_mailbox mbox;
-+ struct bce_timestamp timestamp;
-+ struct bce_queue *queues[BCE_MAX_QUEUE_COUNT];
-+ struct spinlock queues_lock;
-+ struct ida queue_ida;
-+ struct bce_queue_cq *cmd_cq;
-+ struct bce_queue_cmdq *cmd_cmdq;
-+ struct bce_queue_sq *int_sq_list[BCE_MAX_QUEUE_COUNT];
-+ bool is_being_removed;
-+
-+ dma_addr_t saved_data_dma_addr;
-+ void *saved_data_dma_ptr;
-+ size_t saved_data_dma_size;
-+
-+ struct bce_vhci vhci;
-+};
-+
-+extern struct apple_bce_device *global_bce;
-\ 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 000000000000..bd16ddd16c1d
---- /dev/null
-+++ b/drivers/staging/apple-bce/audio/audio.c
-@@ -0,0 +1,711 @@
-+#include <linux/pci.h>
-+#include <linux/spinlock.h>
-+#include <linux/module.h>
-+#include <linux/random.h>
-+#include <sound/core.h>
-+#include <sound/initval.h>
-+#include <sound/pcm.h>
-+#include <sound/jack.h>
-+#include "audio.h"
-+#include "pcm.h"
-+#include <linux/version.h>
-+
-+static int aaudio_alsa_index = SNDRV_DEFAULT_IDX1;
-+static char *aaudio_alsa_id = SNDRV_DEFAULT_STR1;
-+
-+static dev_t aaudio_chrdev;
-+static struct class *aaudio_class;
-+
-+static int aaudio_init_cmd(struct aaudio_device *a);
-+static int aaudio_init_bs(struct aaudio_device *a);
-+static void aaudio_init_dev(struct aaudio_device *a, aaudio_device_id_t dev_id);
-+static void aaudio_free_dev(struct aaudio_subdevice *sdev);
-+
-+static int aaudio_probe(struct pci_dev *dev, const struct pci_device_id *id)
-+{
-+ struct aaudio_device *aaudio = NULL;
-+ struct aaudio_subdevice *sdev = NULL;
-+ int status = 0;
-+ u32 cfg;
-+
-+ pr_info("aaudio: capturing our device\n");
-+
-+ if (pci_enable_device(dev))
-+ return -ENODEV;
-+ if (pci_request_regions(dev, "aaudio")) {
-+ status = -ENODEV;
-+ goto fail;
-+ }
-+ pci_set_master(dev);
-+
-+ aaudio = kzalloc(sizeof(struct aaudio_device), GFP_KERNEL);
-+ if (!aaudio) {
-+ status = -ENOMEM;
-+ goto fail;
-+ }
-+
-+ aaudio->bce = global_bce;
-+ if (!aaudio->bce) {
-+ dev_warn(&dev->dev, "aaudio: No BCE available\n");
-+ status = -EINVAL;
-+ goto fail;
-+ }
-+
-+ aaudio->pci = dev;
-+ pci_set_drvdata(dev, aaudio);
-+
-+ aaudio->devt = aaudio_chrdev;
-+ aaudio->dev = device_create(aaudio_class, &dev->dev, aaudio->devt, NULL, "aaudio");
-+ if (IS_ERR_OR_NULL(aaudio->dev)) {
-+ status = PTR_ERR(aaudio_class);
-+ goto fail;
-+ }
-+ device_link_add(aaudio->dev, aaudio->bce->dev, DL_FLAG_PM_RUNTIME | DL_FLAG_AUTOREMOVE_CONSUMER);
-+
-+ init_completion(&aaudio->remote_alive);
-+ INIT_LIST_HEAD(&aaudio->subdevice_list);
-+
-+ /* Init: set an unknown flag in the bitset */
-+ if (pci_read_config_dword(dev, 4, &cfg))
-+ dev_warn(&dev->dev, "aaudio: pci_read_config_dword fail\n");
-+ if (pci_write_config_dword(dev, 4, cfg | 6u))
-+ dev_warn(&dev->dev, "aaudio: pci_write_config_dword fail\n");
-+
-+ dev_info(aaudio->dev, "aaudio: bs len = %llx\n", pci_resource_len(dev, 0));
-+ aaudio->reg_mem_bs_dma = pci_resource_start(dev, 0);
-+ aaudio->reg_mem_bs = pci_iomap(dev, 0, 0);
-+ aaudio->reg_mem_cfg = pci_iomap(dev, 4, 0);
-+
-+ aaudio->reg_mem_gpr = (u32 __iomem *) ((u8 __iomem *) aaudio->reg_mem_cfg + 0xC000);
-+
-+ if (IS_ERR_OR_NULL(aaudio->reg_mem_bs) || IS_ERR_OR_NULL(aaudio->reg_mem_cfg)) {
-+ dev_warn(&dev->dev, "aaudio: Failed to pci_iomap required regions\n");
-+ goto fail;
-+ }
-+
-+ if (aaudio_bce_init(aaudio)) {
-+ dev_warn(&dev->dev, "aaudio: Failed to init BCE command transport\n");
-+ goto fail;
-+ }
-+
-+ if (snd_card_new(aaudio->dev, aaudio_alsa_index, aaudio_alsa_id, THIS_MODULE, 0, &aaudio->card)) {
-+ dev_err(&dev->dev, "aaudio: Failed to create ALSA card\n");
-+ goto fail;
-+ }
-+
-+ strcpy(aaudio->card->shortname, "Apple T2 Audio");
-+ strcpy(aaudio->card->longname, "Apple T2 Audio");
-+ strcpy(aaudio->card->mixername, "Apple T2 Audio");
-+ /* Dynamic alsa ids start at 100 */
-+ aaudio->next_alsa_id = 100;
-+
-+ if (aaudio_init_cmd(aaudio)) {
-+ dev_err(&dev->dev, "aaudio: Failed to initialize over BCE\n");
-+ goto fail_snd;
-+ }
-+
-+ if (aaudio_init_bs(aaudio)) {
-+ dev_err(&dev->dev, "aaudio: Failed to initialize BufferStruct\n");
-+ goto fail_snd;
-+ }
-+
-+ if ((status = aaudio_cmd_set_remote_access(aaudio, AAUDIO_REMOTE_ACCESS_ON))) {
-+ dev_err(&dev->dev, "Failed to set remote access\n");
-+ return status;
-+ }
-+
-+ if (snd_card_register(aaudio->card)) {
-+ dev_err(&dev->dev, "aaudio: Failed to register ALSA sound device\n");
-+ goto fail_snd;
-+ }
-+
-+ list_for_each_entry(sdev, &aaudio->subdevice_list, list) {
-+ struct aaudio_buffer_struct_device *dev = &aaudio->bs->devices[sdev->buf_id];
-+
-+ if (sdev->out_stream_cnt == 1 && !strcmp(dev->name, "Speaker")) {
-+ struct snd_pcm_hardware *hw = sdev->out_streams[0].alsa_hw_desc;
-+
-+ snprintf(aaudio->card->driver, sizeof(aaudio->card->driver) / sizeof(char), "AppleT2x%d", hw->channels_min);
-+ }
-+ }
-+
-+ return 0;
-+
-+fail_snd:
-+ snd_card_free(aaudio->card);
-+fail:
-+ if (aaudio && aaudio->dev)
-+ device_destroy(aaudio_class, aaudio->devt);
-+ kfree(aaudio);
-+
-+ if (!IS_ERR_OR_NULL(aaudio->reg_mem_bs))
-+ pci_iounmap(dev, aaudio->reg_mem_bs);
-+ if (!IS_ERR_OR_NULL(aaudio->reg_mem_cfg))
-+ pci_iounmap(dev, aaudio->reg_mem_cfg);
-+
-+ pci_release_regions(dev);
-+ pci_disable_device(dev);
-+
-+ if (!status)
-+ status = -EINVAL;
-+ return status;
-+}
-+
-+
-+
-+static void aaudio_remove(struct pci_dev *dev)
-+{
-+ struct aaudio_subdevice *sdev;
-+ struct aaudio_device *aaudio = pci_get_drvdata(dev);
-+
-+ snd_card_free(aaudio->card);
-+ while (!list_empty(&aaudio->subdevice_list)) {
-+ sdev = list_first_entry(&aaudio->subdevice_list, struct aaudio_subdevice, list);
-+ list_del(&sdev->list);
-+ aaudio_free_dev(sdev);
-+ }
-+ pci_iounmap(dev, aaudio->reg_mem_bs);
-+ pci_iounmap(dev, aaudio->reg_mem_cfg);
-+ device_destroy(aaudio_class, aaudio->devt);
-+ pci_free_irq_vectors(dev);
-+ pci_release_regions(dev);
-+ pci_disable_device(dev);
-+ kfree(aaudio);
-+}
-+
-+static int aaudio_suspend(struct device *dev)
-+{
-+ struct aaudio_device *aaudio = pci_get_drvdata(to_pci_dev(dev));
-+
-+ if (aaudio_cmd_set_remote_access(aaudio, AAUDIO_REMOTE_ACCESS_OFF))
-+ dev_warn(aaudio->dev, "Failed to reset remote access\n");
-+
-+ pci_disable_device(aaudio->pci);
-+ return 0;
-+}
-+
-+static int aaudio_resume(struct device *dev)
-+{
-+ int status;
-+ struct aaudio_device *aaudio = pci_get_drvdata(to_pci_dev(dev));
-+
-+ if ((status = pci_enable_device(aaudio->pci)))
-+ return status;
-+ pci_set_master(aaudio->pci);
-+
-+ if ((status = aaudio_cmd_set_remote_access(aaudio, AAUDIO_REMOTE_ACCESS_ON))) {
-+ dev_err(aaudio->dev, "Failed to set remote access\n");
-+ return status;
-+ }
-+
-+ return 0;
-+}
-+
-+static int aaudio_init_cmd(struct aaudio_device *a)
-+{
-+ int status;
-+ struct aaudio_send_ctx sctx;
-+ struct aaudio_msg buf;
-+ u64 dev_cnt, dev_i;
-+ aaudio_device_id_t *dev_l;
-+
-+ if ((status = aaudio_send(a, &sctx, 500,
-+ aaudio_msg_write_alive_notification, 1, 3))) {
-+ dev_err(a->dev, "Sending alive notification failed\n");
-+ return status;
-+ }
-+
-+ if (wait_for_completion_timeout(&a->remote_alive, msecs_to_jiffies(500)) == 0) {
-+ dev_err(a->dev, "Timed out waiting for remote\n");
-+ return -ETIMEDOUT;
-+ }
-+ dev_info(a->dev, "Continuing init\n");
-+
-+ buf = aaudio_reply_alloc();
-+ if ((status = aaudio_cmd_get_device_list(a, &buf, &dev_l, &dev_cnt))) {
-+ dev_err(a->dev, "Failed to get device list\n");
-+ aaudio_reply_free(&buf);
-+ return status;
-+ }
-+ for (dev_i = 0; dev_i < dev_cnt; ++dev_i)
-+ aaudio_init_dev(a, dev_l[dev_i]);
-+ aaudio_reply_free(&buf);
-+
-+ return 0;
-+}
-+
-+static void aaudio_init_stream_info(struct aaudio_subdevice *sdev, struct aaudio_stream *strm);
-+static void aaudio_handle_jack_connection_change(struct aaudio_subdevice *sdev);
-+
-+static void aaudio_init_dev(struct aaudio_device *a, aaudio_device_id_t dev_id)
-+{
-+ struct aaudio_subdevice *sdev;
-+ struct aaudio_msg buf = aaudio_reply_alloc();
-+ u64 uid_len, stream_cnt, i;
-+ aaudio_object_id_t *stream_list;
-+ char *uid;
-+
-+ sdev = kzalloc(sizeof(struct aaudio_subdevice), GFP_KERNEL);
-+
-+ if (aaudio_cmd_get_property(a, &buf, dev_id, dev_id, AAUDIO_PROP(AAUDIO_PROP_SCOPE_GLOBAL, AAUDIO_PROP_UID, 0),
-+ NULL, 0, (void **) &uid, &uid_len) || uid_len > AAUDIO_DEVICE_MAX_UID_LEN) {
-+ dev_err(a->dev, "Failed to get device uid for device %llx\n", dev_id);
-+ goto fail;
-+ }
-+ dev_info(a->dev, "Remote device %llx %.*s\n", dev_id, (int) uid_len, uid);
-+
-+ sdev->a = a;
-+ INIT_LIST_HEAD(&sdev->list);
-+ sdev->dev_id = dev_id;
-+ sdev->buf_id = AAUDIO_BUFFER_ID_NONE;
-+ strncpy(sdev->uid, uid, uid_len);
-+ sdev->uid[uid_len + 1] = '\0';
-+
-+ if (aaudio_cmd_get_primitive_property(a, dev_id, dev_id,
-+ AAUDIO_PROP(AAUDIO_PROP_SCOPE_INPUT, AAUDIO_PROP_LATENCY, 0), NULL, 0, &sdev->in_latency, sizeof(u32)))
-+ dev_warn(a->dev, "Failed to query device input latency\n");
-+ if (aaudio_cmd_get_primitive_property(a, dev_id, dev_id,
-+ AAUDIO_PROP(AAUDIO_PROP_SCOPE_OUTPUT, AAUDIO_PROP_LATENCY, 0), NULL, 0, &sdev->out_latency, sizeof(u32)))
-+ dev_warn(a->dev, "Failed to query device output latency\n");
-+
-+ if (aaudio_cmd_get_input_stream_list(a, &buf, dev_id, &stream_list, &stream_cnt)) {
-+ dev_err(a->dev, "Failed to get input stream list for device %llx\n", dev_id);
-+ goto fail;
-+ }
-+ if (stream_cnt > AAUDIO_DEIVCE_MAX_INPUT_STREAMS) {
-+ dev_warn(a->dev, "Device %s input stream count %llu is larger than the supported count of %u\n",
-+ sdev->uid, stream_cnt, AAUDIO_DEIVCE_MAX_INPUT_STREAMS);
-+ stream_cnt = AAUDIO_DEIVCE_MAX_INPUT_STREAMS;
-+ }
-+ sdev->in_stream_cnt = stream_cnt;
-+ for (i = 0; i < stream_cnt; i++) {
-+ sdev->in_streams[i].id = stream_list[i];
-+ sdev->in_streams[i].buffer_cnt = 0;
-+ aaudio_init_stream_info(sdev, &sdev->in_streams[i]);
-+ sdev->in_streams[i].latency += sdev->in_latency;
-+ }
-+
-+ if (aaudio_cmd_get_output_stream_list(a, &buf, dev_id, &stream_list, &stream_cnt)) {
-+ dev_err(a->dev, "Failed to get output stream list for device %llx\n", dev_id);
-+ goto fail;
-+ }
-+ if (stream_cnt > AAUDIO_DEIVCE_MAX_OUTPUT_STREAMS) {
-+ dev_warn(a->dev, "Device %s input stream count %llu is larger than the supported count of %u\n",
-+ sdev->uid, stream_cnt, AAUDIO_DEIVCE_MAX_OUTPUT_STREAMS);
-+ stream_cnt = AAUDIO_DEIVCE_MAX_OUTPUT_STREAMS;
-+ }
-+ sdev->out_stream_cnt = stream_cnt;
-+ for (i = 0; i < stream_cnt; i++) {
-+ sdev->out_streams[i].id = stream_list[i];
-+ sdev->out_streams[i].buffer_cnt = 0;
-+ aaudio_init_stream_info(sdev, &sdev->out_streams[i]);
-+ sdev->out_streams[i].latency += sdev->in_latency;
-+ }
-+
-+ if (sdev->is_pcm)
-+ aaudio_create_pcm(sdev);
-+ /* Headphone Jack status */
-+ if (!strcmp(sdev->uid, "Codec Output")) {
-+ if (snd_jack_new(a->card, sdev->uid, SND_JACK_HEADPHONE, &sdev->jack, true, false))
-+ dev_warn(a->dev, "Failed to create an attached jack for %s\n", sdev->uid);
-+ aaudio_cmd_property_listener(a, sdev->dev_id, sdev->dev_id,
-+ AAUDIO_PROP(AAUDIO_PROP_SCOPE_OUTPUT, AAUDIO_PROP_JACK_PLUGGED, 0));
-+ aaudio_handle_jack_connection_change(sdev);
-+ }
-+
-+ aaudio_reply_free(&buf);
-+
-+ list_add_tail(&sdev->list, &a->subdevice_list);
-+ return;
-+
-+fail:
-+ aaudio_reply_free(&buf);
-+ kfree(sdev);
-+}
-+
-+static void aaudio_init_stream_info(struct aaudio_subdevice *sdev, struct aaudio_stream *strm)
-+{
-+ if (aaudio_cmd_get_primitive_property(sdev->a, sdev->dev_id, strm->id,
-+ AAUDIO_PROP(AAUDIO_PROP_SCOPE_GLOBAL, AAUDIO_PROP_PHYS_FORMAT, 0), NULL, 0,
-+ &strm->desc, sizeof(strm->desc)))
-+ dev_warn(sdev->a->dev, "Failed to query stream descriptor\n");
-+ if (aaudio_cmd_get_primitive_property(sdev->a, sdev->dev_id, strm->id,
-+ AAUDIO_PROP(AAUDIO_PROP_SCOPE_GLOBAL, AAUDIO_PROP_LATENCY, 0), NULL, 0, &strm->latency, sizeof(u32)))
-+ dev_warn(sdev->a->dev, "Failed to query stream latency\n");
-+ if (strm->desc.format_id == AAUDIO_FORMAT_LPCM)
-+ sdev->is_pcm = true;
-+}
-+
-+static void aaudio_free_dev(struct aaudio_subdevice *sdev)
-+{
-+ size_t i;
-+ for (i = 0; i < sdev->in_stream_cnt; i++) {
-+ if (sdev->in_streams[i].alsa_hw_desc)
-+ kfree(sdev->in_streams[i].alsa_hw_desc);
-+ if (sdev->in_streams[i].buffers)
-+ kfree(sdev->in_streams[i].buffers);
-+ }
-+ for (i = 0; i < sdev->out_stream_cnt; i++) {
-+ if (sdev->out_streams[i].alsa_hw_desc)
-+ kfree(sdev->out_streams[i].alsa_hw_desc);
-+ if (sdev->out_streams[i].buffers)
-+ kfree(sdev->out_streams[i].buffers);
-+ }
-+ kfree(sdev);
-+}
-+
-+static struct aaudio_subdevice *aaudio_find_dev_by_dev_id(struct aaudio_device *a, aaudio_device_id_t dev_id)
-+{
-+ struct aaudio_subdevice *sdev;
-+ list_for_each_entry(sdev, &a->subdevice_list, list) {
-+ if (dev_id == sdev->dev_id)
-+ return sdev;
-+ }
-+ return NULL;
-+}
-+
-+static struct aaudio_subdevice *aaudio_find_dev_by_uid(struct aaudio_device *a, const char *uid)
-+{
-+ struct aaudio_subdevice *sdev;
-+ list_for_each_entry(sdev, &a->subdevice_list, list) {
-+ if (!strcmp(uid, sdev->uid))
-+ return sdev;
-+ }
-+ return NULL;
-+}
-+
-+static void aaudio_init_bs_stream(struct aaudio_device *a, struct aaudio_stream *strm,
-+ struct aaudio_buffer_struct_stream *bs_strm);
-+static void aaudio_init_bs_stream_host(struct aaudio_device *a, struct aaudio_stream *strm,
-+ struct aaudio_buffer_struct_stream *bs_strm);
-+
-+static int aaudio_init_bs(struct aaudio_device *a)
-+{
-+ int i, j;
-+ struct aaudio_buffer_struct_device *dev;
-+ struct aaudio_subdevice *sdev;
-+ u32 ver, sig, bs_base;
-+
-+ ver = ioread32(&a->reg_mem_gpr[0]);
-+ if (ver < 3) {
-+ dev_err(a->dev, "aaudio: Bad GPR version (%u)", ver);
-+ return -EINVAL;
-+ }
-+ sig = ioread32(&a->reg_mem_gpr[1]);
-+ if (sig != AAUDIO_SIG) {
-+ dev_err(a->dev, "aaudio: Bad GPR sig (%x)", sig);
-+ return -EINVAL;
-+ }
-+ bs_base = ioread32(&a->reg_mem_gpr[2]);
-+ a->bs = (struct aaudio_buffer_struct *) ((u8 *) a->reg_mem_bs + bs_base);
-+ if (a->bs->signature != AAUDIO_SIG) {
-+ dev_err(a->dev, "aaudio: Bad BufferStruct sig (%x)", a->bs->signature);
-+ return -EINVAL;
-+ }
-+ dev_info(a->dev, "aaudio: BufferStruct ver = %i\n", a->bs->version);
-+ dev_info(a->dev, "aaudio: Num devices = %i\n", a->bs->num_devices);
-+ for (i = 0; i < a->bs->num_devices; i++) {
-+ dev = &a->bs->devices[i];
-+ dev_info(a->dev, "aaudio: Device %i %s\n", i, dev->name);
-+
-+ sdev = aaudio_find_dev_by_uid(a, dev->name);
-+ if (!sdev) {
-+ dev_err(a->dev, "aaudio: Subdevice not found for BufferStruct device %s\n", dev->name);
-+ continue;
-+ }
-+ sdev->buf_id = (u8) i;
-+ dev->num_input_streams = 0;
-+ for (j = 0; j < dev->num_output_streams; j++) {
-+ dev_info(a->dev, "aaudio: Device %i Stream %i: Output; Buffer Count = %i\n", i, j,
-+ dev->output_streams[j].num_buffers);
-+ if (j < sdev->out_stream_cnt)
-+ aaudio_init_bs_stream(a, &sdev->out_streams[j], &dev->output_streams[j]);
-+ }
-+ }
-+
-+ list_for_each_entry(sdev, &a->subdevice_list, list) {
-+ if (sdev->buf_id != AAUDIO_BUFFER_ID_NONE)
-+ continue;
-+ sdev->buf_id = i;
-+ dev_info(a->dev, "aaudio: Created device %i %s\n", i, sdev->uid);
-+ strcpy(a->bs->devices[i].name, sdev->uid);
-+ a->bs->devices[i].num_input_streams = 0;
-+ a->bs->devices[i].num_output_streams = 0;
-+ a->bs->num_devices = ++i;
-+ }
-+ list_for_each_entry(sdev, &a->subdevice_list, list) {
-+ if (sdev->in_stream_cnt == 1) {
-+ dev_info(a->dev, "aaudio: Device %i Host Stream; Input\n", sdev->buf_id);
-+ aaudio_init_bs_stream_host(a, &sdev->in_streams[0], &a->bs->devices[sdev->buf_id].input_streams[0]);
-+ a->bs->devices[sdev->buf_id].num_input_streams = 1;
-+ wmb();
-+
-+ if (aaudio_cmd_set_input_stream_address_ranges(a, sdev->dev_id)) {
-+ dev_err(a->dev, "aaudio: Failed to set input stream address ranges\n");
-+ }
-+ }
-+ }
-+
-+ return 0;
-+}
-+
-+static void aaudio_init_bs_stream(struct aaudio_device *a, struct aaudio_stream *strm,
-+ struct aaudio_buffer_struct_stream *bs_strm)
-+{
-+ size_t i;
-+ strm->buffer_cnt = bs_strm->num_buffers;
-+ if (bs_strm->num_buffers > AAUDIO_DEIVCE_MAX_BUFFER_COUNT) {
-+ dev_warn(a->dev, "BufferStruct buffer count %u exceeds driver limit of %u\n", bs_strm->num_buffers,
-+ AAUDIO_DEIVCE_MAX_BUFFER_COUNT);
-+ strm->buffer_cnt = AAUDIO_DEIVCE_MAX_BUFFER_COUNT;
-+ }
-+ if (!strm->buffer_cnt)
-+ return;
-+ strm->buffers = kmalloc_array(strm->buffer_cnt, sizeof(struct aaudio_dma_buf), GFP_KERNEL);
-+ if (!strm->buffers) {
-+ dev_err(a->dev, "Buffer list allocation failed\n");
-+ return;
-+ }
-+ for (i = 0; i < strm->buffer_cnt; i++) {
-+ strm->buffers[i].dma_addr = a->reg_mem_bs_dma + (dma_addr_t) bs_strm->buffers[i].address;
-+ strm->buffers[i].ptr = a->reg_mem_bs + bs_strm->buffers[i].address;
-+ strm->buffers[i].size = bs_strm->buffers[i].size;
-+ }
-+
-+ if (strm->buffer_cnt == 1) {
-+ strm->alsa_hw_desc = kmalloc(sizeof(struct snd_pcm_hardware), GFP_KERNEL);
-+ if (aaudio_create_hw_info(&strm->desc, strm->alsa_hw_desc, strm->buffers[0].size)) {
-+ kfree(strm->alsa_hw_desc);
-+ strm->alsa_hw_desc = NULL;
-+ }
-+ }
-+}
-+
-+static void aaudio_init_bs_stream_host(struct aaudio_device *a, struct aaudio_stream *strm,
-+ struct aaudio_buffer_struct_stream *bs_strm)
-+{
-+ size_t size;
-+ dma_addr_t dma_addr;
-+ void *dma_ptr;
-+ size = strm->desc.bytes_per_packet * 16640;
-+ dma_ptr = dma_alloc_coherent(&a->pci->dev, size, &dma_addr, GFP_KERNEL);
-+ if (!dma_ptr) {
-+ dev_err(a->dev, "dma_alloc_coherent failed\n");
-+ return;
-+ }
-+ bs_strm->buffers[0].address = dma_addr;
-+ bs_strm->buffers[0].size = size;
-+ bs_strm->num_buffers = 1;
-+
-+ memset(dma_ptr, 0, size);
-+
-+ strm->buffer_cnt = 1;
-+ strm->buffers = kmalloc_array(strm->buffer_cnt, sizeof(struct aaudio_dma_buf), GFP_KERNEL);
-+ if (!strm->buffers) {
-+ dev_err(a->dev, "Buffer list allocation failed\n");
-+ return;
-+ }
-+ strm->buffers[0].dma_addr = dma_addr;
-+ strm->buffers[0].ptr = dma_ptr;
-+ strm->buffers[0].size = size;
-+
-+ strm->alsa_hw_desc = kmalloc(sizeof(struct snd_pcm_hardware), GFP_KERNEL);
-+ if (aaudio_create_hw_info(&strm->desc, strm->alsa_hw_desc, strm->buffers[0].size)) {
-+ kfree(strm->alsa_hw_desc);
-+ strm->alsa_hw_desc = NULL;
-+ }
-+}
-+
-+static void aaudio_handle_prop_change(struct aaudio_device *a, struct aaudio_msg *msg);
-+
-+void aaudio_handle_notification(struct aaudio_device *a, struct aaudio_msg *msg)
-+{
-+ struct aaudio_send_ctx sctx;
-+ struct aaudio_msg_base base;
-+ if (aaudio_msg_read_base(msg, &base))
-+ return;
-+ switch (base.msg) {
-+ case AAUDIO_MSG_NOTIFICATION_BOOT:
-+ dev_info(a->dev, "Received boot notification from remote\n");
-+
-+ /* Resend the alive notify */
-+ if (aaudio_send(a, &sctx, 500,
-+ aaudio_msg_write_alive_notification, 1, 3)) {
-+ pr_err("Sending alive notification failed\n");
-+ }
-+ break;
-+ case AAUDIO_MSG_NOTIFICATION_ALIVE:
-+ dev_info(a->dev, "Received alive notification from remote\n");
-+ complete_all(&a->remote_alive);
-+ break;
-+ case AAUDIO_MSG_PROPERTY_CHANGED:
-+ aaudio_handle_prop_change(a, msg);
-+ break;
-+ default:
-+ dev_info(a->dev, "Unhandled notification %i", base.msg);
-+ break;
-+ }
-+}
-+
-+struct aaudio_prop_change_work_struct {
-+ struct work_struct ws;
-+ struct aaudio_device *a;
-+ aaudio_device_id_t dev;
-+ aaudio_object_id_t obj;
-+ struct aaudio_prop_addr prop;
-+};
-+
-+static void aaudio_handle_jack_connection_change(struct aaudio_subdevice *sdev)
-+{
-+ u32 plugged;
-+ if (!sdev->jack)
-+ return;
-+ /* NOTE: Apple made the plug status scoped to the input and output streams. This makes no sense for us, so I just
-+ * always pick the OUTPUT status. */
-+ if (aaudio_cmd_get_primitive_property(sdev->a, sdev->dev_id, sdev->dev_id,
-+ AAUDIO_PROP(AAUDIO_PROP_SCOPE_OUTPUT, AAUDIO_PROP_JACK_PLUGGED, 0), NULL, 0, &plugged, sizeof(plugged))) {
-+ dev_err(sdev->a->dev, "Failed to get jack enable status\n");
-+ return;
-+ }
-+ dev_dbg(sdev->a->dev, "Jack is now %s\n", plugged ? "plugged" : "unplugged");
-+ snd_jack_report(sdev->jack, plugged ? sdev->jack->type : 0);
-+}
-+
-+void aaudio_handle_prop_change_work(struct work_struct *ws)
-+{
-+ struct aaudio_prop_change_work_struct *work = container_of(ws, struct aaudio_prop_change_work_struct, ws);
-+ struct aaudio_subdevice *sdev;
-+
-+ sdev = aaudio_find_dev_by_dev_id(work->a, work->dev);
-+ if (!sdev) {
-+ dev_err(work->a->dev, "Property notification change: device not found\n");
-+ goto done;
-+ }
-+ dev_dbg(work->a->dev, "Property changed for device: %s\n", sdev->uid);
-+
-+ if (work->prop.scope == AAUDIO_PROP_SCOPE_OUTPUT && work->prop.selector == AAUDIO_PROP_JACK_PLUGGED) {
-+ aaudio_handle_jack_connection_change(sdev);
-+ }
-+
-+done:
-+ kfree(work);
-+}
-+
-+void aaudio_handle_prop_change(struct aaudio_device *a, struct aaudio_msg *msg)
-+{
-+ /* NOTE: This is a scheduled work because this callback will generally need to query device information and this
-+ * is not possible when we are in the reply parsing code's context. */
-+ struct aaudio_prop_change_work_struct *work;
-+ work = kmalloc(sizeof(struct aaudio_prop_change_work_struct), GFP_KERNEL);
-+ work->a = a;
-+ INIT_WORK(&work->ws, aaudio_handle_prop_change_work);
-+ aaudio_msg_read_property_changed(msg, &work->dev, &work->obj, &work->prop);
-+ schedule_work(&work->ws);
-+}
-+
-+#define aaudio_send_cmd_response(a, sctx, msg, fn, ...) \
-+ if (aaudio_send_with_tag(a, sctx, ((struct aaudio_msg_header *) msg->data)->tag, 500, fn, ##__VA_ARGS__)) \
-+ pr_err("aaudio: Failed to reply to a command\n");
-+
-+void aaudio_handle_cmd_timestamp(struct aaudio_device *a, struct aaudio_msg *msg)
-+{
-+ ktime_t time_os = ktime_get_boottime();
-+ struct aaudio_send_ctx sctx;
-+ struct aaudio_subdevice *sdev;
-+ u64 devid, timestamp, update_seed;
-+ aaudio_msg_read_update_timestamp(msg, &devid, &timestamp, &update_seed);
-+ dev_dbg(a->dev, "Received timestamp update for dev=%llx ts=%llx seed=%llx\n", devid, timestamp, update_seed);
-+
-+ sdev = aaudio_find_dev_by_dev_id(a, devid);
-+ aaudio_handle_timestamp(sdev, time_os, timestamp);
-+
-+ aaudio_send_cmd_response(a, &sctx, msg,
-+ aaudio_msg_write_update_timestamp_response);
-+}
-+
-+void aaudio_handle_command(struct aaudio_device *a, struct aaudio_msg *msg)
-+{
-+ struct aaudio_msg_base base;
-+ if (aaudio_msg_read_base(msg, &base))
-+ return;
-+ switch (base.msg) {
-+ case AAUDIO_MSG_UPDATE_TIMESTAMP:
-+ aaudio_handle_cmd_timestamp(a, msg);
-+ break;
-+ default:
-+ dev_info(a->dev, "Unhandled device command %i", base.msg);
-+ break;
-+ }
-+}
-+
-+static struct pci_device_id aaudio_ids[ ] = {
-+ { PCI_DEVICE(PCI_VENDOR_ID_APPLE, 0x1803) },
-+ { 0, },
-+};
-+
-+struct dev_pm_ops aaudio_pci_driver_pm = {
-+ .suspend = aaudio_suspend,
-+ .resume = aaudio_resume
-+};
-+struct pci_driver aaudio_pci_driver = {
-+ .name = "aaudio",
-+ .id_table = aaudio_ids,
-+ .probe = aaudio_probe,
-+ .remove = aaudio_remove,
-+ .driver = {
-+ .pm = &aaudio_pci_driver_pm
-+ }
-+};
-+
-+
-+int aaudio_module_init(void)
-+{
-+ int result;
-+ if ((result = alloc_chrdev_region(&aaudio_chrdev, 0, 1, "aaudio")))
-+ goto fail_chrdev;
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(6,4,0)
-+ aaudio_class = class_create(THIS_MODULE, "aaudio");
-+#else
-+ aaudio_class = class_create("aaudio");
-+#endif
-+ if (IS_ERR(aaudio_class)) {
-+ result = PTR_ERR(aaudio_class);
-+ goto fail_class;
-+ }
-+
-+ result = pci_register_driver(&aaudio_pci_driver);
-+ if (result)
-+ goto fail_drv;
-+ return 0;
-+
-+fail_drv:
-+ pci_unregister_driver(&aaudio_pci_driver);
-+fail_class:
-+ class_destroy(aaudio_class);
-+fail_chrdev:
-+ unregister_chrdev_region(aaudio_chrdev, 1);
-+ if (!result)
-+ result = -EINVAL;
-+ return result;
-+}
-+
-+void aaudio_module_exit(void)
-+{
-+ pci_unregister_driver(&aaudio_pci_driver);
-+ class_destroy(aaudio_class);
-+ unregister_chrdev_region(aaudio_chrdev, 1);
-+}
-+
-+struct aaudio_alsa_pcm_id_mapping aaudio_alsa_id_mappings[] = {
-+ {"Speaker", 0},
-+ {"Digital Mic", 1},
-+ {"Codec Output", 2},
-+ {"Codec Input", 3},
-+ {"Bridge Loopback", 4},
-+ {}
-+};
-+
-+module_param_named(index, aaudio_alsa_index, int, 0444);
-+MODULE_PARM_DESC(index, "Index value for Apple Internal Audio soundcard.");
-+module_param_named(id, aaudio_alsa_id, charp, 0444);
-+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 000000000000..004bc1e22ea4
---- /dev/null
-+++ b/drivers/staging/apple-bce/audio/audio.h
-@@ -0,0 +1,125 @@
-+#ifndef AAUDIO_H
-+#define AAUDIO_H
-+
-+#include <linux/types.h>
-+#include <sound/pcm.h>
-+#include "../apple_bce.h"
-+#include "protocol_bce.h"
-+#include "description.h"
-+
-+#define AAUDIO_SIG 0x19870423
-+
-+#define AAUDIO_DEVICE_MAX_UID_LEN 128
-+#define AAUDIO_DEIVCE_MAX_INPUT_STREAMS 1
-+#define AAUDIO_DEIVCE_MAX_OUTPUT_STREAMS 1
-+#define AAUDIO_DEIVCE_MAX_BUFFER_COUNT 1
-+
-+#define AAUDIO_BUFFER_ID_NONE 0xffu
-+
-+struct snd_card;
-+struct snd_pcm;
-+struct snd_pcm_hardware;
-+struct snd_jack;
-+
-+struct __attribute__((packed)) __attribute__((aligned(4))) aaudio_buffer_struct_buffer {
-+ size_t address;
-+ size_t size;
-+ size_t pad[4];
-+};
-+struct aaudio_buffer_struct_stream {
-+ u8 num_buffers;
-+ struct aaudio_buffer_struct_buffer buffers[100];
-+ char filler[32];
-+};
-+struct aaudio_buffer_struct_device {
-+ char name[128];
-+ u8 num_input_streams;
-+ u8 num_output_streams;
-+ struct aaudio_buffer_struct_stream input_streams[5];
-+ struct aaudio_buffer_struct_stream output_streams[5];
-+ char filler[128];
-+};
-+struct aaudio_buffer_struct {
-+ u32 version;
-+ u32 signature;
-+ u32 flags;
-+ u8 num_devices;
-+ struct aaudio_buffer_struct_device devices[20];
-+};
-+
-+struct aaudio_device;
-+struct aaudio_dma_buf {
-+ dma_addr_t dma_addr;
-+ void *ptr;
-+ size_t size;
-+};
-+struct aaudio_stream {
-+ aaudio_object_id_t id;
-+ size_t buffer_cnt;
-+ struct aaudio_dma_buf *buffers;
-+
-+ struct aaudio_apple_description desc;
-+ struct snd_pcm_hardware *alsa_hw_desc;
-+ u32 latency;
-+
-+ bool waiting_for_first_ts;
-+
-+ ktime_t remote_timestamp;
-+ snd_pcm_sframes_t frame_min;
-+ int started;
-+};
-+struct aaudio_subdevice {
-+ struct aaudio_device *a;
-+ struct list_head list;
-+ aaudio_device_id_t dev_id;
-+ u32 in_latency, out_latency;
-+ u8 buf_id;
-+ int alsa_id;
-+ char uid[AAUDIO_DEVICE_MAX_UID_LEN + 1];
-+ size_t in_stream_cnt;
-+ struct aaudio_stream in_streams[AAUDIO_DEIVCE_MAX_INPUT_STREAMS];
-+ size_t out_stream_cnt;
-+ struct aaudio_stream out_streams[AAUDIO_DEIVCE_MAX_OUTPUT_STREAMS];
-+ bool is_pcm;
-+ struct snd_pcm *pcm;
-+ struct snd_jack *jack;
-+};
-+struct aaudio_alsa_pcm_id_mapping {
-+ const char *name;
-+ int alsa_id;
-+};
-+
-+struct aaudio_device {
-+ struct pci_dev *pci;
-+ dev_t devt;
-+ struct device *dev;
-+ void __iomem *reg_mem_bs;
-+ dma_addr_t reg_mem_bs_dma;
-+ void __iomem *reg_mem_cfg;
-+
-+ u32 __iomem *reg_mem_gpr;
-+
-+ struct aaudio_buffer_struct *bs;
-+
-+ struct apple_bce_device *bce;
-+ struct aaudio_bce bcem;
-+
-+ struct snd_card *card;
-+
-+ struct list_head subdevice_list;
-+ int next_alsa_id;
-+
-+ struct completion remote_alive;
-+};
-+
-+void aaudio_handle_notification(struct aaudio_device *a, struct aaudio_msg *msg);
-+void aaudio_handle_prop_change_work(struct work_struct *ws);
-+void aaudio_handle_cmd_timestamp(struct aaudio_device *a, struct aaudio_msg *msg);
-+void aaudio_handle_command(struct aaudio_device *a, struct aaudio_msg *msg);
-+
-+int aaudio_module_init(void);
-+void aaudio_module_exit(void);
-+
-+extern struct aaudio_alsa_pcm_id_mapping aaudio_alsa_id_mappings[];
-+
-+#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 000000000000..dfef3ab68f27
---- /dev/null
-+++ b/drivers/staging/apple-bce/audio/description.h
-@@ -0,0 +1,42 @@
-+#ifndef AAUDIO_DESCRIPTION_H
-+#define AAUDIO_DESCRIPTION_H
-+
-+#include <linux/types.h>
-+
-+struct aaudio_apple_description {
-+ u64 sample_rate_double;
-+ u32 format_id;
-+ u32 format_flags;
-+ u32 bytes_per_packet;
-+ u32 frames_per_packet;
-+ u32 bytes_per_frame;
-+ u32 channels_per_frame;
-+ u32 bits_per_channel;
-+ u32 reserved;
-+};
-+
-+enum {
-+ AAUDIO_FORMAT_LPCM = 0x6c70636d // 'lpcm'
-+};
-+
-+enum {
-+ AAUDIO_FORMAT_FLAG_FLOAT = 1,
-+ AAUDIO_FORMAT_FLAG_BIG_ENDIAN = 2,
-+ AAUDIO_FORMAT_FLAG_SIGNED = 4,
-+ AAUDIO_FORMAT_FLAG_PACKED = 8,
-+ AAUDIO_FORMAT_FLAG_ALIGNED_HIGH = 16,
-+ AAUDIO_FORMAT_FLAG_NON_INTERLEAVED = 32,
-+ AAUDIO_FORMAT_FLAG_NON_MIXABLE = 64
-+};
-+
-+static inline u64 aaudio_double_to_u64(u64 d)
-+{
-+ u8 sign = (u8) ((d >> 63) & 1);
-+ s32 exp = (s32) ((d >> 52) & 0x7ff) - 1023;
-+ u64 fr = d & ((1LL << 52) - 1);
-+ if (sign || exp < 0)
-+ return 0;
-+ return (u64) ((1LL << exp) + (fr >> (52 - exp)));
-+}
-+
-+#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 000000000000..1026e10a9ac5
---- /dev/null
-+++ b/drivers/staging/apple-bce/audio/pcm.c
-@@ -0,0 +1,308 @@
-+#include "pcm.h"
-+#include "audio.h"
-+
-+static u64 aaudio_get_alsa_fmtbit(struct aaudio_apple_description *desc)
-+{
-+ if (desc->format_flags & AAUDIO_FORMAT_FLAG_FLOAT) {
-+ if (desc->bits_per_channel == 32) {
-+ if (desc->format_flags & AAUDIO_FORMAT_FLAG_BIG_ENDIAN)
-+ return SNDRV_PCM_FMTBIT_FLOAT_BE;
-+ else
-+ return SNDRV_PCM_FMTBIT_FLOAT_LE;
-+ } else if (desc->bits_per_channel == 64) {
-+ if (desc->format_flags & AAUDIO_FORMAT_FLAG_BIG_ENDIAN)
-+ return SNDRV_PCM_FMTBIT_FLOAT64_BE;
-+ else
-+ return SNDRV_PCM_FMTBIT_FLOAT64_LE;
-+ } else {
-+ pr_err("aaudio: unsupported bits per channel for float format: %u\n", desc->bits_per_channel);
-+ return 0;
-+ }
-+ }
-+#define DEFINE_BPC_OPTION(val, b) \
-+ case val: \
-+ if (desc->format_flags & AAUDIO_FORMAT_FLAG_BIG_ENDIAN) { \
-+ if (desc->format_flags & AAUDIO_FORMAT_FLAG_SIGNED) \
-+ return SNDRV_PCM_FMTBIT_S ## b ## BE; \
-+ else \
-+ return SNDRV_PCM_FMTBIT_U ## b ## BE; \
-+ } else { \
-+ if (desc->format_flags & AAUDIO_FORMAT_FLAG_SIGNED) \
-+ return SNDRV_PCM_FMTBIT_S ## b ## LE; \
-+ else \
-+ return SNDRV_PCM_FMTBIT_U ## b ## LE; \
-+ }
-+ if (desc->format_flags & AAUDIO_FORMAT_FLAG_PACKED) {
-+ switch (desc->bits_per_channel) {
-+ case 8:
-+ case 16:
-+ case 32:
-+ break;
-+ DEFINE_BPC_OPTION(24, 24_3)
-+ default:
-+ pr_err("aaudio: unsupported bits per channel for packed format: %u\n", desc->bits_per_channel);
-+ return 0;
-+ }
-+ }
-+ if (desc->format_flags & AAUDIO_FORMAT_FLAG_ALIGNED_HIGH) {
-+ switch (desc->bits_per_channel) {
-+ DEFINE_BPC_OPTION(24, 32_)
-+ default:
-+ pr_err("aaudio: unsupported bits per channel for high-aligned format: %u\n", desc->bits_per_channel);
-+ return 0;
-+ }
-+ }
-+ switch (desc->bits_per_channel) {
-+ case 8:
-+ if (desc->format_flags & AAUDIO_FORMAT_FLAG_SIGNED)
-+ return SNDRV_PCM_FMTBIT_S8;
-+ else
-+ return SNDRV_PCM_FMTBIT_U8;
-+ DEFINE_BPC_OPTION(16, 16_)
-+ DEFINE_BPC_OPTION(24, 24_)
-+ DEFINE_BPC_OPTION(32, 32_)
-+ default:
-+ pr_err("aaudio: unsupported bits per channel: %u\n", desc->bits_per_channel);
-+ return 0;
-+ }
-+}
-+int aaudio_create_hw_info(struct aaudio_apple_description *desc, struct snd_pcm_hardware *alsa_hw,
-+ size_t buf_size)
-+{
-+ uint rate;
-+ alsa_hw->info = (SNDRV_PCM_INFO_MMAP |
-+ SNDRV_PCM_INFO_BLOCK_TRANSFER |
-+ SNDRV_PCM_INFO_MMAP_VALID |
-+ SNDRV_PCM_INFO_DOUBLE);
-+ if (desc->format_flags & AAUDIO_FORMAT_FLAG_NON_MIXABLE)
-+ pr_warn("aaudio: unsupported hw flag: NON_MIXABLE\n");
-+ if (!(desc->format_flags & AAUDIO_FORMAT_FLAG_NON_INTERLEAVED))
-+ alsa_hw->info |= SNDRV_PCM_INFO_INTERLEAVED;
-+ alsa_hw->formats = aaudio_get_alsa_fmtbit(desc);
-+ if (!alsa_hw->formats)
-+ return -EINVAL;
-+ rate = (uint) aaudio_double_to_u64(desc->sample_rate_double);
-+ alsa_hw->rates = snd_pcm_rate_to_rate_bit(rate);
-+ alsa_hw->rate_min = rate;
-+ alsa_hw->rate_max = rate;
-+ alsa_hw->channels_min = desc->channels_per_frame;
-+ alsa_hw->channels_max = desc->channels_per_frame;
-+ alsa_hw->buffer_bytes_max = buf_size;
-+ alsa_hw->period_bytes_min = desc->bytes_per_packet;
-+ alsa_hw->period_bytes_max = desc->bytes_per_packet;
-+ alsa_hw->periods_min = (uint) (buf_size / desc->bytes_per_packet);
-+ alsa_hw->periods_max = (uint) (buf_size / desc->bytes_per_packet);
-+ pr_debug("aaudio_create_hw_info: format = %llu, rate = %u/%u. channels = %u, periods = %u, period size = %lu\n",
-+ alsa_hw->formats, alsa_hw->rate_min, alsa_hw->rates, alsa_hw->channels_min, alsa_hw->periods_min,
-+ alsa_hw->period_bytes_min);
-+ return 0;
-+}
-+
-+static struct aaudio_stream *aaudio_pcm_stream(struct snd_pcm_substream *substream)
-+{
-+ struct aaudio_subdevice *sdev = snd_pcm_substream_chip(substream);
-+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-+ return &sdev->out_streams[substream->number];
-+ else
-+ return &sdev->in_streams[substream->number];
-+}
-+
-+static int aaudio_pcm_open(struct snd_pcm_substream *substream)
-+{
-+ pr_debug("aaudio_pcm_open\n");
-+ substream->runtime->hw = *aaudio_pcm_stream(substream)->alsa_hw_desc;
-+
-+ return 0;
-+}
-+
-+static int aaudio_pcm_close(struct snd_pcm_substream *substream)
-+{
-+ pr_debug("aaudio_pcm_close\n");
-+ return 0;
-+}
-+
-+static int aaudio_pcm_prepare(struct snd_pcm_substream *substream)
-+{
-+ return 0;
-+}
-+
-+static int aaudio_pcm_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *hw_params)
-+{
-+ struct aaudio_stream *astream = aaudio_pcm_stream(substream);
-+ pr_debug("aaudio_pcm_hw_params\n");
-+
-+ if (!astream->buffer_cnt || !astream->buffers)
-+ return -EINVAL;
-+
-+ substream->runtime->dma_area = astream->buffers[0].ptr;
-+ substream->runtime->dma_addr = astream->buffers[0].dma_addr;
-+ substream->runtime->dma_bytes = astream->buffers[0].size;
-+ return 0;
-+}
-+
-+static int aaudio_pcm_hw_free(struct snd_pcm_substream *substream)
-+{
-+ pr_debug("aaudio_pcm_hw_free\n");
-+ return 0;
-+}
-+
-+static void aaudio_pcm_start(struct snd_pcm_substream *substream)
-+{
-+ struct aaudio_subdevice *sdev = snd_pcm_substream_chip(substream);
-+ struct aaudio_stream *stream = aaudio_pcm_stream(substream);
-+ void *buf;
-+ size_t s;
-+ ktime_t time_start, time_end;
-+ bool back_buffer;
-+ time_start = ktime_get();
-+
-+ back_buffer = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
-+
-+ if (back_buffer) {
-+ s = frames_to_bytes(substream->runtime, substream->runtime->control->appl_ptr);
-+ buf = kmalloc(s, GFP_KERNEL);
-+ memcpy_fromio(buf, substream->runtime->dma_area, s);
-+ time_end = ktime_get();
-+ pr_debug("aaudio: Backed up the buffer in %lluns [%li]\n", ktime_to_ns(time_end - time_start),
-+ substream->runtime->control->appl_ptr);
-+ }
-+
-+ stream->waiting_for_first_ts = true;
-+ stream->frame_min = stream->latency;
-+
-+ aaudio_cmd_start_io(sdev->a, sdev->dev_id);
-+ if (back_buffer)
-+ memcpy_toio(substream->runtime->dma_area, buf, s);
-+
-+ time_end = ktime_get();
-+ pr_debug("aaudio: Started the audio device in %lluns\n", ktime_to_ns(time_end - time_start));
-+}
-+
-+static int aaudio_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
-+{
-+ struct aaudio_subdevice *sdev = snd_pcm_substream_chip(substream);
-+ struct aaudio_stream *stream = aaudio_pcm_stream(substream);
-+ pr_debug("aaudio_pcm_trigger %x\n", cmd);
-+
-+ /* We only supports triggers on the #0 buffer */
-+ if (substream->number != 0)
-+ return 0;
-+ switch (cmd) {
-+ case SNDRV_PCM_TRIGGER_START:
-+ aaudio_pcm_start(substream);
-+ stream->started = 1;
-+ break;
-+ case SNDRV_PCM_TRIGGER_STOP:
-+ aaudio_cmd_stop_io(sdev->a, sdev->dev_id);
-+ stream->started = 0;
-+ break;
-+ default:
-+ return -EINVAL;
-+ }
-+ return 0;
-+}
-+
-+static snd_pcm_uframes_t aaudio_pcm_pointer(struct snd_pcm_substream *substream)
-+{
-+ struct aaudio_stream *stream = aaudio_pcm_stream(substream);
-+ ktime_t time_from_start;
-+ snd_pcm_sframes_t frames;
-+ snd_pcm_sframes_t buffer_time_length;
-+
-+ if (!stream->started || stream->waiting_for_first_ts) {
-+ pr_warn("aaudio_pcm_pointer while not started\n");
-+ return 0;
-+ }
-+
-+ /* Approximate the pointer based on the last received timestamp */
-+ time_from_start = ktime_get_boottime() - stream->remote_timestamp;
-+ buffer_time_length = NSEC_PER_SEC * substream->runtime->buffer_size / substream->runtime->rate;
-+ frames = (ktime_to_ns(time_from_start) % buffer_time_length) * substream->runtime->buffer_size / buffer_time_length;
-+ if (ktime_to_ns(time_from_start) < buffer_time_length) {
-+ if (frames < stream->frame_min)
-+ frames = stream->frame_min;
-+ else
-+ stream->frame_min = 0;
-+ } else {
-+ if (ktime_to_ns(time_from_start) < 2 * buffer_time_length)
-+ stream->frame_min = frames;
-+ else
-+ stream->frame_min = 0; /* Heavy desync */
-+ }
-+ frames -= stream->latency;
-+ if (frames < 0)
-+ frames += ((-frames - 1) / substream->runtime->buffer_size + 1) * substream->runtime->buffer_size;
-+ return (snd_pcm_uframes_t) frames;
-+}
-+
-+static struct snd_pcm_ops aaudio_pcm_ops = {
-+ .open = aaudio_pcm_open,
-+ .close = aaudio_pcm_close,
-+ .ioctl = snd_pcm_lib_ioctl,
-+ .hw_params = aaudio_pcm_hw_params,
-+ .hw_free = aaudio_pcm_hw_free,
-+ .prepare = aaudio_pcm_prepare,
-+ .trigger = aaudio_pcm_trigger,
-+ .pointer = aaudio_pcm_pointer,
-+ .mmap = snd_pcm_lib_mmap_iomem
-+};
-+
-+int aaudio_create_pcm(struct aaudio_subdevice *sdev)
-+{
-+ struct snd_pcm *pcm;
-+ struct aaudio_alsa_pcm_id_mapping *id_mapping;
-+ int err;
-+
-+ if (!sdev->is_pcm || (sdev->in_stream_cnt == 0 && sdev->out_stream_cnt == 0)) {
-+ return -EINVAL;
-+ }
-+
-+ for (id_mapping = aaudio_alsa_id_mappings; id_mapping->name; id_mapping++) {
-+ if (!strcmp(sdev->uid, id_mapping->name)) {
-+ sdev->alsa_id = id_mapping->alsa_id;
-+ break;
-+ }
-+ }
-+ if (!id_mapping->name)
-+ sdev->alsa_id = sdev->a->next_alsa_id++;
-+ err = snd_pcm_new(sdev->a->card, sdev->uid, sdev->alsa_id,
-+ (int) sdev->out_stream_cnt, (int) sdev->in_stream_cnt, &pcm);
-+ if (err < 0)
-+ return err;
-+ pcm->private_data = sdev;
-+ pcm->nonatomic = 1;
-+ sdev->pcm = pcm;
-+ strcpy(pcm->name, sdev->uid);
-+ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &aaudio_pcm_ops);
-+ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &aaudio_pcm_ops);
-+ return 0;
-+}
-+
-+static void aaudio_handle_stream_timestamp(struct snd_pcm_substream *substream, ktime_t timestamp)
-+{
-+ unsigned long flags;
-+ struct aaudio_stream *stream;
-+
-+ stream = aaudio_pcm_stream(substream);
-+ snd_pcm_stream_lock_irqsave(substream, flags);
-+ stream->remote_timestamp = timestamp;
-+ if (stream->waiting_for_first_ts) {
-+ stream->waiting_for_first_ts = false;
-+ snd_pcm_stream_unlock_irqrestore(substream, flags);
-+ return;
-+ }
-+ snd_pcm_stream_unlock_irqrestore(substream, flags);
-+ snd_pcm_period_elapsed(substream);
-+}
-+
-+void aaudio_handle_timestamp(struct aaudio_subdevice *sdev, ktime_t os_timestamp, u64 dev_timestamp)
-+{
-+ struct snd_pcm_substream *substream;
-+
-+ substream = sdev->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
-+ if (substream)
-+ aaudio_handle_stream_timestamp(substream, dev_timestamp);
-+ substream = sdev->pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream;
-+ if (substream)
-+ aaudio_handle_stream_timestamp(substream, os_timestamp);
-+}
-diff --git a/drivers/staging/apple-bce/audio/pcm.h b/drivers/staging/apple-bce/audio/pcm.h
-new file mode 100644
-index 000000000000..ea5f35fbe408
---- /dev/null
-+++ b/drivers/staging/apple-bce/audio/pcm.h
-@@ -0,0 +1,16 @@
-+#ifndef AAUDIO_PCM_H
-+#define AAUDIO_PCM_H
-+
-+#include <linux/types.h>
-+#include <linux/ktime.h>
-+
-+struct aaudio_subdevice;
-+struct aaudio_apple_description;
-+struct snd_pcm_hardware;
-+
-+int aaudio_create_hw_info(struct aaudio_apple_description *desc, struct snd_pcm_hardware *alsa_hw, size_t buf_size);
-+int aaudio_create_pcm(struct aaudio_subdevice *sdev);
-+
-+void aaudio_handle_timestamp(struct aaudio_subdevice *sdev, ktime_t os_timestamp, u64 dev_timestamp);
-+
-+#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 000000000000..2314813aeead
---- /dev/null
-+++ b/drivers/staging/apple-bce/audio/protocol.c
-@@ -0,0 +1,347 @@
-+#include "protocol.h"
-+#include "protocol_bce.h"
-+#include "audio.h"
-+
-+int aaudio_msg_read_base(struct aaudio_msg *msg, struct aaudio_msg_base *base)
-+{
-+ if (msg->size < sizeof(struct aaudio_msg_header) + sizeof(struct aaudio_msg_base) * 2)
-+ return -EINVAL;
-+ *base = *((struct aaudio_msg_base *) ((struct aaudio_msg_header *) msg->data + 1));
-+ return 0;
-+}
-+
-+#define READ_START(type) \
-+ size_t offset = sizeof(struct aaudio_msg_header) + sizeof(struct aaudio_msg_base); (void)offset; \
-+ if (((struct aaudio_msg_base *) ((struct aaudio_msg_header *) msg->data + 1))->msg != type) \
-+ return -EINVAL;
-+#define READ_DEVID_VAR(devid) *devid = ((struct aaudio_msg_header *) msg->data)->device_id
-+#define READ_VAL(type) ({ offset += sizeof(type); *((type *) ((u8 *) msg->data + offset - sizeof(type))); })
-+#define READ_VAR(type, var) *var = READ_VAL(type)
-+
-+int aaudio_msg_read_start_io_response(struct aaudio_msg *msg)
-+{
-+ READ_START(AAUDIO_MSG_START_IO_RESPONSE);
-+ return 0;
-+}
-+
-+int aaudio_msg_read_stop_io_response(struct aaudio_msg *msg)
-+{
-+ READ_START(AAUDIO_MSG_STOP_IO_RESPONSE);
-+ return 0;
-+}
-+
-+int aaudio_msg_read_update_timestamp(struct aaudio_msg *msg, aaudio_device_id_t *devid,
-+ u64 *timestamp, u64 *update_seed)
-+{
-+ READ_START(AAUDIO_MSG_UPDATE_TIMESTAMP);
-+ READ_DEVID_VAR(devid);
-+ READ_VAR(u64, timestamp);
-+ READ_VAR(u64, update_seed);
-+ return 0;
-+}
-+
-+int aaudio_msg_read_get_property_response(struct aaudio_msg *msg, aaudio_object_id_t *obj,
-+ struct aaudio_prop_addr *prop, void **data, u64 *data_size)
-+{
-+ READ_START(AAUDIO_MSG_GET_PROPERTY_RESPONSE);
-+ READ_VAR(aaudio_object_id_t, obj);
-+ READ_VAR(u32, &prop->element);
-+ READ_VAR(u32, &prop->scope);
-+ READ_VAR(u32, &prop->selector);
-+ READ_VAR(u64, data_size);
-+ *data = ((u8 *) msg->data + offset);
-+ /* offset += data_size; */
-+ return 0;
-+}
-+
-+int aaudio_msg_read_set_property_response(struct aaudio_msg *msg, aaudio_object_id_t *obj)
-+{
-+ READ_START(AAUDIO_MSG_SET_PROPERTY_RESPONSE);
-+ READ_VAR(aaudio_object_id_t, obj);
-+ return 0;
-+}
-+
-+int aaudio_msg_read_property_listener_response(struct aaudio_msg *msg, aaudio_object_id_t *obj,
-+ struct aaudio_prop_addr *prop)
-+{
-+ READ_START(AAUDIO_MSG_PROPERTY_LISTENER_RESPONSE);
-+ READ_VAR(aaudio_object_id_t, obj);
-+ READ_VAR(u32, &prop->element);
-+ READ_VAR(u32, &prop->scope);
-+ READ_VAR(u32, &prop->selector);
-+ return 0;
-+}
-+
-+int aaudio_msg_read_property_changed(struct aaudio_msg *msg, aaudio_device_id_t *devid, aaudio_object_id_t *obj,
-+ struct aaudio_prop_addr *prop)
-+{
-+ READ_START(AAUDIO_MSG_PROPERTY_CHANGED);
-+ READ_DEVID_VAR(devid);
-+ READ_VAR(aaudio_object_id_t, obj);
-+ READ_VAR(u32, &prop->element);
-+ READ_VAR(u32, &prop->scope);
-+ READ_VAR(u32, &prop->selector);
-+ return 0;
-+}
-+
-+int aaudio_msg_read_set_input_stream_address_ranges_response(struct aaudio_msg *msg)
-+{
-+ READ_START(AAUDIO_MSG_SET_INPUT_STREAM_ADDRESS_RANGES_RESPONSE);
-+ return 0;
-+}
-+
-+int aaudio_msg_read_get_input_stream_list_response(struct aaudio_msg *msg, aaudio_object_id_t **str_l, u64 *str_cnt)
-+{
-+ READ_START(AAUDIO_MSG_GET_INPUT_STREAM_LIST_RESPONSE);
-+ READ_VAR(u64, str_cnt);
-+ *str_l = (aaudio_device_id_t *) ((u8 *) msg->data + offset);
-+ /* offset += str_cnt * sizeof(aaudio_object_id_t); */
-+ return 0;
-+}
-+
-+int aaudio_msg_read_get_output_stream_list_response(struct aaudio_msg *msg, aaudio_object_id_t **str_l, u64 *str_cnt)
-+{
-+ READ_START(AAUDIO_MSG_GET_OUTPUT_STREAM_LIST_RESPONSE);
-+ READ_VAR(u64, str_cnt);
-+ *str_l = (aaudio_device_id_t *) ((u8 *) msg->data + offset);
-+ /* offset += str_cnt * sizeof(aaudio_object_id_t); */
-+ return 0;
-+}
-+
-+int aaudio_msg_read_set_remote_access_response(struct aaudio_msg *msg)
-+{
-+ READ_START(AAUDIO_MSG_SET_REMOTE_ACCESS_RESPONSE);
-+ return 0;
-+}
-+
-+int aaudio_msg_read_get_device_list_response(struct aaudio_msg *msg, aaudio_device_id_t **dev_l, u64 *dev_cnt)
-+{
-+ READ_START(AAUDIO_MSG_GET_DEVICE_LIST_RESPONSE);
-+ READ_VAR(u64, dev_cnt);
-+ *dev_l = (aaudio_device_id_t *) ((u8 *) msg->data + offset);
-+ /* offset += dev_cnt * sizeof(aaudio_device_id_t); */
-+ return 0;
-+}
-+
-+#define WRITE_START_OF_TYPE(typev, devid) \
-+ size_t offset = sizeof(struct aaudio_msg_header); (void) offset; \
-+ ((struct aaudio_msg_header *) msg->data)->type = (typev); \
-+ ((struct aaudio_msg_header *) msg->data)->device_id = (devid);
-+#define WRITE_START_COMMAND(devid) WRITE_START_OF_TYPE(AAUDIO_MSG_TYPE_COMMAND, devid)
-+#define WRITE_START_RESPONSE() WRITE_START_OF_TYPE(AAUDIO_MSG_TYPE_RESPONSE, 0)
-+#define WRITE_START_NOTIFICATION() WRITE_START_OF_TYPE(AAUDIO_MSG_TYPE_NOTIFICATION, 0)
-+#define WRITE_VAL(type, value) { *((type *) ((u8 *) msg->data + offset)) = value; offset += sizeof(value); }
-+#define WRITE_BIN(value, size) { memcpy((u8 *) msg->data + offset, value, size); offset += size; }
-+#define WRITE_BASE(type) WRITE_VAL(u32, type) WRITE_VAL(u32, 0)
-+#define WRITE_END() { msg->size = offset; }
-+
-+void aaudio_msg_write_start_io(struct aaudio_msg *msg, aaudio_device_id_t dev)
-+{
-+ WRITE_START_COMMAND(dev);
-+ WRITE_BASE(AAUDIO_MSG_START_IO);
-+ WRITE_END();
-+}
-+
-+void aaudio_msg_write_stop_io(struct aaudio_msg *msg, aaudio_device_id_t dev)
-+{
-+ WRITE_START_COMMAND(dev);
-+ WRITE_BASE(AAUDIO_MSG_STOP_IO);
-+ WRITE_END();
-+}
-+
-+void aaudio_msg_write_get_property(struct aaudio_msg *msg, aaudio_device_id_t dev, aaudio_object_id_t obj,
-+ struct aaudio_prop_addr prop, void *qualifier, u64 qualifier_size)
-+{
-+ WRITE_START_COMMAND(dev);
-+ WRITE_BASE(AAUDIO_MSG_GET_PROPERTY);
-+ WRITE_VAL(aaudio_object_id_t, obj);
-+ WRITE_VAL(u32, prop.element);
-+ WRITE_VAL(u32, prop.scope);
-+ WRITE_VAL(u32, prop.selector);
-+ WRITE_VAL(u64, qualifier_size);
-+ WRITE_BIN(qualifier, qualifier_size);
-+ WRITE_END();
-+}
-+
-+void aaudio_msg_write_set_property(struct aaudio_msg *msg, aaudio_device_id_t dev, aaudio_object_id_t obj,
-+ struct aaudio_prop_addr prop, void *data, u64 data_size, void *qualifier, u64 qualifier_size)
-+{
-+ WRITE_START_COMMAND(dev);
-+ WRITE_BASE(AAUDIO_MSG_SET_PROPERTY);
-+ WRITE_VAL(aaudio_object_id_t, obj);
-+ WRITE_VAL(u32, prop.element);
-+ WRITE_VAL(u32, prop.scope);
-+ WRITE_VAL(u32, prop.selector);
-+ WRITE_VAL(u64, data_size);
-+ WRITE_BIN(data, data_size);
-+ WRITE_VAL(u64, qualifier_size);
-+ WRITE_BIN(qualifier, qualifier_size);
-+ WRITE_END();
-+}
-+
-+void aaudio_msg_write_property_listener(struct aaudio_msg *msg, aaudio_device_id_t dev, aaudio_object_id_t obj,
-+ struct aaudio_prop_addr prop)
-+{
-+ WRITE_START_COMMAND(dev);
-+ WRITE_BASE(AAUDIO_MSG_PROPERTY_LISTENER);
-+ WRITE_VAL(aaudio_object_id_t, obj);
-+ WRITE_VAL(u32, prop.element);
-+ WRITE_VAL(u32, prop.scope);
-+ WRITE_VAL(u32, prop.selector);
-+ WRITE_END();
-+}
-+
-+void aaudio_msg_write_set_input_stream_address_ranges(struct aaudio_msg *msg, aaudio_device_id_t devid)
-+{
-+ WRITE_START_COMMAND(devid);
-+ WRITE_BASE(AAUDIO_MSG_SET_INPUT_STREAM_ADDRESS_RANGES);
-+ WRITE_END();
-+}
-+
-+void aaudio_msg_write_get_input_stream_list(struct aaudio_msg *msg, aaudio_device_id_t devid)
-+{
-+ WRITE_START_COMMAND(devid);
-+ WRITE_BASE(AAUDIO_MSG_GET_INPUT_STREAM_LIST);
-+ WRITE_END();
-+}
-+
-+void aaudio_msg_write_get_output_stream_list(struct aaudio_msg *msg, aaudio_device_id_t devid)
-+{
-+ WRITE_START_COMMAND(devid);
-+ WRITE_BASE(AAUDIO_MSG_GET_OUTPUT_STREAM_LIST);
-+ WRITE_END();
-+}
-+
-+void aaudio_msg_write_set_remote_access(struct aaudio_msg *msg, u64 mode)
-+{
-+ WRITE_START_COMMAND(0);
-+ WRITE_BASE(AAUDIO_MSG_SET_REMOTE_ACCESS);
-+ WRITE_VAL(u64, mode);
-+ WRITE_END();
-+}
-+
-+void aaudio_msg_write_alive_notification(struct aaudio_msg *msg, u32 proto_ver, u32 msg_ver)
-+{
-+ WRITE_START_NOTIFICATION();
-+ WRITE_BASE(AAUDIO_MSG_NOTIFICATION_ALIVE);
-+ WRITE_VAL(u32, proto_ver);
-+ WRITE_VAL(u32, msg_ver);
-+ WRITE_END();
-+}
-+
-+void aaudio_msg_write_update_timestamp_response(struct aaudio_msg *msg)
-+{
-+ WRITE_START_RESPONSE();
-+ WRITE_BASE(AAUDIO_MSG_UPDATE_TIMESTAMP_RESPONSE);
-+ WRITE_END();
-+}
-+
-+void aaudio_msg_write_get_device_list(struct aaudio_msg *msg)
-+{
-+ WRITE_START_COMMAND(0);
-+ WRITE_BASE(AAUDIO_MSG_GET_DEVICE_LIST);
-+ WRITE_END();
-+}
-+
-+#define CMD_SHARED_VARS_NO_REPLY \
-+ int status = 0; \
-+ struct aaudio_send_ctx sctx;
-+#define CMD_SHARED_VARS \
-+ CMD_SHARED_VARS_NO_REPLY \
-+ struct aaudio_msg reply = aaudio_reply_alloc(); \
-+ struct aaudio_msg *buf = &reply;
-+#define CMD_SEND_REQUEST(fn, ...) \
-+ if ((status = aaudio_send_cmd_sync(a, &sctx, buf, 500, fn, ##__VA_ARGS__))) \
-+ return status;
-+#define CMD_DEF_SHARED_AND_SEND(fn, ...) \
-+ CMD_SHARED_VARS \
-+ CMD_SEND_REQUEST(fn, ##__VA_ARGS__);
-+#define CMD_DEF_SHARED_NO_REPLY_AND_SEND(fn, ...) \
-+ CMD_SHARED_VARS_NO_REPLY \
-+ CMD_SEND_REQUEST(fn, ##__VA_ARGS__);
-+#define CMD_HNDL_REPLY_NO_FREE(fn, ...) \
-+ status = fn(buf, ##__VA_ARGS__); \
-+ return status;
-+#define CMD_HNDL_REPLY_AND_FREE(fn, ...) \
-+ status = fn(buf, ##__VA_ARGS__); \
-+ aaudio_reply_free(&reply); \
-+ return status;
-+
-+int aaudio_cmd_start_io(struct aaudio_device *a, aaudio_device_id_t devid)
-+{
-+ CMD_DEF_SHARED_AND_SEND(aaudio_msg_write_start_io, devid);
-+ CMD_HNDL_REPLY_AND_FREE(aaudio_msg_read_start_io_response);
-+}
-+int aaudio_cmd_stop_io(struct aaudio_device *a, aaudio_device_id_t devid)
-+{
-+ CMD_DEF_SHARED_AND_SEND(aaudio_msg_write_stop_io, devid);
-+ CMD_HNDL_REPLY_AND_FREE(aaudio_msg_read_stop_io_response);
-+}
-+int aaudio_cmd_get_property(struct aaudio_device *a, struct aaudio_msg *buf,
-+ aaudio_device_id_t devid, aaudio_object_id_t obj,
-+ struct aaudio_prop_addr prop, void *qualifier, u64 qualifier_size, void **data, u64 *data_size)
-+{
-+ CMD_DEF_SHARED_NO_REPLY_AND_SEND(aaudio_msg_write_get_property, devid, obj, prop, qualifier, qualifier_size);
-+ CMD_HNDL_REPLY_NO_FREE(aaudio_msg_read_get_property_response, &obj, &prop, data, data_size);
-+}
-+int aaudio_cmd_get_primitive_property(struct aaudio_device *a,
-+ aaudio_device_id_t devid, aaudio_object_id_t obj,
-+ struct aaudio_prop_addr prop, void *qualifier, u64 qualifier_size, void *data, u64 data_size)
-+{
-+ int status;
-+ struct aaudio_msg reply = aaudio_reply_alloc();
-+ void *r_data;
-+ u64 r_data_size;
-+ if ((status = aaudio_cmd_get_property(a, &reply, devid, obj, prop, qualifier, qualifier_size,
-+ &r_data, &r_data_size)))
-+ goto finish;
-+ if (r_data_size != data_size) {
-+ status = -EINVAL;
-+ goto finish;
-+ }
-+ memcpy(data, r_data, data_size);
-+finish:
-+ aaudio_reply_free(&reply);
-+ return status;
-+}
-+int aaudio_cmd_set_property(struct aaudio_device *a, aaudio_device_id_t devid, aaudio_object_id_t obj,
-+ struct aaudio_prop_addr prop, void *qualifier, u64 qualifier_size, void *data, u64 data_size)
-+{
-+ CMD_DEF_SHARED_AND_SEND(aaudio_msg_write_set_property, devid, obj, prop, data, data_size,
-+ qualifier, qualifier_size);
-+ CMD_HNDL_REPLY_AND_FREE(aaudio_msg_read_set_property_response, &obj);
-+}
-+int aaudio_cmd_property_listener(struct aaudio_device *a, aaudio_device_id_t devid, aaudio_object_id_t obj,
-+ struct aaudio_prop_addr prop)
-+{
-+ CMD_DEF_SHARED_AND_SEND(aaudio_msg_write_property_listener, devid, obj, prop);
-+ CMD_HNDL_REPLY_AND_FREE(aaudio_msg_read_property_listener_response, &obj, &prop);
-+}
-+int aaudio_cmd_set_input_stream_address_ranges(struct aaudio_device *a, aaudio_device_id_t devid)
-+{
-+ CMD_DEF_SHARED_AND_SEND(aaudio_msg_write_set_input_stream_address_ranges, devid);
-+ CMD_HNDL_REPLY_AND_FREE(aaudio_msg_read_set_input_stream_address_ranges_response);
-+}
-+int aaudio_cmd_get_input_stream_list(struct aaudio_device *a, struct aaudio_msg *buf, aaudio_device_id_t devid,
-+ aaudio_object_id_t **str_l, u64 *str_cnt)
-+{
-+ CMD_DEF_SHARED_NO_REPLY_AND_SEND(aaudio_msg_write_get_input_stream_list, devid);
-+ CMD_HNDL_REPLY_NO_FREE(aaudio_msg_read_get_input_stream_list_response, str_l, str_cnt);
-+}
-+int aaudio_cmd_get_output_stream_list(struct aaudio_device *a, struct aaudio_msg *buf, aaudio_device_id_t devid,
-+ aaudio_object_id_t **str_l, u64 *str_cnt)
-+{
-+ CMD_DEF_SHARED_NO_REPLY_AND_SEND(aaudio_msg_write_get_output_stream_list, devid);
-+ CMD_HNDL_REPLY_NO_FREE(aaudio_msg_read_get_output_stream_list_response, str_l, str_cnt);
-+}
-+int aaudio_cmd_set_remote_access(struct aaudio_device *a, u64 mode)
-+{
-+ CMD_DEF_SHARED_AND_SEND(aaudio_msg_write_set_remote_access, mode);
-+ CMD_HNDL_REPLY_AND_FREE(aaudio_msg_read_set_remote_access_response);
-+}
-+int aaudio_cmd_get_device_list(struct aaudio_device *a, struct aaudio_msg *buf,
-+ aaudio_device_id_t **dev_l, u64 *dev_cnt)
-+{
-+ CMD_DEF_SHARED_NO_REPLY_AND_SEND(aaudio_msg_write_get_device_list);
-+ CMD_HNDL_REPLY_NO_FREE(aaudio_msg_read_get_device_list_response, dev_l, dev_cnt);
-+}
-\ 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 000000000000..3427486f3f57
---- /dev/null
-+++ b/drivers/staging/apple-bce/audio/protocol.h
-@@ -0,0 +1,147 @@
-+#ifndef AAUDIO_PROTOCOL_H
-+#define AAUDIO_PROTOCOL_H
-+
-+#include <linux/types.h>
-+
-+struct aaudio_device;
-+
-+typedef u64 aaudio_device_id_t;
-+typedef u64 aaudio_object_id_t;
-+
-+struct aaudio_msg {
-+ void *data;
-+ size_t size;
-+};
-+
-+struct __attribute__((packed)) aaudio_msg_header {
-+ char tag[4];
-+ u8 type;
-+ aaudio_device_id_t device_id; // Idk, use zero for commands?
-+};
-+struct __attribute__((packed)) aaudio_msg_base {
-+ u32 msg;
-+ u32 status;
-+};
-+
-+struct aaudio_prop_addr {
-+ u32 scope;
-+ u32 selector;
-+ u32 element;
-+};
-+#define AAUDIO_PROP(scope, sel, el) (struct aaudio_prop_addr) { scope, sel, el }
-+
-+enum {
-+ AAUDIO_MSG_TYPE_COMMAND = 1,
-+ AAUDIO_MSG_TYPE_RESPONSE = 2,
-+ AAUDIO_MSG_TYPE_NOTIFICATION = 3
-+};
-+
-+enum {
-+ AAUDIO_MSG_START_IO = 0,
-+ AAUDIO_MSG_START_IO_RESPONSE = 1,
-+ AAUDIO_MSG_STOP_IO = 2,
-+ AAUDIO_MSG_STOP_IO_RESPONSE = 3,
-+ AAUDIO_MSG_UPDATE_TIMESTAMP = 4,
-+ AAUDIO_MSG_GET_PROPERTY = 7,
-+ AAUDIO_MSG_GET_PROPERTY_RESPONSE = 8,
-+ AAUDIO_MSG_SET_PROPERTY = 9,
-+ AAUDIO_MSG_SET_PROPERTY_RESPONSE = 10,
-+ AAUDIO_MSG_PROPERTY_LISTENER = 11,
-+ AAUDIO_MSG_PROPERTY_LISTENER_RESPONSE = 12,
-+ AAUDIO_MSG_PROPERTY_CHANGED = 13,
-+ AAUDIO_MSG_SET_INPUT_STREAM_ADDRESS_RANGES = 18,
-+ AAUDIO_MSG_SET_INPUT_STREAM_ADDRESS_RANGES_RESPONSE = 19,
-+ AAUDIO_MSG_GET_INPUT_STREAM_LIST = 24,
-+ AAUDIO_MSG_GET_INPUT_STREAM_LIST_RESPONSE = 25,
-+ AAUDIO_MSG_GET_OUTPUT_STREAM_LIST = 26,
-+ AAUDIO_MSG_GET_OUTPUT_STREAM_LIST_RESPONSE = 27,
-+ AAUDIO_MSG_SET_REMOTE_ACCESS = 32,
-+ AAUDIO_MSG_SET_REMOTE_ACCESS_RESPONSE = 33,
-+ AAUDIO_MSG_UPDATE_TIMESTAMP_RESPONSE = 34,
-+
-+ AAUDIO_MSG_NOTIFICATION_ALIVE = 100,
-+ AAUDIO_MSG_GET_DEVICE_LIST = 101,
-+ AAUDIO_MSG_GET_DEVICE_LIST_RESPONSE = 102,
-+ AAUDIO_MSG_NOTIFICATION_BOOT = 104
-+};
-+
-+enum {
-+ AAUDIO_REMOTE_ACCESS_OFF = 0,
-+ AAUDIO_REMOTE_ACCESS_ON = 2
-+};
-+
-+enum {
-+ AAUDIO_PROP_SCOPE_GLOBAL = 0x676c6f62, // 'glob'
-+ AAUDIO_PROP_SCOPE_INPUT = 0x696e7074, // 'inpt'
-+ AAUDIO_PROP_SCOPE_OUTPUT = 0x6f757470 // 'outp'
-+};
-+
-+enum {
-+ AAUDIO_PROP_UID = 0x75696420, // 'uid '
-+ AAUDIO_PROP_BOOL_VALUE = 0x6263766c, // 'bcvl'
-+ AAUDIO_PROP_JACK_PLUGGED = 0x6a61636b, // 'jack'
-+ AAUDIO_PROP_SEL_VOLUME = 0x64656176, // 'deav'
-+ AAUDIO_PROP_LATENCY = 0x6c746e63, // 'ltnc'
-+ AAUDIO_PROP_PHYS_FORMAT = 0x70667420 // 'pft '
-+};
-+
-+int aaudio_msg_read_base(struct aaudio_msg *msg, struct aaudio_msg_base *base);
-+
-+int aaudio_msg_read_start_io_response(struct aaudio_msg *msg);
-+int aaudio_msg_read_stop_io_response(struct aaudio_msg *msg);
-+int aaudio_msg_read_update_timestamp(struct aaudio_msg *msg, aaudio_device_id_t *devid,
-+ u64 *timestamp, u64 *update_seed);
-+int aaudio_msg_read_get_property_response(struct aaudio_msg *msg, aaudio_object_id_t *obj,
-+ struct aaudio_prop_addr *prop, void **data, u64 *data_size);
-+int aaudio_msg_read_set_property_response(struct aaudio_msg *msg, aaudio_object_id_t *obj);
-+int aaudio_msg_read_property_listener_response(struct aaudio_msg *msg,aaudio_object_id_t *obj,
-+ struct aaudio_prop_addr *prop);
-+int aaudio_msg_read_property_changed(struct aaudio_msg *msg, aaudio_device_id_t *devid, aaudio_object_id_t *obj,
-+ struct aaudio_prop_addr *prop);
-+int aaudio_msg_read_set_input_stream_address_ranges_response(struct aaudio_msg *msg);
-+int aaudio_msg_read_get_input_stream_list_response(struct aaudio_msg *msg, aaudio_object_id_t **str_l, u64 *str_cnt);
-+int aaudio_msg_read_get_output_stream_list_response(struct aaudio_msg *msg, aaudio_object_id_t **str_l, u64 *str_cnt);
-+int aaudio_msg_read_set_remote_access_response(struct aaudio_msg *msg);
-+int aaudio_msg_read_get_device_list_response(struct aaudio_msg *msg, aaudio_device_id_t **dev_l, u64 *dev_cnt);
-+
-+void aaudio_msg_write_start_io(struct aaudio_msg *msg, aaudio_device_id_t dev);
-+void aaudio_msg_write_stop_io(struct aaudio_msg *msg, aaudio_device_id_t dev);
-+void aaudio_msg_write_get_property(struct aaudio_msg *msg, aaudio_device_id_t dev, aaudio_object_id_t obj,
-+ struct aaudio_prop_addr prop, void *qualifier, u64 qualifier_size);
-+void aaudio_msg_write_set_property(struct aaudio_msg *msg, aaudio_device_id_t dev, aaudio_object_id_t obj,
-+ struct aaudio_prop_addr prop, void *data, u64 data_size, void *qualifier, u64 qualifier_size);
-+void aaudio_msg_write_property_listener(struct aaudio_msg *msg, aaudio_device_id_t dev, aaudio_object_id_t obj,
-+ struct aaudio_prop_addr prop);
-+void aaudio_msg_write_set_input_stream_address_ranges(struct aaudio_msg *msg, aaudio_device_id_t devid);
-+void aaudio_msg_write_get_input_stream_list(struct aaudio_msg *msg, aaudio_device_id_t devid);
-+void aaudio_msg_write_get_output_stream_list(struct aaudio_msg *msg, aaudio_device_id_t devid);
-+void aaudio_msg_write_set_remote_access(struct aaudio_msg *msg, u64 mode);
-+void aaudio_msg_write_alive_notification(struct aaudio_msg *msg, u32 proto_ver, u32 msg_ver);
-+void aaudio_msg_write_update_timestamp_response(struct aaudio_msg *msg);
-+void aaudio_msg_write_get_device_list(struct aaudio_msg *msg);
-+
-+
-+int aaudio_cmd_start_io(struct aaudio_device *a, aaudio_device_id_t devid);
-+int aaudio_cmd_stop_io(struct aaudio_device *a, aaudio_device_id_t devid);
-+int aaudio_cmd_get_property(struct aaudio_device *a, struct aaudio_msg *buf,
-+ aaudio_device_id_t devid, aaudio_object_id_t obj,
-+ struct aaudio_prop_addr prop, void *qualifier, u64 qualifier_size, void **data, u64 *data_size);
-+int aaudio_cmd_get_primitive_property(struct aaudio_device *a,
-+ aaudio_device_id_t devid, aaudio_object_id_t obj,
-+ struct aaudio_prop_addr prop, void *qualifier, u64 qualifier_size, void *data, u64 data_size);
-+int aaudio_cmd_set_property(struct aaudio_device *a, aaudio_device_id_t devid, aaudio_object_id_t obj,
-+ struct aaudio_prop_addr prop, void *qualifier, u64 qualifier_size, void *data, u64 data_size);
-+int aaudio_cmd_property_listener(struct aaudio_device *a, aaudio_device_id_t devid, aaudio_object_id_t obj,
-+ struct aaudio_prop_addr prop);
-+int aaudio_cmd_set_input_stream_address_ranges(struct aaudio_device *a, aaudio_device_id_t devid);
-+int aaudio_cmd_get_input_stream_list(struct aaudio_device *a, struct aaudio_msg *buf, aaudio_device_id_t devid,
-+ aaudio_object_id_t **str_l, u64 *str_cnt);
-+int aaudio_cmd_get_output_stream_list(struct aaudio_device *a, struct aaudio_msg *buf, aaudio_device_id_t devid,
-+ aaudio_object_id_t **str_l, u64 *str_cnt);
-+int aaudio_cmd_set_remote_access(struct aaudio_device *a, u64 mode);
-+int aaudio_cmd_get_device_list(struct aaudio_device *a, struct aaudio_msg *buf,
-+ aaudio_device_id_t **dev_l, u64 *dev_cnt);
-+
-+
-+
-+#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 000000000000..28f2dfd44d67
---- /dev/null
-+++ b/drivers/staging/apple-bce/audio/protocol_bce.c
-@@ -0,0 +1,226 @@
-+#include "protocol_bce.h"
-+
-+#include "audio.h"
-+
-+static void aaudio_bce_out_queue_completion(struct bce_queue_sq *sq);
-+static void aaudio_bce_in_queue_completion(struct bce_queue_sq *sq);
-+static int aaudio_bce_queue_init(struct aaudio_device *dev, struct aaudio_bce_queue *q, const char *name, int direction,
-+ bce_sq_completion cfn);
-+void aaudio_bce_in_queue_submit_pending(struct aaudio_bce_queue *q, size_t count);
-+
-+int aaudio_bce_init(struct aaudio_device *dev)
-+{
-+ int status;
-+ struct aaudio_bce *bce = &dev->bcem;
-+ bce->cq = bce_create_cq(dev->bce, 0x80);
-+ spin_lock_init(&bce->spinlock);
-+ if (!bce->cq)
-+ return -EINVAL;
-+ if ((status = aaudio_bce_queue_init(dev, &bce->qout, "com.apple.BridgeAudio.IntelToARM", DMA_TO_DEVICE,
-+ aaudio_bce_out_queue_completion))) {
-+ return status;
-+ }
-+ if ((status = aaudio_bce_queue_init(dev, &bce->qin, "com.apple.BridgeAudio.ARMToIntel", DMA_FROM_DEVICE,
-+ aaudio_bce_in_queue_completion))) {
-+ return status;
-+ }
-+ aaudio_bce_in_queue_submit_pending(&bce->qin, bce->qin.el_count);
-+ return 0;
-+}
-+
-+int aaudio_bce_queue_init(struct aaudio_device *dev, struct aaudio_bce_queue *q, const char *name, int direction,
-+ bce_sq_completion cfn)
-+{
-+ q->cq = dev->bcem.cq;
-+ q->el_size = AAUDIO_BCE_QUEUE_ELEMENT_SIZE;
-+ q->el_count = AAUDIO_BCE_QUEUE_ELEMENT_COUNT;
-+ /* NOTE: The Apple impl uses 0x80 as the queue size, however we use 21 (in fact 20) to simplify the impl */
-+ q->sq = bce_create_sq(dev->bce, q->cq, name, (u32) (q->el_count + 1), direction, cfn, dev);
-+ if (!q->sq)
-+ return -EINVAL;
-+
-+ q->data = dma_alloc_coherent(&dev->bce->pci->dev, q->el_size * q->el_count, &q->dma_addr, GFP_KERNEL);
-+ if (!q->data) {
-+ bce_destroy_sq(dev->bce, q->sq);
-+ return -EINVAL;
-+ }
-+ return 0;
-+}
-+
-+static void aaudio_send_create_tag(struct aaudio_bce *b, int *tagn, char tag[4])
-+{
-+ char tag_zero[5];
-+ b->tag_num = (b->tag_num + 1) % AAUDIO_BCE_QUEUE_TAG_COUNT;
-+ *tagn = b->tag_num;
-+ snprintf(tag_zero, 5, "S%03d", b->tag_num);
-+ *((u32 *) tag) = *((u32 *) tag_zero);
-+}
-+
-+int __aaudio_send_prepare(struct aaudio_bce *b, struct aaudio_send_ctx *ctx, char *tag)
-+{
-+ int status;
-+ size_t index;
-+ void *dptr;
-+ struct aaudio_msg_header *header;
-+ if ((status = bce_reserve_submission(b->qout.sq, &ctx->timeout)))
-+ return status;
-+ spin_lock_irqsave(&b->spinlock, ctx->irq_flags);
-+ index = b->qout.data_tail;
-+ dptr = (u8 *) b->qout.data + index * b->qout.el_size;
-+ ctx->msg.data = dptr;
-+ header = dptr;
-+ if (tag)
-+ *((u32 *) header->tag) = *((u32 *) tag);
-+ else
-+ aaudio_send_create_tag(b, &ctx->tag_n, header->tag);
-+ return 0;
-+}
-+
-+void __aaudio_send(struct aaudio_bce *b, struct aaudio_send_ctx *ctx)
-+{
-+ struct bce_qe_submission *s = bce_next_submission(b->qout.sq);
-+#ifdef DEBUG
-+ pr_debug("aaudio: Sending command data\n");
-+ print_hex_dump(KERN_DEBUG, "aaudio:OUT ", DUMP_PREFIX_NONE, 32, 1, ctx->msg.data, ctx->msg.size, true);
-+#endif
-+ bce_set_submission_single(s, b->qout.dma_addr + (dma_addr_t) (ctx->msg.data - b->qout.data), ctx->msg.size);
-+ bce_submit_to_device(b->qout.sq);
-+ b->qout.data_tail = (b->qout.data_tail + 1) % b->qout.el_count;
-+ spin_unlock_irqrestore(&b->spinlock, ctx->irq_flags);
-+}
-+
-+int __aaudio_send_cmd_sync(struct aaudio_bce *b, struct aaudio_send_ctx *ctx, struct aaudio_msg *reply)
-+{
-+ struct aaudio_bce_queue_entry ent;
-+ DECLARE_COMPLETION_ONSTACK(cmpl);
-+ ent.msg = reply;
-+ ent.cmpl = &cmpl;
-+ b->pending_entries[ctx->tag_n] = &ent;
-+ __aaudio_send(b, ctx); /* unlocks the spinlock */
-+ ctx->timeout = wait_for_completion_timeout(&cmpl, ctx->timeout);
-+ if (ctx->timeout == 0) {
-+ /* Remove the pending queue entry; this will be normally handled by the completion route but
-+ * during a timeout it won't */
-+ spin_lock_irqsave(&b->spinlock, ctx->irq_flags);
-+ if (b->pending_entries[ctx->tag_n] == &ent)
-+ b->pending_entries[ctx->tag_n] = NULL;
-+ spin_unlock_irqrestore(&b->spinlock, ctx->irq_flags);
-+ return -ETIMEDOUT;
-+ }
-+ return 0;
-+}
-+
-+static void aaudio_handle_reply(struct aaudio_bce *b, struct aaudio_msg *reply)
-+{
-+ const char *tag;
-+ int tagn;
-+ unsigned long irq_flags;
-+ char tag_zero[5];
-+ struct aaudio_bce_queue_entry *entry;
-+
-+ tag = ((struct aaudio_msg_header *) reply->data)->tag;
-+ if (tag[0] != 'S') {
-+ pr_err("aaudio_handle_reply: Unexpected tag: %.4s\n", tag);
-+ return;
-+ }
-+ *((u32 *) tag_zero) = *((u32 *) tag);
-+ tag_zero[4] = 0;
-+ if (kstrtoint(&tag_zero[1], 10, &tagn)) {
-+ pr_err("aaudio_handle_reply: Tag parse failed: %.4s\n", tag);
-+ return;
-+ }
-+
-+ spin_lock_irqsave(&b->spinlock, irq_flags);
-+ entry = b->pending_entries[tagn];
-+ if (entry) {
-+ if (reply->size < entry->msg->size)
-+ entry->msg->size = reply->size;
-+ memcpy(entry->msg->data, reply->data, entry->msg->size);
-+ complete(entry->cmpl);
-+
-+ b->pending_entries[tagn] = NULL;
-+ } else {
-+ pr_err("aaudio_handle_reply: No queued item found for tag: %.4s\n", tag);
-+ }
-+ spin_unlock_irqrestore(&b->spinlock, irq_flags);
-+}
-+
-+static void aaudio_bce_out_queue_completion(struct bce_queue_sq *sq)
-+{
-+ while (bce_next_completion(sq)) {
-+ //pr_info("aaudio: Send confirmed\n");
-+ bce_notify_submission_complete(sq);
-+ }
-+}
-+
-+static void aaudio_bce_in_queue_handle_msg(struct aaudio_device *a, struct aaudio_msg *msg);
-+
-+static void aaudio_bce_in_queue_completion(struct bce_queue_sq *sq)
-+{
-+ struct aaudio_msg msg;
-+ struct aaudio_device *dev = sq->userdata;
-+ struct aaudio_bce_queue *q = &dev->bcem.qin;
-+ struct bce_sq_completion_data *c;
-+ size_t cnt = 0;
-+
-+ mb();
-+ while ((c = bce_next_completion(sq))) {
-+ msg.data = (u8 *) q->data + q->data_head * q->el_size;
-+ msg.size = c->data_size;
-+#ifdef DEBUG
-+ pr_debug("aaudio: Received command data %llx\n", c->data_size);
-+ print_hex_dump(KERN_DEBUG, "aaudio:IN ", DUMP_PREFIX_NONE, 32, 1, msg.data, min(msg.size, 128UL), true);
-+#endif
-+ aaudio_bce_in_queue_handle_msg(dev, &msg);
-+
-+ q->data_head = (q->data_head + 1) % q->el_count;
-+
-+ bce_notify_submission_complete(sq);
-+ ++cnt;
-+ }
-+ aaudio_bce_in_queue_submit_pending(q, cnt);
-+}
-+
-+static void aaudio_bce_in_queue_handle_msg(struct aaudio_device *a, struct aaudio_msg *msg)
-+{
-+ struct aaudio_msg_header *header = (struct aaudio_msg_header *) msg->data;
-+ if (msg->size < sizeof(struct aaudio_msg_header)) {
-+ pr_err("aaudio: Msg size smaller than header (%lx)", msg->size);
-+ return;
-+ }
-+ if (header->type == AAUDIO_MSG_TYPE_RESPONSE) {
-+ aaudio_handle_reply(&a->bcem, msg);
-+ } else if (header->type == AAUDIO_MSG_TYPE_COMMAND) {
-+ aaudio_handle_command(a, msg);
-+ } else if (header->type == AAUDIO_MSG_TYPE_NOTIFICATION) {
-+ aaudio_handle_notification(a, msg);
-+ }
-+}
-+
-+void aaudio_bce_in_queue_submit_pending(struct aaudio_bce_queue *q, size_t count)
-+{
-+ struct bce_qe_submission *s;
-+ while (count--) {
-+ if (bce_reserve_submission(q->sq, NULL)) {
-+ pr_err("aaudio: Failed to reserve an event queue submission\n");
-+ break;
-+ }
-+ s = bce_next_submission(q->sq);
-+ bce_set_submission_single(s, q->dma_addr + (dma_addr_t) (q->data_tail * q->el_size), q->el_size);
-+ q->data_tail = (q->data_tail + 1) % q->el_count;
-+ }
-+ bce_submit_to_device(q->sq);
-+}
-+
-+struct aaudio_msg aaudio_reply_alloc(void)
-+{
-+ struct aaudio_msg ret;
-+ ret.size = AAUDIO_BCE_QUEUE_ELEMENT_SIZE;
-+ ret.data = kmalloc(ret.size, GFP_KERNEL);
-+ return ret;
-+}
-+
-+void aaudio_reply_free(struct aaudio_msg *reply)
-+{
-+ kfree(reply->data);
-+}
-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 000000000000..14d26c05ddf9
---- /dev/null
-+++ b/drivers/staging/apple-bce/audio/protocol_bce.h
-@@ -0,0 +1,72 @@
-+#ifndef AAUDIO_PROTOCOL_BCE_H
-+#define AAUDIO_PROTOCOL_BCE_H
-+
-+#include "protocol.h"
-+#include "../queue.h"
-+
-+#define AAUDIO_BCE_QUEUE_ELEMENT_SIZE 0x1000
-+#define AAUDIO_BCE_QUEUE_ELEMENT_COUNT 20
-+
-+#define AAUDIO_BCE_QUEUE_TAG_COUNT 1000
-+
-+struct aaudio_device;
-+
-+struct aaudio_bce_queue_entry {
-+ struct aaudio_msg *msg;
-+ struct completion *cmpl;
-+};
-+struct aaudio_bce_queue {
-+ struct bce_queue_cq *cq;
-+ struct bce_queue_sq *sq;
-+ void *data;
-+ dma_addr_t dma_addr;
-+ size_t data_head, data_tail;
-+ size_t el_size, el_count;
-+};
-+struct aaudio_bce {
-+ struct bce_queue_cq *cq;
-+ struct aaudio_bce_queue qin;
-+ struct aaudio_bce_queue qout;
-+ int tag_num;
-+ struct aaudio_bce_queue_entry *pending_entries[AAUDIO_BCE_QUEUE_TAG_COUNT];
-+ struct spinlock spinlock;
-+};
-+
-+struct aaudio_send_ctx {
-+ int status;
-+ int tag_n;
-+ unsigned long irq_flags;
-+ struct aaudio_msg msg;
-+ unsigned long timeout;
-+};
-+
-+int aaudio_bce_init(struct aaudio_device *dev);
-+int __aaudio_send_prepare(struct aaudio_bce *b, struct aaudio_send_ctx *ctx, char *tag);
-+void __aaudio_send(struct aaudio_bce *b, struct aaudio_send_ctx *ctx);
-+int __aaudio_send_cmd_sync(struct aaudio_bce *b, struct aaudio_send_ctx *ctx, struct aaudio_msg *reply);
-+
-+#define aaudio_send_with_tag(a, ctx, tag, tout, fn, ...) ({ \
-+ (ctx)->timeout = msecs_to_jiffies(tout); \
-+ (ctx)->status = __aaudio_send_prepare(&(a)->bcem, (ctx), (tag)); \
-+ if (!(ctx)->status) { \
-+ fn(&(ctx)->msg, ##__VA_ARGS__); \
-+ __aaudio_send(&(a)->bcem, (ctx)); \
-+ } \
-+ (ctx)->status; \
-+})
-+#define aaudio_send(a, ctx, tout, fn, ...) aaudio_send_with_tag(a, ctx, NULL, tout, fn, ##__VA_ARGS__)
-+
-+#define aaudio_send_cmd_sync(a, ctx, reply, tout, fn, ...) ({ \
-+ (ctx)->timeout = msecs_to_jiffies(tout); \
-+ (ctx)->status = __aaudio_send_prepare(&(a)->bcem, (ctx), NULL); \
-+ if (!(ctx)->status) { \
-+ fn(&(ctx)->msg, ##__VA_ARGS__); \
-+ (ctx)->status = __aaudio_send_cmd_sync(&(a)->bcem, (ctx), (reply)); \
-+ } \
-+ (ctx)->status; \
-+})
-+
-+struct aaudio_msg aaudio_reply_alloc(void);
-+void aaudio_reply_free(struct aaudio_msg *reply);
-+
-+#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 000000000000..e24bd35215c0
---- /dev/null
-+++ b/drivers/staging/apple-bce/mailbox.c
-@@ -0,0 +1,151 @@
-+#include "mailbox.h"
-+#include <linux/atomic.h>
-+#include "apple_bce.h"
-+
-+#define REG_MBOX_OUT_BASE 0x820
-+#define REG_MBOX_REPLY_COUNTER 0x108
-+#define REG_MBOX_REPLY_BASE 0x810
-+#define REG_TIMESTAMP_BASE 0xC000
-+
-+#define BCE_MBOX_TIMEOUT_MS 200
-+
-+void bce_mailbox_init(struct bce_mailbox *mb, void __iomem *reg_mb)
-+{
-+ mb->reg_mb = reg_mb;
-+ init_completion(&mb->mb_completion);
-+}
-+
-+int bce_mailbox_send(struct bce_mailbox *mb, u64 msg, u64* recv)
-+{
-+ u32 __iomem *regb;
-+
-+ if (atomic_cmpxchg(&mb->mb_status, 0, 1) != 0) {
-+ return -EEXIST; // We don't support two messages at once
-+ }
-+ reinit_completion(&mb->mb_completion);
-+
-+ pr_debug("bce_mailbox_send: %llx\n", msg);
-+ regb = (u32*) ((u8*) mb->reg_mb + REG_MBOX_OUT_BASE);
-+ iowrite32((u32) msg, regb);
-+ iowrite32((u32) (msg >> 32), regb + 1);
-+ iowrite32(0, regb + 2);
-+ iowrite32(0, regb + 3);
-+
-+ wait_for_completion_timeout(&mb->mb_completion, msecs_to_jiffies(BCE_MBOX_TIMEOUT_MS));
-+ if (atomic_read(&mb->mb_status) != 2) { // Didn't get the reply
-+ atomic_set(&mb->mb_status, 0);
-+ return -ETIMEDOUT;
-+ }
-+
-+ *recv = mb->mb_result;
-+ pr_debug("bce_mailbox_send: reply %llx\n", *recv);
-+
-+ atomic_set(&mb->mb_status, 0);
-+ return 0;
-+}
-+
-+static int bce_mailbox_retrive_response(struct bce_mailbox *mb)
-+{
-+ u32 __iomem *regb;
-+ u32 lo, hi;
-+ int count, counter;
-+ u32 res = ioread32((u8*) mb->reg_mb + REG_MBOX_REPLY_COUNTER);
-+ count = (res >> 20) & 0xf;
-+ counter = count;
-+ pr_debug("bce_mailbox_retrive_response count=%i\n", count);
-+ while (counter--) {
-+ regb = (u32*) ((u8*) mb->reg_mb + REG_MBOX_REPLY_BASE);
-+ lo = ioread32(regb);
-+ hi = ioread32(regb + 1);
-+ ioread32(regb + 2);
-+ ioread32(regb + 3);
-+ pr_debug("bce_mailbox_retrive_response %llx\n", ((u64) hi << 32) | lo);
-+ mb->mb_result = ((u64) hi << 32) | lo;
-+ }
-+ return count > 0 ? 0 : -ENODATA;
-+}
-+
-+int bce_mailbox_handle_interrupt(struct bce_mailbox *mb)
-+{
-+ int status = bce_mailbox_retrive_response(mb);
-+ if (!status) {
-+ atomic_set(&mb->mb_status, 2);
-+ complete(&mb->mb_completion);
-+ }
-+ return status;
-+}
-+
-+static void bc_send_timestamp(struct timer_list *tl);
-+
-+void bce_timestamp_init(struct bce_timestamp *ts, void __iomem *reg)
-+{
-+ u32 __iomem *regb;
-+
-+ spin_lock_init(&ts->stop_sl);
-+ ts->stopped = false;
-+
-+ ts->reg = reg;
-+
-+ regb = (u32*) ((u8*) ts->reg + REG_TIMESTAMP_BASE);
-+
-+ ioread32(regb);
-+ mb();
-+
-+ timer_setup(&ts->timer, bc_send_timestamp, 0);
-+}
-+
-+void bce_timestamp_start(struct bce_timestamp *ts, bool is_initial)
-+{
-+ unsigned long flags;
-+ u32 __iomem *regb = (u32*) ((u8*) ts->reg + REG_TIMESTAMP_BASE);
-+
-+ if (is_initial) {
-+ iowrite32((u32) -4, regb + 2);
-+ iowrite32((u32) -1, regb);
-+ } else {
-+ iowrite32((u32) -3, regb + 2);
-+ iowrite32((u32) -1, regb);
-+ }
-+
-+ spin_lock_irqsave(&ts->stop_sl, flags);
-+ ts->stopped = false;
-+ spin_unlock_irqrestore(&ts->stop_sl, flags);
-+ mod_timer(&ts->timer, jiffies + msecs_to_jiffies(150));
-+}
-+
-+void bce_timestamp_stop(struct bce_timestamp *ts)
-+{
-+ unsigned long flags;
-+ u32 __iomem *regb = (u32*) ((u8*) ts->reg + REG_TIMESTAMP_BASE);
-+
-+ spin_lock_irqsave(&ts->stop_sl, flags);
-+ ts->stopped = true;
-+ spin_unlock_irqrestore(&ts->stop_sl, flags);
-+ del_timer_sync(&ts->timer);
-+
-+ iowrite32((u32) -2, regb + 2);
-+ iowrite32((u32) -1, regb);
-+}
-+
-+static void bc_send_timestamp(struct timer_list *tl)
-+{
-+ struct bce_timestamp *ts;
-+ unsigned long flags;
-+ u32 __iomem *regb;
-+ ktime_t bt;
-+
-+ ts = container_of(tl, struct bce_timestamp, timer);
-+ regb = (u32*) ((u8*) ts->reg + REG_TIMESTAMP_BASE);
-+ local_irq_save(flags);
-+ ioread32(regb + 2);
-+ mb();
-+ bt = ktime_get_boottime();
-+ iowrite32((u32) bt, regb + 2);
-+ iowrite32((u32) (bt >> 32), regb);
-+
-+ spin_lock(&ts->stop_sl);
-+ if (!ts->stopped)
-+ mod_timer(&ts->timer, jiffies + msecs_to_jiffies(150));
-+ spin_unlock(&ts->stop_sl);
-+ local_irq_restore(flags);
-+}
-\ 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 000000000000..f3323f95ba51
---- /dev/null
-+++ b/drivers/staging/apple-bce/mailbox.h
-@@ -0,0 +1,53 @@
-+#ifndef BCE_MAILBOX_H
-+#define BCE_MAILBOX_H
-+
-+#include <linux/completion.h>
-+#include <linux/pci.h>
-+#include <linux/timer.h>
-+
-+struct bce_mailbox {
-+ void __iomem *reg_mb;
-+
-+ atomic_t mb_status; // possible statuses: 0 (no msg), 1 (has active msg), 2 (got reply)
-+ struct completion mb_completion;
-+ uint64_t mb_result;
-+};
-+
-+enum bce_message_type {
-+ BCE_MB_REGISTER_COMMAND_SQ = 0x7, // to-device
-+ BCE_MB_REGISTER_COMMAND_CQ = 0x8, // to-device
-+ BCE_MB_REGISTER_COMMAND_QUEUE_REPLY = 0xB, // to-host
-+ BCE_MB_SET_FW_PROTOCOL_VERSION = 0xC, // both
-+ BCE_MB_SLEEP_NO_STATE = 0x14, // to-device
-+ BCE_MB_RESTORE_NO_STATE = 0x15, // to-device
-+ BCE_MB_SAVE_STATE_AND_SLEEP = 0x17, // to-device
-+ BCE_MB_RESTORE_STATE_AND_WAKE = 0x18, // to-device
-+ BCE_MB_SAVE_STATE_AND_SLEEP_FAILURE = 0x19, // from-device
-+ BCE_MB_SAVE_RESTORE_STATE_COMPLETE = 0x1A, // from-device
-+};
-+
-+#define BCE_MB_MSG(type, value) (((u64) (type) << 58) | ((value) & 0x3FFFFFFFFFFFFFFLL))
-+#define BCE_MB_TYPE(v) ((u32) (v >> 58))
-+#define BCE_MB_VALUE(v) (v & 0x3FFFFFFFFFFFFFFLL)
-+
-+void bce_mailbox_init(struct bce_mailbox *mb, void __iomem *reg_mb);
-+
-+int bce_mailbox_send(struct bce_mailbox *mb, u64 msg, u64* recv);
-+
-+int bce_mailbox_handle_interrupt(struct bce_mailbox *mb);
-+
-+
-+struct bce_timestamp {
-+ void __iomem *reg;
-+ struct timer_list timer;
-+ struct spinlock stop_sl;
-+ bool stopped;
-+};
-+
-+void bce_timestamp_init(struct bce_timestamp *ts, void __iomem *reg);
-+
-+void bce_timestamp_start(struct bce_timestamp *ts, bool is_initial);
-+
-+void bce_timestamp_stop(struct bce_timestamp *ts);
-+
-+#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 000000000000..bc9cd3bc6f0c
---- /dev/null
-+++ b/drivers/staging/apple-bce/queue.c
-@@ -0,0 +1,390 @@
-+#include "queue.h"
-+#include "apple_bce.h"
-+
-+#define REG_DOORBELL_BASE 0x44000
-+
-+struct bce_queue_cq *bce_alloc_cq(struct apple_bce_device *dev, int qid, u32 el_count)
-+{
-+ struct bce_queue_cq *q;
-+ q = kzalloc(sizeof(struct bce_queue_cq), GFP_KERNEL);
-+ q->qid = qid;
-+ q->type = BCE_QUEUE_CQ;
-+ q->el_count = el_count;
-+ q->data = dma_alloc_coherent(&dev->pci->dev, el_count * sizeof(struct bce_qe_completion),
-+ &q->dma_handle, GFP_KERNEL);
-+ if (!q->data) {
-+ pr_err("DMA queue memory alloc failed\n");
-+ kfree(q);
-+ return NULL;
-+ }
-+ return q;
-+}
-+
-+void bce_get_cq_memcfg(struct bce_queue_cq *cq, struct bce_queue_memcfg *cfg)
-+{
-+ cfg->qid = (u16) cq->qid;
-+ cfg->el_count = (u16) cq->el_count;
-+ cfg->vector_or_cq = 0;
-+ cfg->_pad = 0;
-+ cfg->addr = cq->dma_handle;
-+ cfg->length = cq->el_count * sizeof(struct bce_qe_completion);
-+}
-+
-+void bce_free_cq(struct apple_bce_device *dev, struct bce_queue_cq *cq)
-+{
-+ dma_free_coherent(&dev->pci->dev, cq->el_count * sizeof(struct bce_qe_completion), cq->data, cq->dma_handle);
-+ kfree(cq);
-+}
-+
-+static void bce_handle_cq_completion(struct apple_bce_device *dev, struct bce_qe_completion *e, size_t *ce)
-+{
-+ struct bce_queue *target;
-+ struct bce_queue_sq *target_sq;
-+ struct bce_sq_completion_data *cmpl;
-+ if (e->qid >= BCE_MAX_QUEUE_COUNT) {
-+ pr_err("Device sent a response for qid (%u) >= BCE_MAX_QUEUE_COUNT\n", e->qid);
-+ return;
-+ }
-+ target = dev->queues[e->qid];
-+ if (!target || target->type != BCE_QUEUE_SQ) {
-+ pr_err("Device sent a response for qid (%u), which does not exist\n", e->qid);
-+ return;
-+ }
-+ target_sq = (struct bce_queue_sq *) target;
-+ if (target_sq->completion_tail != e->completion_index) {
-+ pr_err("Completion index mismatch; this is likely going to make this driver unusable\n");
-+ return;
-+ }
-+ if (!target_sq->has_pending_completions) {
-+ target_sq->has_pending_completions = true;
-+ dev->int_sq_list[(*ce)++] = target_sq;
-+ }
-+ cmpl = &target_sq->completion_data[e->completion_index];
-+ cmpl->status = e->status;
-+ cmpl->data_size = e->data_size;
-+ cmpl->result = e->result;
-+ wmb();
-+ target_sq->completion_tail = (target_sq->completion_tail + 1) % target_sq->el_count;
-+}
-+
-+void bce_handle_cq_completions(struct apple_bce_device *dev, struct bce_queue_cq *cq)
-+{
-+ size_t ce = 0;
-+ struct bce_qe_completion *e;
-+ struct bce_queue_sq *sq;
-+ e = bce_cq_element(cq, cq->index);
-+ if (!(e->flags & BCE_COMPLETION_FLAG_PENDING))
-+ return;
-+ mb();
-+ while (true) {
-+ e = bce_cq_element(cq, cq->index);
-+ if (!(e->flags & BCE_COMPLETION_FLAG_PENDING))
-+ break;
-+ // pr_info("apple-bce: compl: %i: %i %llx %llx", e->qid, e->status, e->data_size, e->result);
-+ bce_handle_cq_completion(dev, e, &ce);
-+ e->flags = 0;
-+ cq->index = (cq->index + 1) % cq->el_count;
-+ }
-+ mb();
-+ iowrite32(cq->index, (u32 *) ((u8 *) dev->reg_mem_dma + REG_DOORBELL_BASE) + cq->qid);
-+ while (ce) {
-+ --ce;
-+ sq = dev->int_sq_list[ce];
-+ sq->completion(sq);
-+ sq->has_pending_completions = false;
-+ }
-+}
-+
-+
-+struct bce_queue_sq *bce_alloc_sq(struct apple_bce_device *dev, int qid, u32 el_size, u32 el_count,
-+ bce_sq_completion compl, void *userdata)
-+{
-+ struct bce_queue_sq *q;
-+ q = kzalloc(sizeof(struct bce_queue_sq), GFP_KERNEL);
-+ q->qid = qid;
-+ q->type = BCE_QUEUE_SQ;
-+ q->el_size = el_size;
-+ q->el_count = el_count;
-+ q->data = dma_alloc_coherent(&dev->pci->dev, el_count * el_size,
-+ &q->dma_handle, GFP_KERNEL);
-+ q->completion = compl;
-+ q->userdata = userdata;
-+ q->completion_data = kzalloc(sizeof(struct bce_sq_completion_data) * el_count, GFP_KERNEL);
-+ q->reg_mem_dma = dev->reg_mem_dma;
-+ atomic_set(&q->available_commands, el_count - 1);
-+ init_completion(&q->available_command_completion);
-+ atomic_set(&q->available_command_completion_waiting_count, 0);
-+ if (!q->data) {
-+ pr_err("DMA queue memory alloc failed\n");
-+ kfree(q);
-+ return NULL;
-+ }
-+ return q;
-+}
-+
-+void bce_get_sq_memcfg(struct bce_queue_sq *sq, struct bce_queue_cq *cq, struct bce_queue_memcfg *cfg)
-+{
-+ cfg->qid = (u16) sq->qid;
-+ cfg->el_count = (u16) sq->el_count;
-+ cfg->vector_or_cq = (u16) cq->qid;
-+ cfg->_pad = 0;
-+ cfg->addr = sq->dma_handle;
-+ cfg->length = sq->el_count * sq->el_size;
-+}
-+
-+void bce_free_sq(struct apple_bce_device *dev, struct bce_queue_sq *sq)
-+{
-+ dma_free_coherent(&dev->pci->dev, sq->el_count * sq->el_size, sq->data, sq->dma_handle);
-+ kfree(sq);
-+}
-+
-+int bce_reserve_submission(struct bce_queue_sq *sq, unsigned long *timeout)
-+{
-+ while (atomic_dec_if_positive(&sq->available_commands) < 0) {
-+ if (!timeout || !*timeout)
-+ return -EAGAIN;
-+ atomic_inc(&sq->available_command_completion_waiting_count);
-+ *timeout = wait_for_completion_timeout(&sq->available_command_completion, *timeout);
-+ if (!*timeout) {
-+ if (atomic_dec_if_positive(&sq->available_command_completion_waiting_count) < 0)
-+ try_wait_for_completion(&sq->available_command_completion); /* consume the pending completion */
-+ }
-+ }
-+ return 0;
-+}
-+
-+void bce_cancel_submission_reservation(struct bce_queue_sq *sq)
-+{
-+ atomic_inc(&sq->available_commands);
-+}
-+
-+void *bce_next_submission(struct bce_queue_sq *sq)
-+{
-+ void *ret = bce_sq_element(sq, sq->tail);
-+ sq->tail = (sq->tail + 1) % sq->el_count;
-+ return ret;
-+}
-+
-+void bce_submit_to_device(struct bce_queue_sq *sq)
-+{
-+ mb();
-+ iowrite32(sq->tail, (u32 *) ((u8 *) sq->reg_mem_dma + REG_DOORBELL_BASE) + sq->qid);
-+}
-+
-+void bce_notify_submission_complete(struct bce_queue_sq *sq)
-+{
-+ sq->head = (sq->head + 1) % sq->el_count;
-+ atomic_inc(&sq->available_commands);
-+ if (atomic_dec_if_positive(&sq->available_command_completion_waiting_count) >= 0) {
-+ complete(&sq->available_command_completion);
-+ }
-+}
-+
-+void bce_set_submission_single(struct bce_qe_submission *element, dma_addr_t addr, size_t size)
-+{
-+ element->addr = addr;
-+ element->length = size;
-+ element->segl_addr = element->segl_length = 0;
-+}
-+
-+static void bce_cmdq_completion(struct bce_queue_sq *q);
-+
-+struct bce_queue_cmdq *bce_alloc_cmdq(struct apple_bce_device *dev, int qid, u32 el_count)
-+{
-+ struct bce_queue_cmdq *q;
-+ q = kzalloc(sizeof(struct bce_queue_cmdq), GFP_KERNEL);
-+ q->sq = bce_alloc_sq(dev, qid, BCE_CMD_SIZE, el_count, bce_cmdq_completion, q);
-+ if (!q->sq) {
-+ kfree(q);
-+ return NULL;
-+ }
-+ spin_lock_init(&q->lck);
-+ q->tres = kzalloc(sizeof(struct bce_queue_cmdq_result_el*) * el_count, GFP_KERNEL);
-+ if (!q->tres) {
-+ kfree(q);
-+ return NULL;
-+ }
-+ return q;
-+}
-+
-+void bce_free_cmdq(struct apple_bce_device *dev, struct bce_queue_cmdq *cmdq)
-+{
-+ bce_free_sq(dev, cmdq->sq);
-+ kfree(cmdq->tres);
-+ kfree(cmdq);
-+}
-+
-+void bce_cmdq_completion(struct bce_queue_sq *q)
-+{
-+ struct bce_queue_cmdq_result_el *el;
-+ struct bce_queue_cmdq *cmdq = q->userdata;
-+ struct bce_sq_completion_data *result;
-+
-+ spin_lock(&cmdq->lck);
-+ while ((result = bce_next_completion(q))) {
-+ el = cmdq->tres[cmdq->sq->head];
-+ if (el) {
-+ el->result = result->result;
-+ el->status = result->status;
-+ mb();
-+ complete(&el->cmpl);
-+ } else {
-+ pr_err("apple-bce: Unexpected command queue completion\n");
-+ }
-+ cmdq->tres[cmdq->sq->head] = NULL;
-+ bce_notify_submission_complete(q);
-+ }
-+ spin_unlock(&cmdq->lck);
-+}
-+
-+static __always_inline void *bce_cmd_start(struct bce_queue_cmdq *cmdq, struct bce_queue_cmdq_result_el *res)
-+{
-+ void *ret;
-+ unsigned long timeout;
-+ init_completion(&res->cmpl);
-+ mb();
-+
-+ timeout = msecs_to_jiffies(1000L * 60 * 5); /* wait for up to ~5 minutes */
-+ if (bce_reserve_submission(cmdq->sq, &timeout))
-+ return NULL;
-+
-+ spin_lock(&cmdq->lck);
-+ cmdq->tres[cmdq->sq->tail] = res;
-+ ret = bce_next_submission(cmdq->sq);
-+ return ret;
-+}
-+
-+static __always_inline void bce_cmd_finish(struct bce_queue_cmdq *cmdq, struct bce_queue_cmdq_result_el *res)
-+{
-+ bce_submit_to_device(cmdq->sq);
-+ spin_unlock(&cmdq->lck);
-+
-+ wait_for_completion(&res->cmpl);
-+ mb();
-+}
-+
-+u32 bce_cmd_register_queue(struct bce_queue_cmdq *cmdq, struct bce_queue_memcfg *cfg, const char *name, bool isdirout)
-+{
-+ struct bce_queue_cmdq_result_el res;
-+ struct bce_cmdq_register_memory_queue_cmd *cmd = bce_cmd_start(cmdq, &res);
-+ if (!cmd)
-+ return (u32) -1;
-+ cmd->cmd = BCE_CMD_REGISTER_MEMORY_QUEUE;
-+ cmd->flags = (u16) ((name ? 2 : 0) | (isdirout ? 1 : 0));
-+ cmd->qid = cfg->qid;
-+ cmd->el_count = cfg->el_count;
-+ cmd->vector_or_cq = cfg->vector_or_cq;
-+ memset(cmd->name, 0, sizeof(cmd->name));
-+ if (name) {
-+ cmd->name_len = (u16) min(strlen(name), (size_t) sizeof(cmd->name));
-+ memcpy(cmd->name, name, cmd->name_len);
-+ } else {
-+ cmd->name_len = 0;
-+ }
-+ cmd->addr = cfg->addr;
-+ cmd->length = cfg->length;
-+
-+ bce_cmd_finish(cmdq, &res);
-+ return res.status;
-+}
-+
-+u32 bce_cmd_unregister_memory_queue(struct bce_queue_cmdq *cmdq, u16 qid)
-+{
-+ struct bce_queue_cmdq_result_el res;
-+ struct bce_cmdq_simple_memory_queue_cmd *cmd = bce_cmd_start(cmdq, &res);
-+ if (!cmd)
-+ return (u32) -1;
-+ cmd->cmd = BCE_CMD_UNREGISTER_MEMORY_QUEUE;
-+ cmd->flags = 0;
-+ cmd->qid = qid;
-+ bce_cmd_finish(cmdq, &res);
-+ return res.status;
-+}
-+
-+u32 bce_cmd_flush_memory_queue(struct bce_queue_cmdq *cmdq, u16 qid)
-+{
-+ struct bce_queue_cmdq_result_el res;
-+ struct bce_cmdq_simple_memory_queue_cmd *cmd = bce_cmd_start(cmdq, &res);
-+ if (!cmd)
-+ return (u32) -1;
-+ cmd->cmd = BCE_CMD_FLUSH_MEMORY_QUEUE;
-+ cmd->flags = 0;
-+ cmd->qid = qid;
-+ bce_cmd_finish(cmdq, &res);
-+ return res.status;
-+}
-+
-+
-+struct bce_queue_cq *bce_create_cq(struct apple_bce_device *dev, u32 el_count)
-+{
-+ struct bce_queue_cq *cq;
-+ struct bce_queue_memcfg cfg;
-+ int qid = ida_simple_get(&dev->queue_ida, BCE_QUEUE_USER_MIN, BCE_QUEUE_USER_MAX, GFP_KERNEL);
-+ if (qid < 0)
-+ return NULL;
-+ cq = bce_alloc_cq(dev, qid, el_count);
-+ if (!cq)
-+ return NULL;
-+ bce_get_cq_memcfg(cq, &cfg);
-+ if (bce_cmd_register_queue(dev->cmd_cmdq, &cfg, NULL, false) != 0) {
-+ pr_err("apple-bce: CQ registration failed (%i)", qid);
-+ bce_free_cq(dev, cq);
-+ ida_simple_remove(&dev->queue_ida, (uint) qid);
-+ return NULL;
-+ }
-+ dev->queues[qid] = (struct bce_queue *) cq;
-+ return cq;
-+}
-+
-+struct bce_queue_sq *bce_create_sq(struct apple_bce_device *dev, struct bce_queue_cq *cq, const char *name, u32 el_count,
-+ int direction, bce_sq_completion compl, void *userdata)
-+{
-+ struct bce_queue_sq *sq;
-+ struct bce_queue_memcfg cfg;
-+ int qid;
-+ if (cq == NULL)
-+ return NULL; /* cq can not be null */
-+ if (name == NULL)
-+ return NULL; /* name can not be null */
-+ if (direction != DMA_TO_DEVICE && direction != DMA_FROM_DEVICE)
-+ return NULL; /* unsupported direction */
-+ qid = ida_simple_get(&dev->queue_ida, BCE_QUEUE_USER_MIN, BCE_QUEUE_USER_MAX, GFP_KERNEL);
-+ if (qid < 0)
-+ return NULL;
-+ sq = bce_alloc_sq(dev, qid, sizeof(struct bce_qe_submission), el_count, compl, userdata);
-+ if (!sq)
-+ return NULL;
-+ bce_get_sq_memcfg(sq, cq, &cfg);
-+ if (bce_cmd_register_queue(dev->cmd_cmdq, &cfg, name, direction != DMA_FROM_DEVICE) != 0) {
-+ pr_err("apple-bce: SQ registration failed (%i)", qid);
-+ bce_free_sq(dev, sq);
-+ ida_simple_remove(&dev->queue_ida, (uint) qid);
-+ return NULL;
-+ }
-+ spin_lock(&dev->queues_lock);
-+ dev->queues[qid] = (struct bce_queue *) sq;
-+ spin_unlock(&dev->queues_lock);
-+ return sq;
-+}
-+
-+void bce_destroy_cq(struct apple_bce_device *dev, struct bce_queue_cq *cq)
-+{
-+ if (!dev->is_being_removed && bce_cmd_unregister_memory_queue(dev->cmd_cmdq, (u16) cq->qid))
-+ pr_err("apple-bce: CQ unregister failed");
-+ spin_lock(&dev->queues_lock);
-+ dev->queues[cq->qid] = NULL;
-+ spin_unlock(&dev->queues_lock);
-+ ida_simple_remove(&dev->queue_ida, (uint) cq->qid);
-+ bce_free_cq(dev, cq);
-+}
-+
-+void bce_destroy_sq(struct apple_bce_device *dev, struct bce_queue_sq *sq)
-+{
-+ if (!dev->is_being_removed && bce_cmd_unregister_memory_queue(dev->cmd_cmdq, (u16) sq->qid))
-+ pr_err("apple-bce: CQ unregister failed");
-+ spin_lock(&dev->queues_lock);
-+ dev->queues[sq->qid] = NULL;
-+ spin_unlock(&dev->queues_lock);
-+ ida_simple_remove(&dev->queue_ida, (uint) sq->qid);
-+ bce_free_sq(dev, sq);
-+}
-\ 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 000000000000..8368ac5dfca8
---- /dev/null
-+++ b/drivers/staging/apple-bce/queue.h
-@@ -0,0 +1,177 @@
-+#ifndef BCE_QUEUE_H
-+#define BCE_QUEUE_H
-+
-+#include <linux/completion.h>
-+#include <linux/pci.h>
-+
-+#define BCE_CMD_SIZE 0x40
-+
-+struct apple_bce_device;
-+
-+enum bce_queue_type {
-+ BCE_QUEUE_CQ, BCE_QUEUE_SQ
-+};
-+struct bce_queue {
-+ int qid;
-+ int type;
-+};
-+struct bce_queue_cq {
-+ int qid;
-+ int type;
-+ u32 el_count;
-+ dma_addr_t dma_handle;
-+ void *data;
-+
-+ u32 index;
-+};
-+struct bce_queue_sq;
-+typedef void (*bce_sq_completion)(struct bce_queue_sq *q);
-+struct bce_sq_completion_data {
-+ u32 status;
-+ u64 data_size;
-+ u64 result;
-+};
-+struct bce_queue_sq {
-+ int qid;
-+ int type;
-+ u32 el_size;
-+ u32 el_count;
-+ dma_addr_t dma_handle;
-+ void *data;
-+ void *userdata;
-+ void __iomem *reg_mem_dma;
-+
-+ atomic_t available_commands;
-+ struct completion available_command_completion;
-+ atomic_t available_command_completion_waiting_count;
-+ u32 head, tail;
-+
-+ u32 completion_cidx, completion_tail;
-+ struct bce_sq_completion_data *completion_data;
-+ bool has_pending_completions;
-+ bce_sq_completion completion;
-+};
-+
-+struct bce_queue_cmdq_result_el {
-+ struct completion cmpl;
-+ u32 status;
-+ u64 result;
-+};
-+struct bce_queue_cmdq {
-+ struct bce_queue_sq *sq;
-+ struct spinlock lck;
-+ struct bce_queue_cmdq_result_el **tres;
-+};
-+
-+struct bce_queue_memcfg {
-+ u16 qid;
-+ u16 el_count;
-+ u16 vector_or_cq;
-+ u16 _pad;
-+ u64 addr;
-+ u64 length;
-+};
-+
-+enum bce_qe_completion_status {
-+ BCE_COMPLETION_SUCCESS = 0,
-+ BCE_COMPLETION_ERROR = 1,
-+ BCE_COMPLETION_ABORTED = 2,
-+ BCE_COMPLETION_NO_SPACE = 3,
-+ BCE_COMPLETION_OVERRUN = 4
-+};
-+enum bce_qe_completion_flags {
-+ BCE_COMPLETION_FLAG_PENDING = 0x8000
-+};
-+struct bce_qe_completion {
-+ u64 result;
-+ u64 data_size;
-+ u16 qid;
-+ u16 completion_index;
-+ u16 status; // bce_qe_completion_status
-+ u16 flags; // bce_qe_completion_flags
-+};
-+
-+struct bce_qe_submission {
-+ u64 length;
-+ u64 addr;
-+
-+ u64 segl_addr;
-+ u64 segl_length;
-+};
-+
-+enum bce_cmdq_command {
-+ BCE_CMD_REGISTER_MEMORY_QUEUE = 0x20,
-+ BCE_CMD_UNREGISTER_MEMORY_QUEUE = 0x30,
-+ BCE_CMD_FLUSH_MEMORY_QUEUE = 0x40,
-+ BCE_CMD_SET_MEMORY_QUEUE_PROPERTY = 0x50
-+};
-+struct bce_cmdq_simple_memory_queue_cmd {
-+ u16 cmd; // bce_cmdq_command
-+ u16 flags;
-+ u16 qid;
-+};
-+struct bce_cmdq_register_memory_queue_cmd {
-+ u16 cmd; // bce_cmdq_command
-+ u16 flags;
-+ u16 qid;
-+ u16 _pad;
-+ u16 el_count;
-+ u16 vector_or_cq;
-+ u16 _pad2;
-+ u16 name_len;
-+ char name[0x20];
-+ u64 addr;
-+ u64 length;
-+};
-+
-+static __always_inline void *bce_sq_element(struct bce_queue_sq *q, int i) {
-+ return (void *) ((u8 *) q->data + q->el_size * i);
-+}
-+static __always_inline void *bce_cq_element(struct bce_queue_cq *q, int i) {
-+ return (void *) ((struct bce_qe_completion *) q->data + i);
-+}
-+
-+static __always_inline struct bce_sq_completion_data *bce_next_completion(struct bce_queue_sq *sq) {
-+ struct bce_sq_completion_data *res;
-+ rmb();
-+ if (sq->completion_cidx == sq->completion_tail)
-+ return NULL;
-+ res = &sq->completion_data[sq->completion_cidx];
-+ sq->completion_cidx = (sq->completion_cidx + 1) % sq->el_count;
-+ return res;
-+}
-+
-+struct bce_queue_cq *bce_alloc_cq(struct apple_bce_device *dev, int qid, u32 el_count);
-+void bce_get_cq_memcfg(struct bce_queue_cq *cq, struct bce_queue_memcfg *cfg);
-+void bce_free_cq(struct apple_bce_device *dev, struct bce_queue_cq *cq);
-+void bce_handle_cq_completions(struct apple_bce_device *dev, struct bce_queue_cq *cq);
-+
-+struct bce_queue_sq *bce_alloc_sq(struct apple_bce_device *dev, int qid, u32 el_size, u32 el_count,
-+ bce_sq_completion compl, void *userdata);
-+void bce_get_sq_memcfg(struct bce_queue_sq *sq, struct bce_queue_cq *cq, struct bce_queue_memcfg *cfg);
-+void bce_free_sq(struct apple_bce_device *dev, struct bce_queue_sq *sq);
-+int bce_reserve_submission(struct bce_queue_sq *sq, unsigned long *timeout);
-+void bce_cancel_submission_reservation(struct bce_queue_sq *sq);
-+void *bce_next_submission(struct bce_queue_sq *sq);
-+void bce_submit_to_device(struct bce_queue_sq *sq);
-+void bce_notify_submission_complete(struct bce_queue_sq *sq);
-+
-+void bce_set_submission_single(struct bce_qe_submission *element, dma_addr_t addr, size_t size);
-+
-+struct bce_queue_cmdq *bce_alloc_cmdq(struct apple_bce_device *dev, int qid, u32 el_count);
-+void bce_free_cmdq(struct apple_bce_device *dev, struct bce_queue_cmdq *cmdq);
-+
-+u32 bce_cmd_register_queue(struct bce_queue_cmdq *cmdq, struct bce_queue_memcfg *cfg, const char *name, bool isdirout);
-+u32 bce_cmd_unregister_memory_queue(struct bce_queue_cmdq *cmdq, u16 qid);
-+u32 bce_cmd_flush_memory_queue(struct bce_queue_cmdq *cmdq, u16 qid);
-+
-+
-+/* User API - Creates and registers the queue */
-+
-+struct bce_queue_cq *bce_create_cq(struct apple_bce_device *dev, u32 el_count);
-+struct bce_queue_sq *bce_create_sq(struct apple_bce_device *dev, struct bce_queue_cq *cq, const char *name, u32 el_count,
-+ int direction, bce_sq_completion compl, void *userdata);
-+void bce_destroy_cq(struct apple_bce_device *dev, struct bce_queue_cq *cq);
-+void bce_destroy_sq(struct apple_bce_device *dev, struct bce_queue_sq *sq);
-+
-+#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 000000000000..b236613285c0
---- /dev/null
-+++ b/drivers/staging/apple-bce/queue_dma.c
-@@ -0,0 +1,220 @@
-+#include "queue_dma.h"
-+#include <linux/vmalloc.h>
-+#include <linux/mm.h>
-+#include "queue.h"
-+
-+static int bce_alloc_scatterlist_from_vm(struct sg_table *tbl, void *data, size_t len);
-+static struct bce_segment_list_element_hostinfo *bce_map_segment_list(
-+ struct device *dev, struct scatterlist *pages, int pagen);
-+static void bce_unmap_segement_list(struct device *dev, struct bce_segment_list_element_hostinfo *list);
-+
-+int bce_map_dma_buffer(struct device *dev, struct bce_dma_buffer *buf, struct sg_table scatterlist,
-+ enum dma_data_direction dir)
-+{
-+ int cnt;
-+
-+ buf->direction = dir;
-+ buf->scatterlist = scatterlist;
-+ buf->seglist_hostinfo = NULL;
-+
-+ cnt = dma_map_sg(dev, buf->scatterlist.sgl, buf->scatterlist.nents, dir);
-+ if (cnt != buf->scatterlist.nents) {
-+ pr_err("apple-bce: DMA scatter list mapping returned an unexpected count: %i\n", cnt);
-+ dma_unmap_sg(dev, buf->scatterlist.sgl, buf->scatterlist.nents, dir);
-+ return -EIO;
-+ }
-+ if (cnt == 1)
-+ return 0;
-+
-+ buf->seglist_hostinfo = bce_map_segment_list(dev, buf->scatterlist.sgl, buf->scatterlist.nents);
-+ if (!buf->seglist_hostinfo) {
-+ pr_err("apple-bce: Creating segment list failed\n");
-+ dma_unmap_sg(dev, buf->scatterlist.sgl, buf->scatterlist.nents, dir);
-+ return -EIO;
-+ }
-+ return 0;
-+}
-+
-+int bce_map_dma_buffer_vm(struct device *dev, struct bce_dma_buffer *buf, void *data, size_t len,
-+ enum dma_data_direction dir)
-+{
-+ int status;
-+ struct sg_table scatterlist;
-+ if ((status = bce_alloc_scatterlist_from_vm(&scatterlist, data, len)))
-+ return status;
-+ if ((status = bce_map_dma_buffer(dev, buf, scatterlist, dir))) {
-+ sg_free_table(&scatterlist);
-+ return status;
-+ }
-+ return 0;
-+}
-+
-+int bce_map_dma_buffer_km(struct device *dev, struct bce_dma_buffer *buf, void *data, size_t len,
-+ enum dma_data_direction dir)
-+{
-+ /* Kernel memory is continuous which is great for us. */
-+ int status;
-+ struct sg_table scatterlist;
-+ if ((status = sg_alloc_table(&scatterlist, 1, GFP_KERNEL))) {
-+ sg_free_table(&scatterlist);
-+ return status;
-+ }
-+ sg_set_buf(scatterlist.sgl, data, (uint) len);
-+ if ((status = bce_map_dma_buffer(dev, buf, scatterlist, dir))) {
-+ sg_free_table(&scatterlist);
-+ return status;
-+ }
-+ return 0;
-+}
-+
-+void bce_unmap_dma_buffer(struct device *dev, struct bce_dma_buffer *buf)
-+{
-+ dma_unmap_sg(dev, buf->scatterlist.sgl, buf->scatterlist.nents, buf->direction);
-+ bce_unmap_segement_list(dev, buf->seglist_hostinfo);
-+}
-+
-+
-+static int bce_alloc_scatterlist_from_vm(struct sg_table *tbl, void *data, size_t len)
-+{
-+ int status, i;
-+ struct page **pages;
-+ size_t off, start_page, end_page, page_count;
-+ off = (size_t) data % PAGE_SIZE;
-+ start_page = (size_t) data / PAGE_SIZE;
-+ end_page = ((size_t) data + len - 1) / PAGE_SIZE;
-+ page_count = end_page - start_page + 1;
-+
-+ if (page_count > PAGE_SIZE / sizeof(struct page *))
-+ pages = vmalloc(page_count * sizeof(struct page *));
-+ else
-+ pages = kmalloc(page_count * sizeof(struct page *), GFP_KERNEL);
-+
-+ for (i = 0; i < page_count; i++)
-+ pages[i] = vmalloc_to_page((void *) ((start_page + i) * PAGE_SIZE));
-+
-+ if ((status = sg_alloc_table_from_pages(tbl, pages, page_count, (unsigned int) off, len, GFP_KERNEL))) {
-+ sg_free_table(tbl);
-+ }
-+
-+ if (page_count > PAGE_SIZE / sizeof(struct page *))
-+ vfree(pages);
-+ else
-+ kfree(pages);
-+ return status;
-+}
-+
-+#define BCE_ELEMENTS_PER_PAGE ((PAGE_SIZE - sizeof(struct bce_segment_list_header)) \
-+ / sizeof(struct bce_segment_list_element))
-+#define BCE_ELEMENTS_PER_ADDITIONAL_PAGE (PAGE_SIZE / sizeof(struct bce_segment_list_element))
-+
-+static struct bce_segment_list_element_hostinfo *bce_map_segment_list(
-+ struct device *dev, struct scatterlist *pages, int pagen)
-+{
-+ size_t ptr, pptr = 0;
-+ struct bce_segment_list_header theader; /* a temp header, to store the initial seg */
-+ struct bce_segment_list_header *header;
-+ struct bce_segment_list_element *el, *el_end;
-+ struct bce_segment_list_element_hostinfo *out, *pout, *out_root;
-+ struct scatterlist *sg;
-+ int i;
-+ header = &theader;
-+ out = out_root = NULL;
-+ el = el_end = NULL;
-+ for_each_sg(pages, sg, pagen, i) {
-+ if (el >= el_end) {
-+ /* allocate a new page, this will be also done for the first element */
-+ ptr = __get_free_page(GFP_KERNEL);
-+ if (pptr && ptr == pptr + PAGE_SIZE) {
-+ out->page_count++;
-+ header->element_count += BCE_ELEMENTS_PER_ADDITIONAL_PAGE;
-+ el_end += BCE_ELEMENTS_PER_ADDITIONAL_PAGE;
-+ } else {
-+ header = (void *) ptr;
-+ header->element_count = BCE_ELEMENTS_PER_PAGE;
-+ header->data_size = 0;
-+ header->next_segl_addr = 0;
-+ header->next_segl_length = 0;
-+ el = (void *) (header + 1);
-+ el_end = el + BCE_ELEMENTS_PER_PAGE;
-+
-+ if (out) {
-+ out->next = kmalloc(sizeof(struct bce_segment_list_element_hostinfo), GFP_KERNEL);
-+ out = out->next;
-+ } else {
-+ out_root = out = kmalloc(sizeof(struct bce_segment_list_element_hostinfo), GFP_KERNEL);
-+ }
-+ out->page_start = (void *) ptr;
-+ out->page_count = 1;
-+ out->dma_start = DMA_MAPPING_ERROR;
-+ out->next = NULL;
-+ }
-+ pptr = ptr;
-+ }
-+ el->addr = sg->dma_address;
-+ el->length = sg->length;
-+ header->data_size += el->length;
-+ }
-+
-+ /* DMA map */
-+ out = out_root;
-+ pout = NULL;
-+ while (out) {
-+ out->dma_start = dma_map_single(dev, out->page_start, out->page_count * PAGE_SIZE, DMA_TO_DEVICE);
-+ if (dma_mapping_error(dev, out->dma_start))
-+ goto error;
-+ if (pout) {
-+ header = pout->page_start;
-+ header->next_segl_addr = out->dma_start;
-+ header->next_segl_length = out->page_count * PAGE_SIZE;
-+ }
-+ pout = out;
-+ out = out->next;
-+ }
-+ return out_root;
-+
-+ error:
-+ bce_unmap_segement_list(dev, out_root);
-+ return NULL;
-+}
-+
-+static void bce_unmap_segement_list(struct device *dev, struct bce_segment_list_element_hostinfo *list)
-+{
-+ struct bce_segment_list_element_hostinfo *next;
-+ while (list) {
-+ if (list->dma_start != DMA_MAPPING_ERROR)
-+ dma_unmap_single(dev, list->dma_start, list->page_count * PAGE_SIZE, DMA_TO_DEVICE);
-+ next = list->next;
-+ kfree(list);
-+ list = next;
-+ }
-+}
-+
-+int bce_set_submission_buf(struct bce_qe_submission *element, struct bce_dma_buffer *buf, size_t offset, size_t length)
-+{
-+ struct bce_segment_list_element_hostinfo *seg;
-+ struct bce_segment_list_header *seg_header;
-+
-+ seg = buf->seglist_hostinfo;
-+ if (!seg) {
-+ element->addr = buf->scatterlist.sgl->dma_address + offset;
-+ element->length = length;
-+ element->segl_addr = 0;
-+ element->segl_length = 0;
-+ return 0;
-+ }
-+
-+ while (seg) {
-+ seg_header = seg->page_start;
-+ if (offset <= seg_header->data_size)
-+ break;
-+ offset -= seg_header->data_size;
-+ seg = seg->next;
-+ }
-+ if (!seg)
-+ return -EINVAL;
-+ element->addr = offset;
-+ element->length = buf->scatterlist.sgl->dma_length;
-+ element->segl_addr = seg->dma_start;
-+ element->segl_length = seg->page_count * PAGE_SIZE;
-+ return 0;
-+}
-\ 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 000000000000..f8a57e50e7a3
---- /dev/null
-+++ b/drivers/staging/apple-bce/queue_dma.h
-@@ -0,0 +1,50 @@
-+#ifndef BCE_QUEUE_DMA_H
-+#define BCE_QUEUE_DMA_H
-+
-+#include <linux/pci.h>
-+
-+struct bce_qe_submission;
-+
-+struct bce_segment_list_header {
-+ u64 element_count;
-+ u64 data_size;
-+
-+ u64 next_segl_addr;
-+ u64 next_segl_length;
-+};
-+struct bce_segment_list_element {
-+ u64 addr;
-+ u64 length;
-+};
-+
-+struct bce_segment_list_element_hostinfo {
-+ struct bce_segment_list_element_hostinfo *next;
-+ void *page_start;
-+ size_t page_count;
-+ dma_addr_t dma_start;
-+};
-+
-+
-+struct bce_dma_buffer {
-+ enum dma_data_direction direction;
-+ struct sg_table scatterlist;
-+ struct bce_segment_list_element_hostinfo *seglist_hostinfo;
-+};
-+
-+/* NOTE: Takes ownership of the sg_table if it succeeds. Ownership is not transferred on failure. */
-+int bce_map_dma_buffer(struct device *dev, struct bce_dma_buffer *buf, struct sg_table scatterlist,
-+ enum dma_data_direction dir);
-+
-+/* Creates a buffer from virtual memory (vmalloc) */
-+int bce_map_dma_buffer_vm(struct device *dev, struct bce_dma_buffer *buf, void *data, size_t len,
-+ enum dma_data_direction dir);
-+
-+/* Creates a buffer from kernel memory (kmalloc) */
-+int bce_map_dma_buffer_km(struct device *dev, struct bce_dma_buffer *buf, void *data, size_t len,
-+ enum dma_data_direction dir);
-+
-+void bce_unmap_dma_buffer(struct device *dev, struct bce_dma_buffer *buf);
-+
-+int bce_set_submission_buf(struct bce_qe_submission *element, struct bce_dma_buffer *buf, size_t offset, size_t length);
-+
-+#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 000000000000..26619e0bccfa
---- /dev/null
-+++ b/drivers/staging/apple-bce/vhci/command.h
-@@ -0,0 +1,204 @@
-+#ifndef BCE_VHCI_COMMAND_H
-+#define BCE_VHCI_COMMAND_H
-+
-+#include "queue.h"
-+#include <linux/jiffies.h>
-+#include <linux/usb.h>
-+
-+#define BCE_VHCI_CMD_TIMEOUT_SHORT msecs_to_jiffies(2000)
-+#define BCE_VHCI_CMD_TIMEOUT_LONG msecs_to_jiffies(30000)
-+
-+#define BCE_VHCI_BULK_MAX_ACTIVE_URBS_POW2 2
-+#define BCE_VHCI_BULK_MAX_ACTIVE_URBS (1 << BCE_VHCI_BULK_MAX_ACTIVE_URBS_POW2)
-+
-+typedef u8 bce_vhci_port_t;
-+typedef u8 bce_vhci_device_t;
-+
-+enum bce_vhci_command {
-+ BCE_VHCI_CMD_CONTROLLER_ENABLE = 1,
-+ BCE_VHCI_CMD_CONTROLLER_DISABLE = 2,
-+ BCE_VHCI_CMD_CONTROLLER_START = 3,
-+ BCE_VHCI_CMD_CONTROLLER_PAUSE = 4,
-+
-+ BCE_VHCI_CMD_PORT_POWER_ON = 0x10,
-+ BCE_VHCI_CMD_PORT_POWER_OFF = 0x11,
-+ BCE_VHCI_CMD_PORT_RESUME = 0x12,
-+ BCE_VHCI_CMD_PORT_SUSPEND = 0x13,
-+ BCE_VHCI_CMD_PORT_RESET = 0x14,
-+ BCE_VHCI_CMD_PORT_DISABLE = 0x15,
-+ BCE_VHCI_CMD_PORT_STATUS = 0x16,
-+
-+ BCE_VHCI_CMD_DEVICE_CREATE = 0x30,
-+ BCE_VHCI_CMD_DEVICE_DESTROY = 0x31,
-+
-+ BCE_VHCI_CMD_ENDPOINT_CREATE = 0x40,
-+ BCE_VHCI_CMD_ENDPOINT_DESTROY = 0x41,
-+ BCE_VHCI_CMD_ENDPOINT_SET_STATE = 0x42,
-+ BCE_VHCI_CMD_ENDPOINT_RESET = 0x44,
-+
-+ /* Device to host only */
-+ BCE_VHCI_CMD_ENDPOINT_REQUEST_STATE = 0x43,
-+ BCE_VHCI_CMD_TRANSFER_REQUEST = 0x1000,
-+ BCE_VHCI_CMD_CONTROL_TRANSFER_STATUS = 0x1005
-+};
-+
-+enum bce_vhci_endpoint_state {
-+ BCE_VHCI_ENDPOINT_ACTIVE = 0,
-+ BCE_VHCI_ENDPOINT_PAUSED = 1,
-+ BCE_VHCI_ENDPOINT_STALLED = 2
-+};
-+
-+static inline int bce_vhci_cmd_controller_enable(struct bce_vhci_command_queue *q, u8 busNum, u16 *portMask)
-+{
-+ int status;
-+ struct bce_vhci_message cmd, res;
-+ cmd.cmd = BCE_VHCI_CMD_CONTROLLER_ENABLE;
-+ cmd.param1 = 0x7100u | busNum;
-+ status = bce_vhci_command_queue_execute(q, &cmd, &res, BCE_VHCI_CMD_TIMEOUT_LONG);
-+ if (!status)
-+ *portMask = (u16) res.param2;
-+ return status;
-+}
-+static inline int bce_vhci_cmd_controller_disable(struct bce_vhci_command_queue *q)
-+{
-+ struct bce_vhci_message cmd, res;
-+ cmd.cmd = BCE_VHCI_CMD_CONTROLLER_DISABLE;
-+ return bce_vhci_command_queue_execute(q, &cmd, &res, BCE_VHCI_CMD_TIMEOUT_LONG);
-+}
-+static inline int bce_vhci_cmd_controller_start(struct bce_vhci_command_queue *q)
-+{
-+ struct bce_vhci_message cmd, res;
-+ cmd.cmd = BCE_VHCI_CMD_CONTROLLER_START;
-+ return bce_vhci_command_queue_execute(q, &cmd, &res, BCE_VHCI_CMD_TIMEOUT_LONG);
-+}
-+static inline int bce_vhci_cmd_controller_pause(struct bce_vhci_command_queue *q)
-+{
-+ struct bce_vhci_message cmd, res;
-+ cmd.cmd = BCE_VHCI_CMD_CONTROLLER_PAUSE;
-+ return bce_vhci_command_queue_execute(q, &cmd, &res, BCE_VHCI_CMD_TIMEOUT_LONG);
-+}
-+
-+static inline int bce_vhci_cmd_port_power_on(struct bce_vhci_command_queue *q, bce_vhci_port_t port)
-+{
-+ struct bce_vhci_message cmd, res;
-+ cmd.cmd = BCE_VHCI_CMD_PORT_POWER_ON;
-+ cmd.param1 = port;
-+ return bce_vhci_command_queue_execute(q, &cmd, &res, BCE_VHCI_CMD_TIMEOUT_SHORT);
-+}
-+static inline int bce_vhci_cmd_port_power_off(struct bce_vhci_command_queue *q, bce_vhci_port_t port)
-+{
-+ struct bce_vhci_message cmd, res;
-+ cmd.cmd = BCE_VHCI_CMD_PORT_POWER_OFF;
-+ cmd.param1 = port;
-+ return bce_vhci_command_queue_execute(q, &cmd, &res, BCE_VHCI_CMD_TIMEOUT_SHORT);
-+}
-+static inline int bce_vhci_cmd_port_resume(struct bce_vhci_command_queue *q, bce_vhci_port_t port)
-+{
-+ struct bce_vhci_message cmd, res;
-+ cmd.cmd = BCE_VHCI_CMD_PORT_RESUME;
-+ cmd.param1 = port;
-+ return bce_vhci_command_queue_execute(q, &cmd, &res, BCE_VHCI_CMD_TIMEOUT_LONG);
-+}
-+static inline int bce_vhci_cmd_port_suspend(struct bce_vhci_command_queue *q, bce_vhci_port_t port)
-+{
-+ struct bce_vhci_message cmd, res;
-+ cmd.cmd = BCE_VHCI_CMD_PORT_SUSPEND;
-+ cmd.param1 = port;
-+ return bce_vhci_command_queue_execute(q, &cmd, &res, BCE_VHCI_CMD_TIMEOUT_LONG);
-+}
-+static inline int bce_vhci_cmd_port_reset(struct bce_vhci_command_queue *q, bce_vhci_port_t port, u32 timeout)
-+{
-+ struct bce_vhci_message cmd, res;
-+ cmd.cmd = BCE_VHCI_CMD_PORT_RESET;
-+ cmd.param1 = port;
-+ cmd.param2 = timeout;
-+ return bce_vhci_command_queue_execute(q, &cmd, &res, BCE_VHCI_CMD_TIMEOUT_SHORT);
-+}
-+static inline int bce_vhci_cmd_port_disable(struct bce_vhci_command_queue *q, bce_vhci_port_t port)
-+{
-+ struct bce_vhci_message cmd, res;
-+ cmd.cmd = BCE_VHCI_CMD_PORT_DISABLE;
-+ cmd.param1 = port;
-+ return bce_vhci_command_queue_execute(q, &cmd, &res, BCE_VHCI_CMD_TIMEOUT_SHORT);
-+}
-+static inline int bce_vhci_cmd_port_status(struct bce_vhci_command_queue *q, bce_vhci_port_t port,
-+ u32 clearFlags, u32 *resStatus)
-+{
-+ int status;
-+ struct bce_vhci_message cmd, res;
-+ cmd.cmd = BCE_VHCI_CMD_PORT_STATUS;
-+ cmd.param1 = port;
-+ cmd.param2 = clearFlags & 0x560000;
-+ status = bce_vhci_command_queue_execute(q, &cmd, &res, BCE_VHCI_CMD_TIMEOUT_SHORT);
-+ if (status >= 0)
-+ *resStatus = (u32) res.param2;
-+ return status;
-+}
-+
-+static inline int bce_vhci_cmd_device_create(struct bce_vhci_command_queue *q, bce_vhci_port_t port,
-+ bce_vhci_device_t *dev)
-+{
-+ int status;
-+ struct bce_vhci_message cmd, res;
-+ cmd.cmd = BCE_VHCI_CMD_DEVICE_CREATE;
-+ cmd.param1 = port;
-+ status = bce_vhci_command_queue_execute(q, &cmd, &res, BCE_VHCI_CMD_TIMEOUT_SHORT);
-+ if (!status)
-+ *dev = (bce_vhci_device_t) res.param2;
-+ return status;
-+}
-+static inline int bce_vhci_cmd_device_destroy(struct bce_vhci_command_queue *q, bce_vhci_device_t dev)
-+{
-+ struct bce_vhci_message cmd, res;
-+ cmd.cmd = BCE_VHCI_CMD_DEVICE_DESTROY;
-+ cmd.param1 = dev;
-+ return bce_vhci_command_queue_execute(q, &cmd, &res, BCE_VHCI_CMD_TIMEOUT_LONG);
-+}
-+
-+static inline int bce_vhci_cmd_endpoint_create(struct bce_vhci_command_queue *q, bce_vhci_device_t dev,
-+ struct usb_endpoint_descriptor *desc)
-+{
-+ struct bce_vhci_message cmd, res;
-+ int endpoint_type = usb_endpoint_type(desc);
-+ int maxp = usb_endpoint_maxp(desc);
-+ int maxp_burst = usb_endpoint_maxp_mult(desc) * maxp;
-+ u8 max_active_requests_pow2 = 0;
-+ cmd.cmd = BCE_VHCI_CMD_ENDPOINT_CREATE;
-+ cmd.param1 = dev | ((desc->bEndpointAddress & 0x8Fu) << 8);
-+ if (endpoint_type == USB_ENDPOINT_XFER_BULK)
-+ max_active_requests_pow2 = BCE_VHCI_BULK_MAX_ACTIVE_URBS_POW2;
-+ cmd.param2 = endpoint_type | ((max_active_requests_pow2 & 0xf) << 4) | (maxp << 16) | ((u64) maxp_burst << 32);
-+ if (endpoint_type == USB_ENDPOINT_XFER_INT)
-+ cmd.param2 |= (desc->bInterval - 1) << 8;
-+ return bce_vhci_command_queue_execute(q, &cmd, &res, BCE_VHCI_CMD_TIMEOUT_SHORT);
-+}
-+static inline int bce_vhci_cmd_endpoint_destroy(struct bce_vhci_command_queue *q, bce_vhci_device_t dev, u8 endpoint)
-+{
-+ struct bce_vhci_message cmd, res;
-+ cmd.cmd = BCE_VHCI_CMD_ENDPOINT_DESTROY;
-+ cmd.param1 = dev | (endpoint << 8);
-+ return bce_vhci_command_queue_execute(q, &cmd, &res, BCE_VHCI_CMD_TIMEOUT_SHORT);
-+}
-+static inline int bce_vhci_cmd_endpoint_set_state(struct bce_vhci_command_queue *q, bce_vhci_device_t dev, u8 endpoint,
-+ enum bce_vhci_endpoint_state newState, enum bce_vhci_endpoint_state *retState)
-+{
-+ int status;
-+ struct bce_vhci_message cmd, res;
-+ cmd.cmd = BCE_VHCI_CMD_ENDPOINT_SET_STATE;
-+ cmd.param1 = dev | (endpoint << 8);
-+ cmd.param2 = (u64) newState;
-+ status = bce_vhci_command_queue_execute(q, &cmd, &res, BCE_VHCI_CMD_TIMEOUT_SHORT);
-+ if (status != BCE_VHCI_INTERNAL_ERROR && status != BCE_VHCI_NO_POWER)
-+ *retState = (enum bce_vhci_endpoint_state) res.param2;
-+ return status;
-+}
-+static inline int bce_vhci_cmd_endpoint_reset(struct bce_vhci_command_queue *q, bce_vhci_device_t dev, u8 endpoint)
-+{
-+ struct bce_vhci_message cmd, res;
-+ cmd.cmd = BCE_VHCI_CMD_ENDPOINT_RESET;
-+ cmd.param1 = dev | (endpoint << 8);
-+ return bce_vhci_command_queue_execute(q, &cmd, &res, BCE_VHCI_CMD_TIMEOUT_SHORT);
-+}
-+
-+
-+#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 000000000000..7b0b5027157b
---- /dev/null
-+++ b/drivers/staging/apple-bce/vhci/queue.c
-@@ -0,0 +1,268 @@
-+#include "queue.h"
-+#include "vhci.h"
-+#include "../apple_bce.h"
-+
-+
-+static void bce_vhci_message_queue_completion(struct bce_queue_sq *sq);
-+
-+int bce_vhci_message_queue_create(struct bce_vhci *vhci, struct bce_vhci_message_queue *ret, const char *name)
-+{
-+ int status;
-+ ret->cq = bce_create_cq(vhci->dev, VHCI_EVENT_QUEUE_EL_COUNT);
-+ if (!ret->cq)
-+ return -EINVAL;
-+ ret->sq = bce_create_sq(vhci->dev, ret->cq, name, VHCI_EVENT_QUEUE_EL_COUNT, DMA_TO_DEVICE,
-+ bce_vhci_message_queue_completion, ret);
-+ if (!ret->sq) {
-+ status = -EINVAL;
-+ goto fail_cq;
-+ }
-+ ret->data = dma_alloc_coherent(&vhci->dev->pci->dev, sizeof(struct bce_vhci_message) * VHCI_EVENT_QUEUE_EL_COUNT,
-+ &ret->dma_addr, GFP_KERNEL);
-+ if (!ret->data) {
-+ status = -EINVAL;
-+ goto fail_sq;
-+ }
-+ return 0;
-+
-+fail_sq:
-+ bce_destroy_sq(vhci->dev, ret->sq);
-+ ret->sq = NULL;
-+fail_cq:
-+ bce_destroy_cq(vhci->dev, ret->cq);
-+ ret->cq = NULL;
-+ return status;
-+}
-+
-+void bce_vhci_message_queue_destroy(struct bce_vhci *vhci, struct bce_vhci_message_queue *q)
-+{
-+ if (!q->cq)
-+ return;
-+ dma_free_coherent(&vhci->dev->pci->dev, sizeof(struct bce_vhci_message) * VHCI_EVENT_QUEUE_EL_COUNT,
-+ q->data, q->dma_addr);
-+ bce_destroy_sq(vhci->dev, q->sq);
-+ bce_destroy_cq(vhci->dev, q->cq);
-+}
-+
-+void bce_vhci_message_queue_write(struct bce_vhci_message_queue *q, struct bce_vhci_message *req)
-+{
-+ int sidx;
-+ struct bce_qe_submission *s;
-+ sidx = q->sq->tail;
-+ s = bce_next_submission(q->sq);
-+ pr_debug("bce-vhci: Send message: %x s=%x p1=%x p2=%llx\n", req->cmd, req->status, req->param1, req->param2);
-+ q->data[sidx] = *req;
-+ bce_set_submission_single(s, q->dma_addr + sizeof(struct bce_vhci_message) * sidx,
-+ sizeof(struct bce_vhci_message));
-+ bce_submit_to_device(q->sq);
-+}
-+
-+static void bce_vhci_message_queue_completion(struct bce_queue_sq *sq)
-+{
-+ while (bce_next_completion(sq))
-+ bce_notify_submission_complete(sq);
-+}
-+
-+
-+
-+static void bce_vhci_event_queue_completion(struct bce_queue_sq *sq);
-+
-+int __bce_vhci_event_queue_create(struct bce_vhci *vhci, struct bce_vhci_event_queue *ret, const char *name,
-+ bce_sq_completion compl)
-+{
-+ ret->vhci = vhci;
-+
-+ ret->sq = bce_create_sq(vhci->dev, vhci->ev_cq, name, VHCI_EVENT_QUEUE_EL_COUNT, DMA_FROM_DEVICE, compl, ret);
-+ if (!ret->sq)
-+ return -EINVAL;
-+ ret->data = dma_alloc_coherent(&vhci->dev->pci->dev, sizeof(struct bce_vhci_message) * VHCI_EVENT_QUEUE_EL_COUNT,
-+ &ret->dma_addr, GFP_KERNEL);
-+ if (!ret->data) {
-+ bce_destroy_sq(vhci->dev, ret->sq);
-+ ret->sq = NULL;
-+ return -EINVAL;
-+ }
-+
-+ init_completion(&ret->queue_empty_completion);
-+ bce_vhci_event_queue_submit_pending(ret, VHCI_EVENT_PENDING_COUNT);
-+ return 0;
-+}
-+
-+int bce_vhci_event_queue_create(struct bce_vhci *vhci, struct bce_vhci_event_queue *ret, const char *name,
-+ bce_vhci_event_queue_callback cb)
-+{
-+ ret->cb = cb;
-+ return __bce_vhci_event_queue_create(vhci, ret, name, bce_vhci_event_queue_completion);
-+}
-+
-+void bce_vhci_event_queue_destroy(struct bce_vhci *vhci, struct bce_vhci_event_queue *q)
-+{
-+ if (!q->sq)
-+ return;
-+ dma_free_coherent(&vhci->dev->pci->dev, sizeof(struct bce_vhci_message) * VHCI_EVENT_QUEUE_EL_COUNT,
-+ q->data, q->dma_addr);
-+ bce_destroy_sq(vhci->dev, q->sq);
-+}
-+
-+static void bce_vhci_event_queue_completion(struct bce_queue_sq *sq)
-+{
-+ struct bce_sq_completion_data *cd;
-+ struct bce_vhci_event_queue *ev = sq->userdata;
-+ struct bce_vhci_message *msg;
-+ size_t cnt = 0;
-+
-+ while ((cd = bce_next_completion(sq))) {
-+ if (cd->status == BCE_COMPLETION_ABORTED) { /* We flushed the queue */
-+ bce_notify_submission_complete(sq);
-+ continue;
-+ }
-+ msg = &ev->data[sq->head];
-+ pr_debug("bce-vhci: Got event: %x s=%x p1=%x p2=%llx\n", msg->cmd, msg->status, msg->param1, msg->param2);
-+ ev->cb(ev, msg);
-+
-+ bce_notify_submission_complete(sq);
-+ ++cnt;
-+ }
-+ bce_vhci_event_queue_submit_pending(ev, cnt);
-+ if (atomic_read(&sq->available_commands) == sq->el_count - 1)
-+ complete(&ev->queue_empty_completion);
-+}
-+
-+void bce_vhci_event_queue_submit_pending(struct bce_vhci_event_queue *q, size_t count)
-+{
-+ int idx;
-+ struct bce_qe_submission *s;
-+ while (count--) {
-+ if (bce_reserve_submission(q->sq, NULL)) {
-+ pr_err("bce-vhci: Failed to reserve an event queue submission\n");
-+ break;
-+ }
-+ idx = q->sq->tail;
-+ s = bce_next_submission(q->sq);
-+ bce_set_submission_single(s,
-+ q->dma_addr + idx * sizeof(struct bce_vhci_message), sizeof(struct bce_vhci_message));
-+ }
-+ bce_submit_to_device(q->sq);
-+}
-+
-+void bce_vhci_event_queue_pause(struct bce_vhci_event_queue *q)
-+{
-+ unsigned long timeout;
-+ reinit_completion(&q->queue_empty_completion);
-+ if (bce_cmd_flush_memory_queue(q->vhci->dev->cmd_cmdq, q->sq->qid))
-+ pr_warn("bce-vhci: failed to flush event queue\n");
-+ timeout = msecs_to_jiffies(5000);
-+ while (atomic_read(&q->sq->available_commands) != q->sq->el_count - 1) {
-+ timeout = wait_for_completion_timeout(&q->queue_empty_completion, timeout);
-+ if (timeout == 0) {
-+ pr_err("bce-vhci: waiting for queue to be flushed timed out\n");
-+ break;
-+ }
-+ }
-+}
-+
-+void bce_vhci_event_queue_resume(struct bce_vhci_event_queue *q)
-+{
-+ if (atomic_read(&q->sq->available_commands) != q->sq->el_count - 1) {
-+ pr_err("bce-vhci: resume of a queue with pending submissions\n");
-+ return;
-+ }
-+ bce_vhci_event_queue_submit_pending(q, VHCI_EVENT_PENDING_COUNT);
-+}
-+
-+void bce_vhci_command_queue_create(struct bce_vhci_command_queue *ret, struct bce_vhci_message_queue *mq)
-+{
-+ ret->mq = mq;
-+ ret->completion.result = NULL;
-+ init_completion(&ret->completion.completion);
-+ spin_lock_init(&ret->completion_lock);
-+ mutex_init(&ret->mutex);
-+}
-+
-+void bce_vhci_command_queue_destroy(struct bce_vhci_command_queue *cq)
-+{
-+ spin_lock(&cq->completion_lock);
-+ if (cq->completion.result) {
-+ memset(cq->completion.result, 0, sizeof(struct bce_vhci_message));
-+ cq->completion.result->status = BCE_VHCI_ABORT;
-+ complete(&cq->completion.completion);
-+ cq->completion.result = NULL;
-+ }
-+ spin_unlock(&cq->completion_lock);
-+ mutex_lock(&cq->mutex);
-+ mutex_unlock(&cq->mutex);
-+ mutex_destroy(&cq->mutex);
-+}
-+
-+void bce_vhci_command_queue_deliver_completion(struct bce_vhci_command_queue *cq, struct bce_vhci_message *msg)
-+{
-+ struct bce_vhci_command_queue_completion *c = &cq->completion;
-+
-+ spin_lock(&cq->completion_lock);
-+ if (c->result) {
-+ *c->result = *msg;
-+ complete(&c->completion);
-+ c->result = NULL;
-+ }
-+ spin_unlock(&cq->completion_lock);
-+}
-+
-+static int __bce_vhci_command_queue_execute(struct bce_vhci_command_queue *cq, struct bce_vhci_message *req,
-+ struct bce_vhci_message *res, unsigned long timeout)
-+{
-+ int status;
-+ struct bce_vhci_command_queue_completion *c;
-+ struct bce_vhci_message creq;
-+ c = &cq->completion;
-+
-+ if ((status = bce_reserve_submission(cq->mq->sq, &timeout)))
-+ return status;
-+
-+ spin_lock(&cq->completion_lock);
-+ c->result = res;
-+ reinit_completion(&c->completion);
-+ spin_unlock(&cq->completion_lock);
-+
-+ bce_vhci_message_queue_write(cq->mq, req);
-+
-+ if (!wait_for_completion_timeout(&c->completion, timeout)) {
-+ /* we ran out of time, send cancellation */
-+ pr_debug("bce-vhci: command timed out req=%x\n", req->cmd);
-+ if ((status = bce_reserve_submission(cq->mq->sq, &timeout)))
-+ return status;
-+
-+ creq = *req;
-+ creq.cmd |= 0x4000;
-+ bce_vhci_message_queue_write(cq->mq, &creq);
-+
-+ if (!wait_for_completion_timeout(&c->completion, 1000)) {
-+ pr_err("bce-vhci: Possible desync, cmd cancel timed out\n");
-+
-+ spin_lock(&cq->completion_lock);
-+ c->result = NULL;
-+ spin_unlock(&cq->completion_lock);
-+ return -ETIMEDOUT;
-+ }
-+ if ((res->cmd & ~0x8000) == creq.cmd)
-+ return -ETIMEDOUT;
-+ /* reply for the previous command most likely arrived */
-+ }
-+
-+ if ((res->cmd & ~0x8000) != req->cmd) {
-+ pr_err("bce-vhci: Possible desync, cmd reply mismatch req=%x, res=%x\n", req->cmd, res->cmd);
-+ return -EIO;
-+ }
-+ if (res->status == BCE_VHCI_SUCCESS)
-+ return 0;
-+ return res->status;
-+}
-+
-+int bce_vhci_command_queue_execute(struct bce_vhci_command_queue *cq, struct bce_vhci_message *req,
-+ struct bce_vhci_message *res, unsigned long timeout)
-+{
-+ int status;
-+ mutex_lock(&cq->mutex);
-+ status = __bce_vhci_command_queue_execute(cq, req, res, timeout);
-+ mutex_unlock(&cq->mutex);
-+ return status;
-+}
-diff --git a/drivers/staging/apple-bce/vhci/queue.h b/drivers/staging/apple-bce/vhci/queue.h
-new file mode 100644
-index 000000000000..adb705b6ba1d
---- /dev/null
-+++ b/drivers/staging/apple-bce/vhci/queue.h
-@@ -0,0 +1,76 @@
-+#ifndef BCE_VHCI_QUEUE_H
-+#define BCE_VHCI_QUEUE_H
-+
-+#include <linux/completion.h>
-+#include "../queue.h"
-+
-+#define VHCI_EVENT_QUEUE_EL_COUNT 256
-+#define VHCI_EVENT_PENDING_COUNT 32
-+
-+struct bce_vhci;
-+struct bce_vhci_event_queue;
-+
-+enum bce_vhci_message_status {
-+ BCE_VHCI_SUCCESS = 1,
-+ BCE_VHCI_ERROR = 2,
-+ BCE_VHCI_USB_PIPE_STALL = 3,
-+ BCE_VHCI_ABORT = 4,
-+ BCE_VHCI_BAD_ARGUMENT = 5,
-+ BCE_VHCI_OVERRUN = 6,
-+ BCE_VHCI_INTERNAL_ERROR = 7,
-+ BCE_VHCI_NO_POWER = 8,
-+ BCE_VHCI_UNSUPPORTED = 9
-+};
-+struct bce_vhci_message {
-+ u16 cmd;
-+ u16 status; // bce_vhci_message_status
-+ u32 param1;
-+ u64 param2;
-+};
-+
-+struct bce_vhci_message_queue {
-+ struct bce_queue_cq *cq;
-+ struct bce_queue_sq *sq;
-+ struct bce_vhci_message *data;
-+ dma_addr_t dma_addr;
-+};
-+typedef void (*bce_vhci_event_queue_callback)(struct bce_vhci_event_queue *q, struct bce_vhci_message *msg);
-+struct bce_vhci_event_queue {
-+ struct bce_vhci *vhci;
-+ struct bce_queue_sq *sq;
-+ struct bce_vhci_message *data;
-+ dma_addr_t dma_addr;
-+ bce_vhci_event_queue_callback cb;
-+ struct completion queue_empty_completion;
-+};
-+struct bce_vhci_command_queue_completion {
-+ struct bce_vhci_message *result;
-+ struct completion completion;
-+};
-+struct bce_vhci_command_queue {
-+ struct bce_vhci_message_queue *mq;
-+ struct bce_vhci_command_queue_completion completion;
-+ struct spinlock completion_lock;
-+ struct mutex mutex;
-+};
-+
-+int bce_vhci_message_queue_create(struct bce_vhci *vhci, struct bce_vhci_message_queue *ret, const char *name);
-+void bce_vhci_message_queue_destroy(struct bce_vhci *vhci, struct bce_vhci_message_queue *q);
-+void bce_vhci_message_queue_write(struct bce_vhci_message_queue *q, struct bce_vhci_message *req);
-+
-+int __bce_vhci_event_queue_create(struct bce_vhci *vhci, struct bce_vhci_event_queue *ret, const char *name,
-+ bce_sq_completion compl);
-+int bce_vhci_event_queue_create(struct bce_vhci *vhci, struct bce_vhci_event_queue *ret, const char *name,
-+ bce_vhci_event_queue_callback cb);
-+void bce_vhci_event_queue_destroy(struct bce_vhci *vhci, struct bce_vhci_event_queue *q);
-+void bce_vhci_event_queue_submit_pending(struct bce_vhci_event_queue *q, size_t count);
-+void bce_vhci_event_queue_pause(struct bce_vhci_event_queue *q);
-+void bce_vhci_event_queue_resume(struct bce_vhci_event_queue *q);
-+
-+void bce_vhci_command_queue_create(struct bce_vhci_command_queue *ret, struct bce_vhci_message_queue *mq);
-+void bce_vhci_command_queue_destroy(struct bce_vhci_command_queue *cq);
-+int bce_vhci_command_queue_execute(struct bce_vhci_command_queue *cq, struct bce_vhci_message *req,
-+ struct bce_vhci_message *res, unsigned long timeout);
-+void bce_vhci_command_queue_deliver_completion(struct bce_vhci_command_queue *cq, struct bce_vhci_message *msg);
-+
-+#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 000000000000..8226363d69c8
---- /dev/null
-+++ b/drivers/staging/apple-bce/vhci/transfer.c
-@@ -0,0 +1,661 @@
-+#include "transfer.h"
-+#include "../queue.h"
-+#include "vhci.h"
-+#include "../apple_bce.h"
-+#include <linux/usb/hcd.h>
-+
-+static void bce_vhci_transfer_queue_completion(struct bce_queue_sq *sq);
-+static void bce_vhci_transfer_queue_giveback(struct bce_vhci_transfer_queue *q);
-+static void bce_vhci_transfer_queue_remove_pending(struct bce_vhci_transfer_queue *q);
-+
-+static int bce_vhci_urb_init(struct bce_vhci_urb *vurb);
-+static int bce_vhci_urb_update(struct bce_vhci_urb *urb, struct bce_vhci_message *msg);
-+static int bce_vhci_urb_transfer_completion(struct bce_vhci_urb *urb, struct bce_sq_completion_data *c);
-+
-+static void bce_vhci_transfer_queue_reset_w(struct work_struct *work);
-+
-+void bce_vhci_create_transfer_queue(struct bce_vhci *vhci, struct bce_vhci_transfer_queue *q,
-+ struct usb_host_endpoint *endp, bce_vhci_device_t dev_addr, enum dma_data_direction dir)
-+{
-+ char name[0x21];
-+ INIT_LIST_HEAD(&q->evq);
-+ INIT_LIST_HEAD(&q->giveback_urb_list);
-+ spin_lock_init(&q->urb_lock);
-+ mutex_init(&q->pause_lock);
-+ q->vhci = vhci;
-+ q->endp = endp;
-+ q->dev_addr = dev_addr;
-+ q->endp_addr = (u8) (endp->desc.bEndpointAddress & 0x8F);
-+ q->state = BCE_VHCI_ENDPOINT_ACTIVE;
-+ q->active = true;
-+ q->stalled = false;
-+ q->max_active_requests = 1;
-+ if (usb_endpoint_type(&endp->desc) == USB_ENDPOINT_XFER_BULK)
-+ q->max_active_requests = BCE_VHCI_BULK_MAX_ACTIVE_URBS;
-+ q->remaining_active_requests = q->max_active_requests;
-+ q->cq = bce_create_cq(vhci->dev, 0x100);
-+ INIT_WORK(&q->w_reset, bce_vhci_transfer_queue_reset_w);
-+ q->sq_in = NULL;
-+ if (dir == DMA_FROM_DEVICE || dir == DMA_BIDIRECTIONAL) {
-+ snprintf(name, sizeof(name), "VHC1-%i-%02x", dev_addr, 0x80 | usb_endpoint_num(&endp->desc));
-+ q->sq_in = bce_create_sq(vhci->dev, q->cq, name, 0x100, DMA_FROM_DEVICE,
-+ bce_vhci_transfer_queue_completion, q);
-+ }
-+ q->sq_out = NULL;
-+ if (dir == DMA_TO_DEVICE || dir == DMA_BIDIRECTIONAL) {
-+ snprintf(name, sizeof(name), "VHC1-%i-%02x", dev_addr, usb_endpoint_num(&endp->desc));
-+ q->sq_out = bce_create_sq(vhci->dev, q->cq, name, 0x100, DMA_TO_DEVICE,
-+ bce_vhci_transfer_queue_completion, q);
-+ }
-+}
-+
-+void bce_vhci_destroy_transfer_queue(struct bce_vhci *vhci, struct bce_vhci_transfer_queue *q)
-+{
-+ bce_vhci_transfer_queue_giveback(q);
-+ bce_vhci_transfer_queue_remove_pending(q);
-+ if (q->sq_in)
-+ bce_destroy_sq(vhci->dev, q->sq_in);
-+ if (q->sq_out)
-+ bce_destroy_sq(vhci->dev, q->sq_out);
-+ bce_destroy_cq(vhci->dev, q->cq);
-+}
-+
-+static inline bool bce_vhci_transfer_queue_can_init_urb(struct bce_vhci_transfer_queue *q)
-+{
-+ return q->remaining_active_requests > 0;
-+}
-+
-+static void bce_vhci_transfer_queue_defer_event(struct bce_vhci_transfer_queue *q, struct bce_vhci_message *msg)
-+{
-+ struct bce_vhci_list_message *lm;
-+ lm = kmalloc(sizeof(struct bce_vhci_list_message), GFP_KERNEL);
-+ INIT_LIST_HEAD(&lm->list);
-+ lm->msg = *msg;
-+ list_add_tail(&lm->list, &q->evq);
-+}
-+
-+static void bce_vhci_transfer_queue_giveback(struct bce_vhci_transfer_queue *q)
-+{
-+ unsigned long flags;
-+ struct urb *urb;
-+ spin_lock_irqsave(&q->urb_lock, flags);
-+ while (!list_empty(&q->giveback_urb_list)) {
-+ urb = list_first_entry(&q->giveback_urb_list, struct urb, urb_list);
-+ list_del(&urb->urb_list);
-+
-+ spin_unlock_irqrestore(&q->urb_lock, flags);
-+ usb_hcd_giveback_urb(q->vhci->hcd, urb, urb->status);
-+ spin_lock_irqsave(&q->urb_lock, flags);
-+ }
-+ spin_unlock_irqrestore(&q->urb_lock, flags);
-+}
-+
-+static void bce_vhci_transfer_queue_init_pending_urbs(struct bce_vhci_transfer_queue *q);
-+
-+static void bce_vhci_transfer_queue_deliver_pending(struct bce_vhci_transfer_queue *q)
-+{
-+ struct urb *urb;
-+ struct bce_vhci_list_message *lm;
-+
-+ while (!list_empty(&q->endp->urb_list) && !list_empty(&q->evq)) {
-+ urb = list_first_entry(&q->endp->urb_list, struct urb, urb_list);
-+
-+ lm = list_first_entry(&q->evq, struct bce_vhci_list_message, list);
-+ if (bce_vhci_urb_update(urb->hcpriv, &lm->msg) == -EAGAIN)
-+ break;
-+ list_del(&lm->list);
-+ kfree(lm);
-+ }
-+
-+ /* some of the URBs could have been completed, so initialize more URBs if possible */
-+ bce_vhci_transfer_queue_init_pending_urbs(q);
-+}
-+
-+static void bce_vhci_transfer_queue_remove_pending(struct bce_vhci_transfer_queue *q)
-+{
-+ unsigned long flags;
-+ struct bce_vhci_list_message *lm;
-+ spin_lock_irqsave(&q->urb_lock, flags);
-+ while (!list_empty(&q->evq)) {
-+ lm = list_first_entry(&q->evq, struct bce_vhci_list_message, list);
-+ list_del(&lm->list);
-+ kfree(lm);
-+ }
-+ spin_unlock_irqrestore(&q->urb_lock, flags);
-+}
-+
-+void bce_vhci_transfer_queue_event(struct bce_vhci_transfer_queue *q, struct bce_vhci_message *msg)
-+{
-+ unsigned long flags;
-+ struct bce_vhci_urb *turb;
-+ struct urb *urb;
-+ spin_lock_irqsave(&q->urb_lock, flags);
-+ bce_vhci_transfer_queue_deliver_pending(q);
-+
-+ if (msg->cmd == BCE_VHCI_CMD_TRANSFER_REQUEST &&
-+ (!list_empty(&q->evq) || list_empty(&q->endp->urb_list))) {
-+ bce_vhci_transfer_queue_defer_event(q, msg);
-+ goto complete;
-+ }
-+ if (list_empty(&q->endp->urb_list)) {
-+ pr_err("bce-vhci: [%02x] Unexpected transfer queue event\n", q->endp_addr);
-+ goto complete;
-+ }
-+ urb = list_first_entry(&q->endp->urb_list, struct urb, urb_list);
-+ turb = urb->hcpriv;
-+ if (bce_vhci_urb_update(turb, msg) == -EAGAIN) {
-+ bce_vhci_transfer_queue_defer_event(q, msg);
-+ } else {
-+ bce_vhci_transfer_queue_init_pending_urbs(q);
-+ }
-+
-+complete:
-+ spin_unlock_irqrestore(&q->urb_lock, flags);
-+ bce_vhci_transfer_queue_giveback(q);
-+}
-+
-+static void bce_vhci_transfer_queue_completion(struct bce_queue_sq *sq)
-+{
-+ unsigned long flags;
-+ struct bce_sq_completion_data *c;
-+ struct urb *urb;
-+ struct bce_vhci_transfer_queue *q = sq->userdata;
-+ spin_lock_irqsave(&q->urb_lock, flags);
-+ while ((c = bce_next_completion(sq))) {
-+ if (c->status == BCE_COMPLETION_ABORTED) { /* We flushed the queue */
-+ pr_debug("bce-vhci: [%02x] Got an abort completion\n", q->endp_addr);
-+ bce_notify_submission_complete(sq);
-+ continue;
-+ }
-+ if (list_empty(&q->endp->urb_list)) {
-+ pr_err("bce-vhci: [%02x] Got a completion while no requests are pending\n", q->endp_addr);
-+ continue;
-+ }
-+ pr_debug("bce-vhci: [%02x] Got a transfer queue completion\n", q->endp_addr);
-+ urb = list_first_entry(&q->endp->urb_list, struct urb, urb_list);
-+ bce_vhci_urb_transfer_completion(urb->hcpriv, c);
-+ bce_notify_submission_complete(sq);
-+ }
-+ bce_vhci_transfer_queue_deliver_pending(q);
-+ spin_unlock_irqrestore(&q->urb_lock, flags);
-+ bce_vhci_transfer_queue_giveback(q);
-+}
-+
-+int bce_vhci_transfer_queue_do_pause(struct bce_vhci_transfer_queue *q)
-+{
-+ unsigned long flags;
-+ int status;
-+ u8 endp_addr = (u8) (q->endp->desc.bEndpointAddress & 0x8F);
-+ spin_lock_irqsave(&q->urb_lock, flags);
-+ q->active = false;
-+ spin_unlock_irqrestore(&q->urb_lock, flags);
-+ if (q->sq_out) {
-+ pr_err("bce-vhci: Not implemented: wait for pending output requests\n");
-+ }
-+ bce_vhci_transfer_queue_remove_pending(q);
-+ if ((status = bce_vhci_cmd_endpoint_set_state(
-+ &q->vhci->cq, q->dev_addr, endp_addr, BCE_VHCI_ENDPOINT_PAUSED, &q->state)))
-+ return status;
-+ if (q->state != BCE_VHCI_ENDPOINT_PAUSED)
-+ return -EINVAL;
-+ if (q->sq_in)
-+ bce_cmd_flush_memory_queue(q->vhci->dev->cmd_cmdq, (u16) q->sq_in->qid);
-+ if (q->sq_out)
-+ bce_cmd_flush_memory_queue(q->vhci->dev->cmd_cmdq, (u16) q->sq_out->qid);
-+ return 0;
-+}
-+
-+static void bce_vhci_urb_resume(struct bce_vhci_urb *urb);
-+
-+int bce_vhci_transfer_queue_do_resume(struct bce_vhci_transfer_queue *q)
-+{
-+ unsigned long flags;
-+ int status;
-+ struct urb *urb, *urbt;
-+ struct bce_vhci_urb *vurb;
-+ u8 endp_addr = (u8) (q->endp->desc.bEndpointAddress & 0x8F);
-+ if ((status = bce_vhci_cmd_endpoint_set_state(
-+ &q->vhci->cq, q->dev_addr, endp_addr, BCE_VHCI_ENDPOINT_ACTIVE, &q->state)))
-+ return status;
-+ if (q->state != BCE_VHCI_ENDPOINT_ACTIVE)
-+ return -EINVAL;
-+ spin_lock_irqsave(&q->urb_lock, flags);
-+ q->active = true;
-+ list_for_each_entry_safe(urb, urbt, &q->endp->urb_list, urb_list) {
-+ vurb = urb->hcpriv;
-+ if (vurb->state == BCE_VHCI_URB_INIT_PENDING) {
-+ if (!bce_vhci_transfer_queue_can_init_urb(q))
-+ break;
-+ bce_vhci_urb_init(vurb);
-+ } else {
-+ bce_vhci_urb_resume(vurb);
-+ }
-+ }
-+ bce_vhci_transfer_queue_deliver_pending(q);
-+ spin_unlock_irqrestore(&q->urb_lock, flags);
-+ return 0;
-+}
-+
-+int bce_vhci_transfer_queue_pause(struct bce_vhci_transfer_queue *q, enum bce_vhci_pause_source src)
-+{
-+ int ret = 0;
-+ mutex_lock(&q->pause_lock);
-+ if ((q->paused_by & src) != src) {
-+ if (!q->paused_by)
-+ ret = bce_vhci_transfer_queue_do_pause(q);
-+ if (!ret)
-+ q->paused_by |= src;
-+ }
-+ mutex_unlock(&q->pause_lock);
-+ return ret;
-+}
-+
-+int bce_vhci_transfer_queue_resume(struct bce_vhci_transfer_queue *q, enum bce_vhci_pause_source src)
-+{
-+ int ret = 0;
-+ mutex_lock(&q->pause_lock);
-+ if (q->paused_by & src) {
-+ if (!(q->paused_by & ~src))
-+ ret = bce_vhci_transfer_queue_do_resume(q);
-+ if (!ret)
-+ q->paused_by &= ~src;
-+ }
-+ mutex_unlock(&q->pause_lock);
-+ return ret;
-+}
-+
-+static void bce_vhci_transfer_queue_reset_w(struct work_struct *work)
-+{
-+ unsigned long flags;
-+ struct bce_vhci_transfer_queue *q = container_of(work, struct bce_vhci_transfer_queue, w_reset);
-+
-+ mutex_lock(&q->pause_lock);
-+ spin_lock_irqsave(&q->urb_lock, flags);
-+ if (!q->stalled) {
-+ spin_unlock_irqrestore(&q->urb_lock, flags);
-+ mutex_unlock(&q->pause_lock);
-+ return;
-+ }
-+ q->active = false;
-+ spin_unlock_irqrestore(&q->urb_lock, flags);
-+ q->paused_by |= BCE_VHCI_PAUSE_INTERNAL_WQ;
-+ bce_vhci_transfer_queue_remove_pending(q);
-+ if (q->sq_in)
-+ bce_cmd_flush_memory_queue(q->vhci->dev->cmd_cmdq, (u16) q->sq_in->qid);
-+ if (q->sq_out)
-+ bce_cmd_flush_memory_queue(q->vhci->dev->cmd_cmdq, (u16) q->sq_out->qid);
-+ bce_vhci_cmd_endpoint_reset(&q->vhci->cq, q->dev_addr, (u8) (q->endp->desc.bEndpointAddress & 0x8F));
-+ spin_lock_irqsave(&q->urb_lock, flags);
-+ q->stalled = false;
-+ spin_unlock_irqrestore(&q->urb_lock, flags);
-+ mutex_unlock(&q->pause_lock);
-+ bce_vhci_transfer_queue_resume(q, BCE_VHCI_PAUSE_INTERNAL_WQ);
-+}
-+
-+void bce_vhci_transfer_queue_request_reset(struct bce_vhci_transfer_queue *q)
-+{
-+ queue_work(q->vhci->tq_state_wq, &q->w_reset);
-+}
-+
-+static void bce_vhci_transfer_queue_init_pending_urbs(struct bce_vhci_transfer_queue *q)
-+{
-+ struct urb *urb, *urbt;
-+ struct bce_vhci_urb *vurb;
-+ list_for_each_entry_safe(urb, urbt, &q->endp->urb_list, urb_list) {
-+ vurb = urb->hcpriv;
-+ if (!bce_vhci_transfer_queue_can_init_urb(q))
-+ break;
-+ if (vurb->state == BCE_VHCI_URB_INIT_PENDING)
-+ bce_vhci_urb_init(vurb);
-+ }
-+}
-+
-+
-+
-+static int bce_vhci_urb_data_start(struct bce_vhci_urb *urb, unsigned long *timeout);
-+
-+int bce_vhci_urb_create(struct bce_vhci_transfer_queue *q, struct urb *urb)
-+{
-+ unsigned long flags;
-+ int status = 0;
-+ struct bce_vhci_urb *vurb;
-+ vurb = kzalloc(sizeof(struct bce_vhci_urb), GFP_KERNEL);
-+ urb->hcpriv = vurb;
-+
-+ vurb->q = q;
-+ vurb->urb = urb;
-+ vurb->dir = usb_urb_dir_in(urb) ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
-+ vurb->is_control = (usb_endpoint_num(&urb->ep->desc) == 0);
-+
-+ spin_lock_irqsave(&q->urb_lock, flags);
-+ status = usb_hcd_link_urb_to_ep(q->vhci->hcd, urb);
-+ if (status) {
-+ spin_unlock_irqrestore(&q->urb_lock, flags);
-+ urb->hcpriv = NULL;
-+ kfree(vurb);
-+ return status;
-+ }
-+
-+ if (q->active) {
-+ if (bce_vhci_transfer_queue_can_init_urb(vurb->q))
-+ status = bce_vhci_urb_init(vurb);
-+ else
-+ vurb->state = BCE_VHCI_URB_INIT_PENDING;
-+ } else {
-+ if (q->stalled)
-+ bce_vhci_transfer_queue_request_reset(q);
-+ vurb->state = BCE_VHCI_URB_INIT_PENDING;
-+ }
-+ if (status) {
-+ usb_hcd_unlink_urb_from_ep(q->vhci->hcd, urb);
-+ urb->hcpriv = NULL;
-+ kfree(vurb);
-+ } else {
-+ bce_vhci_transfer_queue_deliver_pending(q);
-+ }
-+ spin_unlock_irqrestore(&q->urb_lock, flags);
-+ pr_debug("bce-vhci: [%02x] URB enqueued (dir = %s, size = %i)\n", q->endp_addr,
-+ usb_urb_dir_in(urb) ? "IN" : "OUT", urb->transfer_buffer_length);
-+ return status;
-+}
-+
-+static int bce_vhci_urb_init(struct bce_vhci_urb *vurb)
-+{
-+ int status = 0;
-+
-+ if (vurb->q->remaining_active_requests == 0) {
-+ pr_err("bce-vhci: cannot init request (remaining_active_requests = 0)\n");
-+ return -EINVAL;
-+ }
-+
-+ if (vurb->is_control) {
-+ vurb->state = BCE_VHCI_URB_CONTROL_WAITING_FOR_SETUP_REQUEST;
-+ } else {
-+ status = bce_vhci_urb_data_start(vurb, NULL);
-+ }
-+
-+ if (!status) {
-+ --vurb->q->remaining_active_requests;
-+ }
-+ return status;
-+}
-+
-+static void bce_vhci_urb_complete(struct bce_vhci_urb *urb, int status)
-+{
-+ struct bce_vhci_transfer_queue *q = urb->q;
-+ struct bce_vhci *vhci = q->vhci;
-+ struct urb *real_urb = urb->urb;
-+ pr_debug("bce-vhci: [%02x] URB complete %i\n", q->endp_addr, status);
-+ usb_hcd_unlink_urb_from_ep(vhci->hcd, real_urb);
-+ real_urb->hcpriv = NULL;
-+ real_urb->status = status;
-+ if (urb->state != BCE_VHCI_URB_INIT_PENDING)
-+ ++urb->q->remaining_active_requests;
-+ kfree(urb);
-+ list_add_tail(&real_urb->urb_list, &q->giveback_urb_list);
-+}
-+
-+int bce_vhci_urb_request_cancel(struct bce_vhci_transfer_queue *q, struct urb *urb, int status)
-+{
-+ struct bce_vhci_urb *vurb;
-+ unsigned long flags;
-+ int ret;
-+
-+ spin_lock_irqsave(&q->urb_lock, flags);
-+ if ((ret = usb_hcd_check_unlink_urb(q->vhci->hcd, urb, status))) {
-+ spin_unlock_irqrestore(&q->urb_lock, flags);
-+ return ret;
-+ }
-+
-+ vurb = urb->hcpriv;
-+ /* If the URB wasn't posted to the device yet, we can still remove it on the host without pausing the queue. */
-+ if (vurb->state != BCE_VHCI_URB_INIT_PENDING) {
-+ pr_debug("bce-vhci: [%02x] Cancelling URB\n", q->endp_addr);
-+
-+ spin_unlock_irqrestore(&q->urb_lock, flags);
-+ bce_vhci_transfer_queue_pause(q, BCE_VHCI_PAUSE_INTERNAL_WQ);
-+ spin_lock_irqsave(&q->urb_lock, flags);
-+
-+ ++q->remaining_active_requests;
-+ }
-+
-+ usb_hcd_unlink_urb_from_ep(q->vhci->hcd, urb);
-+
-+ spin_unlock_irqrestore(&q->urb_lock, flags);
-+
-+ usb_hcd_giveback_urb(q->vhci->hcd, urb, status);
-+
-+ if (vurb->state != BCE_VHCI_URB_INIT_PENDING)
-+ bce_vhci_transfer_queue_resume(q, BCE_VHCI_PAUSE_INTERNAL_WQ);
-+
-+ kfree(vurb);
-+
-+ return 0;
-+}
-+
-+static int bce_vhci_urb_data_transfer_in(struct bce_vhci_urb *urb, unsigned long *timeout)
-+{
-+ struct bce_vhci_message msg;
-+ struct bce_qe_submission *s;
-+ u32 tr_len;
-+ int reservation1, reservation2 = -EFAULT;
-+
-+ pr_debug("bce-vhci: [%02x] DMA from device %llx %x\n", urb->q->endp_addr,
-+ (u64) urb->urb->transfer_dma, urb->urb->transfer_buffer_length);
-+
-+ /* Reserve both a message and a submission, so we don't run into issues later. */
-+ reservation1 = bce_reserve_submission(urb->q->vhci->msg_asynchronous.sq, timeout);
-+ if (!reservation1)
-+ reservation2 = bce_reserve_submission(urb->q->sq_in, timeout);
-+ if (reservation1 || reservation2) {
-+ pr_err("bce-vhci: Failed to reserve a submission for URB data transfer\n");
-+ if (!reservation1)
-+ bce_cancel_submission_reservation(urb->q->vhci->msg_asynchronous.sq);
-+ return -ENOMEM;
-+ }
-+
-+ urb->send_offset = urb->receive_offset;
-+
-+ tr_len = urb->urb->transfer_buffer_length - urb->send_offset;
-+
-+ spin_lock(&urb->q->vhci->msg_asynchronous_lock);
-+ msg.cmd = BCE_VHCI_CMD_TRANSFER_REQUEST;
-+ msg.status = 0;
-+ msg.param1 = ((urb->urb->ep->desc.bEndpointAddress & 0x8Fu) << 8) | urb->q->dev_addr;
-+ msg.param2 = tr_len;
-+ bce_vhci_message_queue_write(&urb->q->vhci->msg_asynchronous, &msg);
-+ spin_unlock(&urb->q->vhci->msg_asynchronous_lock);
-+
-+ s = bce_next_submission(urb->q->sq_in);
-+ bce_set_submission_single(s, urb->urb->transfer_dma + urb->send_offset, tr_len);
-+ bce_submit_to_device(urb->q->sq_in);
-+
-+ urb->state = BCE_VHCI_URB_WAITING_FOR_COMPLETION;
-+ return 0;
-+}
-+
-+static int bce_vhci_urb_data_start(struct bce_vhci_urb *urb, unsigned long *timeout)
-+{
-+ if (urb->dir == DMA_TO_DEVICE) {
-+ if (urb->urb->transfer_buffer_length > 0)
-+ urb->state = BCE_VHCI_URB_WAITING_FOR_TRANSFER_REQUEST;
-+ else
-+ urb->state = BCE_VHCI_URB_DATA_TRANSFER_COMPLETE;
-+ return 0;
-+ } else {
-+ return bce_vhci_urb_data_transfer_in(urb, timeout);
-+ }
-+}
-+
-+static int bce_vhci_urb_send_out_data(struct bce_vhci_urb *urb, dma_addr_t addr, size_t size)
-+{
-+ struct bce_qe_submission *s;
-+ unsigned long timeout = 0;
-+ if (bce_reserve_submission(urb->q->sq_out, &timeout)) {
-+ pr_err("bce-vhci: Failed to reserve a submission for URB data transfer\n");
-+ return -EPIPE;
-+ }
-+
-+ pr_debug("bce-vhci: [%02x] DMA to device %llx %lx\n", urb->q->endp_addr, (u64) addr, size);
-+
-+ s = bce_next_submission(urb->q->sq_out);
-+ bce_set_submission_single(s, addr, size);
-+ bce_submit_to_device(urb->q->sq_out);
-+ return 0;
-+}
-+
-+static int bce_vhci_urb_data_update(struct bce_vhci_urb *urb, struct bce_vhci_message *msg)
-+{
-+ u32 tr_len;
-+ int status;
-+ if (urb->state == BCE_VHCI_URB_WAITING_FOR_TRANSFER_REQUEST) {
-+ if (msg->cmd == BCE_VHCI_CMD_TRANSFER_REQUEST) {
-+ tr_len = min(urb->urb->transfer_buffer_length - urb->send_offset, (u32) msg->param2);
-+ if ((status = bce_vhci_urb_send_out_data(urb, urb->urb->transfer_dma + urb->send_offset, tr_len)))
-+ return status;
-+ urb->send_offset += tr_len;
-+ urb->state = BCE_VHCI_URB_WAITING_FOR_COMPLETION;
-+ return 0;
-+ }
-+ }
-+
-+ /* 0x1000 in out queues aren't really unexpected */
-+ if (msg->cmd == BCE_VHCI_CMD_TRANSFER_REQUEST && urb->q->sq_out != NULL)
-+ return -EAGAIN;
-+ pr_err("bce-vhci: [%02x] %s URB unexpected message (state = %x, msg: %x %x %x %llx)\n",
-+ urb->q->endp_addr, (urb->is_control ? "Control (data update)" : "Data"), urb->state,
-+ msg->cmd, msg->status, msg->param1, msg->param2);
-+ return -EAGAIN;
-+}
-+
-+static int bce_vhci_urb_data_transfer_completion(struct bce_vhci_urb *urb, struct bce_sq_completion_data *c)
-+{
-+ if (urb->state == BCE_VHCI_URB_WAITING_FOR_COMPLETION) {
-+ urb->receive_offset += c->data_size;
-+ if (urb->dir == DMA_FROM_DEVICE || urb->receive_offset >= urb->urb->transfer_buffer_length) {
-+ urb->urb->actual_length = (u32) urb->receive_offset;
-+ urb->state = BCE_VHCI_URB_DATA_TRANSFER_COMPLETE;
-+ if (!urb->is_control) {
-+ bce_vhci_urb_complete(urb, 0);
-+ return -ENOENT;
-+ }
-+ }
-+ } else {
-+ pr_err("bce-vhci: [%02x] Data URB unexpected completion\n", urb->q->endp_addr);
-+ }
-+ return 0;
-+}
-+
-+
-+static int bce_vhci_urb_control_check_status(struct bce_vhci_urb *urb)
-+{
-+ struct bce_vhci_transfer_queue *q = urb->q;
-+ if (urb->received_status == 0)
-+ return 0;
-+ if (urb->state == BCE_VHCI_URB_DATA_TRANSFER_COMPLETE ||
-+ (urb->received_status != BCE_VHCI_SUCCESS && urb->state != BCE_VHCI_URB_CONTROL_WAITING_FOR_SETUP_REQUEST &&
-+ urb->state != BCE_VHCI_URB_CONTROL_WAITING_FOR_SETUP_COMPLETION)) {
-+ urb->state = BCE_VHCI_URB_CONTROL_COMPLETE;
-+ if (urb->received_status != BCE_VHCI_SUCCESS) {
-+ pr_err("bce-vhci: [%02x] URB failed: %x\n", urb->q->endp_addr, urb->received_status);
-+ urb->q->active = false;
-+ urb->q->stalled = true;
-+ bce_vhci_urb_complete(urb, -EPIPE);
-+ if (!list_empty(&q->endp->urb_list))
-+ bce_vhci_transfer_queue_request_reset(q);
-+ return -ENOENT;
-+ }
-+ bce_vhci_urb_complete(urb, 0);
-+ return -ENOENT;
-+ }
-+ return 0;
-+}
-+
-+static int bce_vhci_urb_control_update(struct bce_vhci_urb *urb, struct bce_vhci_message *msg)
-+{
-+ int status;
-+ if (msg->cmd == BCE_VHCI_CMD_CONTROL_TRANSFER_STATUS) {
-+ urb->received_status = msg->status;
-+ return bce_vhci_urb_control_check_status(urb);
-+ }
-+
-+ if (urb->state == BCE_VHCI_URB_CONTROL_WAITING_FOR_SETUP_REQUEST) {
-+ if (msg->cmd == BCE_VHCI_CMD_TRANSFER_REQUEST) {
-+ if (bce_vhci_urb_send_out_data(urb, urb->urb->setup_dma, sizeof(struct usb_ctrlrequest))) {
-+ pr_err("bce-vhci: [%02x] Failed to start URB setup transfer\n", urb->q->endp_addr);
-+ return 0; /* TODO: fail the URB? */
-+ }
-+ urb->state = BCE_VHCI_URB_CONTROL_WAITING_FOR_SETUP_COMPLETION;
-+ pr_debug("bce-vhci: [%02x] Sent setup %llx\n", urb->q->endp_addr, urb->urb->setup_dma);
-+ return 0;
-+ }
-+ } else if (urb->state == BCE_VHCI_URB_WAITING_FOR_TRANSFER_REQUEST ||
-+ urb->state == BCE_VHCI_URB_WAITING_FOR_COMPLETION) {
-+ if ((status = bce_vhci_urb_data_update(urb, msg)))
-+ return status;
-+ return bce_vhci_urb_control_check_status(urb);
-+ }
-+
-+ /* 0x1000 in out queues aren't really unexpected */
-+ if (msg->cmd == BCE_VHCI_CMD_TRANSFER_REQUEST && urb->q->sq_out != NULL)
-+ return -EAGAIN;
-+ pr_err("bce-vhci: [%02x] Control URB unexpected message (state = %x, msg: %x %x %x %llx)\n", urb->q->endp_addr,
-+ urb->state, msg->cmd, msg->status, msg->param1, msg->param2);
-+ return -EAGAIN;
-+}
-+
-+static int bce_vhci_urb_control_transfer_completion(struct bce_vhci_urb *urb, struct bce_sq_completion_data *c)
-+{
-+ int status;
-+ unsigned long timeout;
-+
-+ if (urb->state == BCE_VHCI_URB_CONTROL_WAITING_FOR_SETUP_COMPLETION) {
-+ if (c->data_size != sizeof(struct usb_ctrlrequest))
-+ pr_err("bce-vhci: [%02x] transfer complete data size mistmatch for usb_ctrlrequest (%llx instead of %lx)\n",
-+ urb->q->endp_addr, c->data_size, sizeof(struct usb_ctrlrequest));
-+
-+ timeout = 1000;
-+ status = bce_vhci_urb_data_start(urb, &timeout);
-+ if (status) {
-+ bce_vhci_urb_complete(urb, status);
-+ return -ENOENT;
-+ }
-+ return 0;
-+ } else if (urb->state == BCE_VHCI_URB_WAITING_FOR_TRANSFER_REQUEST ||
-+ urb->state == BCE_VHCI_URB_WAITING_FOR_COMPLETION) {
-+ if ((status = bce_vhci_urb_data_transfer_completion(urb, c)))
-+ return status;
-+ return bce_vhci_urb_control_check_status(urb);
-+ } else {
-+ pr_err("bce-vhci: [%02x] Control URB unexpected completion (state = %x)\n", urb->q->endp_addr, urb->state);
-+ }
-+ return 0;
-+}
-+
-+static int bce_vhci_urb_update(struct bce_vhci_urb *urb, struct bce_vhci_message *msg)
-+{
-+ if (urb->state == BCE_VHCI_URB_INIT_PENDING)
-+ return -EAGAIN;
-+ if (urb->is_control)
-+ return bce_vhci_urb_control_update(urb, msg);
-+ else
-+ return bce_vhci_urb_data_update(urb, msg);
-+}
-+
-+static int bce_vhci_urb_transfer_completion(struct bce_vhci_urb *urb, struct bce_sq_completion_data *c)
-+{
-+ if (urb->is_control)
-+ return bce_vhci_urb_control_transfer_completion(urb, c);
-+ else
-+ return bce_vhci_urb_data_transfer_completion(urb, c);
-+}
-+
-+static void bce_vhci_urb_resume(struct bce_vhci_urb *urb)
-+{
-+ int status = 0;
-+ if (urb->state == BCE_VHCI_URB_WAITING_FOR_COMPLETION) {
-+ status = bce_vhci_urb_data_transfer_in(urb, NULL);
-+ }
-+ if (status)
-+ bce_vhci_urb_complete(urb, status);
-+}
-diff --git a/drivers/staging/apple-bce/vhci/transfer.h b/drivers/staging/apple-bce/vhci/transfer.h
-new file mode 100644
-index 000000000000..89ecad6bcf8f
---- /dev/null
-+++ b/drivers/staging/apple-bce/vhci/transfer.h
-@@ -0,0 +1,73 @@
-+#ifndef BCEDRIVER_TRANSFER_H
-+#define BCEDRIVER_TRANSFER_H
-+
-+#include <linux/usb.h>
-+#include "queue.h"
-+#include "command.h"
-+#include "../queue.h"
-+
-+struct bce_vhci_list_message {
-+ struct list_head list;
-+ struct bce_vhci_message msg;
-+};
-+enum bce_vhci_pause_source {
-+ BCE_VHCI_PAUSE_INTERNAL_WQ = 1,
-+ BCE_VHCI_PAUSE_FIRMWARE = 2,
-+ BCE_VHCI_PAUSE_SUSPEND = 4,
-+ BCE_VHCI_PAUSE_SHUTDOWN = 8
-+};
-+struct bce_vhci_transfer_queue {
-+ struct bce_vhci *vhci;
-+ struct usb_host_endpoint *endp;
-+ enum bce_vhci_endpoint_state state;
-+ u32 max_active_requests, remaining_active_requests;
-+ bool active, stalled;
-+ u32 paused_by;
-+ bce_vhci_device_t dev_addr;
-+ u8 endp_addr;
-+ struct bce_queue_cq *cq;
-+ struct bce_queue_sq *sq_in;
-+ struct bce_queue_sq *sq_out;
-+ struct list_head evq;
-+ struct spinlock urb_lock;
-+ struct mutex pause_lock;
-+ struct list_head giveback_urb_list;
-+
-+ struct work_struct w_reset;
-+};
-+enum bce_vhci_urb_state {
-+ BCE_VHCI_URB_INIT_PENDING,
-+
-+ BCE_VHCI_URB_WAITING_FOR_TRANSFER_REQUEST,
-+ BCE_VHCI_URB_WAITING_FOR_COMPLETION,
-+ BCE_VHCI_URB_DATA_TRANSFER_COMPLETE,
-+
-+ BCE_VHCI_URB_CONTROL_WAITING_FOR_SETUP_REQUEST,
-+ BCE_VHCI_URB_CONTROL_WAITING_FOR_SETUP_COMPLETION,
-+ BCE_VHCI_URB_CONTROL_COMPLETE
-+};
-+struct bce_vhci_urb {
-+ struct urb *urb;
-+ struct bce_vhci_transfer_queue *q;
-+ enum dma_data_direction dir;
-+ bool is_control;
-+ enum bce_vhci_urb_state state;
-+ int received_status;
-+ u32 send_offset;
-+ u32 receive_offset;
-+};
-+
-+void bce_vhci_create_transfer_queue(struct bce_vhci *vhci, struct bce_vhci_transfer_queue *q,
-+ struct usb_host_endpoint *endp, bce_vhci_device_t dev_addr, enum dma_data_direction dir);
-+void bce_vhci_destroy_transfer_queue(struct bce_vhci *vhci, struct bce_vhci_transfer_queue *q);
-+void bce_vhci_transfer_queue_event(struct bce_vhci_transfer_queue *q, struct bce_vhci_message *msg);
-+int bce_vhci_transfer_queue_do_pause(struct bce_vhci_transfer_queue *q);
-+int bce_vhci_transfer_queue_do_resume(struct bce_vhci_transfer_queue *q);
-+int bce_vhci_transfer_queue_pause(struct bce_vhci_transfer_queue *q, enum bce_vhci_pause_source src);
-+int bce_vhci_transfer_queue_resume(struct bce_vhci_transfer_queue *q, enum bce_vhci_pause_source src);
-+void bce_vhci_transfer_queue_request_reset(struct bce_vhci_transfer_queue *q);
-+
-+int bce_vhci_urb_create(struct bce_vhci_transfer_queue *q, struct urb *urb);
-+int bce_vhci_urb_request_cancel(struct bce_vhci_transfer_queue *q, struct urb *urb, int status);
-+
-+#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 000000000000..eb26f55000d8
---- /dev/null
-+++ b/drivers/staging/apple-bce/vhci/vhci.c
-@@ -0,0 +1,759 @@
-+#include "vhci.h"
-+#include "../apple_bce.h"
-+#include "command.h"
-+#include <linux/usb.h>
-+#include <linux/usb/hcd.h>
-+#include <linux/module.h>
-+#include <linux/version.h>
-+
-+static dev_t bce_vhci_chrdev;
-+static struct class *bce_vhci_class;
-+static const struct hc_driver bce_vhci_driver;
-+static u16 bce_vhci_port_mask = U16_MAX;
-+
-+static int bce_vhci_create_event_queues(struct bce_vhci *vhci);
-+static void bce_vhci_destroy_event_queues(struct bce_vhci *vhci);
-+static int bce_vhci_create_message_queues(struct bce_vhci *vhci);
-+static void bce_vhci_destroy_message_queues(struct bce_vhci *vhci);
-+static void bce_vhci_handle_firmware_events_w(struct work_struct *ws);
-+static void bce_vhci_firmware_event_completion(struct bce_queue_sq *sq);
-+
-+int bce_vhci_create(struct apple_bce_device *dev, struct bce_vhci *vhci)
-+{
-+ int status;
-+
-+ spin_lock_init(&vhci->hcd_spinlock);
-+
-+ vhci->dev = dev;
-+
-+ vhci->vdevt = bce_vhci_chrdev;
-+ vhci->vdev = device_create(bce_vhci_class, dev->dev, vhci->vdevt, NULL, "bce-vhci");
-+ if (IS_ERR_OR_NULL(vhci->vdev)) {
-+ status = PTR_ERR(vhci->vdev);
-+ goto fail_dev;
-+ }
-+
-+ if ((status = bce_vhci_create_message_queues(vhci)))
-+ goto fail_mq;
-+ if ((status = bce_vhci_create_event_queues(vhci)))
-+ goto fail_eq;
-+
-+ vhci->tq_state_wq = alloc_ordered_workqueue("bce-vhci-tq-state", 0);
-+ INIT_WORK(&vhci->w_fw_events, bce_vhci_handle_firmware_events_w);
-+
-+ vhci->hcd = usb_create_hcd(&bce_vhci_driver, vhci->vdev, "bce-vhci");
-+ if (!vhci->hcd) {
-+ status = -ENOMEM;
-+ goto fail_hcd;
-+ }
-+ vhci->hcd->self.sysdev = &dev->pci->dev;
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(5,4,0)
-+ vhci->hcd->self.uses_dma = 1;
-+#endif
-+ *((struct bce_vhci **) vhci->hcd->hcd_priv) = vhci;
-+ vhci->hcd->speed = HCD_USB2;
-+
-+ if ((status = usb_add_hcd(vhci->hcd, 0, 0)))
-+ goto fail_hcd;
-+
-+ return 0;
-+
-+fail_hcd:
-+ bce_vhci_destroy_event_queues(vhci);
-+fail_eq:
-+ bce_vhci_destroy_message_queues(vhci);
-+fail_mq:
-+ device_destroy(bce_vhci_class, vhci->vdevt);
-+fail_dev:
-+ if (!status)
-+ status = -EINVAL;
-+ return status;
-+}
-+
-+void bce_vhci_destroy(struct bce_vhci *vhci)
-+{
-+ usb_remove_hcd(vhci->hcd);
-+ bce_vhci_destroy_event_queues(vhci);
-+ bce_vhci_destroy_message_queues(vhci);
-+ device_destroy(bce_vhci_class, vhci->vdevt);
-+}
-+
-+struct bce_vhci *bce_vhci_from_hcd(struct usb_hcd *hcd)
-+{
-+ return *((struct bce_vhci **) hcd->hcd_priv);
-+}
-+
-+int bce_vhci_start(struct usb_hcd *hcd)
-+{
-+ struct bce_vhci *vhci = bce_vhci_from_hcd(hcd);
-+ int status;
-+ u16 port_mask = 0;
-+ bce_vhci_port_t port_no = 0;
-+ if ((status = bce_vhci_cmd_controller_enable(&vhci->cq, 1, &port_mask)))
-+ return status;
-+ vhci->port_mask = port_mask;
-+ vhci->port_power_mask = 0;
-+ if ((status = bce_vhci_cmd_controller_start(&vhci->cq)))
-+ return status;
-+ port_mask = vhci->port_mask;
-+ while (port_mask) {
-+ port_no += 1;
-+ port_mask >>= 1;
-+ }
-+ vhci->port_count = port_no;
-+ return 0;
-+}
-+
-+void bce_vhci_stop(struct usb_hcd *hcd)
-+{
-+ struct bce_vhci *vhci = bce_vhci_from_hcd(hcd);
-+ bce_vhci_cmd_controller_disable(&vhci->cq);
-+}
-+
-+static int bce_vhci_hub_status_data(struct usb_hcd *hcd, char *buf)
-+{
-+ return 0;
-+}
-+
-+static int bce_vhci_reset_device(struct bce_vhci *vhci, int index, u16 timeout);
-+
-+static int bce_vhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, u16 wIndex, char *buf, u16 wLength)
-+{
-+ struct bce_vhci *vhci = bce_vhci_from_hcd(hcd);
-+ int status;
-+ struct usb_hub_descriptor *hd;
-+ struct usb_hub_status *hs;
-+ struct usb_port_status *ps;
-+ u32 port_status;
-+ // pr_info("bce-vhci: bce_vhci_hub_control %x %i %i [bufl=%i]\n", typeReq, wValue, wIndex, wLength);
-+ if (typeReq == GetHubDescriptor && wLength >= sizeof(struct usb_hub_descriptor)) {
-+ hd = (struct usb_hub_descriptor *) buf;
-+ memset(hd, 0, sizeof(*hd));
-+ hd->bDescLength = sizeof(struct usb_hub_descriptor);
-+ hd->bDescriptorType = USB_DT_HUB;
-+ hd->bNbrPorts = (u8) vhci->port_count;
-+ hd->wHubCharacteristics = HUB_CHAR_INDV_PORT_LPSM | HUB_CHAR_INDV_PORT_OCPM;
-+ hd->bPwrOn2PwrGood = 0;
-+ hd->bHubContrCurrent = 0;
-+ return 0;
-+ } else if (typeReq == GetHubStatus && wLength >= sizeof(struct usb_hub_status)) {
-+ hs = (struct usb_hub_status *) buf;
-+ memset(hs, 0, sizeof(*hs));
-+ hs->wHubStatus = 0;
-+ hs->wHubChange = 0;
-+ return 0;
-+ } else if (typeReq == GetPortStatus && wLength >= 4 /* usb 2.0 */) {
-+ ps = (struct usb_port_status *) buf;
-+ ps->wPortStatus = 0;
-+ ps->wPortChange = 0;
-+
-+ if (vhci->port_power_mask & BIT(wIndex))
-+ ps->wPortStatus |= USB_PORT_STAT_POWER;
-+
-+ if (!(bce_vhci_port_mask & BIT(wIndex)))
-+ return 0;
-+
-+ if ((status = bce_vhci_cmd_port_status(&vhci->cq, (u8) wIndex, 0, &port_status)))
-+ return status;
-+
-+ if (port_status & 16)
-+ ps->wPortStatus |= USB_PORT_STAT_ENABLE | USB_PORT_STAT_HIGH_SPEED;
-+ if (port_status & 4)
-+ ps->wPortStatus |= USB_PORT_STAT_CONNECTION;
-+ if (port_status & 2)
-+ ps->wPortStatus |= USB_PORT_STAT_OVERCURRENT;
-+ if (port_status & 8)
-+ ps->wPortStatus |= USB_PORT_STAT_RESET;
-+ if (port_status & 0x60)
-+ ps->wPortStatus |= USB_PORT_STAT_SUSPEND;
-+
-+ if (port_status & 0x40000)
-+ ps->wPortChange |= USB_PORT_STAT_C_CONNECTION;
-+
-+ pr_debug("bce-vhci: Translated status %x to %x:%x\n", port_status, ps->wPortStatus, ps->wPortChange);
-+ return 0;
-+ } else if (typeReq == SetPortFeature) {
-+ if (wValue == USB_PORT_FEAT_POWER) {
-+ status = bce_vhci_cmd_port_power_on(&vhci->cq, (u8) wIndex);
-+ /* As far as I am aware, power status is not part of the port status so store it separately */
-+ if (!status)
-+ vhci->port_power_mask |= BIT(wIndex);
-+ return status;
-+ }
-+ if (wValue == USB_PORT_FEAT_RESET) {
-+ return bce_vhci_reset_device(vhci, wIndex, wValue);
-+ }
-+ if (wValue == USB_PORT_FEAT_SUSPEND) {
-+ /* TODO: Am I supposed to also suspend the endpoints? */
-+ pr_debug("bce-vhci: Suspending port %i\n", wIndex);
-+ return bce_vhci_cmd_port_suspend(&vhci->cq, (u8) wIndex);
-+ }
-+ } else if (typeReq == ClearPortFeature) {
-+ if (wValue == USB_PORT_FEAT_ENABLE)
-+ return bce_vhci_cmd_port_disable(&vhci->cq, (u8) wIndex);
-+ if (wValue == USB_PORT_FEAT_POWER) {
-+ status = bce_vhci_cmd_port_power_off(&vhci->cq, (u8) wIndex);
-+ if (!status)
-+ vhci->port_power_mask &= ~BIT(wIndex);
-+ return status;
-+ }
-+ if (wValue == USB_PORT_FEAT_C_CONNECTION)
-+ return bce_vhci_cmd_port_status(&vhci->cq, (u8) wIndex, 0x40000, &port_status);
-+ if (wValue == USB_PORT_FEAT_C_RESET) { /* I don't think I can transfer it in any way */
-+ return 0;
-+ }
-+ if (wValue == USB_PORT_FEAT_SUSPEND) {
-+ pr_debug("bce-vhci: Resuming port %i\n", wIndex);
-+ return bce_vhci_cmd_port_resume(&vhci->cq, (u8) wIndex);
-+ }
-+ }
-+ pr_err("bce-vhci: bce_vhci_hub_control unhandled request: %x %i %i [bufl=%i]\n", typeReq, wValue, wIndex, wLength);
-+ dump_stack();
-+ return -EIO;
-+}
-+
-+static int bce_vhci_enable_device(struct usb_hcd *hcd, struct usb_device *udev)
-+{
-+ struct bce_vhci *vhci = bce_vhci_from_hcd(hcd);
-+ struct bce_vhci_device *vdev;
-+ bce_vhci_device_t devid;
-+ pr_info("bce_vhci_enable_device\n");
-+
-+ if (vhci->port_to_device[udev->portnum])
-+ return 0;
-+
-+ /* We need to early address the device */
-+ if (bce_vhci_cmd_device_create(&vhci->cq, udev->portnum, &devid))
-+ return -EIO;
-+
-+ pr_info("bce_vhci_cmd_device_create %i -> %i\n", udev->portnum, devid);
-+
-+ vdev = kzalloc(sizeof(struct bce_vhci_device), GFP_KERNEL);
-+ vhci->port_to_device[udev->portnum] = devid;
-+ vhci->devices[devid] = vdev;
-+
-+ bce_vhci_create_transfer_queue(vhci, &vdev->tq[0], &udev->ep0, devid, DMA_BIDIRECTIONAL);
-+ udev->ep0.hcpriv = &vdev->tq[0];
-+ vdev->tq_mask |= BIT(0);
-+
-+ bce_vhci_cmd_endpoint_create(&vhci->cq, devid, &udev->ep0.desc);
-+ return 0;
-+}
-+
-+static int bce_vhci_address_device(struct usb_hcd *hcd, struct usb_device *udev, unsigned int timeout_ms) //TODO: follow timeout
-+{
-+ /* This is the same as enable_device, but instead in the old scheme */
-+ return bce_vhci_enable_device(hcd, udev);
-+}
-+
-+static void bce_vhci_free_device(struct usb_hcd *hcd, struct usb_device *udev)
-+{
-+ struct bce_vhci *vhci = bce_vhci_from_hcd(hcd);
-+ int i;
-+ bce_vhci_device_t devid;
-+ struct bce_vhci_device *dev;
-+ pr_info("bce_vhci_free_device %i\n", udev->portnum);
-+ if (!vhci->port_to_device[udev->portnum])
-+ return;
-+ devid = vhci->port_to_device[udev->portnum];
-+ dev = vhci->devices[devid];
-+ for (i = 0; i < 32; i++) {
-+ if (dev->tq_mask & BIT(i)) {
-+ bce_vhci_transfer_queue_pause(&dev->tq[i], BCE_VHCI_PAUSE_SHUTDOWN);
-+ bce_vhci_cmd_endpoint_destroy(&vhci->cq, devid, (u8) i);
-+ bce_vhci_destroy_transfer_queue(vhci, &dev->tq[i]);
-+ }
-+ }
-+ vhci->devices[devid] = NULL;
-+ vhci->port_to_device[udev->portnum] = 0;
-+ bce_vhci_cmd_device_destroy(&vhci->cq, devid);
-+ kfree(dev);
-+}
-+
-+static int bce_vhci_reset_device(struct bce_vhci *vhci, int index, u16 timeout)
-+{
-+ struct bce_vhci_device *dev = NULL;
-+ bce_vhci_device_t devid;
-+ int i;
-+ int status;
-+ enum dma_data_direction dir;
-+ pr_info("bce_vhci_reset_device %i\n", index);
-+
-+ devid = vhci->port_to_device[index];
-+ if (devid) {
-+ dev = vhci->devices[devid];
-+
-+ for (i = 0; i < 32; i++) {
-+ if (dev->tq_mask & BIT(i)) {
-+ bce_vhci_transfer_queue_pause(&dev->tq[i], BCE_VHCI_PAUSE_SHUTDOWN);
-+ bce_vhci_cmd_endpoint_destroy(&vhci->cq, devid, (u8) i);
-+ bce_vhci_destroy_transfer_queue(vhci, &dev->tq[i]);
-+ }
-+ }
-+ vhci->devices[devid] = NULL;
-+ vhci->port_to_device[index] = 0;
-+ bce_vhci_cmd_device_destroy(&vhci->cq, devid);
-+ }
-+ status = bce_vhci_cmd_port_reset(&vhci->cq, (u8) index, timeout);
-+
-+ if (dev) {
-+ if ((status = bce_vhci_cmd_device_create(&vhci->cq, index, &devid)))
-+ return status;
-+ vhci->devices[devid] = dev;
-+ vhci->port_to_device[index] = devid;
-+
-+ for (i = 0; i < 32; i++) {
-+ if (dev->tq_mask & BIT(i)) {
-+ dir = usb_endpoint_dir_in(&dev->tq[i].endp->desc) ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
-+ if (i == 0)
-+ dir = DMA_BIDIRECTIONAL;
-+ bce_vhci_create_transfer_queue(vhci, &dev->tq[i], dev->tq[i].endp, devid, dir);
-+ bce_vhci_cmd_endpoint_create(&vhci->cq, devid, &dev->tq[i].endp->desc);
-+ }
-+ }
-+ }
-+
-+ return status;
-+}
-+
-+static int bce_vhci_check_bandwidth(struct usb_hcd *hcd, struct usb_device *udev)
-+{
-+ return 0;
-+}
-+
-+static int bce_vhci_get_frame_number(struct usb_hcd *hcd)
-+{
-+ return 0;
-+}
-+
-+static int bce_vhci_bus_suspend(struct usb_hcd *hcd)
-+{
-+ int i, j;
-+ int status;
-+ struct bce_vhci *vhci = bce_vhci_from_hcd(hcd);
-+ pr_info("bce_vhci: suspend started\n");
-+
-+ pr_info("bce_vhci: suspend endpoints\n");
-+ for (i = 0; i < 16; i++) {
-+ if (!vhci->port_to_device[i])
-+ continue;
-+ for (j = 0; j < 32; j++) {
-+ if (!(vhci->devices[vhci->port_to_device[i]]->tq_mask & BIT(j)))
-+ continue;
-+ bce_vhci_transfer_queue_pause(&vhci->devices[vhci->port_to_device[i]]->tq[j],
-+ BCE_VHCI_PAUSE_SUSPEND);
-+ }
-+ }
-+
-+ pr_info("bce_vhci: suspend ports\n");
-+ for (i = 0; i < 16; i++) {
-+ if (!vhci->port_to_device[i])
-+ continue;
-+ bce_vhci_cmd_port_suspend(&vhci->cq, i);
-+ }
-+ pr_info("bce_vhci: suspend controller\n");
-+ if ((status = bce_vhci_cmd_controller_pause(&vhci->cq)))
-+ return status;
-+
-+ bce_vhci_event_queue_pause(&vhci->ev_commands);
-+ bce_vhci_event_queue_pause(&vhci->ev_system);
-+ bce_vhci_event_queue_pause(&vhci->ev_isochronous);
-+ bce_vhci_event_queue_pause(&vhci->ev_interrupt);
-+ bce_vhci_event_queue_pause(&vhci->ev_asynchronous);
-+ pr_info("bce_vhci: suspend done\n");
-+ return 0;
-+}
-+
-+static int bce_vhci_bus_resume(struct usb_hcd *hcd)
-+{
-+ int i, j;
-+ int status;
-+ struct bce_vhci *vhci = bce_vhci_from_hcd(hcd);
-+ pr_info("bce_vhci: resume started\n");
-+
-+ bce_vhci_event_queue_resume(&vhci->ev_system);
-+ bce_vhci_event_queue_resume(&vhci->ev_isochronous);
-+ bce_vhci_event_queue_resume(&vhci->ev_interrupt);
-+ bce_vhci_event_queue_resume(&vhci->ev_asynchronous);
-+ bce_vhci_event_queue_resume(&vhci->ev_commands);
-+
-+ pr_info("bce_vhci: resume controller\n");
-+ if ((status = bce_vhci_cmd_controller_start(&vhci->cq)))
-+ return status;
-+
-+ pr_info("bce_vhci: resume ports\n");
-+ for (i = 0; i < 16; i++) {
-+ if (!vhci->port_to_device[i])
-+ continue;
-+ bce_vhci_cmd_port_resume(&vhci->cq, i);
-+ }
-+ pr_info("bce_vhci: resume endpoints\n");
-+ for (i = 0; i < 16; i++) {
-+ if (!vhci->port_to_device[i])
-+ continue;
-+ for (j = 0; j < 32; j++) {
-+ if (!(vhci->devices[vhci->port_to_device[i]]->tq_mask & BIT(j)))
-+ continue;
-+ bce_vhci_transfer_queue_resume(&vhci->devices[vhci->port_to_device[i]]->tq[j],
-+ BCE_VHCI_PAUSE_SUSPEND);
-+ }
-+ }
-+
-+ pr_info("bce_vhci: resume done\n");
-+ return 0;
-+}
-+
-+static int bce_vhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flags)
-+{
-+ struct bce_vhci_transfer_queue *q = urb->ep->hcpriv;
-+ pr_debug("bce_vhci_urb_enqueue %i:%x\n", q->dev_addr, urb->ep->desc.bEndpointAddress);
-+ if (!q)
-+ return -ENOENT;
-+ return bce_vhci_urb_create(q, urb);
-+}
-+
-+static int bce_vhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
-+{
-+ struct bce_vhci_transfer_queue *q = urb->ep->hcpriv;
-+ pr_debug("bce_vhci_urb_dequeue %x\n", urb->ep->desc.bEndpointAddress);
-+ return bce_vhci_urb_request_cancel(q, urb, status);
-+}
-+
-+static void bce_vhci_endpoint_reset(struct usb_hcd *hcd, struct usb_host_endpoint *ep)
-+{
-+ struct bce_vhci_transfer_queue *q = ep->hcpriv;
-+ pr_debug("bce_vhci_endpoint_reset\n");
-+ if (q)
-+ bce_vhci_transfer_queue_request_reset(q);
-+}
-+
-+static u8 bce_vhci_endpoint_index(u8 addr)
-+{
-+ if (addr & 0x80)
-+ return (u8) (0x10 + (addr & 0xf));
-+ return (u8) (addr & 0xf);
-+}
-+
-+static int bce_vhci_add_endpoint(struct usb_hcd *hcd, struct usb_device *udev, struct usb_host_endpoint *endp)
-+{
-+ u8 endp_index = bce_vhci_endpoint_index(endp->desc.bEndpointAddress);
-+ struct bce_vhci *vhci = bce_vhci_from_hcd(hcd);
-+ bce_vhci_device_t devid = vhci->port_to_device[udev->portnum];
-+ struct bce_vhci_device *vdev = vhci->devices[devid];
-+ pr_debug("bce_vhci_add_endpoint %x/%x:%x\n", udev->portnum, devid, endp_index);
-+
-+ if (udev->bus->root_hub == udev) /* The USB hub */
-+ return 0;
-+ if (vdev == NULL)
-+ return -ENODEV;
-+ if (vdev->tq_mask & BIT(endp_index)) {
-+ endp->hcpriv = &vdev->tq[endp_index];
-+ return 0;
-+ }
-+
-+ bce_vhci_create_transfer_queue(vhci, &vdev->tq[endp_index], endp, devid,
-+ usb_endpoint_dir_in(&endp->desc) ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
-+ endp->hcpriv = &vdev->tq[endp_index];
-+ vdev->tq_mask |= BIT(endp_index);
-+
-+ bce_vhci_cmd_endpoint_create(&vhci->cq, devid, &endp->desc);
-+ return 0;
-+}
-+
-+static int bce_vhci_drop_endpoint(struct usb_hcd *hcd, struct usb_device *udev, struct usb_host_endpoint *endp)
-+{
-+ u8 endp_index = bce_vhci_endpoint_index(endp->desc.bEndpointAddress);
-+ struct bce_vhci *vhci = bce_vhci_from_hcd(hcd);
-+ bce_vhci_device_t devid = vhci->port_to_device[udev->portnum];
-+ struct bce_vhci_transfer_queue *q = endp->hcpriv;
-+ struct bce_vhci_device *vdev = vhci->devices[devid];
-+ pr_info("bce_vhci_drop_endpoint %x:%x\n", udev->portnum, endp_index);
-+ if (!q) {
-+ if (vdev && vdev->tq_mask & BIT(endp_index)) {
-+ pr_err("something deleted the hcpriv?\n");
-+ q = &vdev->tq[endp_index];
-+ } else {
-+ return 0;
-+ }
-+ }
-+
-+ bce_vhci_cmd_endpoint_destroy(&vhci->cq, devid, (u8) (endp->desc.bEndpointAddress & 0x8Fu));
-+ vhci->devices[devid]->tq_mask &= ~BIT(endp_index);
-+ bce_vhci_destroy_transfer_queue(vhci, q);
-+ return 0;
-+}
-+
-+static int bce_vhci_create_message_queues(struct bce_vhci *vhci)
-+{
-+ if (bce_vhci_message_queue_create(vhci, &vhci->msg_commands, "VHC1HostCommands") ||
-+ bce_vhci_message_queue_create(vhci, &vhci->msg_system, "VHC1HostSystemEvents") ||
-+ bce_vhci_message_queue_create(vhci, &vhci->msg_isochronous, "VHC1HostIsochronousEvents") ||
-+ bce_vhci_message_queue_create(vhci, &vhci->msg_interrupt, "VHC1HostInterruptEvents") ||
-+ bce_vhci_message_queue_create(vhci, &vhci->msg_asynchronous, "VHC1HostAsynchronousEvents")) {
-+ bce_vhci_destroy_message_queues(vhci);
-+ return -EINVAL;
-+ }
-+ spin_lock_init(&vhci->msg_asynchronous_lock);
-+ bce_vhci_command_queue_create(&vhci->cq, &vhci->msg_commands);
-+ return 0;
-+}
-+
-+static void bce_vhci_destroy_message_queues(struct bce_vhci *vhci)
-+{
-+ bce_vhci_command_queue_destroy(&vhci->cq);
-+ bce_vhci_message_queue_destroy(vhci, &vhci->msg_commands);
-+ bce_vhci_message_queue_destroy(vhci, &vhci->msg_system);
-+ bce_vhci_message_queue_destroy(vhci, &vhci->msg_isochronous);
-+ bce_vhci_message_queue_destroy(vhci, &vhci->msg_interrupt);
-+ bce_vhci_message_queue_destroy(vhci, &vhci->msg_asynchronous);
-+}
-+
-+static void bce_vhci_handle_system_event(struct bce_vhci_event_queue *q, struct bce_vhci_message *msg);
-+static void bce_vhci_handle_usb_event(struct bce_vhci_event_queue *q, struct bce_vhci_message *msg);
-+
-+static int bce_vhci_create_event_queues(struct bce_vhci *vhci)
-+{
-+ vhci->ev_cq = bce_create_cq(vhci->dev, 0x100);
-+ if (!vhci->ev_cq)
-+ return -EINVAL;
-+#define CREATE_EVENT_QUEUE(field, name, cb) bce_vhci_event_queue_create(vhci, &vhci->field, name, cb)
-+ if (__bce_vhci_event_queue_create(vhci, &vhci->ev_commands, "VHC1FirmwareCommands",
-+ bce_vhci_firmware_event_completion) ||
-+ CREATE_EVENT_QUEUE(ev_system, "VHC1FirmwareSystemEvents", bce_vhci_handle_system_event) ||
-+ CREATE_EVENT_QUEUE(ev_isochronous, "VHC1FirmwareIsochronousEvents", bce_vhci_handle_usb_event) ||
-+ CREATE_EVENT_QUEUE(ev_interrupt, "VHC1FirmwareInterruptEvents", bce_vhci_handle_usb_event) ||
-+ CREATE_EVENT_QUEUE(ev_asynchronous, "VHC1FirmwareAsynchronousEvents", bce_vhci_handle_usb_event)) {
-+ bce_vhci_destroy_event_queues(vhci);
-+ return -EINVAL;
-+ }
-+#undef CREATE_EVENT_QUEUE
-+ return 0;
-+}
-+
-+static void bce_vhci_destroy_event_queues(struct bce_vhci *vhci)
-+{
-+ bce_vhci_event_queue_destroy(vhci, &vhci->ev_commands);
-+ bce_vhci_event_queue_destroy(vhci, &vhci->ev_system);
-+ bce_vhci_event_queue_destroy(vhci, &vhci->ev_isochronous);
-+ bce_vhci_event_queue_destroy(vhci, &vhci->ev_interrupt);
-+ bce_vhci_event_queue_destroy(vhci, &vhci->ev_asynchronous);
-+ if (vhci->ev_cq)
-+ bce_destroy_cq(vhci->dev, vhci->ev_cq);
-+}
-+
-+static void bce_vhci_send_fw_event_response(struct bce_vhci *vhci, struct bce_vhci_message *req, u16 status)
-+{
-+ unsigned long timeout = 1000;
-+ struct bce_vhci_message r = *req;
-+ r.cmd = (u16) (req->cmd | 0x8000u);
-+ r.status = status;
-+ r.param1 = req->param1;
-+ r.param2 = 0;
-+
-+ if (bce_reserve_submission(vhci->msg_system.sq, &timeout)) {
-+ pr_err("bce-vhci: Cannot reserve submision for FW event reply\n");
-+ return;
-+ }
-+ bce_vhci_message_queue_write(&vhci->msg_system, &r);
-+}
-+
-+static int bce_vhci_handle_firmware_event(struct bce_vhci *vhci, struct bce_vhci_message *msg)
-+{
-+ unsigned long flags;
-+ bce_vhci_device_t devid;
-+ u8 endp;
-+ struct bce_vhci_device *dev;
-+ struct bce_vhci_transfer_queue *tq;
-+ if (msg->cmd == BCE_VHCI_CMD_ENDPOINT_REQUEST_STATE || msg->cmd == BCE_VHCI_CMD_ENDPOINT_SET_STATE) {
-+ devid = (bce_vhci_device_t) (msg->param1 & 0xff);
-+ endp = bce_vhci_endpoint_index((u8) ((msg->param1 >> 8) & 0xff));
-+ dev = vhci->devices[devid];
-+ if (!dev || !(dev->tq_mask & BIT(endp)))
-+ return BCE_VHCI_BAD_ARGUMENT;
-+ tq = &dev->tq[endp];
-+ }
-+
-+ if (msg->cmd == BCE_VHCI_CMD_ENDPOINT_REQUEST_STATE) {
-+ if (msg->param2 == BCE_VHCI_ENDPOINT_ACTIVE) {
-+ bce_vhci_transfer_queue_resume(tq, BCE_VHCI_PAUSE_FIRMWARE);
-+ return BCE_VHCI_SUCCESS;
-+ } else if (msg->param2 == BCE_VHCI_ENDPOINT_PAUSED) {
-+ bce_vhci_transfer_queue_pause(tq, BCE_VHCI_PAUSE_FIRMWARE);
-+ return BCE_VHCI_SUCCESS;
-+ }
-+ return BCE_VHCI_BAD_ARGUMENT;
-+ } else if (msg->cmd == BCE_VHCI_CMD_ENDPOINT_SET_STATE) {
-+ if (msg->param2 == BCE_VHCI_ENDPOINT_STALLED) {
-+ tq->state = msg->param2;
-+ spin_lock_irqsave(&tq->urb_lock, flags);
-+ tq->stalled = true;
-+ spin_unlock_irqrestore(&tq->urb_lock, flags);
-+ return BCE_VHCI_SUCCESS;
-+ }
-+ return BCE_VHCI_BAD_ARGUMENT;
-+ }
-+ pr_warn("bce-vhci: Unhandled firmware event: %x s=%x p1=%x p2=%llx\n",
-+ msg->cmd, msg->status, msg->param1, msg->param2);
-+ return BCE_VHCI_BAD_ARGUMENT;
-+}
-+
-+static void bce_vhci_handle_firmware_events_w(struct work_struct *ws)
-+{
-+ size_t cnt = 0;
-+ int result;
-+ struct bce_vhci *vhci = container_of(ws, struct bce_vhci, w_fw_events);
-+ struct bce_queue_sq *sq = vhci->ev_commands.sq;
-+ struct bce_sq_completion_data *cq;
-+ struct bce_vhci_message *msg, *msg2 = NULL;
-+
-+ while (true) {
-+ if (msg2) {
-+ msg = msg2;
-+ msg2 = NULL;
-+ } else if ((cq = bce_next_completion(sq))) {
-+ if (cq->status == BCE_COMPLETION_ABORTED) {
-+ bce_notify_submission_complete(sq);
-+ continue;
-+ }
-+ msg = &vhci->ev_commands.data[sq->head];
-+ } else {
-+ break;
-+ }
-+
-+ pr_debug("bce-vhci: Got fw event: %x s=%x p1=%x p2=%llx\n", msg->cmd, msg->status, msg->param1, msg->param2);
-+ if ((cq = bce_next_completion(sq))) {
-+ msg2 = &vhci->ev_commands.data[(sq->head + 1) % sq->el_count];
-+ pr_debug("bce-vhci: Got second fw event: %x s=%x p1=%x p2=%llx\n",
-+ msg->cmd, msg->status, msg->param1, msg->param2);
-+ if (cq->status != BCE_COMPLETION_ABORTED &&
-+ msg2->cmd == (msg->cmd | 0x4000) && msg2->param1 == msg->param1) {
-+ /* Take two elements */
-+ pr_debug("bce-vhci: Cancelled\n");
-+ bce_vhci_send_fw_event_response(vhci, msg, BCE_VHCI_ABORT);
-+
-+ bce_notify_submission_complete(sq);
-+ bce_notify_submission_complete(sq);
-+ msg2 = NULL;
-+ cnt += 2;
-+ continue;
-+ }
-+
-+ pr_warn("bce-vhci: Handle fw event - unexpected cancellation\n");
-+ }
-+
-+ result = bce_vhci_handle_firmware_event(vhci, msg);
-+ bce_vhci_send_fw_event_response(vhci, msg, (u16) result);
-+
-+
-+ bce_notify_submission_complete(sq);
-+ ++cnt;
-+ }
-+ bce_vhci_event_queue_submit_pending(&vhci->ev_commands, cnt);
-+ if (atomic_read(&sq->available_commands) == sq->el_count - 1) {
-+ pr_debug("bce-vhci: complete\n");
-+ complete(&vhci->ev_commands.queue_empty_completion);
-+ }
-+}
-+
-+static void bce_vhci_firmware_event_completion(struct bce_queue_sq *sq)
-+{
-+ struct bce_vhci_event_queue *q = sq->userdata;
-+ queue_work(q->vhci->tq_state_wq, &q->vhci->w_fw_events);
-+}
-+
-+static void bce_vhci_handle_system_event(struct bce_vhci_event_queue *q, struct bce_vhci_message *msg)
-+{
-+ if (msg->cmd & 0x8000) {
-+ bce_vhci_command_queue_deliver_completion(&q->vhci->cq, msg);
-+ } else {
-+ pr_warn("bce-vhci: Unhandled system event: %x s=%x p1=%x p2=%llx\n",
-+ msg->cmd, msg->status, msg->param1, msg->param2);
-+ }
-+}
-+
-+static void bce_vhci_handle_usb_event(struct bce_vhci_event_queue *q, struct bce_vhci_message *msg)
-+{
-+ bce_vhci_device_t devid;
-+ u8 endp;
-+ struct bce_vhci_device *dev;
-+ if (msg->cmd & 0x8000) {
-+ bce_vhci_command_queue_deliver_completion(&q->vhci->cq, msg);
-+ } else if (msg->cmd == BCE_VHCI_CMD_TRANSFER_REQUEST || msg->cmd == BCE_VHCI_CMD_CONTROL_TRANSFER_STATUS) {
-+ devid = (bce_vhci_device_t) (msg->param1 & 0xff);
-+ endp = bce_vhci_endpoint_index((u8) ((msg->param1 >> 8) & 0xff));
-+ dev = q->vhci->devices[devid];
-+ if (!dev || (dev->tq_mask & BIT(endp)) == 0) {
-+ pr_err("bce-vhci: Didn't find destination for transfer queue event\n");
-+ return;
-+ }
-+ bce_vhci_transfer_queue_event(&dev->tq[endp], msg);
-+ } else {
-+ pr_warn("bce-vhci: Unhandled USB event: %x s=%x p1=%x p2=%llx\n",
-+ msg->cmd, msg->status, msg->param1, msg->param2);
-+ }
-+}
-+
-+
-+
-+static const struct hc_driver bce_vhci_driver = {
-+ .description = "bce-vhci",
-+ .product_desc = "BCE VHCI Host Controller",
-+ .hcd_priv_size = sizeof(struct bce_vhci *),
-+
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(5,4,0)
-+ .flags = HCD_USB2,
-+#else
-+ .flags = HCD_USB2 | HCD_DMA,
-+#endif
-+
-+ .start = bce_vhci_start,
-+ .stop = bce_vhci_stop,
-+ .hub_status_data = bce_vhci_hub_status_data,
-+ .hub_control = bce_vhci_hub_control,
-+ .urb_enqueue = bce_vhci_urb_enqueue,
-+ .urb_dequeue = bce_vhci_urb_dequeue,
-+ .enable_device = bce_vhci_enable_device,
-+ .free_dev = bce_vhci_free_device,
-+ .address_device = bce_vhci_address_device,
-+ .add_endpoint = bce_vhci_add_endpoint,
-+ .drop_endpoint = bce_vhci_drop_endpoint,
-+ .endpoint_reset = bce_vhci_endpoint_reset,
-+ .check_bandwidth = bce_vhci_check_bandwidth,
-+ .get_frame_number = bce_vhci_get_frame_number,
-+ .bus_suspend = bce_vhci_bus_suspend,
-+ .bus_resume = bce_vhci_bus_resume
-+};
-+
-+
-+int __init bce_vhci_module_init(void)
-+{
-+ int result;
-+ if ((result = alloc_chrdev_region(&bce_vhci_chrdev, 0, 1, "bce-vhci")))
-+ goto fail_chrdev;
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(6,4,0)
-+ bce_vhci_class = class_create(THIS_MODULE, "bce-vhci");
-+#else
-+ bce_vhci_class = class_create("bce-vhci");
-+#endif
-+ if (IS_ERR(bce_vhci_class)) {
-+ result = PTR_ERR(bce_vhci_class);
-+ goto fail_class;
-+ }
-+ return 0;
-+
-+fail_class:
-+ class_destroy(bce_vhci_class);
-+fail_chrdev:
-+ unregister_chrdev_region(bce_vhci_chrdev, 1);
-+ if (!result)
-+ result = -EINVAL;
-+ return result;
-+}
-+void __exit bce_vhci_module_exit(void)
-+{
-+ class_destroy(bce_vhci_class);
-+ unregister_chrdev_region(bce_vhci_chrdev, 1);
-+}
-+
-+module_param_named(vhci_port_mask, bce_vhci_port_mask, ushort, 0444);
-+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 000000000000..6c2e22622f4c
---- /dev/null
-+++ b/drivers/staging/apple-bce/vhci/vhci.h
-@@ -0,0 +1,52 @@
-+#ifndef BCE_VHCI_H
-+#define BCE_VHCI_H
-+
-+#include "queue.h"
-+#include "transfer.h"
-+
-+struct usb_hcd;
-+struct bce_queue_cq;
-+
-+struct bce_vhci_device {
-+ struct bce_vhci_transfer_queue tq[32];
-+ u32 tq_mask;
-+};
-+struct bce_vhci {
-+ struct apple_bce_device *dev;
-+ dev_t vdevt;
-+ struct device *vdev;
-+ struct usb_hcd *hcd;
-+ struct spinlock hcd_spinlock;
-+ struct bce_vhci_message_queue msg_commands;
-+ struct bce_vhci_message_queue msg_system;
-+ struct bce_vhci_message_queue msg_isochronous;
-+ struct bce_vhci_message_queue msg_interrupt;
-+ struct bce_vhci_message_queue msg_asynchronous;
-+ struct spinlock msg_asynchronous_lock;
-+ struct bce_vhci_command_queue cq;
-+ struct bce_queue_cq *ev_cq;
-+ struct bce_vhci_event_queue ev_commands;
-+ struct bce_vhci_event_queue ev_system;
-+ struct bce_vhci_event_queue ev_isochronous;
-+ struct bce_vhci_event_queue ev_interrupt;
-+ struct bce_vhci_event_queue ev_asynchronous;
-+ u16 port_mask;
-+ u8 port_count;
-+ u16 port_power_mask;
-+ bce_vhci_device_t port_to_device[16];
-+ struct bce_vhci_device *devices[16];
-+ struct workqueue_struct *tq_state_wq;
-+ struct work_struct w_fw_events;
-+};
-+
-+int __init bce_vhci_module_init(void);
-+void __exit bce_vhci_module_exit(void);
-+
-+int bce_vhci_create(struct apple_bce_device *dev, struct bce_vhci *vhci);
-+void bce_vhci_destroy(struct bce_vhci *vhci);
-+int bce_vhci_start(struct usb_hcd *hcd);
-+void bce_vhci_stop(struct usb_hcd *hcd);
-+
-+struct bce_vhci *bce_vhci_from_hcd(struct usb_hcd *hcd);
-+
-+#endif //BCE_VHCI_H
-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;
- }
-
-+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
-@@ -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)
- {
-- 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,
- };
-
-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));
-
--#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 8e06d89698e6..6cdb5a451453 100644
---- a/include/linux/hid.h
-+++ b/include/linux/hid.h
-@@ -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 *);
-
-+struct hid_field *hid_find_field(struct hid_device *hdev, unsigned int report_type,
-+ unsigned int application, unsigned int usage);
- 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);
-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);
-
-+ void (*shutdown)(struct usb_interface *intf);
-+
- 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 69b6a5e177f2..a318bb72a165 100644
---- a/lib/test_printf.c
-+++ b/lib/test_printf.c
-@@ -745,18 +745,26 @@ static void __init fwnode_pointer(void)
- static void __init fourcc_pointer(void)
- {
- struct {
-+ char type;
- u32 code;
- char *str;
- } const try[] = {
-- { 0x3231564e, "NV12 little-endian (0x3231564e)", },
-- { 0xb231564e, "NV12 big-endian (0xb231564e)", },
-- { 0x10111213, ".... little-endian (0x10111213)", },
-- { 0x20303159, "Y10 little-endian (0x20303159)", },
-+ { 'c', 0x3231564e, "NV12 little-endian (0x3231564e)", },
-+ { 'c', 0xb231564e, "NV12 big-endian (0xb231564e)", },
-+ { 'c', 0x10111213, ".... little-endian (0x10111213)", },
-+ { 'c', 0x20303159, "Y10 little-endian (0x20303159)", },
-+ { 'h', 0x67503030, "gP00 (0x67503030)", },
-+ { 'r', 0x30305067, "gP00 (0x67503030)", },
-+ { 'l', cpu_to_le32(0x67503030), "gP00 (0x67503030)", },
-+ { 'b', cpu_to_be32(0x67503030), "gP00 (0x67503030)", },
- };
- unsigned int i;
-
-- for (i = 0; i < ARRAY_SIZE(try); i++)
-- test(try[i].str, "%p4cc", &try[i].code);
-+ for (i = 0; i < ARRAY_SIZE(try); i++) {
-+ char fmt[] = { '%', 'p', '4', 'c', try[i].type, '\0' };
-+
-+ test(try[i].str, fmt, &try[i].code);
-+ }
- }
-
- static void __init
-diff --git a/lib/vsprintf.c b/lib/vsprintf.c
-index cdd4e2314bfc..4feaea1815fa 100644
---- a/lib/vsprintf.c
-+++ b/lib/vsprintf.c
-@@ -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;
-+ bool pix_fmt = false;
- u32 orig, val;
-
-- if (fmt[1] != 'c' || fmt[2] != 'c')
-+ if (fmt[1] != 'c')
- return error_string(buf, end, "(%p4?)", spec);
-
- if (check_pointer(&buf, end, fourcc, spec))
- return buf;
-
- orig = get_unaligned(fourcc);
-- val = orig & ~BIT(31);
-+ switch (fmt[2]) {
-+ case 'h':
-+ val = orig;
-+ break;
-+ case 'r':
-+ val = orig = swab32(orig);
-+ break;
-+ case 'l':
-+ val = orig = le32_to_cpu(orig);
-+ break;
-+ case 'b':
-+ val = orig = be32_to_cpu(orig);
-+ break;
-+ case 'c':
-+ /* Pixel formats are printed LSB-first */
-+ val = swab32(orig & ~BIT(31));
-+ pix_fmt = true;
-+ break;
-+ default:
-+ return error_string(buf, end, "(%p4?)", spec);
-+ }
-
- for (i = 0; i < sizeof(u32); i++) {
-- unsigned char c = val >> (i * 8);
-+ unsigned char c = val >> ((3 - i) * 8);
-
- /* Print non-control ASCII characters as-is, dot otherwise */
- *p++ = isascii(c) && isprint(c) ? c : '.';
- }
-
-- *p++ = ' ';
-- strcpy(p, orig & BIT(31) ? "big-endian" : "little-endian");
-- p += strlen(p);
-+ if (pix_fmt) {
-+ *p++ = ' ';
-+ strcpy(p, orig & BIT(31) ? "big-endian" : "little-endian");
-+ p += strlen(p);
-+ }
-
- *p++ = ' ';
- *p++ = '(';
-@@ -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.
-+ * - '4c[hlbr]' Generic FourCC code.
- * - 'h[CDN]' For a variable-length buffer, it prints it as a hex string with
- * a certain separator (' ' by default):
- * C colon
-diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl
-index 2b812210b412..4c3a8cc6ef15 100755
---- a/scripts/checkpatch.pl
-+++ b/scripts/checkpatch.pl
-@@ -6909,7 +6909,7 @@ sub process {
- ($extension eq "f" &&
- defined $qualifier && $qualifier !~ /^w/) ||
- ($extension eq "4" &&
-- defined $qualifier && $qualifier !~ /^cc/)) {
-+ defined $qualifier && $qualifier !~ /^c[chlbr]/)) {
- $bad_specifier = $specifier;
- last;
- }
---
-2.46.0.rc1
-