aboutsummaryrefslogtreecommitdiff
path: root/SOURCES
diff options
context:
space:
mode:
Diffstat (limited to 'SOURCES')
-rw-r--r--SOURCES/0001-Set-amdgpu.ppfeaturemask-0xffffffff-as-default.patch25
-rw-r--r--SOURCES/0001-bump-the-sensitivity-of-AMD-SFH.patch450
-rw-r--r--SOURCES/0001-drm-i915-quirks-disable-async-flipping-on-specific-d.patch8
-rw-r--r--SOURCES/Patchlist.changelog3
-rw-r--r--SOURCES/asus-linux.patch5069
-rw-r--r--SOURCES/kernel-s390x-debug-fedora.config1
-rw-r--r--SOURCES/kernel-s390x-debug-rhel.config1
-rw-r--r--SOURCES/kernel-s390x-fedora.config1
-rw-r--r--SOURCES/kernel-s390x-rhel.config1
-rw-r--r--SOURCES/kernel-s390x-zfcpdump-rhel.config1
-rw-r--r--SOURCES/kernel.changelog19
-rw-r--r--SOURCES/linux-surface.patch639
-rw-r--r--SOURCES/patch-6.10-redhat.patch110
-rw-r--r--SOURCES/t2linux.patch10707
-rw-r--r--SOURCES/tkg-misc-additions.patch19
-rw-r--r--SOURCES/v0-speaker-multifix.patch7
16 files changed, 293 insertions, 16768 deletions
diff --git a/SOURCES/0001-Set-amdgpu.ppfeaturemask-0xffffffff-as-default.patch b/SOURCES/0001-Set-amdgpu.ppfeaturemask-0xffffffff-as-default.patch
deleted file mode 100644
index 26e3ab7..0000000
--- a/SOURCES/0001-Set-amdgpu.ppfeaturemask-0xffffffff-as-default.patch
+++ /dev/null
@@ -1,25 +0,0 @@
-From 9179080ffaaf1d438db6e0a5a37bdf8dafe233a6 Mon Sep 17 00:00:00 2001
-From: Thomas Crider <gloriouseggroll@gmail.com>
-Date: Mon, 27 Nov 2023 16:13:13 -0500
-Subject: [PATCH] Set amdgpu.ppfeaturemask=0xffffffff as default
-
----
- drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
-index e06009966..4e791eb8f 100644
---- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
-+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
-@@ -158,7 +158,7 @@ bool enforce_isolation;
- * OverDrive(bit 14) disabled by default
- * GFX DCS(bit 19) disabled by default
- */
--uint amdgpu_pp_feature_mask = 0xfff7bfff;
-+uint amdgpu_pp_feature_mask = 0xffffffff;
- uint amdgpu_force_long_training;
- int amdgpu_lbpw = -1;
- int amdgpu_compute_multipipe = -1;
---
-2.43.0
-
diff --git a/SOURCES/0001-bump-the-sensitivity-of-AMD-SFH.patch b/SOURCES/0001-bump-the-sensitivity-of-AMD-SFH.patch
deleted file mode 100644
index 092fab2..0000000
--- a/SOURCES/0001-bump-the-sensitivity-of-AMD-SFH.patch
+++ /dev/null
@@ -1,450 +0,0 @@
-From 34423c936dd27c7f836823d3dfc0041607946ba0 Mon Sep 17 00:00:00 2001
-From: Jan200101 <sentrycraft123@gmail.com>
-Date: Sat, 9 Mar 2024 20:00:58 +0100
-Subject: [PATCH] bump the sensitivity of AMD SFH
-
-Bumps the sensitivity of AMD sfh gyro and accelerometers by removing the division
-operation and rebasing the units in the hid descriptor.
-This helps with the gyro deadzone of the Legion Go. Should not affect existing
-devices.
-
-Since most of the magic happens in firmware thej SFH 1.0 HID report descriptor is left untouched.
-
-Co-authored-by: antheas <git@antheas.dev>
-Signed-off-by: Jan200101 <sentrycraft123@gmail.com>
----
- drivers/hid/amd-sfh-hid/sfh1_1/amd_sfh_desc.c | 29 +-
- .../sfh1_1/amd_sfh_hid_report_desc1_1.h | 344 ++++++++++++++++++
- 2 files changed, 359 insertions(+), 14 deletions(-)
- create mode 100644 drivers/hid/amd-sfh-hid/sfh1_1/amd_sfh_hid_report_desc1_1.h
-
-diff --git a/drivers/hid/amd-sfh-hid/sfh1_1/amd_sfh_desc.c b/drivers/hid/amd-sfh-hid/sfh1_1/amd_sfh_desc.c
-index 8a037de08e92..9426320a4a9c 100644
---- a/drivers/hid/amd-sfh-hid/sfh1_1/amd_sfh_desc.c
-+++ b/drivers/hid/amd-sfh-hid/sfh1_1/amd_sfh_desc.c
-@@ -13,6 +13,7 @@
- #include "amd_sfh_interface.h"
- #include "../hid_descriptor/amd_sfh_hid_desc.h"
- #include "../hid_descriptor/amd_sfh_hid_report_desc.h"
-+#include "amd_sfh_hid_report_desc1_1.h"
-
- #define SENSOR_PROP_REPORTING_STATE_ALL_EVENTS_ENUM 0x41
- #define SENSOR_PROP_POWER_STATE_D0_FULL_POWER_ENUM 0x51
-@@ -30,14 +31,14 @@ static int get_report_desc(int sensor_idx, u8 *rep_desc)
- {
- switch (sensor_idx) {
- case ACCEL_IDX: /* accelerometer */
-- memset(rep_desc, 0, sizeof(accel3_report_descriptor));
-- memcpy(rep_desc, accel3_report_descriptor,
-- sizeof(accel3_report_descriptor));
-+ memset(rep_desc, 0, sizeof(accel3_report_descriptor1_1));
-+ memcpy(rep_desc, accel3_report_descriptor1_1,
-+ sizeof(accel3_report_descriptor1_1));
- break;
- case GYRO_IDX: /* gyroscope */
-- memset(rep_desc, 0, sizeof(gyro3_report_descriptor));
-- memcpy(rep_desc, gyro3_report_descriptor,
-- sizeof(gyro3_report_descriptor));
-+ memset(rep_desc, 0, sizeof(gyro3_report_descriptor1_1));
-+ memcpy(rep_desc, gyro3_report_descriptor1_1,
-+ sizeof(gyro3_report_descriptor1_1));
- break;
- case MAG_IDX: /* magnetometer */
- memset(rep_desc, 0, sizeof(comp3_report_descriptor));
-@@ -201,9 +201,9 @@
- OFFSET_SENSOR_DATA_DEFAULT;
- memcpy_fromio(&accel_data, sensoraddr, sizeof(struct sfh_accel_data));
- get_common_inputs(&acc_input.common_property, report_id);
-- acc_input.in_accel_x_value = amd_sfh_float_to_int(accel_data.acceldata.x) / 100;
-- acc_input.in_accel_y_value = amd_sfh_float_to_int(accel_data.acceldata.y) / 100;
-- acc_input.in_accel_z_value = amd_sfh_float_to_int(accel_data.acceldata.z) / 100;
-+ acc_input.in_accel_x_value = amd_sfh_float_to_int(accel_data.acceldata.x);
-+ acc_input.in_accel_y_value = amd_sfh_float_to_int(accel_data.acceldata.y);
-+ acc_input.in_accel_z_value = amd_sfh_float_to_int(accel_data.acceldata.z);
- memcpy(input_report, &acc_input, sizeof(acc_input));
- report_size = sizeof(acc_input);
- break;
-@@ -212,9 +212,9 @@
- OFFSET_SENSOR_DATA_DEFAULT;
- memcpy_fromio(&gyro_data, sensoraddr, sizeof(struct sfh_gyro_data));
- get_common_inputs(&gyro_input.common_property, report_id);
-- gyro_input.in_angel_x_value = amd_sfh_float_to_int(gyro_data.gyrodata.x) / 1000;
-- gyro_input.in_angel_y_value = amd_sfh_float_to_int(gyro_data.gyrodata.y) / 1000;
-- gyro_input.in_angel_z_value = amd_sfh_float_to_int(gyro_data.gyrodata.z) / 1000;
-+ gyro_input.in_angel_x_value = amd_sfh_float_to_int(gyro_data.gyrodata.x);
-+ gyro_input.in_angel_y_value = amd_sfh_float_to_int(gyro_data.gyrodata.y);
-+ gyro_input.in_angel_z_value = amd_sfh_float_to_int(gyro_data.gyrodata.z);
- memcpy(input_report, &gyro_input, sizeof(gyro_input));
- report_size = sizeof(gyro_input);
- break;
-@@ -264,7 +265,7 @@ static u32 get_desc_size(int sensor_idx, int descriptor_name)
- case ACCEL_IDX:
- switch (descriptor_name) {
- case descr_size:
-- return sizeof(accel3_report_descriptor);
-+ return sizeof(accel3_report_descriptor1_1);
- case input_size:
- return sizeof(struct accel3_input_report);
- case feature_size:
-@@ -274,7 +275,7 @@ static u32 get_desc_size(int sensor_idx, int descriptor_name)
- case GYRO_IDX:
- switch (descriptor_name) {
- case descr_size:
-- return sizeof(gyro3_report_descriptor);
-+ return sizeof(gyro3_report_descriptor1_1);
- case input_size:
- return sizeof(struct gyro_input_report);
- case feature_size:
-diff --git a/drivers/hid/amd-sfh-hid/sfh1_1/amd_sfh_hid_report_desc1_1.h b/drivers/hid/amd-sfh-hid/sfh1_1/amd_sfh_hid_report_desc1_1.h
-new file mode 100644
-index 000000000000..f54ae5be3d58
---- /dev/null
-+++ b/drivers/hid/amd-sfh-hid/sfh1_1/amd_sfh_hid_report_desc1_1.h
-@@ -0,0 +1,344 @@
-+/* SPDX-License-Identifier: GPL-2.0-or-later */
-+/*
-+ * HID descriptor structures 1_1 copy
-+ * Modified for better accuracy
-+ * Copyright 2020-2021 Advanced Micro Devices, Inc.
-+ * Authors: Nehal Bakulchandra Shah <Nehal-bakulchandra.shah@amd.com>
-+ * Sandeep Singh <Sandeep.singh@amd.com>
-+ * Basavaraj Natikar <Basavaraj.Natikar@amd.com>
-+ */
-+
-+#ifndef AMD_SFH_HID_REPORT_DESCRIPTOR1_1_H
-+#define AMD_SFH_HID_REPORT_DESCRIPTOR1_1_H
-+
-+// Accelerometer 3D Sensor
-+static const u8 accel3_report_descriptor1_1[] = {
-+0x05, 0x20, /* Usage page */
-+0x09, 0x73, /* Motion type Accel 3D */
-+0xA1, 0x00, /* HID Collection (Physical) */
-+
-+//feature reports(xmit/receive)
-+0x85, 1, /* HID Report ID */
-+0x05, 0x20, /* HID usage page sensor */
-+0x0A, 0x09, 0x03, /* Sensor property and sensor connection type */
-+0x15, 0, /* HID logical MIN_8(0) */
-+0x25, 2, /* HID logical MAX_8(2) */
-+0x75, 8, /* HID report size(8) */
-+0x95, 1, /* HID report count(1) */
-+0xA1, 0x02, /* HID collection (logical) */
-+0x0A, 0x30, 0x08, /* Sensor property connection type intergated sel*/
-+0x0A, 0x31, 0x08, /* Sensor property connection type attached sel */
-+0x0A, 0x32, 0x08, /* Sensor property connection type external sel */
-+0xB1, 0x00, /* HID feature (Data_Arr_Abs) */
-+0xC0, /* HID end collection */
-+0x0A, 0x16, 0x03, /* HID usage sensor property reporting state */
-+0x15, 0, /* HID logical Min_8(0) */
-+0x25, 5, /* HID logical Max_8(5) */
-+0x75, 8, /* HID report size(8) */
-+0x95, 1, /* HID report count(1) */
-+0xA1, 0x02, /* HID collection(logical) */
-+0x0A, 0x40, 0x08, /* Sensor property report state no events sel */
-+0x0A, 0x41, 0x08, /* Sensor property report state all events sel */
-+0x0A, 0x42, 0x08, /* Sensor property report state threshold events sel */
-+0x0A, 0x43, 0x08, /* Sensor property report state no events wake sel */
-+0x0A, 0x44, 0x08, /* Sensor property report state all events wake sel */
-+0x0A, 0x45, 0x08, /* Sensor property report state threshold events wake sel */
-+0xB1, 0x00, /* HID feature (Data_Arr_Abs) */
-+0xC0, /* HID end collection */
-+0x0A, 0x19, 0x03, /* HID usage sensor property power state */
-+0x15, 0, /* HID logical Min_8(0) */
-+0x25, 5, /* HID logical Max_8(5) */
-+0x75, 8, /* HID report size(8) */
-+0x95, 1, /* HID report count(1) */
-+0xA1, 0x02, /* HID collection(logical) */
-+0x0A, 0x50, 0x08, /* Sensor property power state undefined sel */
-+0x0A, 0x51, 0x08, /* Sensor property power state D0 full power sel */
-+0x0A, 0x52, 0x08, /* Sensor property power state D1 low power sel */
-+0x0A, 0x53, 0x08, /* Sensor property power state D2 standby with wake sel */
-+0x0A, 0x54, 0x08, /* Sensor property power state D3 sleep with wake sel */
-+0x0A, 0x55, 0x08, /* Sensor property power state D4 power off sel */
-+0xB1, 0x00, /* HID feature (Data_Arr_Abs) */
-+0xC0, /* HID end collection */
-+0x0A, 0x01, 0x02, /* HID usage sensor state */
-+0x15, 0, /* HID logical Min_8(0) */
-+0x25, 6, /* HID logical Max_8(6) */
-+0x75, 8, /* HID report size(8) */
-+0x95, 1, /* HID report count(1) */
-+0xA1, 0x02, /* HID collection(logical) */
-+0x0A, 0x00, 0x08, /* HID usage sensor state unknown sel */
-+0x0A, 0x01, 0x08, /* HID usage sensor state ready sel */
-+0x0A, 0x02, 0x08, /* HID usage sensor state not available sel */
-+0x0A, 0x03, 0x08, /* HID usage sensor state no data sel */
-+0x0A, 0x04, 0x08, /* HID usage sensor state initializing sel */
-+0x0A, 0x05, 0x08, /* HID usage sensor state access denied sel */
-+0x0A, 0x06, 0x08, /* HID usage sensor state error sel */
-+0xB1, 0x00, /* HID feature (Data_Arr_Abs) */
-+0xC0, /* HID end collection */
-+0x0A, 0x0E, 0x03, /* HID usage sensor property report interval */
-+0x15, 0, /* HID logical Min_8(0) */
-+0x27, 0xFF, 0xFF, 0xFF, 0xFF, /* HID logical Max_32 */
-+
-+0x75, 32, /* HID report size(32) */
-+0x95, 1, /* HID report count(1) */
-+0x55, 0, /* HID unit exponent(0) */
-+0xB1, 0x02, /* HID feature (Data_Arr_Abs) */
-+0x0A, 0x52, 0x14, /* Sensor data motion accel and mod change sensitivity ABS) */
-+
-+0x15, 0, /* HID logical Min_8(0) */
-+0x26, 0xFF, 0xFF, /* HID logical Max_16(0xFF,0xFF) */
-+
-+0x75, 16, /* HID report size(16) */
-+0x95, 1, /* HID report count(1) */
-+0x55, 0x0E, /* HID unit exponent(0x0E) */
-+0xB1, 0x02, /* HID feature (Data_Arr_Abs) */
-+0x0A, 0x52, 0x24, /* HID usage sensor data (motion accel and mod max) */
-+
-+0x16, 0x01, 0x80, /* HID logical Min_16(0x01,0x80) */
-+
-+0x26, 0xFF, 0x7F, /* HID logical Max_16(0xFF,0x7F) */
-+
-+0x75, 16, /* HID report size(16) */
-+0x95, 1, /* HID report count(1) */
-+0x55, 0x0E, /* HID unit exponent(0x0E) */
-+0xB1, 0x02, /* HID feature (Data_Arr_Abs) */
-+0x0A, 0x52, 0x34, /* HID usage sensor data (motion accel and mod min) */
-+
-+0x16, 0x01, 0x80, /* HID logical Min_16(0x01,0x80) */
-+
-+0x26, 0xFF, 0x7F, /* HID logical Max_16(0xFF,0x7F) */
-+
-+0x75, 16, /* HID report size(16) */
-+0x95, 1, /* HID report count(1) */
-+0x55, 0x0E, /* HID unit exponent(0x0E) */
-+0xB1, 0x02, /* HID feature (Data_Arr_Abs) */
-+
-+//input report (transmit)
-+0x05, 0x20, /* HID usage page sensors */
-+0x0A, 0x01, 0x02, /* HID usage sensor state */
-+0x15, 0, /* HID logical Min_8(0) */
-+0x25, 6, /* HID logical Max_8(6) */
-+0x75, 8, /* HID report size(8) */
-+0x95, 1, /* HID report count (1) */
-+0xA1, 0x02, /* HID end collection (logical) */
-+0x0A, 0x00, 0x08, /* HID usage sensor state unknown sel */
-+0x0A, 0x01, 0x08, /* HID usage sensor state ready sel */
-+0x0A, 0x02, 0x08, /* HID usage sensor state not available sel */
-+0x0A, 0x03, 0x08, /* HID usage sensor state no data sel */
-+0x0A, 0x04, 0x08, /* HID usage sensor state initializing sel */
-+0x0A, 0x05, 0x08, /* HID usage sensor state access denied sel */
-+0x0A, 0x06, 0x08, /* HID usage sensor state error sel */
-+0X81, 0x00, /* HID Input (Data_Arr_Abs) */
-+0xC0, /* HID end collection */
-+0x0A, 0x02, 0x02, /* HID usage sensor event */
-+0x15, 0, /* HID logical Min_8(0) */
-+0x25, 5, /* HID logical Max_8(5) */
-+0x75, 8, /* HID report size(8) */
-+0x95, 1, /* HID report count (1) */
-+0xA1, 0x02, /* HID end collection (logical) */
-+0x0A, 0x10, 0x08, /* HID usage sensor event unknown sel */
-+0x0A, 0x11, 0x08, /* HID usage sensor event state changed sel */
-+0x0A, 0x12, 0x08, /* HID usage sensor event property changed sel */
-+0x0A, 0x13, 0x08, /* HID usage sensor event data updated sel */
-+0x0A, 0x14, 0x08, /* HID usage sensor event poll response sel */
-+0x0A, 0x15, 0x08, /* HID usage sensor event change sensitivity sel */
-+0X81, 0x00, /* HID Input (Data_Arr_Abs) */
-+0xC0, /* HID end collection */
-+0x0A, 0x53, 0x04, /* HID usage sensor data motion Acceleration X axis */
-+0x17, 0x00, 0x00, 0x01, 0x80, /* HID logical Min_32 */
-+
-+0x27, 0xFF, 0xff, 0XFF, 0XFF, /* HID logical Max_32 */
-+
-+0x75, 32, /* HID report size(32) */
-+0x95, 1, /* HID report count (1) */
-+0x55, 0x0C, /* HID unit exponent(0x0C) modified */
-+0X81, 0x02, /* HID Input (Data_Arr_Abs) */
-+0x0A, 0x54, 0x04, /* HID usage sensor data motion Acceleration Y axis */
-+0x17, 0X00, 0X00, 0x01, 0x80, /* HID logical Min_32 */
-+
-+0x27, 0xFF, 0xFF, 0XFF, 0XFF, /* HID logical Max_32 */
-+
-+0x75, 32, /* HID report size(32) */
-+0x95, 1, /* HID report count (1) */
-+0x55, 0x0C, /* HID unit exponent(0x0C) modified */
-+0X81, 0x02, /* HID Input (Data_Arr_Abs) */
-+0x0A, 0x55, 0x04, /* HID usage sensor data motion Acceleration Z axis */
-+0x17, 0X00, 0X00, 0x01, 0x80, /* HID logical Min_32 */
-+
-+0x27, 0XFF, 0XFF, 0xFF, 0x7F, /* HID logical Max_32 */
-+
-+0x75, 32, /* HID report size(32) */
-+0x95, 1, /* HID report count (1) */
-+0x55, 0x0C, /* HID unit exponent(0x0C) modified */
-+0X81, 0x02, /* HID Input (Data_Arr_Abs) */
-+
-+0x0A, 0x51, 0x04, /* HID usage sensor data motion state */
-+0x15, 0, /* HID logical Min_8(0) False = Still*/
-+0x25, 1, /* HID logical Min_8(1) True = In motion */
-+0x75, 8, /* HID report size(8) */
-+0x95, 1, /* HID report count (1) */
-+0X81, 0x02, /* HID Input (Data_Arr_Abs) */
-+0xC0 /* HID end collection */
-+};
-+
-+static const u8 gyro3_report_descriptor1_1[] = {
-+0x05, 0x20, /* Usage page */
-+0x09, 0x76, /* Motion type Gyro3D */
-+0xA1, 0x00, /* HID Collection (Physical) */
-+
-+0x85, 2, /* HID Report ID */
-+0x05, 0x20, /* HID usage page sensor */
-+0x0A, 0x09, 0x03, /* Sensor property and sensor connection type */
-+0x15, 0, /* HID logical MIN_8(0) */
-+0x25, 2, /* HID logical MAX_8(2) */
-+0x75, 8, /* HID report size(8) */
-+0x95, 1, /* HID report count(1) */
-+0xA1, 0x02, /* HID collection (logical) */
-+0x0A, 0x30, 0x08, /* Sensor property connection type intergated sel */
-+0x0A, 0x31, 0x08, /* Sensor property connection type attached sel */
-+0x0A, 0x32, 0x08, /* Sensor property connection type external sel */
-+0xB1, 0x00, /* HID feature (Data_Arr_Abs) */
-+0xC0, /* HID end collection */
-+0x0A, 0x16, 0x03, /* HID usage sensor property reporting state */
-+0x15, 0, /* HID logical Min_8(0) */
-+0x25, 5, /* HID logical Max_8(5) */
-+0x75, 8, /* HID report size(8) */
-+0x95, 1, /* HID report count(1) */
-+0xA1, 0x02, /* HID collection(logical) */
-+0x0A, 0x40, 0x08, /* Sensor reporting state no events sel */
-+0x0A, 0x41, 0x08, /* Sensor reporting state all events sel */
-+0x0A, 0x42, 0x08, /* Sensor reporting state threshold events sel */
-+0x0A, 0x43, 0x08, /* Sensor reporting state no events wake sel */
-+0x0A, 0x44, 0x08, /* Sensor reporting state all events wake sel */
-+0x0A, 0x45, 0x08, /* Sensor reporting state threshold events wake sel */
-+0xB1, 0x00, /* HID feature (Data_Arr_Abs) */
-+0xC0, /* HID end collection */
-+0x0A, 0x19, 0x03, /* HID usage sensor property power state */
-+0x15, 0, /* HID logical Min_8(0) */
-+0x25, 5, /* HID logical Max_8(5) */
-+0x75, 8, /* HID report size(8) */
-+0x95, 1, /* HID report count(1) */
-+0xA1, 0x02, /* HID collection(logical) */
-+0x0A, 0x50, 0x08, /* Sensor power state undefined sel */
-+0x0A, 0x51, 0x08, /* Sensor power state D0 full power sel */
-+0x0A, 0x52, 0x08, /* Sensor power state D1 low power sel */
-+0x0A, 0x53, 0x08, /* Sensor power state D2 standby with wake sel */
-+0x0A, 0x54, 0x08, /* Sensor power state D3 sleep with wake sel */
-+0x0A, 0x55, 0x08, /* Sensor power state D4 power off sel */
-+0xB1, 0x00, /* HID feature (Data_Arr_Abs) */
-+0xC0, /* HID end collection */
-+0x0A, 0x01, 0x02, /* HID usage sensor state */
-+0x15, 0, /* HID logical Min_8(0) */
-+0x25, 6, /* HID logical Max_8(6) */
-+0x75, 8, /* HID report size(8) */
-+0x95, 1, /* HID report count(1) */
-+0xA1, 0x02, /* HID collection(logical) */
-+0x0A, 0x00, 0x08, /* HID usage sensor state unknown sel */
-+0x0A, 0x01, 0x08, /* HID usage sensor state ready sel */
-+0x0A, 0x02, 0x08, /* HID usage sensor state not available sel */
-+0x0A, 0x03, 0x08, /* HID usage sensor state no data sel */
-+0x0A, 0x04, 0x08, /* HID usage sensor state initializing sel */
-+0x0A, 0x05, 0x08, /* HID usage sensor state access denied sel */
-+0x0A, 0x06, 0x08, /* HID usage sensor state error sel */
-+0xB1, 0x00, /* HID feature (Data_Arr_Abs) */
-+0xC0, /* HID end collection */
-+0x0A, 0x0E, 0x03, /* HID usage sensor property report interval */
-+0x15, 0, /* HID logical Min_8(0) */
-+0x27, 0xFF, 0xFF, 0xFF, 0xFF, /* HID logical Max_32 */
-+
-+0x75, 32, /* HID report size(32) */
-+0x95, 1, /* HID report count(1) */
-+0x55, 0, /* HID unit exponent(0) */
-+0xB1, 0x02, /* HID feature (Data_Arr_Abs) */
-+0x0A, 0x56, 0x14, /* Angular velocity and mod change sensitivity ABS)*/
-+
-+0x15, 0, /* HID logical Min_8(0) */
-+0x26, 0xFF, 0xFF, /* HID logical Max_16(0xFF,0xFF) */
-+
-+0x75, 16, /* HID report size(16) */
-+0x95, 1, /* HID report count(1) */
-+0x55, 0x0E, /* HID unit exponent(0x0E) */
-+0xB1, 0x02, /* HID feature (Data_Arr_Abs) */
-+0x0A, 0x56, 0x24, /* Sensor data (motion angular velocity and mod max) */
-+
-+0x16, 0x01, 0x80, /* HID logical Min_16(0x01,0x80) */
-+
-+0x26, 0xFF, 0x7F, /* HID logical Max_16(0xFF,0x7F) */
-+
-+0x75, 16, /* HID report size(16) */
-+0x95, 1, /* HID report count(1) */
-+0x55, 0x0E, /* HID unit exponent(0x0E) */
-+0xB1, 0x02, /* HID feature (Data_Arr_Abs) */
-+0x0A, 0x56, 0x34, /* HID usage sensor data (motion accel and mod min) */
-+
-+0x16, 0x01, 0x80, /* HID logical Min_16(0x01,0x80) */
-+
-+0x26, 0xFF, 0x7F, /* HID logical Max_16(0xFF,0x7F) */
-+
-+0x75, 16, /* HID report size(16) */
-+0x95, 1, /* HID report count(1) */
-+0x55, 0x0E, /* HID unit exponent(0x0E) */
-+0xB1, 0x02, /* HID feature (Data_Arr_Abs) */
-+
-+//Input reports(transmit)
-+0x05, 0x20, /* HID usage page sensors */
-+0x0A, 0x01, 0x02, /* HID usage sensor state */
-+0x15, 0, /* HID logical Min_8(0) */
-+0x25, 6, /* HID logical Max_8(6) */
-+0x75, 8, /* HID report size(8) */
-+0x95, 1, /* HID report count (1) */
-+0xA1, 0x02, /* HID end collection (logical) */
-+0x0A, 0x00, 0x08, /* HID usage sensor state unknown sel */
-+0x0A, 0x01, 0x08, /* HID usage sensor state ready sel */
-+0x0A, 0x02, 0x08, /* HID usage sensor state not available sel */
-+0x0A, 0x03, 0x08, /* HID usage sensor state no data sel */
-+0x0A, 0x04, 0x08, /* HID usage sensor state initializing sel */
-+0x0A, 0x05, 0x08, /* HID usage sensor state access denied sel */
-+0x0A, 0x06, 0x08, /* HID usage sensor state error sel */
-+0X81, 0x00, /* HID Input (Data_Arr_Abs) */
-+0xC0, /* HID end collection */
-+0x0A, 0x02, 0x02, /* HID usage sensor event */
-+0x15, 0, /* HID logical Min_8(0) */
-+0x25, 5, /* HID logical Max_8(5) */
-+0x75, 8, /* HID report size(8) */
-+0x95, 1, /* HID report count (1) */
-+0xA1, 0x02, /* HID end collection (logical) */
-+0x0A, 0x10, 0x08, /* HID usage sensor event unknown sel */
-+0x0A, 0x11, 0x08, /* HID usage sensor event state changed sel */
-+0x0A, 0x12, 0x08, /* HID usage sensor event property changed sel */
-+0x0A, 0x13, 0x08, /* HID usage sensor event data updated sel */
-+0x0A, 0x14, 0x08, /* HID usage sensor event poll response sel */
-+0x0A, 0x15, 0x08, /* HID usage sensor event change sensitivity sel */
-+0X81, 0x00, /* HID Input (Data_Arr_Abs) */
-+0xC0, /* HID end collection */
-+0x0A, 0x57, 0x04, /* Sensor data motion Angular velocity X axis */
-+0x17, 0x00, 0x00, 0x01, 0x80, /* HID logical Min_32 */
-+
-+0x27, 0xFF, 0xFF, 0xFF, 0x7F, /* HID logical Max_32 */
-+
-+0x75, 32, /* HID report size(32) */
-+0x95, 1, /* HID report count (1) */
-+0x55, 0x0B, /* HID unit exponent(0x0B) modified */
-+0X81, 0x02, /* HID Input (Data_Arr_Abs) */
-+0x0A, 0x58, 0x04, /* Sensor data motion Angular velocity Y axis */
-+0x17, 0x00, 0x00, 0x01, 0x80, /* HID logical Min_32 */
-+
-+0x27, 0xFF, 0xFF, 0xFF, 0x7F, /* HID logical Max_32 */
-+
-+0x75, 32, /* HID report size(32) */
-+0x95, 1, /* HID report count (1) */
-+0x55, 0x0B, /* HID unit exponent(0x0B) modified */
-+0X81, 0x02, /* HID Input (Data_Arr_Abs) */
-+0x0A, 0x59, 0x04, /* Sensor data motion Angular velocity Z axis */
-+0x17, 0x00, 0x00, 0x01, 0x80, /* HID logical Min_32 */
-+
-+0x27, 0xFF, 0xFF, 0xFF, 0x7F, /* HID logical Max_32 */
-+
-+0x75, 32, /* HID report size(32) */
-+0x95, 1, /* HID report count (1) */
-+0x55, 0x0B, /* HID unit exponent(0x0B) modified */
-+0X81, 0x02, /* HID Input (Data_Arr_Abs) */
-+
-+0xC0, /* HID end collection */
-+};
-+
-+#endif
---
-2.44.0
-
diff --git a/SOURCES/0001-drm-i915-quirks-disable-async-flipping-on-specific-d.patch b/SOURCES/0001-drm-i915-quirks-disable-async-flipping-on-specific-d.patch
index c5c52b5..582c999 100644
--- a/SOURCES/0001-drm-i915-quirks-disable-async-flipping-on-specific-d.patch
+++ b/SOURCES/0001-drm-i915-quirks-disable-async-flipping-on-specific-d.patch
@@ -12,8 +12,8 @@ diff --git a/drivers/gpu/drm/i915/display/intel_quirks.c b/drivers/gpu/drm/i915/
index a280448df771..1596114dd9ae 100644
--- a/drivers/gpu/drm/i915/display/intel_quirks.c
+++ b/drivers/gpu/drm/i915/display/intel_quirks.c
-@@ -65,6 +65,12 @@
- drm_info(display->drm, "Applying no pps backlight power quirk\n");
+@@ -78,6 +78,12 @@
+ drm_info(display->drm, "Applying Fast Wake sync pulse count quirk\n");
}
+static void quirk_async_page_flips_force_disable(struct intel_display *display)
@@ -25,7 +25,7 @@ index a280448df771..1596114dd9ae 100644
struct intel_quirk {
int device;
int subsystem_vendor;
-@@ -136,6 +142,20 @@ static const struct intel_dmi_quirk intel_dmi_quirks[] = {
+@@ -164,6 +170,20 @@
},
.hook = quirk_no_pps_backlight_power_hook,
},
@@ -36,7 +36,7 @@ index a280448df771..1596114dd9ae 100644
+ .ident = "ASUS TUF DASH F15",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
-+ DMI_MATCH(DMI_PRODUCT_NAME, "ASUS TUF Dash F15 FX516PC_FX516PC"),
++ DMI_MATCH(DMI_PRODUCT_NAME, "ASUS TUF Dash F15 FX516PC"),
+ },
+ },
+ { }
diff --git a/SOURCES/Patchlist.changelog b/SOURCES/Patchlist.changelog
index faa5304..e388f8c 100644
--- a/SOURCES/Patchlist.changelog
+++ b/SOURCES/Patchlist.changelog
@@ -1,3 +1,6 @@
+https://gitlab.com/cki-project/kernel-ark/-/commit/7c261c4b600417524d07c5494a381e58abe404b1
+ 7c261c4b600417524d07c5494a381e58abe404b1 drm/nouveau/fb: restore init() for ramgp102
+
https://gitlab.com/cki-project/kernel-ark/-/commit/3b2f4b84968261c49a19cde5a2c01c32c09cc1f8
3b2f4b84968261c49a19cde5a2c01c32c09cc1f8 xfs: xfs_finobt_count_blocks() walks the wrong btree
diff --git a/SOURCES/asus-linux.patch b/SOURCES/asus-linux.patch
deleted file mode 100644
index e22d980..0000000
--- a/SOURCES/asus-linux.patch
+++ /dev/null
@@ -1,5069 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Jan200101 <sentrycraft123@gmail.com>
-Date: Sun, 8 Sep 2024 01:49:57 +0200
-Subject: [PATCH] asus-linux 6.10.6
-
-Signed-off-by: Jan200101 <sentrycraft123@gmail.com>
----
- drivers/hid/Kconfig | 9 +
- drivers/hid/Makefile | 1 +
- drivers/hid/hid-asus-ally.c | 2284 +++++++++++++++++++
- drivers/hid/hid-asus-ally.h | 544 +++++
- drivers/hid/hid-asus.c | 29 +
- drivers/hid/hid-ids.h | 3 +
- drivers/platform/x86/Kconfig | 14 +
- drivers/platform/x86/Makefile | 1 +
- drivers/platform/x86/amd/pmf/pmf-quirks.c | 9 +-
- drivers/platform/x86/asus-armoury.c | 1049 +++++++++
- drivers/platform/x86/asus-armoury.h | 259 +++
- drivers/platform/x86/asus-wmi.c | 254 ++-
- drivers/platform/x86/intel/int3472/Makefile | 9 +-
- drivers/platform/x86/intel/int3472/common.c | 7 +
- include/linux/platform_data/x86/asus-wmi.h | 56 +
- sound/pci/hda/patch_realtek.c | 8 +
- 16 files changed, 4466 insertions(+), 70 deletions(-)
- create mode 100644 drivers/hid/hid-asus-ally.c
- create mode 100644 drivers/hid/hid-asus-ally.h
- create mode 100644 drivers/platform/x86/asus-armoury.c
- create mode 100644 drivers/platform/x86/asus-armoury.h
-
-diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
-index 08446c89eff6..ea0dbe9111c4 100644
---- a/drivers/hid/Kconfig
-+++ b/drivers/hid/Kconfig
-@@ -164,6 +164,15 @@ config HID_ASUS
- - GL553V series
- - GL753V series
-
-+config HID_ASUS_ALLY
-+ tristate "Asus Ally gamepad configuration support"
-+ depends on USB_HID
-+ depends on LEDS_CLASS
-+ depends on LEDS_CLASS_MULTICOLOR
-+ select POWER_SUPPLY
-+ help
-+ Support for configuring the Asus ROG Ally gamepad using attributes.
-+
- config HID_AUREAL
- tristate "Aureal"
- help
-diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile
-index ce71b53ea6c5..98b346d8f783 100644
---- a/drivers/hid/Makefile
-+++ b/drivers/hid/Makefile
-@@ -31,6 +31,7 @@ obj-$(CONFIG_HID_APPLE) += hid-apple.o
- obj-$(CONFIG_HID_APPLEIR) += hid-appleir.o
- obj-$(CONFIG_HID_CREATIVE_SB0540) += hid-creative-sb0540.o
- obj-$(CONFIG_HID_ASUS) += hid-asus.o
-+obj-$(CONFIG_HID_ASUS_ALLY) += hid-asus-ally.o
- obj-$(CONFIG_HID_AUREAL) += hid-aureal.o
- obj-$(CONFIG_HID_BELKIN) += hid-belkin.o
- obj-$(CONFIG_HID_BETOP_FF) += hid-betopff.o
-diff --git a/drivers/hid/hid-asus-ally.c b/drivers/hid/hid-asus-ally.c
-new file mode 100644
-index 000000000000..fd3d23b2c284
---- /dev/null
-+++ b/drivers/hid/hid-asus-ally.c
-@@ -0,0 +1,2284 @@
-+// SPDX-License-Identifier: GPL-2.0-or-later
-+/*
-+ * HID driver for Asus ROG laptops and Ally
-+ *
-+ * Copyright (c) 2023 Luke Jones <luke@ljones.dev>
-+ */
-+
-+#include "linux/delay.h"
-+#include "linux/device.h"
-+#include "linux/err.h"
-+#include "linux/input-event-codes.h"
-+#include "linux/kstrtox.h"
-+#include "linux/printk.h"
-+#include "linux/slab.h"
-+#include "linux/stddef.h"
-+#include "linux/sysfs.h"
-+#include <linux/hid.h>
-+#include <linux/types.h>
-+#include <linux/usb.h>
-+#include <linux/leds.h>
-+#include <linux/led-class-multicolor.h>
-+
-+#include "hid-ids.h"
-+#include "hid-asus-ally.h"
-+
-+#define READY_MAX_TRIES 3
-+#define FEATURE_REPORT_ID 0x0d
-+#define FEATURE_ROG_ALLY_REPORT_ID 0x5a
-+#define FEATURE_ROG_ALLY_CODE_PAGE 0xD1
-+#define FEATURE_ROG_ALLY_REPORT_SIZE 64
-+#define ALLY_X_INPUT_REPORT_USB 0x0B
-+#define ALLY_X_INPUT_REPORT_USB_SIZE 16
-+
-+#define ALLY_CFG_INTF_IN_ADDRESS 0x83
-+#define ALLY_CFG_INTF_OUT_ADDRESS 0x04
-+#define ALLY_X_INTERFACE_ADDRESS 0x87
-+
-+#define FEATURE_KBD_LED_REPORT_ID1 0x5d
-+#define FEATURE_KBD_LED_REPORT_ID2 0x5e
-+
-+enum ROG_ALLY_TYPE {
-+ ROG_ALLY_TYPE,
-+ ROG_ALLY_TYPE_X,
-+};
-+
-+static const struct hid_device_id rog_ally_devices[] = {
-+ { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK, USB_DEVICE_ID_ASUSTEK_ROG_NKEY_ALLY),
-+ .driver_data = ROG_ALLY_TYPE },
-+ { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK, USB_DEVICE_ID_ASUSTEK_ROG_NKEY_ALLY_X),
-+ .driver_data = ROG_ALLY_TYPE_X },
-+ {}
-+};
-+
-+struct KeyCode {
-+ const char *label;
-+ u8 code;
-+};
-+
-+static const struct KeyCode gamepad_codes[] = {
-+ { "PAD_A", 0x01 }, { "PAD_B", 0x02 }, { "PAD_X", 0x03 },
-+ { "PAD_Y", 0x04 }, { "PAD_LB", 0x05 }, { "PAD_RB", 0x06 },
-+ { "PAD_LS", 0x07 }, { "PAD_RS", 0x08 }, { "PAD_DPAD_UP", 0x09 },
-+ { "PAD_DPAD_DOWN", 0x0a }, { "PAD_DPAD_LEFT", 0x0b }, { "PAD_DPAD_RIGHT", 0x0c },
-+ { "PAD_VIEW", 0x11 }, { "PAD_MENU", 0x12 }, { "PAD_XBOX", 0x13 }
-+};
-+
-+static const struct KeyCode keyboard_codes[] = { { "KB_M1", 0x8f },
-+ { "KB_M2", 0x8e },
-+ { "KB_ESC", 0x76 },
-+ { "KB_F1", 0x50 },
-+ { "KB_F2", 0x60 },
-+ { "KB_F3", 0x40 },
-+ { "KB_F4", 0x0c },
-+ { "KB_F5", 0x03 },
-+ { "KB_F6", 0x0b },
-+ { "KB_F7", 0x80 },
-+ { "KB_F8", 0x0a },
-+ { "KB_F9", 0x01 },
-+ { "KB_F10", 0x09 },
-+ { "KB_F11", 0x78 },
-+ { "KB_F12", 0x07 },
-+ { "KB_F14", 0x10 },
-+ { "KB_F15", 0x18 },
-+ { "KB_BACKTICK", 0x0e },
-+ { "KB_1", 0x16 },
-+ { "KB_2", 0x1e },
-+ { "KB_3", 0x26 },
-+ { "KB_4", 0x25 },
-+ { "KB_5", 0x2e },
-+ { "KB_6", 0x36 },
-+ { "KB_7", 0x3d },
-+ { "KB_8", 0x3e },
-+ { "KB_9", 0x46 },
-+ { "KB_0", 0x45 },
-+ { "KB_HYPHEN", 0x4e },
-+ { "KB_EQUALS", 0x55 },
-+ { "KB_BACKSPACE", 0x66 },
-+ { "KB_TAB", 0x0d },
-+ { "KB_Q", 0x15 },
-+ { "KB_W", 0x1d },
-+ { "KB_E", 0x24 },
-+ { "KB_R", 0x2d },
-+ { "KB_T", 0x2d },
-+ { "KB_Y", 0x35 },
-+ { "KB_U", 0x3c },
-+ { "KB_I", 0x43 },
-+ { "KB_O", 0x44 },
-+ { "KB_P", 0x4d },
-+ { "KB_LBRACKET", 0x54 },
-+ { "KB_RBRACKET", 0x5b },
-+ { "KB_BACKSLASH", 0x5d },
-+ { "KB_CAPS", 0x58 },
-+ { "KB_A", 0x1c },
-+ { "KB_S", 0x1b },
-+ { "KB_D", 0x23 },
-+ { "KB_F", 0x2b },
-+ { "KB_G", 0x34 },
-+ { "KB_H", 0x33 },
-+ { "KB_J", 0x3b },
-+ { "KB_K", 0x42 },
-+ { "KB_L", 0x4b },
-+ { "KB_SEMI", 0x4c },
-+ { "KB_QUOTE", 0x52 },
-+ { "KB_RET", 0x5a },
-+ { "KB_LSHIFT", 0x88 },
-+ { "KB_Z", 0x1a },
-+ { "KB_X", 0x22 },
-+ { "KB_C", 0x21 },
-+ { "KB_V", 0x2a },
-+ { "KB_B", 0x32 },
-+ { "KB_N", 0x31 },
-+ { "KB_M", 0x3a },
-+ { "KB_COMMA", 0x41 },
-+ { "KB_PERIOD", 0x49 },
-+ { "KB_FWDSLASH", 0x4a },
-+ { "KB_RSHIFT", 0x89 },
-+ { "KB_LCTL", 0x8c },
-+ { "KB_META", 0x82 },
-+ { "KB_LALT", 0xba },
-+ { "KB_SPACE", 0x29 },
-+ { "KB_RALT", 0x8b },
-+ { "KB_MENU", 0x84 },
-+ { "KB_RCTL", 0x8d },
-+ { "KB_PRNTSCN", 0xc3 },
-+ { "KB_SCRLCK", 0x7e },
-+ { "KB_PAUSE", 0x91 },
-+ { "KB_INS", 0xc2 },
-+ { "KB_HOME", 0x94 },
-+ { "KB_PGUP", 0x96 },
-+ { "KB_DEL", 0xc0 },
-+ { "KB_END", 0x95 },
-+ { "KB_PGDWN", 0x97 },
-+ { "KB_UP_ARROW", 0x99 },
-+ { "KB_DOWN_ARROW", 0x98 },
-+ { "KB_LEFT_ARROW", 0x91 },
-+ { "KB_RIGHT_ARROW", 0x9b },
-+ { "NUMPAD_LOCK", 0x77 },
-+ { "NUMPAD_FWDSLASH", 0x90 },
-+ { "NUMPAD_ASTERISK", 0x7c },
-+ { "NUMPAD_HYPHEN", 0x7b },
-+ { "NUMPAD_0", 0x70 },
-+ { "NUMPAD_1", 0x69 },
-+ { "NUMPAD_2", 0x72 },
-+ { "NUMPAD_3", 0x7a },
-+ { "NUMPAD_4", 0x6b },
-+ { "NUMPAD_5", 0x73 },
-+ { "NUMPAD_6", 0x74 },
-+ { "NUMPAD_7", 0x6c },
-+ { "NUMPAD_8", 0x75 },
-+ { "NUMPAD_9", 0x7d },
-+ { "NUMPAD_PLUS", 0x79 },
-+ { "NUMPAD_ENTER", 0x81 },
-+ { "NUMPAD_PERIOD", 0x71 } };
-+
-+static const struct KeyCode mouse_codes[] = { { "MOUSE_LCLICK", 0x01 },
-+ { "MOUSE_RCLICK", 0x02 },
-+ { "MOUSE_MCLICK", 0x03 },
-+ { "MOUSE_WHEEL_UP", 0x04 },
-+ { "MOUSE_WHEEL_DOWN", 0x05 } };
-+
-+static const struct KeyCode media_codes[] = {
-+ { "MEDIA_SCREENSHOT", 0x16 }, { "MEDIA_SHOW_KEYBOARD", 0x19 },
-+ { "MEDIA_SHOW_DESKTOP", 0x1c }, { "MEDIA_START_RECORDING", 0x1e },
-+ { "MEDIA_MIC_OFF", 0x01 }, { "MEDIA_VOL_DOWN", 0x02 },
-+ { "MEDIA_VOL_UP", 0x03 }
-+};
-+
-+/* The hatswitch outputs integers, we use them to index this X|Y pair */
-+static const int hat_values[][2] = {
-+ { 0, 0 }, { 0, -1 }, { 1, -1 }, { 1, 0 }, { 1, 1 },
-+ { 0, 1 }, { -1, 1 }, { -1, 0 }, { -1, -1 },
-+};
-+
-+/* rumble packet structure */
-+struct ff_data {
-+ u8 enable;
-+ u8 magnitude_left;
-+ u8 magnitude_right;
-+ u8 magnitude_strong;
-+ u8 magnitude_weak;
-+ u8 pulse_sustain_10ms;
-+ u8 pulse_release_10ms;
-+ u8 loop_count;
-+} __packed;
-+
-+struct ff_report {
-+ u8 report_id;
-+ struct ff_data ff;
-+} __packed;
-+
-+struct ally_x_input_report {
-+ uint16_t x, y;
-+ uint16_t rx, ry;
-+ uint16_t z, rz;
-+ uint8_t buttons[4];
-+} __packed;
-+
-+struct ally_x_device {
-+ struct input_dev *input;
-+ struct hid_device *hdev;
-+ spinlock_t lock;
-+
-+ struct ff_report *ff_packet;
-+ struct work_struct output_worker;
-+ bool output_worker_initialized;
-+ /* Prevent multiple queued event due to the enforced delay in worker */
-+ bool update_qam_btn;
-+ /* Set if the QAM and AC buttons emit Xbox and Xbox+A */
-+ bool qam_btns_steam_mode;
-+ bool update_ff;
-+};
-+
-+struct ally_rgb_leds {
-+ struct hid_device *hdev;
-+ /* Need two dev here to enable the 3 step brightness */
-+ struct led_classdev led_bright_dev;
-+ struct led_classdev_mc led_rgb_dev;
-+ struct work_struct work;
-+ spinlock_t lock;
-+
-+ bool removed;
-+
-+ /* Update the main brightness 0-2 using a single raw write */
-+ bool update_bright;
-+ unsigned int brightness;
-+
-+ /* Update the RGB only to keep write efficient */
-+ bool update_rgb;
-+ uint8_t gamepad_red;
-+ uint8_t gamepad_green;
-+ uint8_t gamepad_blue;
-+};
-+
-+/* ROG Ally has many settings related to the gamepad, all using the same n-key endpoint */
-+struct ally_gamepad_cfg {
-+ struct hid_device *hdev;
-+ struct input_dev *input;
-+
-+ enum xpad_mode mode;
-+ /*
-+ * index: [joysticks/triggers][left(2 bytes), right(2 bytes)]
-+ * joysticks: 2 bytes: inner, outer
-+ * triggers: 2 bytes: lower, upper
-+ * min/max: 0-64
-+ */
-+ u8 deadzones[xpad_mode_mouse][2][4];
-+ /*
-+ * index: left, right
-+ * max: 64
-+ */
-+ u8 vibration_intensity[xpad_mode_mouse][2];
-+ /*
-+ * index: [joysticks][2 byte stepping per point]
-+ * - 4 points of 2 bytes each
-+ * - byte 0 of pair = stick move %
-+ * - byte 1 of pair = stick response %
-+ * - min/max: 1-63
-+ */
-+ bool supports_response_curves;
-+ u8 response_curve[xpad_mode_mouse][2][8];
-+ /*
-+ * left = byte 0, right = byte 1
-+ */
-+ bool supports_anti_deadzones;
-+ u8 anti_deadzones[xpad_mode_mouse][2];
-+ /*
-+ * index: [mode][phys pair][b1, b1 secondary, b2, b2 secondary, blocks of 11]
-+ */
-+ u8 key_mapping[xpad_mode_mouse][btn_pair_lt_rt][MAPPING_BLOCK_LEN];
-+ /*
-+ * index: [mode][button index]
-+ */
-+ u8 turbo_btns[xpad_mode_mouse][TURBO_BLOCK_LEN];
-+ /*
-+ * index: [joystick side][Y-stable, Y-min, Y-max, X-stable, X-min, X-max]
-+ */
-+ u32 js_calibrations[2][6];
-+ /*
-+ * index: [trigger side][stable, max]
-+ */
-+ u32 tr_calibrations[2][2];
-+};
-+
-+static struct ally_drvdata {
-+ struct hid_device *hdev;
-+ struct ally_x_device *ally_x;
-+ struct ally_gamepad_cfg *gamepad_cfg;
-+ struct ally_rgb_leds *led_rgb;
-+} drvdata;
-+
-+static int asus_dev_get_report(struct hid_device *hdev, u8 *out_buf, size_t out_buf_size)
-+{
-+ return hid_hw_raw_request(hdev, FEATURE_REPORT_ID, out_buf, out_buf_size,
-+ HID_FEATURE_REPORT, HID_REQ_GET_REPORT);
-+}
-+
-+static int asus_dev_set_report(struct hid_device *hdev, const u8 *buf, size_t buf_size)
-+{
-+ unsigned char *dmabuf;
-+ int ret;
-+
-+ dmabuf = kmemdup(buf, buf_size, GFP_KERNEL);
-+ if (!dmabuf)
-+ return -ENOMEM;
-+
-+ ret = hid_hw_raw_request(hdev, buf[0], dmabuf, buf_size, HID_FEATURE_REPORT,
-+ HID_REQ_SET_REPORT);
-+ kfree(dmabuf);
-+
-+ return ret;
-+}
-+
-+/**************************************************************************************************/
-+/* ROG Ally gamepad i/o and force-feedback */
-+/**************************************************************************************************/
-+static int ally_x_raw_event(struct ally_x_device *ally_x, struct hid_report *report, u8 *data,
-+ int size)
-+{
-+ struct ally_x_input_report *in_report;
-+ unsigned long flags;
-+ u8 byte;
-+
-+ if (data[0] == 0x0B) {
-+ in_report = (struct ally_x_input_report *)&data[1];
-+
-+ input_report_abs(ally_x->input, ABS_X, in_report->x);
-+ input_report_abs(ally_x->input, ABS_Y, in_report->y);
-+ input_report_abs(ally_x->input, ABS_RX, in_report->rx);
-+ input_report_abs(ally_x->input, ABS_RY, in_report->ry);
-+ input_report_abs(ally_x->input, ABS_Z, in_report->z);
-+ input_report_abs(ally_x->input, ABS_RZ, in_report->rz);
-+
-+ byte = in_report->buttons[0];
-+ input_report_key(ally_x->input, BTN_A, byte & BIT(0));
-+ input_report_key(ally_x->input, BTN_B, byte & BIT(1));
-+ input_report_key(ally_x->input, BTN_X, byte & BIT(2));
-+ input_report_key(ally_x->input, BTN_Y, byte & BIT(3));
-+ input_report_key(ally_x->input, BTN_TL, byte & BIT(4));
-+ input_report_key(ally_x->input, BTN_TR, byte & BIT(5));
-+ input_report_key(ally_x->input, BTN_SELECT, byte & BIT(6));
-+ input_report_key(ally_x->input, BTN_START, byte & BIT(7));
-+
-+ byte = in_report->buttons[1];
-+ input_report_key(ally_x->input, BTN_THUMBL, byte & BIT(0));
-+ input_report_key(ally_x->input, BTN_THUMBR, byte & BIT(1));
-+ input_report_key(ally_x->input, BTN_MODE, byte & BIT(2));
-+
-+ byte = in_report->buttons[2];
-+ input_report_abs(ally_x->input, ABS_HAT0X, hat_values[byte][0]);
-+ input_report_abs(ally_x->input, ABS_HAT0Y, hat_values[byte][1]);
-+ }
-+ /*
-+ * The MCU used on Ally provides many devices: gamepad, keyboord, mouse, other.
-+ * The AC and QAM buttons route through another interface making it difficult to
-+ * use the events unless we grab those and use them here. Only works for Ally X.
-+ */
-+ else if (data[0] == 0x5A) {
-+ if (ally_x->qam_btns_steam_mode) {
-+ spin_lock_irqsave(&ally_x->lock, flags);
-+ if (data[1] == 0x38 && !ally_x->update_qam_btn) {
-+ ally_x->update_qam_btn = true;
-+ if (ally_x->output_worker_initialized)
-+ schedule_work(&ally_x->output_worker);
-+ }
-+ spin_unlock_irqrestore(&ally_x->lock, flags);
-+ /* Left/XBox button. Long press does ctrl+alt+del which we can't catch */
-+ input_report_key(ally_x->input, BTN_MODE, data[1] == 0xA6);
-+ } else {
-+ input_report_key(ally_x->input, KEY_F16, data[1] == 0xA6);
-+ input_report_key(ally_x->input, KEY_PROG1, data[1] == 0x38);
-+ }
-+ /* QAM long press */
-+ input_report_key(ally_x->input, KEY_F17, data[1] == 0xA7);
-+ /* QAM long press released */
-+ input_report_key(ally_x->input, KEY_F18, data[1] == 0xA8);
-+ }
-+
-+ input_sync(ally_x->input);
-+
-+ return 0;
-+}
-+
-+static struct input_dev *ally_x_alloc_input_dev(struct hid_device *hdev,
-+ const char *name_suffix)
-+{
-+ struct input_dev *input_dev;
-+
-+ input_dev = devm_input_allocate_device(&hdev->dev);
-+ if (!input_dev)
-+ return ERR_PTR(-ENOMEM);
-+
-+ input_dev->id.bustype = hdev->bus;
-+ input_dev->id.vendor = hdev->vendor;
-+ input_dev->id.product = hdev->product;
-+ input_dev->id.version = hdev->version;
-+ input_dev->uniq = hdev->uniq;
-+ input_dev->name = "ASUS ROG Ally X Gamepad";
-+
-+ input_set_drvdata(input_dev, hdev);
-+
-+ return input_dev;
-+}
-+
-+static int ally_x_play_effect(struct input_dev *idev, void *data, struct ff_effect *effect)
-+{
-+ struct ally_x_device *ally_x = drvdata.ally_x;
-+ unsigned long flags;
-+
-+ if (effect->type != FF_RUMBLE)
-+ return 0;
-+
-+ spin_lock_irqsave(&ally_x->lock, flags);
-+ ally_x->ff_packet->ff.magnitude_strong = effect->u.rumble.strong_magnitude / 512;
-+ ally_x->ff_packet->ff.magnitude_weak = effect->u.rumble.weak_magnitude / 512;
-+ ally_x->update_ff = true;
-+ spin_unlock_irqrestore(&ally_x->lock, flags);
-+
-+ if (ally_x->output_worker_initialized)
-+ schedule_work(&ally_x->output_worker);
-+
-+ return 0;
-+}
-+
-+static void ally_x_work(struct work_struct *work)
-+{
-+ struct ally_x_device *ally_x = container_of(work, struct ally_x_device, output_worker);
-+ struct ff_report *ff_report = NULL;
-+ bool update_qam = false;
-+ bool update_ff = false;
-+ unsigned long flags;
-+
-+ spin_lock_irqsave(&ally_x->lock, flags);
-+ update_ff = ally_x->update_ff;
-+ if (ally_x->update_ff) {
-+ ff_report = kmemdup(ally_x->ff_packet, sizeof(*ally_x->ff_packet), GFP_KERNEL);
-+ ally_x->update_ff = false;
-+ }
-+ update_qam = ally_x->update_qam_btn;
-+ spin_unlock_irqrestore(&ally_x->lock, flags);
-+
-+ if (update_ff && ff_report) {
-+ ff_report->ff.magnitude_left = ff_report->ff.magnitude_strong;
-+ ff_report->ff.magnitude_right = ff_report->ff.magnitude_weak;
-+ asus_dev_set_report(ally_x->hdev, (u8 *)ff_report, sizeof(*ff_report));
-+ }
-+ kfree(ff_report);
-+
-+ if (update_qam) {
-+ /*
-+ * The sleeps here are required to allow steam to register the button combo.
-+ */
-+ usleep_range(1000, 2000);
-+ input_report_key(ally_x->input, BTN_MODE, 1);
-+ input_sync(ally_x->input);
-+
-+ msleep(80);
-+ input_report_key(ally_x->input, BTN_A, 1);
-+ input_sync(ally_x->input);
-+
-+ msleep(80);
-+ input_report_key(ally_x->input, BTN_A, 0);
-+ input_sync(ally_x->input);
-+
-+ msleep(80);
-+ input_report_key(ally_x->input, BTN_MODE, 0);
-+ input_sync(ally_x->input);
-+
-+ spin_lock_irqsave(&ally_x->lock, flags);
-+ ally_x->update_qam_btn = false;
-+ spin_unlock_irqrestore(&ally_x->lock, flags);
-+ }
-+}
-+
-+static struct input_dev *ally_x_setup_input(struct hid_device *hdev)
-+{
-+ int ret, abs_min = 0, js_abs_max = 65535, tr_abs_max = 1023;
-+ struct input_dev *input;
-+
-+ input = ally_x_alloc_input_dev(hdev, NULL);
-+ if (IS_ERR(input))
-+ return ERR_CAST(input);
-+
-+ input_set_abs_params(input, ABS_X, abs_min, js_abs_max, 0, 0);
-+ input_set_abs_params(input, ABS_Y, abs_min, js_abs_max, 0, 0);
-+ input_set_abs_params(input, ABS_RX, abs_min, js_abs_max, 0, 0);
-+ input_set_abs_params(input, ABS_RY, abs_min, js_abs_max, 0, 0);
-+ input_set_abs_params(input, ABS_Z, abs_min, tr_abs_max, 0, 0);
-+ input_set_abs_params(input, ABS_RZ, abs_min, tr_abs_max, 0, 0);
-+ input_set_abs_params(input, ABS_HAT0X, -1, 1, 0, 0);
-+ input_set_abs_params(input, ABS_HAT0Y, -1, 1, 0, 0);
-+ input_set_capability(input, EV_KEY, BTN_A);
-+ input_set_capability(input, EV_KEY, BTN_B);
-+ input_set_capability(input, EV_KEY, BTN_X);
-+ input_set_capability(input, EV_KEY, BTN_Y);
-+ input_set_capability(input, EV_KEY, BTN_TL);
-+ input_set_capability(input, EV_KEY, BTN_TR);
-+ input_set_capability(input, EV_KEY, BTN_SELECT);
-+ input_set_capability(input, EV_KEY, BTN_START);
-+ input_set_capability(input, EV_KEY, BTN_MODE);
-+ input_set_capability(input, EV_KEY, BTN_THUMBL);
-+ input_set_capability(input, EV_KEY, BTN_THUMBR);
-+
-+ input_set_capability(input, EV_KEY, KEY_PROG1);
-+ input_set_capability(input, EV_KEY, KEY_F16);
-+ input_set_capability(input, EV_KEY, KEY_F17);
-+ input_set_capability(input, EV_KEY, KEY_F18);
-+
-+ input_set_capability(input, EV_FF, FF_RUMBLE);
-+ input_ff_create_memless(input, NULL, ally_x_play_effect);
-+
-+ ret = input_register_device(input);
-+ if (ret)
-+ return ERR_PTR(ret);
-+
-+ return input;
-+}
-+
-+static ssize_t ally_x_qam_mode_show(struct device *dev, struct device_attribute *attr,
-+ char *buf)
-+{
-+ struct ally_x_device *ally_x = drvdata.ally_x;
-+
-+ return sysfs_emit(buf, "%d\n", ally_x->qam_btns_steam_mode);
-+}
-+
-+static ssize_t ally_x_qam_mode_store(struct device *dev, struct device_attribute *attr,
-+ const char *buf, size_t count)
-+{
-+ struct ally_x_device *ally_x = drvdata.ally_x;
-+ bool val;
-+ int ret;
-+
-+ ret = kstrtobool(buf, &val);
-+ if (ret < 0)
-+ return ret;
-+
-+ ally_x->qam_btns_steam_mode = val;
-+
-+ return count;
-+}
-+ALLY_DEVICE_ATTR_RW(ally_x_qam_mode, qam_mode);
-+
-+static struct ally_x_device *ally_x_create(struct hid_device *hdev)
-+{
-+ uint8_t max_output_report_size;
-+ struct ally_x_device *ally_x;
-+ struct ff_report *report;
-+ int ret;
-+
-+ ally_x = devm_kzalloc(&hdev->dev, sizeof(*ally_x), GFP_KERNEL);
-+ if (!ally_x)
-+ return ERR_PTR(-ENOMEM);
-+
-+ ally_x->hdev = hdev;
-+ INIT_WORK(&ally_x->output_worker, ally_x_work);
-+ spin_lock_init(&ally_x->lock);
-+ ally_x->output_worker_initialized = true;
-+ ally_x->qam_btns_steam_mode =
-+ true; /* Always default to steam mode, it can be changed by userspace attr */
-+
-+ max_output_report_size = sizeof(struct ally_x_input_report);
-+ report = devm_kzalloc(&hdev->dev, sizeof(*report), GFP_KERNEL);
-+ if (!report) {
-+ ret = -ENOMEM;
-+ goto free_ally_x;
-+ }
-+
-+ /* None of these bytes will change for the FF command for now */
-+ report->report_id = 0x0D;
-+ report->ff.enable = 0x0F; /* Enable all by default */
-+ report->ff.pulse_sustain_10ms = 0xFF; /* Duration */
-+ report->ff.pulse_release_10ms = 0x00; /* Start Delay */
-+ report->ff.loop_count = 0xEB; /* Loop Count */
-+ ally_x->ff_packet = report;
-+
-+ ally_x->input = ally_x_setup_input(hdev);
-+ if (IS_ERR(ally_x->input)) {
-+ ret = PTR_ERR(ally_x->input);
-+ goto free_ff_packet;
-+ }
-+
-+ if (sysfs_create_file(&hdev->dev.kobj, &dev_attr_ally_x_qam_mode.attr)) {
-+ ret = -ENODEV;
-+ goto unregister_input;
-+ }
-+
-+ ally_x->update_ff = true;
-+ if (ally_x->output_worker_initialized)
-+ schedule_work(&ally_x->output_worker);
-+
-+ hid_info(hdev, "Registered Ally X controller using %s\n",
-+ dev_name(&ally_x->input->dev));
-+ return ally_x;
-+
-+unregister_input:
-+ input_unregister_device(ally_x->input);
-+free_ff_packet:
-+ kfree(ally_x->ff_packet);
-+free_ally_x:
-+ kfree(ally_x);
-+ return ERR_PTR(ret);
-+}
-+
-+static void ally_x_remove(struct hid_device *hdev)
-+{
-+ struct ally_x_device *ally_x = drvdata.ally_x;
-+ unsigned long flags;
-+
-+ spin_lock_irqsave(&ally_x->lock, flags);
-+ ally_x->output_worker_initialized = false;
-+ spin_unlock_irqrestore(&ally_x->lock, flags);
-+ cancel_work_sync(&ally_x->output_worker);
-+ sysfs_remove_file(&hdev->dev.kobj, &dev_attr_ally_x_qam_mode.attr);
-+}
-+
-+/**************************************************************************************************/
-+/* ROG Ally configuration */
-+/**************************************************************************************************/
-+static int __gamepad_write_all_to_mcu(struct hid_device *hdev,
-+ struct ally_gamepad_cfg *ally_cfg);
-+
-+static int process_key_code(const struct KeyCode *codes, int code_count, const char *buf_copy,
-+ u8 *out, int out_idx)
-+{
-+ for (int i = 0; i < code_count; i++) {
-+ if (strcmp(buf_copy, codes[i].label) == 0) {
-+ out[out_idx] = codes[i].code;
-+ return 0; // Found
-+ }
-+ }
-+ return -EINVAL; // Not found
-+}
-+
-+static int __string_to_key_code(const char *buf, u8 *out, int out_len)
-+{
-+ char buf_copy[32];
-+ u8 *save_buf;
-+
-+ if (out_len != BTN_CODE_LEN)
-+ return -EINVAL;
-+
-+ save_buf = kzalloc(out_len, GFP_KERNEL);
-+ if (!save_buf)
-+ return -ENOMEM;
-+ memcpy(save_buf, out, out_len);
-+ memset(out, 0, out_len); /* always clear before adjusting */
-+
-+ strscpy(buf_copy, buf);
-+ buf_copy[strcspn(buf_copy, "\n")] = 0;
-+
-+ /* Gamepad group */
-+ out[0] = 0x01;
-+ if (process_key_code(gamepad_codes, ARRAY_SIZE(gamepad_codes), buf_copy, out, 1) == 0)
-+ goto success;
-+
-+ /* Keyboard group */
-+ out[0] = 0x02;
-+ if (process_key_code(keyboard_codes, ARRAY_SIZE(keyboard_codes), buf_copy, out, 2) == 0)
-+ goto success;
-+
-+ /* Mouse group */
-+ out[0] = 0x03;
-+ if (process_key_code(mouse_codes, ARRAY_SIZE(mouse_codes), buf_copy, out, 4) == 0)
-+ goto success;
-+
-+ /* Media group */
-+ out[0] = 0x05;
-+ if (process_key_code(media_codes, ARRAY_SIZE(media_codes), buf_copy, out, 3) == 0)
-+ goto success;
-+
-+ /* Restore bytes if invalid input */
-+ memcpy(out, save_buf, out_len);
-+ kfree(save_buf);
-+ return -EINVAL;
-+
-+success:
-+ kfree(save_buf);
-+ return 0;
-+}
-+
-+static const char *key_code_to_string(const struct KeyCode *codes, int code_count, u8 code)
-+{
-+ for (int i = 0; i < code_count; i++) {
-+ if (codes[i].code == code)
-+ return codes[i].label;
-+ }
-+ return "";
-+}
-+
-+static u8 *__get_btn_block(struct ally_gamepad_cfg *ally_cfg, enum btn_pair pair,
-+ enum btn_pair_side side, bool secondary)
-+{
-+ int offs;
-+
-+ offs = side ? MAPPING_BLOCK_LEN / 2 : 0;
-+ offs = secondary ? offs + BTN_CODE_LEN : offs;
-+ return ally_cfg->key_mapping[ally_cfg->mode - 1][pair - 1] + offs;
-+}
-+
-+static const char *__btn_map_to_string(struct ally_gamepad_cfg *ally_cfg, enum btn_pair pair,
-+ enum btn_pair_side side, bool secondary)
-+{
-+ u8 *out_arg = __get_btn_block(ally_cfg, pair, side, secondary);
-+
-+ switch (out_arg[0]) {
-+ case 0x01: // Gamepad buttons
-+ return key_code_to_string(gamepad_codes, ARRAY_SIZE(gamepad_codes), out_arg[1]);
-+ case 0x02: // Keyboard keys
-+ return key_code_to_string(keyboard_codes, ARRAY_SIZE(keyboard_codes),
-+ out_arg[2]);
-+ case 0x03: // Mouse buttons
-+ return key_code_to_string(mouse_codes, ARRAY_SIZE(mouse_codes), out_arg[4]);
-+ case 0x05: // Media controls
-+ return key_code_to_string(media_codes, ARRAY_SIZE(media_codes), out_arg[3]);
-+ default:
-+ return "";
-+ }
-+}
-+
-+/* ASUS ROG Ally device specific attributes */
-+
-+/* This should be called before any attempts to set device functions */
-+static int __gamepad_check_ready(struct hid_device *hdev)
-+{
-+ int ret, count;
-+ u8 *hidbuf;
-+
-+ hidbuf = kzalloc(FEATURE_ROG_ALLY_REPORT_SIZE, GFP_KERNEL);
-+ if (!hidbuf)
-+ return -ENOMEM;
-+
-+ ret = 0;
-+ for (count = 0; count < READY_MAX_TRIES; count++) {
-+ hidbuf[0] = FEATURE_ROG_ALLY_REPORT_ID;
-+ hidbuf[1] = FEATURE_ROG_ALLY_CODE_PAGE;
-+ hidbuf[2] = xpad_cmd_check_ready;
-+ hidbuf[3] = 01;
-+ ret = asus_dev_set_report(hdev, hidbuf, FEATURE_ROG_ALLY_REPORT_SIZE);
-+ if (ret < 0)
-+ hid_warn(hdev, "ROG Ally check failed set report: %d\n", ret);
-+
-+ hidbuf[0] = hidbuf[1] = hidbuf[2] = hidbuf[3] = 0;
-+ ret = asus_dev_get_report(hdev, hidbuf, FEATURE_ROG_ALLY_REPORT_SIZE);
-+ if (ret < 0)
-+ hid_warn(hdev, "ROG Ally check failed get report: %d\n", ret);
-+
-+ ret = hidbuf[2] == xpad_cmd_check_ready;
-+ if (ret)
-+ break;
-+ usleep_range(
-+ 1000,
-+ 2000); /* don't spam the entire loop in less than USB response time */
-+ }
-+
-+ if (count == READY_MAX_TRIES)
-+ hid_warn(hdev, "ROG Ally never responded with a ready\n");
-+
-+ kfree(hidbuf);
-+ return ret;
-+}
-+
-+/* BUTTON REMAPPING *******************************************************************************/
-+static void __btn_pair_to_pkt(struct ally_gamepad_cfg *ally_cfg, enum btn_pair pair, u8 *out,
-+ int out_len)
-+{
-+ out[0] = FEATURE_ROG_ALLY_REPORT_ID;
-+ out[1] = FEATURE_ROG_ALLY_CODE_PAGE;
-+ out[2] = xpad_cmd_set_mapping;
-+ out[3] = pair;
-+ out[4] = xpad_cmd_len_mapping;
-+ memcpy(&out[5], &ally_cfg->key_mapping[ally_cfg->mode - 1][pair - 1],
-+ MAPPING_BLOCK_LEN);
-+}
-+
-+/* Store the button setting in driver data. Does not apply to device until __gamepad_set_mapping */
-+static int __gamepad_mapping_store(struct ally_gamepad_cfg *ally_cfg, const char *buf,
-+ enum btn_pair pair, int side, bool secondary)
-+{
-+ u8 *out_arg;
-+
-+ out_arg = __get_btn_block(ally_cfg, pair, side, secondary);
-+
-+ return __string_to_key_code(buf, out_arg, BTN_CODE_LEN);
-+}
-+
-+/* Apply the mapping pair to the device */
-+static int __gamepad_set_mapping(struct hid_device *hdev, struct ally_gamepad_cfg *ally_cfg,
-+ enum btn_pair pair)
-+{
-+ u8 *hidbuf;
-+ int ret;
-+
-+ ret = __gamepad_check_ready(hdev);
-+ if (ret < 0)
-+ return ret;
-+
-+ hidbuf = kzalloc(FEATURE_ROG_ALLY_REPORT_SIZE, GFP_KERNEL);
-+ if (!hidbuf)
-+ return -ENOMEM;
-+
-+ __btn_pair_to_pkt(ally_cfg, pair, hidbuf, FEATURE_ROG_ALLY_REPORT_SIZE);
-+ ret = asus_dev_set_report(hdev, hidbuf, FEATURE_ROG_ALLY_REPORT_SIZE);
-+
-+ kfree(hidbuf);
-+
-+ return ret;
-+}
-+
-+static ssize_t btn_mapping_apply_store(struct device *dev, struct device_attribute *attr,
-+ const char *buf, size_t count)
-+{
-+ struct ally_gamepad_cfg *ally_cfg = drvdata.gamepad_cfg;
-+ struct hid_device *hdev = to_hid_device(dev);
-+ int ret;
-+
-+ if (!drvdata.gamepad_cfg)
-+ return -ENODEV;
-+
-+ ret = __gamepad_write_all_to_mcu(hdev, ally_cfg);
-+ if (ret < 0)
-+ return ret;
-+
-+ return count;
-+}
-+ALLY_DEVICE_ATTR_WO(btn_mapping_apply, apply_all);
-+
-+/* BUTTON TURBO ***********************************************************************************/
-+static int __btn_turbo_index(enum btn_pair pair, int side)
-+{
-+ return (pair - 1) * (2 * TURBO_BLOCK_STEP) + (side * TURBO_BLOCK_STEP);
-+};
-+
-+static int __gamepad_turbo_show(struct device *dev, enum btn_pair pair, int side)
-+{
-+ struct ally_gamepad_cfg *ally_cfg = drvdata.gamepad_cfg;
-+
-+ if (!drvdata.gamepad_cfg)
-+ return -ENODEV;
-+
-+ return ally_cfg->turbo_btns[ally_cfg->mode - 1][__btn_turbo_index(pair, side)];
-+};
-+
-+static int __gamepad_turbo_store(struct device *dev, const char *buf, enum btn_pair pair,
-+ int side)
-+{
-+ struct ally_gamepad_cfg *ally_cfg = drvdata.gamepad_cfg;
-+ int ret, val;
-+
-+ if (!drvdata.gamepad_cfg)
-+ return -ENODEV;
-+
-+ ret = kstrtoint(buf, 0, &val);
-+ if (ret)
-+ return ret;
-+ if (val < 0 || val > 16)
-+ return -EINVAL;
-+
-+ ally_cfg->turbo_btns[ally_cfg->mode - 1][__btn_turbo_index(pair, side)] = val;
-+
-+ return 0;
-+};
-+
-+/* button map attributes, regular and macro*/
-+ALLY_BTN_MAPPING(m2, btn_pair_m1_m2, btn_pair_side_left);
-+ALLY_BTN_MAPPING(m1, btn_pair_m1_m2, btn_pair_side_right);
-+ALLY_BTN_MAPPING(a, btn_pair_a_b, btn_pair_side_left);
-+ALLY_BTN_MAPPING(b, btn_pair_a_b, btn_pair_side_right);
-+ALLY_BTN_MAPPING(x, btn_pair_x_y, btn_pair_side_left);
-+ALLY_BTN_MAPPING(y, btn_pair_x_y, btn_pair_side_right);
-+ALLY_BTN_MAPPING(lb, btn_pair_lb_rb, btn_pair_side_left);
-+ALLY_BTN_MAPPING(rb, btn_pair_lb_rb, btn_pair_side_right);
-+ALLY_BTN_MAPPING(ls, btn_pair_ls_rs, btn_pair_side_left);
-+ALLY_BTN_MAPPING(rs, btn_pair_ls_rs, btn_pair_side_right);
-+ALLY_BTN_MAPPING(lt, btn_pair_lt_rt, btn_pair_side_left);
-+ALLY_BTN_MAPPING(rt, btn_pair_lt_rt, btn_pair_side_right);
-+ALLY_BTN_MAPPING(dpad_u, btn_pair_dpad_u_d, btn_pair_side_left);
-+ALLY_BTN_MAPPING(dpad_d, btn_pair_dpad_u_d, btn_pair_side_right);
-+ALLY_BTN_MAPPING(dpad_l, btn_pair_dpad_l_r, btn_pair_side_left);
-+ALLY_BTN_MAPPING(dpad_r, btn_pair_dpad_l_r, btn_pair_side_right);
-+ALLY_BTN_MAPPING(view, btn_pair_view_menu, btn_pair_side_left);
-+ALLY_BTN_MAPPING(menu, btn_pair_view_menu, btn_pair_side_right);
-+
-+static void __gamepad_mapping_xpad_default(struct ally_gamepad_cfg *ally_cfg)
-+{
-+ memcpy(&ally_cfg->key_mapping[0][0], &XPAD_DEF1, MAPPING_BLOCK_LEN);
-+ memcpy(&ally_cfg->key_mapping[0][1], &XPAD_DEF2, MAPPING_BLOCK_LEN);
-+ memcpy(&ally_cfg->key_mapping[0][2], &XPAD_DEF3, MAPPING_BLOCK_LEN);
-+ memcpy(&ally_cfg->key_mapping[0][3], &XPAD_DEF4, MAPPING_BLOCK_LEN);
-+ memcpy(&ally_cfg->key_mapping[0][4], &XPAD_DEF5, MAPPING_BLOCK_LEN);
-+ memcpy(&ally_cfg->key_mapping[0][5], &XPAD_DEF6, MAPPING_BLOCK_LEN);
-+ memcpy(&ally_cfg->key_mapping[0][6], &XPAD_DEF7, MAPPING_BLOCK_LEN);
-+ memcpy(&ally_cfg->key_mapping[0][7], &XPAD_DEF8, MAPPING_BLOCK_LEN);
-+ memcpy(&ally_cfg->key_mapping[0][8], &XPAD_DEF9, MAPPING_BLOCK_LEN);
-+}
-+
-+static void __gamepad_mapping_wasd_default(struct ally_gamepad_cfg *ally_cfg)
-+{
-+ memcpy(&ally_cfg->key_mapping[1][0], &WASD_DEF1, MAPPING_BLOCK_LEN);
-+ memcpy(&ally_cfg->key_mapping[1][1], &WASD_DEF2, MAPPING_BLOCK_LEN);
-+ memcpy(&ally_cfg->key_mapping[1][2], &WASD_DEF3, MAPPING_BLOCK_LEN);
-+ memcpy(&ally_cfg->key_mapping[1][3], &WASD_DEF4, MAPPING_BLOCK_LEN);
-+ memcpy(&ally_cfg->key_mapping[1][4], &WASD_DEF5, MAPPING_BLOCK_LEN);
-+ memcpy(&ally_cfg->key_mapping[1][5], &WASD_DEF6, MAPPING_BLOCK_LEN);
-+ memcpy(&ally_cfg->key_mapping[1][6], &WASD_DEF7, MAPPING_BLOCK_LEN);
-+ memcpy(&ally_cfg->key_mapping[1][7], &WASD_DEF8, MAPPING_BLOCK_LEN);
-+ memcpy(&ally_cfg->key_mapping[1][8], &WASD_DEF9, MAPPING_BLOCK_LEN);
-+}
-+
-+static ssize_t btn_mapping_reset_store(struct device *dev, struct device_attribute *attr,
-+ const char *buf, size_t count)
-+{
-+ struct ally_gamepad_cfg *ally_cfg = drvdata.gamepad_cfg;
-+
-+ if (!drvdata.gamepad_cfg)
-+ return -ENODEV;
-+
-+ switch (ally_cfg->mode) {
-+ case xpad_mode_game:
-+ __gamepad_mapping_xpad_default(ally_cfg);
-+ break;
-+ case xpad_mode_wasd:
-+ __gamepad_mapping_wasd_default(ally_cfg);
-+ break;
-+ default:
-+ __gamepad_mapping_xpad_default(ally_cfg);
-+ break;
-+ }
-+
-+ return count;
-+}
-+
-+ALLY_DEVICE_ATTR_WO(btn_mapping_reset, reset_btn_mapping);
-+
-+/* GAMEPAD MODE ***********************************************************************************/
-+static ssize_t __gamepad_set_mode(struct hid_device *hdev, struct ally_gamepad_cfg *ally_cfg,
-+ int val)
-+{
-+ u8 *hidbuf;
-+ int ret;
-+
-+ ret = __gamepad_check_ready(hdev);
-+ if (ret < 0)
-+ return ret;
-+
-+ hidbuf = kzalloc(FEATURE_ROG_ALLY_REPORT_SIZE, GFP_KERNEL);
-+ if (!hidbuf)
-+ return -ENOMEM;
-+
-+ hidbuf[0] = FEATURE_ROG_ALLY_REPORT_ID;
-+ hidbuf[1] = FEATURE_ROG_ALLY_CODE_PAGE;
-+ hidbuf[2] = xpad_cmd_set_mode;
-+ hidbuf[3] = xpad_cmd_len_mode;
-+ hidbuf[4] = val;
-+
-+ ret = __gamepad_check_ready(hdev);
-+ if (ret < 0)
-+ goto report_fail;
-+
-+ ret = asus_dev_set_report(hdev, hidbuf, FEATURE_ROG_ALLY_REPORT_SIZE);
-+ if (ret < 0)
-+ goto report_fail;
-+
-+ ret = __gamepad_write_all_to_mcu(hdev, ally_cfg);
-+ if (ret < 0)
-+ goto report_fail;
-+
-+report_fail:
-+ kfree(hidbuf);
-+ return ret;
-+}
-+
-+static ssize_t gamepad_mode_show(struct device *dev, struct device_attribute *attr, char *buf)
-+{
-+ struct ally_gamepad_cfg *ally_cfg = drvdata.gamepad_cfg;
-+
-+ if (!drvdata.gamepad_cfg)
-+ return -ENODEV;
-+
-+ return sysfs_emit(buf, "%d\n", ally_cfg->mode);
-+}
-+
-+static ssize_t gamepad_mode_store(struct device *dev, struct device_attribute *attr,
-+ const char *buf, size_t count)
-+{
-+ struct hid_device *hdev = to_hid_device(dev);
-+ struct ally_gamepad_cfg *ally_cfg = drvdata.gamepad_cfg;
-+ int ret, val;
-+
-+ if (!drvdata.gamepad_cfg)
-+ return -ENODEV;
-+
-+ ret = kstrtoint(buf, 0, &val);
-+ if (ret)
-+ return ret;
-+
-+ if (val < xpad_mode_game || val > xpad_mode_mouse)
-+ return -EINVAL;
-+
-+ ally_cfg->mode = val;
-+
-+ ret = __gamepad_set_mode(hdev, ally_cfg, val);
-+ if (ret < 0)
-+ return ret;
-+
-+ return count;
-+}
-+
-+DEVICE_ATTR_RW(gamepad_mode);
-+
-+/* VIBRATION INTENSITY ****************************************************************************/
-+static ssize_t gamepad_vibration_intensity_index_show(struct device *dev,
-+ struct device_attribute *attr, char *buf)
-+{
-+ return sysfs_emit(buf, "left right\n");
-+}
-+
-+ALLY_DEVICE_ATTR_RO(gamepad_vibration_intensity_index, vibration_intensity_index);
-+
-+static ssize_t __gamepad_write_vibe_intensity_to_mcu(struct hid_device *hdev,
-+ struct ally_gamepad_cfg *ally_cfg)
-+{
-+ u8 *hidbuf;
-+ int ret;
-+
-+ ret = __gamepad_check_ready(hdev);
-+ if (ret < 0)
-+ return ret;
-+
-+ hidbuf = kzalloc(FEATURE_ROG_ALLY_REPORT_SIZE, GFP_KERNEL);
-+ if (!hidbuf)
-+ return -ENOMEM;
-+
-+ hidbuf[0] = FEATURE_ROG_ALLY_REPORT_ID;
-+ hidbuf[1] = FEATURE_ROG_ALLY_CODE_PAGE;
-+ hidbuf[2] = xpad_cmd_set_vibe_intensity;
-+ hidbuf[3] = xpad_cmd_len_vibe_intensity;
-+ hidbuf[4] = ally_cfg->vibration_intensity[ally_cfg->mode - 1][btn_pair_side_left];
-+ hidbuf[5] = ally_cfg->vibration_intensity[ally_cfg->mode - 1][btn_pair_side_right];
-+
-+ ret = __gamepad_check_ready(hdev);
-+ if (ret < 0)
-+ goto report_fail;
-+
-+ ret = asus_dev_set_report(hdev, hidbuf, FEATURE_ROG_ALLY_REPORT_SIZE);
-+ if (ret < 0)
-+ goto report_fail;
-+
-+report_fail:
-+ kfree(hidbuf);
-+ return ret;
-+}
-+
-+static ssize_t gamepad_vibration_intensity_show(struct device *dev,
-+ struct device_attribute *attr, char *buf)
-+{
-+ struct ally_gamepad_cfg *ally_cfg = drvdata.gamepad_cfg;
-+
-+ if (!drvdata.gamepad_cfg)
-+ return -ENODEV;
-+
-+ return sysfs_emit(
-+ buf, "%d %d\n",
-+ ally_cfg->vibration_intensity[ally_cfg->mode - 1][btn_pair_side_left],
-+ ally_cfg->vibration_intensity[ally_cfg->mode - 1][btn_pair_side_right]);
-+}
-+
-+static ssize_t gamepad_vibration_intensity_store(struct device *dev,
-+ struct device_attribute *attr, const char *buf,
-+ size_t count)
-+{
-+ struct hid_device *hdev = to_hid_device(dev);
-+ struct ally_gamepad_cfg *ally_cfg = drvdata.gamepad_cfg;
-+ u32 left, right;
-+ int ret;
-+
-+ if (!drvdata.gamepad_cfg)
-+ return -ENODEV;
-+
-+ if (sscanf(buf, "%d %d", &left, &right) != 2)
-+ return -EINVAL;
-+
-+ if (left > 64 || right > 64)
-+ return -EINVAL;
-+
-+ ally_cfg->vibration_intensity[ally_cfg->mode - 1][btn_pair_side_left] = left;
-+ ally_cfg->vibration_intensity[ally_cfg->mode - 1][btn_pair_side_right] = right;
-+
-+ ret = __gamepad_write_vibe_intensity_to_mcu(hdev, ally_cfg);
-+ if (ret < 0)
-+ return ret;
-+
-+ return count;
-+}
-+
-+ALLY_DEVICE_ATTR_RW(gamepad_vibration_intensity, vibration_intensity);
-+
-+/* ROOT LEVEL ATTRS *******************************************************************************/
-+static struct attribute *gamepad_device_attrs[] = {
-+ &dev_attr_gamepad_mode.attr,
-+ &dev_attr_btn_mapping_reset.attr,
-+ &dev_attr_btn_mapping_apply.attr,
-+ &dev_attr_gamepad_vibration_intensity.attr,
-+ &dev_attr_gamepad_vibration_intensity_index.attr,
-+ NULL
-+};
-+
-+static const struct attribute_group ally_controller_attr_group = {
-+ .attrs = gamepad_device_attrs,
-+};
-+
-+/* ANALOGUE DEADZONES *****************************************************************************/
-+static ssize_t __gamepad_set_deadzones(struct hid_device *hdev,
-+ struct ally_gamepad_cfg *ally_cfg)
-+{
-+ u8 *hidbuf;
-+ int ret;
-+
-+ ret = __gamepad_check_ready(hdev);
-+ if (ret < 0)
-+ return ret;
-+
-+ hidbuf = kzalloc(FEATURE_ROG_ALLY_REPORT_SIZE, GFP_KERNEL);
-+ if (!hidbuf)
-+ return -ENOMEM;
-+
-+ hidbuf[0] = FEATURE_ROG_ALLY_REPORT_ID;
-+ hidbuf[1] = FEATURE_ROG_ALLY_CODE_PAGE;
-+ hidbuf[2] = xpad_cmd_set_js_dz;
-+ hidbuf[3] = xpad_cmd_len_deadzone;
-+ hidbuf[4] = ally_cfg->deadzones[ally_cfg->mode - 1][0][0];
-+ hidbuf[5] = ally_cfg->deadzones[ally_cfg->mode - 1][0][1];
-+ hidbuf[6] = ally_cfg->deadzones[ally_cfg->mode - 1][0][2];
-+ hidbuf[7] = ally_cfg->deadzones[ally_cfg->mode - 1][0][3];
-+
-+ ret = asus_dev_set_report(hdev, hidbuf, FEATURE_ROG_ALLY_REPORT_SIZE);
-+ if (ret < 0)
-+ goto end;
-+
-+ hidbuf[2] = xpad_cmd_set_tr_dz;
-+ hidbuf[4] = ally_cfg->deadzones[ally_cfg->mode - 1][1][0];
-+ hidbuf[5] = ally_cfg->deadzones[ally_cfg->mode - 1][1][1];
-+ hidbuf[6] = ally_cfg->deadzones[ally_cfg->mode - 1][1][2];
-+ hidbuf[7] = ally_cfg->deadzones[ally_cfg->mode - 1][1][3];
-+
-+ ret = asus_dev_set_report(hdev, hidbuf, FEATURE_ROG_ALLY_REPORT_SIZE);
-+ if (ret < 0)
-+ goto end;
-+
-+end:
-+ kfree(hidbuf);
-+ return ret;
-+}
-+
-+static ssize_t __gamepad_store_deadzones(struct ally_gamepad_cfg *ally_cfg, enum xpad_axis axis,
-+ const char *buf)
-+{
-+ int cmd, side, is_tr;
-+ u32 inner, outer;
-+
-+ if (sscanf(buf, "%d %d", &inner, &outer) != 2)
-+ return -EINVAL;
-+
-+ if (inner > 64 || outer > 64 || inner > outer)
-+ return -EINVAL;
-+
-+ is_tr = axis > xpad_axis_xy_right;
-+ side = axis == xpad_axis_xy_right || axis == xpad_axis_z_right ? 2 : 0;
-+ cmd = is_tr ? xpad_cmd_set_js_dz : xpad_cmd_set_tr_dz;
-+
-+ ally_cfg->deadzones[ally_cfg->mode - 1][is_tr][side] = inner;
-+ ally_cfg->deadzones[ally_cfg->mode - 1][is_tr][side + 1] = outer;
-+
-+ return 0;
-+}
-+
-+static ssize_t axis_xyz_deadzone_index_show(struct device *dev, struct device_attribute *attr,
-+ char *buf)
-+{
-+ return sysfs_emit(buf, "inner outer\n");
-+}
-+
-+ALLY_DEVICE_ATTR_RO(axis_xyz_deadzone_index, deadzone_index);
-+
-+ALLY_AXIS_DEADZONE(xpad_axis_xy_left, deadzone);
-+ALLY_AXIS_DEADZONE(xpad_axis_xy_right, deadzone);
-+ALLY_AXIS_DEADZONE(xpad_axis_z_left, deadzone);
-+ALLY_AXIS_DEADZONE(xpad_axis_z_right, deadzone);
-+
-+/* ANTI-DEADZONES *********************************************************************************/
-+static ssize_t __gamepad_write_js_ADZ_to_mcu(struct hid_device *hdev,
-+ struct ally_gamepad_cfg *ally_cfg)
-+{
-+ u8 *hidbuf;
-+ int ret;
-+
-+ ret = __gamepad_check_ready(hdev);
-+ if (ret < 0)
-+ return ret;
-+
-+ hidbuf = kzalloc(FEATURE_ROG_ALLY_REPORT_SIZE, GFP_KERNEL);
-+ if (!hidbuf)
-+ return -ENOMEM;
-+
-+ hidbuf[0] = FEATURE_ROG_ALLY_REPORT_ID;
-+ hidbuf[1] = FEATURE_ROG_ALLY_CODE_PAGE;
-+ hidbuf[2] = xpad_cmd_set_adz;
-+ hidbuf[3] = xpad_cmd_len_adz;
-+ hidbuf[4] = ally_cfg->anti_deadzones[ally_cfg->mode - 1][btn_pair_side_left];
-+ hidbuf[5] = ally_cfg->anti_deadzones[ally_cfg->mode - 1][btn_pair_side_right];
-+
-+ ret = __gamepad_check_ready(hdev);
-+ if (ret < 0)
-+ goto report_fail;
-+
-+ ret = asus_dev_set_report(hdev, hidbuf, FEATURE_ROG_ALLY_REPORT_SIZE);
-+ if (ret < 0)
-+ goto report_fail;
-+
-+report_fail:
-+ kfree(hidbuf);
-+ return ret;
-+}
-+
-+static ssize_t __gamepad_js_ADZ_store(struct device *dev, const char *buf,
-+ enum btn_pair_side side)
-+{
-+ struct ally_gamepad_cfg *ally_cfg = drvdata.gamepad_cfg;
-+ int ret, val;
-+
-+ if (!drvdata.gamepad_cfg)
-+ return -ENODEV;
-+
-+ ret = kstrtoint(buf, 0, &val);
-+ if (ret)
-+ return ret;
-+
-+ if (val < 0 || val > 32)
-+ return -EINVAL;
-+
-+ ally_cfg->anti_deadzones[ally_cfg->mode - 1][side] = val;
-+
-+ return ret;
-+}
-+
-+static ssize_t xpad_axis_xy_left_ADZ_show(struct device *dev, struct device_attribute *attr,
-+ char *buf)
-+{
-+ struct ally_gamepad_cfg *ally_cfg = drvdata.gamepad_cfg;
-+
-+ if (!drvdata.gamepad_cfg)
-+ return -ENODEV;
-+
-+ return sysfs_emit(buf, "%d\n",
-+ ally_cfg->anti_deadzones[ally_cfg->mode - 1][btn_pair_side_left]);
-+}
-+
-+static ssize_t xpad_axis_xy_left_ADZ_store(struct device *dev, struct device_attribute *attr,
-+ const char *buf, size_t count)
-+{
-+ int ret = __gamepad_js_ADZ_store(dev, buf, btn_pair_side_left);
-+
-+ if (ret)
-+ return ret;
-+
-+ return count;
-+}
-+
-+ALLY_DEVICE_ATTR_RW(xpad_axis_xy_left_ADZ, anti_deadzone);
-+
-+static ssize_t xpad_axis_xy_right_ADZ_show(struct device *dev, struct device_attribute *attr,
-+ char *buf)
-+{
-+ struct ally_gamepad_cfg *ally_cfg = drvdata.gamepad_cfg;
-+
-+ if (!drvdata.gamepad_cfg)
-+ return -ENODEV;
-+
-+ return sysfs_emit(buf, "%d\n",
-+ ally_cfg->anti_deadzones[ally_cfg->mode - 1][btn_pair_side_right]);
-+}
-+
-+static ssize_t xpad_axis_xy_right_ADZ_store(struct device *dev, struct device_attribute *attr,
-+ const char *buf, size_t count)
-+{
-+ int ret = __gamepad_js_ADZ_store(dev, buf, btn_pair_side_right);
-+
-+ if (ret)
-+ return ret;
-+
-+ return count;
-+}
-+
-+ALLY_DEVICE_ATTR_RW(xpad_axis_xy_right_ADZ, anti_deadzone);
-+
-+/* JS RESPONSE CURVES *****************************************************************************/
-+static ssize_t rc_point_index_show(struct device *dev, struct device_attribute *attr, char *buf)
-+{
-+ return sysfs_emit(buf, "move response\n");
-+}
-+
-+ALLY_DEVICE_ATTR_RO(rc_point_index, rc_point_index);
-+
-+static ssize_t __gamepad_write_response_curves_to_mcu(struct hid_device *hdev,
-+ struct ally_gamepad_cfg *ally_cfg)
-+{
-+ u8 *hidbuf;
-+ int ret;
-+
-+ ret = __gamepad_check_ready(hdev);
-+ if (ret < 0)
-+ return ret;
-+
-+ hidbuf = kzalloc(FEATURE_ROG_ALLY_REPORT_SIZE, GFP_KERNEL);
-+ if (!hidbuf)
-+ return -ENOMEM;
-+
-+ hidbuf[0] = FEATURE_ROG_ALLY_REPORT_ID;
-+ hidbuf[1] = FEATURE_ROG_ALLY_CODE_PAGE;
-+ hidbuf[2] = xpad_cmd_set_response_curve;
-+ hidbuf[3] = xpad_cmd_len_response_curve;
-+ hidbuf[4] = 0x01;
-+ memcpy(&hidbuf[5], &ally_cfg->response_curve[ally_cfg->mode - 1][btn_pair_side_left],
-+ 8);
-+
-+ ret = __gamepad_check_ready(hdev);
-+ if (ret < 0)
-+ goto report_fail;
-+
-+ hidbuf[4] = 0x02;
-+ memcpy(&hidbuf[5], &ally_cfg->response_curve[ally_cfg->mode - 1][btn_pair_side_right],
-+ 8);
-+
-+ ret = __gamepad_check_ready(hdev);
-+ if (ret < 0)
-+ goto report_fail;
-+
-+ ret = asus_dev_set_report(hdev, hidbuf, FEATURE_ROG_ALLY_REPORT_SIZE);
-+ if (ret < 0)
-+ goto report_fail;
-+
-+report_fail:
-+ kfree(hidbuf);
-+ return ret;
-+}
-+
-+static ssize_t __gamepad_store_response_curve(struct device *dev, const char *buf,
-+ enum btn_pair_side side, int point)
-+{
-+ struct ally_gamepad_cfg *ally_cfg = drvdata.gamepad_cfg;
-+ u32 move, response;
-+ int idx;
-+
-+ idx = (point - 1) * 2;
-+
-+ if (!drvdata.gamepad_cfg)
-+ return -ENODEV;
-+
-+ if (sscanf(buf, "%d %d", &move, &response) != 2)
-+ return -EINVAL;
-+
-+ if (move > 64 || response > 64)
-+ return -EINVAL;
-+
-+ ally_cfg->response_curve[ally_cfg->mode - 1][side][idx] = move;
-+ ally_cfg->response_curve[ally_cfg->mode - 1][side][idx + 1] = response;
-+
-+ return 0;
-+}
-+
-+ALLY_JS_RC_POINT(left, 1, rc_point_);
-+ALLY_JS_RC_POINT(left, 2, rc_point_);
-+ALLY_JS_RC_POINT(left, 3, rc_point_);
-+ALLY_JS_RC_POINT(left, 4, rc_point_);
-+
-+ALLY_JS_RC_POINT(right, 1, rc_point_);
-+ALLY_JS_RC_POINT(right, 2, rc_point_);
-+ALLY_JS_RC_POINT(right, 3, rc_point_);
-+ALLY_JS_RC_POINT(right, 4, rc_point_);
-+
-+/* CALIBRATIONS ***********************************************************************************/
-+static int __gamepad_get_calibration(struct hid_device *hdev)
-+{
-+ struct ally_gamepad_cfg *ally_cfg = drvdata.gamepad_cfg;
-+ u8 *hidbuf;
-+ int ret, i;
-+
-+ if (!drvdata.gamepad_cfg)
-+ return -ENODEV;
-+
-+ hidbuf = kzalloc(FEATURE_ROG_ALLY_REPORT_SIZE, GFP_KERNEL);
-+ if (!hidbuf)
-+ return -ENOMEM;
-+
-+ for (i = 0; i < 2; i++) {
-+ hidbuf[0] = FEATURE_ROG_ALLY_REPORT_ID;
-+ hidbuf[1] = 0xD0;
-+ hidbuf[2] = 0x03;
-+ hidbuf[3] = i + 1; // 0x01 JS, 0x02 TR
-+ hidbuf[4] = 0x20;
-+
-+ ret = asus_dev_set_report(hdev, hidbuf, FEATURE_ROG_ALLY_REPORT_SIZE);
-+ if (ret < 0) {
-+ hid_warn(hdev, "ROG Ally check failed set report: %d\n", ret);
-+ goto cleanup;
-+ }
-+
-+ memset(hidbuf, 0, FEATURE_ROG_ALLY_REPORT_SIZE);
-+ ret = asus_dev_get_report(hdev, hidbuf, FEATURE_ROG_ALLY_REPORT_SIZE);
-+ if (ret < 0 || hidbuf[5] != 1) {
-+ hid_warn(hdev, "ROG Ally check failed get report: %d\n", ret);
-+ goto cleanup;
-+ }
-+
-+ if (i == 0) {
-+ /* Joystick calibration */
-+ /* [left][index] is Y: stable, min, max. X: stable, min, max */
-+ ally_cfg->js_calibrations[0][3] = (hidbuf[6] << 8) | hidbuf[7];
-+ ally_cfg->js_calibrations[0][4] = (hidbuf[8] << 8) | hidbuf[9];
-+ ally_cfg->js_calibrations[0][5] = (hidbuf[10] << 8) | hidbuf[11];
-+ ally_cfg->js_calibrations[0][0] = (hidbuf[12] << 8) | hidbuf[13];
-+ ally_cfg->js_calibrations[0][1] = (hidbuf[14] << 8) | hidbuf[15];
-+ ally_cfg->js_calibrations[0][2] = (hidbuf[16] << 8) | hidbuf[17];
-+ /* [right][index] is Y: stable, min, max. X: stable, min, max */
-+ ally_cfg->js_calibrations[1][0] = (hidbuf[24] << 8) | hidbuf[25];
-+ ally_cfg->js_calibrations[1][1] = (hidbuf[26] << 8) | hidbuf[27];
-+ ally_cfg->js_calibrations[1][2] = (hidbuf[28] << 8) | hidbuf[29];
-+ ally_cfg->js_calibrations[1][3] = (hidbuf[18] << 8) | hidbuf[19];
-+ ally_cfg->js_calibrations[1][4] = (hidbuf[20] << 8) | hidbuf[21];
-+ ally_cfg->js_calibrations[1][5] = (hidbuf[22] << 8) | hidbuf[23];
-+ } else {
-+ /* Trigger calibration */
-+ /* [left/right][stable/max] */
-+ ally_cfg->tr_calibrations[0][0] = (hidbuf[6] << 8) | hidbuf[7];
-+ ally_cfg->tr_calibrations[0][1] = (hidbuf[8] << 8) | hidbuf[9];
-+ ally_cfg->tr_calibrations[1][0] = (hidbuf[10] << 8) | hidbuf[11];
-+ ally_cfg->tr_calibrations[1][1] = (hidbuf[12] << 8) | hidbuf[13];
-+ }
-+ }
-+
-+cleanup:
-+ kfree(hidbuf);
-+ return ret;
-+}
-+
-+static ssize_t __gamepad_write_cal_to_mcu(struct device *dev, enum xpad_axis axis)
-+{
-+ struct hid_device *hdev = to_hid_device(dev);
-+ struct ally_gamepad_cfg *ally_cfg = drvdata.gamepad_cfg;
-+ u8 *c, side, pkt_len, data_len;
-+ int ret, cal, checksum = 0;
-+ u8 *hidbuf;
-+ int *head;
-+
-+ if (!drvdata.gamepad_cfg)
-+ return -ENODEV;
-+
-+ ret = __gamepad_check_ready(hdev);
-+ if (ret < 0)
-+ return ret;
-+
-+ hidbuf = kzalloc(FEATURE_ROG_ALLY_REPORT_SIZE, GFP_KERNEL);
-+ if (!hidbuf)
-+ return -ENOMEM;
-+
-+ side = axis == xpad_axis_xy_right || axis == xpad_axis_z_right ? 1 : 0;
-+ pkt_len = axis > xpad_axis_xy_right ? 0x06 : 0x0E;
-+ data_len = axis > xpad_axis_xy_right ? 2 : 6;
-+ head = axis > xpad_axis_xy_right ? ally_cfg->tr_calibrations[side] :
-+ ally_cfg->js_calibrations[side];
-+
-+ hidbuf[0] = FEATURE_ROG_ALLY_REPORT_ID;
-+ hidbuf[1] = FEATURE_ROG_ALLY_CODE_PAGE;
-+ hidbuf[2] = xpad_cmd_set_calibration;
-+ hidbuf[3] = pkt_len;
-+ hidbuf[4] = 0x01; /* second command (write calibration) */
-+ hidbuf[5] = axis;
-+ c = &hidbuf[6]; /* pointer to data start */
-+
-+ for (size_t i = 0; i < data_len; i++) {
-+ cal = head[i];
-+ *c = (u8)((cal & 0xff00) >> 8);
-+ checksum += *c;
-+ c += 1;
-+ *c = (u8)(cal & 0xff);
-+ checksum += *c;
-+ c += 1;
-+ }
-+
-+ hidbuf[6 + data_len * 2] = checksum;
-+
-+ ret = asus_dev_set_report(hdev, hidbuf, FEATURE_ROG_ALLY_REPORT_SIZE);
-+ if (ret < 0)
-+ goto report_fail;
-+
-+ memset(hidbuf, 0, FEATURE_ROG_ALLY_REPORT_SIZE);
-+ hidbuf[0] = FEATURE_ROG_ALLY_REPORT_ID;
-+ hidbuf[1] = FEATURE_ROG_ALLY_CODE_PAGE;
-+ hidbuf[2] = xpad_cmd_set_calibration;
-+ hidbuf[3] = xpad_cmd_len_calibration3;
-+ hidbuf[4] = 0x03; /* second command (apply the calibration that was written) */
-+
-+ ret = asus_dev_set_report(hdev, hidbuf, FEATURE_ROG_ALLY_REPORT_SIZE);
-+ if (ret < 0)
-+ goto report_fail;
-+
-+report_fail:
-+ kfree(hidbuf);
-+ return ret;
-+}
-+
-+static ssize_t __gamepad_cal_store(struct device *dev, const char *buf, enum xpad_axis axis)
-+{
-+ struct ally_gamepad_cfg *ally_cfg = drvdata.gamepad_cfg;
-+ u32 x_stable, x_min, x_max, y_stable, y_min, y_max, side;
-+
-+ if (!drvdata.gamepad_cfg)
-+ return -ENODEV;
-+
-+ if (axis == xpad_axis_xy_left || axis == xpad_axis_xy_right) {
-+ if (sscanf(buf, "%d %d %d %d %d %d", &x_stable, &x_min, &x_max, &y_stable,
-+ &y_min, &y_max) != 6)
-+ return -EINVAL;
-+
-+ side = axis == xpad_axis_xy_right || axis == xpad_axis_z_right ? 1 : 0;
-+ /* stored in reverse order for easy copy to packet */
-+ ally_cfg->js_calibrations[side][0] = y_stable;
-+ ally_cfg->js_calibrations[side][1] = y_min;
-+ ally_cfg->js_calibrations[side][2] = y_max;
-+ ally_cfg->js_calibrations[side][3] = x_stable;
-+ ally_cfg->js_calibrations[side][4] = x_min;
-+ ally_cfg->js_calibrations[side][5] = x_max;
-+
-+ return __gamepad_write_cal_to_mcu(dev, axis);
-+ }
-+ if (sscanf(buf, "%d %d", &x_stable, &x_max) != 2)
-+ return -EINVAL;
-+
-+ side = axis == xpad_axis_xy_right || axis == xpad_axis_z_right ? 1 : 0;
-+ /* stored in reverse order for easy copy to packet */
-+ ally_cfg->tr_calibrations[side][0] = x_stable;
-+ ally_cfg->tr_calibrations[side][1] = x_max;
-+
-+ return __gamepad_write_cal_to_mcu(dev, axis);
-+}
-+
-+static ssize_t __gamepad_cal_show(struct device *dev, char *buf, enum xpad_axis axis)
-+{
-+ struct ally_gamepad_cfg *ally_cfg = drvdata.gamepad_cfg;
-+ int side = (axis == xpad_axis_xy_right || axis == xpad_axis_z_right) ? 1 : 0;
-+
-+ if (!drvdata.gamepad_cfg)
-+ return -ENODEV;
-+
-+ if (axis == xpad_axis_xy_left || axis == xpad_axis_xy_right) {
-+ return sysfs_emit(
-+ buf, "%d %d %d %d %d %d\n", ally_cfg->js_calibrations[side][3],
-+ ally_cfg->js_calibrations[side][4], ally_cfg->js_calibrations[side][5],
-+ ally_cfg->js_calibrations[side][0], ally_cfg->js_calibrations[side][1],
-+ ally_cfg->js_calibrations[side][2]);
-+ }
-+
-+ return sysfs_emit(buf, "%d %d\n", ally_cfg->tr_calibrations[side][0],
-+ ally_cfg->tr_calibrations[side][1]);
-+}
-+
-+ALLY_CAL_ATTR(xpad_axis_xy_left_cal, xpad_axis_xy_left, calibration);
-+ALLY_CAL_ATTR(xpad_axis_xy_right_cal, xpad_axis_xy_right, calibration);
-+ALLY_CAL_ATTR(xpad_axis_z_left_cal, xpad_axis_z_left, calibration);
-+ALLY_CAL_ATTR(xpad_axis_z_right_cal, xpad_axis_z_right, calibration);
-+
-+static ssize_t xpad_axis_xy_cal_index_show(struct device *dev, struct device_attribute *attr,
-+ char *buf)
-+{
-+ return sysfs_emit(buf, "x_stable x_min x_max y_stable y_min y_max\n");
-+}
-+
-+ALLY_DEVICE_ATTR_RO(xpad_axis_xy_cal_index, calibration_index);
-+
-+static ssize_t xpad_axis_z_cal_index_show(struct device *dev, struct device_attribute *attr,
-+ char *buf)
-+{
-+ return sysfs_emit(buf, "z_stable z_max\n");
-+}
-+
-+ALLY_DEVICE_ATTR_RO(xpad_axis_z_cal_index, calibration_index);
-+
-+static ssize_t __gamepad_cal_reset(struct device *dev, const char *buf, enum xpad_axis axis)
-+{
-+ struct hid_device *hdev = to_hid_device(dev);
-+ u8 *hidbuf;
-+ int ret;
-+
-+ ret = __gamepad_check_ready(hdev);
-+ if (ret < 0)
-+ return ret;
-+
-+ hidbuf = kzalloc(FEATURE_ROG_ALLY_REPORT_SIZE, GFP_KERNEL);
-+ if (!hidbuf)
-+ return -ENOMEM;
-+
-+ /* Write the reset value, then apply it */
-+ for (u8 cmd = 0x02; cmd <= 0x03; cmd++) {
-+ memset(hidbuf, 0, FEATURE_ROG_ALLY_REPORT_SIZE);
-+ hidbuf[0] = FEATURE_ROG_ALLY_REPORT_ID;
-+ hidbuf[1] = FEATURE_ROG_ALLY_CODE_PAGE;
-+ hidbuf[2] = xpad_cmd_set_calibration;
-+ hidbuf[3] = (cmd == 0x02) ? xpad_cmd_len_calibration2 :
-+ xpad_cmd_len_calibration3;
-+ hidbuf[4] = cmd;
-+ hidbuf[5] = axis;
-+
-+ ret = asus_dev_set_report(hdev, hidbuf, FEATURE_ROG_ALLY_REPORT_SIZE);
-+ if (ret < 0)
-+ break;
-+ }
-+
-+ __gamepad_get_calibration(hdev);
-+
-+ kfree(hidbuf);
-+ return ret;
-+}
-+
-+ALLY_CAL_RESET_ATTR(xpad_axis_xy_left_cal_reset, xpad_axis_xy_left, calibration_reset);
-+ALLY_CAL_RESET_ATTR(xpad_axis_xy_right_cal_reset, xpad_axis_xy_right, calibration_reset);
-+ALLY_CAL_RESET_ATTR(xpad_axis_z_left_cal_reset, xpad_axis_z_left, calibration_reset);
-+ALLY_CAL_RESET_ATTR(xpad_axis_z_right_cal_reset, xpad_axis_z_right, calibration_reset);
-+
-+static struct attribute *gamepad_axis_xy_left_attrs[] = {
-+ &dev_attr_xpad_axis_xy_left_deadzone.attr,
-+ &dev_attr_axis_xyz_deadzone_index.attr,
-+ &dev_attr_xpad_axis_xy_left_ADZ.attr,
-+ &dev_attr_xpad_axis_xy_left_cal_reset.attr,
-+ &dev_attr_xpad_axis_xy_left_cal.attr,
-+ &dev_attr_xpad_axis_xy_cal_index.attr,
-+ &dev_attr_rc_point_left_1.attr,
-+ &dev_attr_rc_point_left_2.attr,
-+ &dev_attr_rc_point_left_3.attr,
-+ &dev_attr_rc_point_left_4.attr,
-+ &dev_attr_rc_point_index.attr,
-+ NULL
-+};
-+static const struct attribute_group ally_controller_axis_xy_left_attr_group = {
-+ .name = "axis_xy_left",
-+ .attrs = gamepad_axis_xy_left_attrs,
-+};
-+
-+static struct attribute *gamepad_axis_xy_right_attrs[] = {
-+ &dev_attr_xpad_axis_xy_right_deadzone.attr,
-+ &dev_attr_axis_xyz_deadzone_index.attr,
-+ &dev_attr_xpad_axis_xy_right_ADZ.attr,
-+ &dev_attr_xpad_axis_xy_right_cal_reset.attr,
-+ &dev_attr_xpad_axis_xy_right_cal.attr,
-+ &dev_attr_xpad_axis_xy_cal_index.attr,
-+ &dev_attr_rc_point_right_1.attr,
-+ &dev_attr_rc_point_right_2.attr,
-+ &dev_attr_rc_point_right_3.attr,
-+ &dev_attr_rc_point_right_4.attr,
-+ &dev_attr_rc_point_index.attr,
-+ NULL
-+};
-+static const struct attribute_group ally_controller_axis_xy_right_attr_group = {
-+ .name = "axis_xy_right",
-+ .attrs = gamepad_axis_xy_right_attrs,
-+};
-+
-+static struct attribute *gamepad_axis_z_left_attrs[] = {
-+ &dev_attr_xpad_axis_z_left_deadzone.attr, &dev_attr_axis_xyz_deadzone_index.attr,
-+ &dev_attr_xpad_axis_z_left_cal.attr, &dev_attr_xpad_axis_z_cal_index.attr,
-+ &dev_attr_xpad_axis_z_left_cal_reset.attr, NULL
-+};
-+static const struct attribute_group ally_controller_axis_z_left_attr_group = {
-+ .name = "axis_z_left",
-+ .attrs = gamepad_axis_z_left_attrs,
-+};
-+
-+static struct attribute *gamepad_axis_z_right_attrs[] = {
-+ &dev_attr_xpad_axis_z_right_deadzone.attr, &dev_attr_axis_xyz_deadzone_index.attr,
-+ &dev_attr_xpad_axis_z_right_cal.attr, &dev_attr_xpad_axis_z_cal_index.attr,
-+ &dev_attr_xpad_axis_z_right_cal_reset.attr, NULL
-+};
-+static const struct attribute_group ally_controller_axis_z_right_attr_group = {
-+ .name = "axis_z_right",
-+ .attrs = gamepad_axis_z_right_attrs,
-+};
-+
-+static const struct attribute_group *gamepad_device_attr_groups[] = {
-+ &ally_controller_attr_group,
-+ &ally_controller_axis_xy_left_attr_group,
-+ &ally_controller_axis_xy_right_attr_group,
-+ &ally_controller_axis_z_left_attr_group,
-+ &ally_controller_axis_z_right_attr_group,
-+ &btn_mapping_m1_attr_group,
-+ &btn_mapping_m2_attr_group,
-+ &btn_mapping_a_attr_group,
-+ &btn_mapping_b_attr_group,
-+ &btn_mapping_x_attr_group,
-+ &btn_mapping_y_attr_group,
-+ &btn_mapping_lb_attr_group,
-+ &btn_mapping_rb_attr_group,
-+ &btn_mapping_ls_attr_group,
-+ &btn_mapping_rs_attr_group,
-+ &btn_mapping_dpad_u_attr_group,
-+ &btn_mapping_dpad_d_attr_group,
-+ &btn_mapping_dpad_l_attr_group,
-+ &btn_mapping_dpad_r_attr_group,
-+ &btn_mapping_view_attr_group,
-+ &btn_mapping_menu_attr_group,
-+ NULL
-+};
-+
-+static int __gamepad_write_all_to_mcu(struct hid_device *hdev,
-+ struct ally_gamepad_cfg *ally_cfg)
-+{
-+ u8 *hidbuf;
-+ int ret;
-+
-+ ret = __gamepad_set_mapping(hdev, ally_cfg, btn_pair_dpad_u_d);
-+ if (ret < 0)
-+ return ret;
-+ ret = __gamepad_set_mapping(hdev, ally_cfg, btn_pair_dpad_l_r);
-+ if (ret < 0)
-+ return ret;
-+ ret = __gamepad_set_mapping(hdev, ally_cfg, btn_pair_ls_rs);
-+ if (ret < 0)
-+ return ret;
-+ ret = __gamepad_set_mapping(hdev, ally_cfg, btn_pair_lb_rb);
-+ if (ret < 0)
-+ return ret;
-+ ret = __gamepad_set_mapping(hdev, ally_cfg, btn_pair_a_b);
-+ if (ret < 0)
-+ return ret;
-+ ret = __gamepad_set_mapping(hdev, ally_cfg, btn_pair_x_y);
-+ if (ret < 0)
-+ return ret;
-+ ret = __gamepad_set_mapping(hdev, ally_cfg, btn_pair_view_menu);
-+ if (ret < 0)
-+ return ret;
-+ ret = __gamepad_set_mapping(hdev, ally_cfg, btn_pair_m1_m2);
-+ if (ret < 0)
-+ return ret;
-+ __gamepad_set_mapping(hdev, ally_cfg, btn_pair_lt_rt);
-+ if (ret < 0)
-+ return ret;
-+ __gamepad_set_deadzones(hdev, ally_cfg);
-+ if (ret < 0)
-+ return ret;
-+ __gamepad_write_js_ADZ_to_mcu(hdev, ally_cfg);
-+ if (ret < 0)
-+ return ret;
-+ __gamepad_write_vibe_intensity_to_mcu(hdev, ally_cfg);
-+ if (ret < 0)
-+ return ret;
-+ __gamepad_write_response_curves_to_mcu(hdev, ally_cfg);
-+ if (ret < 0)
-+ return ret;
-+ ret = __gamepad_check_ready(hdev);
-+ if (ret < 0)
-+ return ret;
-+
-+ /* set turbo */
-+ hidbuf = kzalloc(FEATURE_ROG_ALLY_REPORT_SIZE, GFP_KERNEL);
-+ if (!hidbuf)
-+ return -ENOMEM;
-+ hidbuf[0] = FEATURE_ROG_ALLY_REPORT_ID;
-+ hidbuf[1] = FEATURE_ROG_ALLY_CODE_PAGE;
-+ hidbuf[2] = xpad_cmd_set_turbo;
-+ hidbuf[3] = xpad_cmd_len_turbo;
-+ memcpy(&hidbuf[4], ally_cfg->turbo_btns[ally_cfg->mode - 1], TURBO_BLOCK_LEN);
-+ ret = asus_dev_set_report(hdev, hidbuf, FEATURE_ROG_ALLY_REPORT_SIZE);
-+
-+ kfree(hidbuf);
-+ return ret;
-+}
-+
-+static struct ally_gamepad_cfg *ally_gamepad_cfg_create(struct hid_device *hdev)
-+{
-+ struct ally_gamepad_cfg *ally_cfg;
-+ struct input_dev *input_dev;
-+ int i, err;
-+
-+ ally_cfg = devm_kzalloc(&hdev->dev, sizeof(*ally_cfg), GFP_KERNEL);
-+ if (!ally_cfg)
-+ return ERR_PTR(-ENOMEM);
-+ ally_cfg->hdev = hdev;
-+
-+ input_dev = devm_input_allocate_device(&hdev->dev);
-+ if (!input_dev) {
-+ err = -ENOMEM;
-+ goto free_ally_cfg;
-+ }
-+ ally_cfg->input = input_dev;
-+
-+ input_dev->id.bustype = hdev->bus;
-+ input_dev->id.vendor = hdev->vendor;
-+ input_dev->id.product = hdev->product;
-+ input_dev->id.version = hdev->version;
-+ input_dev->uniq = hdev->uniq;
-+ input_dev->name = "ASUS ROG Ally Config";
-+ input_set_capability(input_dev, EV_KEY, KEY_PROG1);
-+ input_set_capability(input_dev, EV_KEY, KEY_F16);
-+ input_set_capability(input_dev, EV_KEY, KEY_F17);
-+ input_set_capability(input_dev, EV_KEY, KEY_F18);
-+
-+ input_set_drvdata(input_dev, hdev);
-+
-+ err = input_register_device(input_dev);
-+ if (err)
-+ goto free_input_dev;
-+
-+ ally_cfg->mode = xpad_mode_game;
-+ for (i = 0; i < xpad_mode_mouse; i++) {
-+ ally_cfg->deadzones[i][0][1] = 64;
-+ ally_cfg->deadzones[i][0][3] = 64;
-+ ally_cfg->deadzones[i][1][1] = 64;
-+ ally_cfg->deadzones[i][1][3] = 64;
-+ ally_cfg->response_curve[i][0][0] = 0x14;
-+ ally_cfg->response_curve[i][0][1] = 0x14;
-+ ally_cfg->response_curve[i][0][2] = 0x28;
-+ ally_cfg->response_curve[i][0][3] = 0x28;
-+ ally_cfg->response_curve[i][0][4] = 0x3c;
-+ ally_cfg->response_curve[i][0][5] = 0x3c;
-+ ally_cfg->response_curve[i][0][6] = 0x63;
-+ ally_cfg->response_curve[i][0][7] = 0x63;
-+ ally_cfg->response_curve[i][1][0] = 0x14;
-+ ally_cfg->response_curve[i][1][1] = 0x14;
-+ ally_cfg->response_curve[i][1][2] = 0x28;
-+ ally_cfg->response_curve[i][1][3] = 0x28;
-+ ally_cfg->response_curve[i][1][4] = 0x3c;
-+ ally_cfg->response_curve[i][1][5] = 0x3c;
-+ ally_cfg->response_curve[i][1][6] = 0x63;
-+ ally_cfg->response_curve[i][1][7] = 0x63;
-+ ally_cfg->vibration_intensity[i][0] = 64;
-+ ally_cfg->vibration_intensity[i][1] = 64;
-+ }
-+ drvdata.gamepad_cfg = ally_cfg;
-+
-+ /* ignore all errors for this as they are related to USB HID I/O */
-+ __gamepad_mapping_xpad_default(ally_cfg);
-+ __gamepad_mapping_wasd_default(ally_cfg);
-+ /* these calls will never error so ignore the return */
-+ __gamepad_mapping_store(ally_cfg, KB_M2, btn_pair_m1_m2, btn_pair_side_left, false);
-+ __gamepad_mapping_store(ally_cfg, KB_M1, btn_pair_m1_m2, btn_pair_side_right, false);
-+ __gamepad_set_mode(hdev, ally_cfg, xpad_mode_game);
-+ __gamepad_set_mapping(hdev, ally_cfg, btn_pair_m1_m2);
-+ /* ensure we have data for users to start from */
-+ __gamepad_get_calibration(hdev);
-+
-+ if (sysfs_create_groups(&hdev->dev.kobj, gamepad_device_attr_groups)) {
-+ err = -ENODEV;
-+ goto unregister_input_dev;
-+ }
-+
-+ return ally_cfg;
-+
-+unregister_input_dev:
-+ input_unregister_device(input_dev);
-+ ally_cfg->input = NULL; // Prevent double free when kfree(ally_cfg) happens
-+
-+free_input_dev:
-+ devm_kfree(&hdev->dev, input_dev);
-+
-+free_ally_cfg:
-+ devm_kfree(&hdev->dev, ally_cfg);
-+ return ERR_PTR(err);
-+}
-+
-+static void ally_cfg_remove(struct hid_device *hdev)
-+{
-+ __gamepad_set_mode(hdev, drvdata.gamepad_cfg, xpad_mode_mouse);
-+ sysfs_remove_groups(&hdev->dev.kobj, gamepad_device_attr_groups);
-+}
-+
-+/**************************************************************************************************/
-+/* ROG Ally LED control */
-+/**************************************************************************************************/
-+static void ally_schedule_work(struct ally_rgb_leds *led)
-+{
-+ unsigned long flags;
-+
-+ spin_lock_irqsave(&led->lock, flags);
-+ if (!led->removed)
-+ schedule_work(&led->work);
-+ spin_unlock_irqrestore(&led->lock, flags);
-+ pr_warn("5");
-+}
-+
-+static void ally_led_do_brightness(struct work_struct *work)
-+{
-+ struct ally_rgb_leds *led = container_of(work, struct ally_rgb_leds, work);
-+ u8 buf1[] = { FEATURE_ROG_ALLY_REPORT_ID, 0xb4, 0x00, 0x00, 0x00 };
-+ u8 buf[] = { FEATURE_ROG_ALLY_REPORT_ID, 0xba, 0xc5, 0xc4, 0x00 };
-+ unsigned long flags;
-+
-+ spin_lock_irqsave(&led->lock, flags);
-+ if (!led->update_bright) {
-+ spin_unlock_irqrestore(&led->lock, flags);
-+ return;
-+ }
-+ led->update_bright = false;
-+ buf[4] = led->brightness;
-+ spin_unlock_irqrestore(&led->lock, flags);
-+
-+ if (asus_dev_set_report(led->hdev, buf, sizeof(buf)) < 0)
-+ hid_err(led->hdev, "Ally failed to set backlight\n");
-+ if (asus_dev_set_report(led->hdev, buf1, sizeof(buf1)) < 0)
-+ hid_err(led->hdev, "Ally failed to set backlight\n");
-+}
-+
-+static void ally_led_do_rgb(struct work_struct *work)
-+{
-+ struct ally_rgb_leds *led = container_of(work, struct ally_rgb_leds, work);
-+ unsigned long flags;
-+ int ret;
-+
-+ u8 buf[16] = { [0] = FEATURE_ROG_ALLY_REPORT_ID,
-+ [1] = FEATURE_ROG_ALLY_CODE_PAGE,
-+ [2] = xpad_cmd_set_leds,
-+ [3] = xpad_cmd_len_leds };
-+
-+ spin_lock_irqsave(&led->lock, flags);
-+ if (!led->update_rgb) {
-+ spin_unlock_irqrestore(&led->lock, flags);
-+ return;
-+ }
-+ for (int i = 0; i < 4; i++) {
-+ buf[4 + i * 3] = led->gamepad_red;
-+ buf[5 + i * 3] = led->gamepad_green;
-+ buf[6 + i * 3] = led->gamepad_blue;
-+ }
-+ led->update_rgb = false;
-+ spin_unlock_irqrestore(&led->lock, flags);
-+
-+ ret = asus_dev_set_report(led->hdev, buf, sizeof(buf));
-+ if (ret < 0)
-+ hid_err(led->hdev, "Ally failed to set gamepad backlight: %d\n", ret);
-+}
-+
-+static void ally_led_work(struct work_struct *work)
-+{
-+ ally_led_do_brightness(work);
-+ ally_led_do_rgb(work);
-+}
-+
-+static void ally_backlight_set(struct led_classdev *led_cdev, enum led_brightness brightness)
-+{
-+ struct ally_rgb_leds *led =
-+ container_of(led_cdev, struct ally_rgb_leds, led_bright_dev);
-+ unsigned long flags;
-+
-+ spin_lock_irqsave(&led->lock, flags);
-+ led->update_bright = true;
-+ led->brightness = brightness;
-+ spin_unlock_irqrestore(&led->lock, flags);
-+
-+ ally_schedule_work(led);
-+}
-+
-+static enum led_brightness ally_backlight_get(struct led_classdev *led_cdev)
-+{
-+ struct ally_rgb_leds *led =
-+ container_of(led_cdev, struct ally_rgb_leds, led_bright_dev);
-+ enum led_brightness brightness;
-+ unsigned long flags;
-+
-+ spin_lock_irqsave(&led->lock, flags);
-+ brightness = led->brightness;
-+ spin_unlock_irqrestore(&led->lock, flags);
-+
-+ return brightness;
-+}
-+
-+static void ally_set_rgb_brightness(struct led_classdev *cdev, enum led_brightness brightness)
-+{
-+ struct led_classdev_mc *mc_cdev = lcdev_to_mccdev(cdev);
-+ struct ally_rgb_leds *led = container_of(mc_cdev, struct ally_rgb_leds, led_rgb_dev);
-+ unsigned long flags;
-+
-+ led_mc_calc_color_components(mc_cdev, brightness);
-+ spin_lock_irqsave(&led->lock, flags);
-+ led->update_rgb = true;
-+ led->gamepad_red = mc_cdev->subled_info[0].brightness;
-+ led->gamepad_green = mc_cdev->subled_info[1].brightness;
-+ led->gamepad_blue = mc_cdev->subled_info[2].brightness;
-+ spin_unlock_irqrestore(&led->lock, flags);
-+
-+ ally_schedule_work(led);
-+}
-+
-+static int ally_gamepad_register_brightness(struct hid_device *hdev,
-+ struct ally_rgb_leds *led_rgb)
-+{
-+ struct led_classdev *led_cdev;
-+
-+ led_cdev = &led_rgb->led_bright_dev;
-+ led_cdev->name = "ally:kbd_backlight"; /* Let a desktop control it also */
-+ led_cdev->max_brightness = 3;
-+ led_cdev->brightness_set = ally_backlight_set;
-+ led_cdev->brightness_get = ally_backlight_get;
-+
-+ return devm_led_classdev_register(&hdev->dev, &led_rgb->led_bright_dev);
-+}
-+
-+static int ally_gamepad_register_rgb_leds(struct hid_device *hdev,
-+ struct ally_rgb_leds *led_rgb)
-+{
-+ struct mc_subled *mc_led_info;
-+ struct led_classdev *led_cdev;
-+
-+ mc_led_info = devm_kmalloc_array(&hdev->dev, 3, sizeof(*mc_led_info),
-+ GFP_KERNEL | __GFP_ZERO);
-+ if (!mc_led_info)
-+ return -ENOMEM;
-+
-+ mc_led_info[0].color_index = LED_COLOR_ID_RED;
-+ mc_led_info[1].color_index = LED_COLOR_ID_GREEN;
-+ mc_led_info[2].color_index = LED_COLOR_ID_BLUE;
-+
-+ led_rgb->led_rgb_dev.subled_info = mc_led_info;
-+ led_rgb->led_rgb_dev.num_colors = 3;
-+
-+ led_cdev = &led_rgb->led_rgb_dev.led_cdev;
-+ led_cdev->name = "ally:rgb:gamepad";
-+ led_cdev->brightness = 128;
-+ led_cdev->max_brightness = 255;
-+ led_cdev->brightness_set = ally_set_rgb_brightness;
-+
-+ return devm_led_classdev_multicolor_register(&hdev->dev, &led_rgb->led_rgb_dev);
-+}
-+
-+static struct ally_rgb_leds *ally_gamepad_rgb_create(struct hid_device *hdev)
-+{
-+ struct ally_rgb_leds *led_rgb;
-+ int ret;
-+
-+ led_rgb = devm_kzalloc(&hdev->dev, sizeof(struct ally_rgb_leds), GFP_KERNEL);
-+ if (!led_rgb)
-+ return ERR_PTR(-ENOMEM);
-+
-+ ret = ally_gamepad_register_rgb_leds(hdev, led_rgb);
-+ if (ret < 0) {
-+ cancel_work_sync(&led_rgb->work);
-+ devm_kfree(&hdev->dev, led_rgb);
-+ return ERR_PTR(ret);
-+ }
-+
-+ ret = ally_gamepad_register_brightness(hdev, led_rgb);
-+ if (ret < 0) {
-+ cancel_work_sync(&led_rgb->work);
-+ devm_kfree(&hdev->dev, led_rgb);
-+ return ERR_PTR(ret);
-+ }
-+
-+ led_rgb->hdev = hdev;
-+ led_rgb->brightness = 3;
-+ led_rgb->removed = false;
-+
-+ INIT_WORK(&led_rgb->work, ally_led_work);
-+ spin_lock_init(&led_rgb->lock);
-+
-+ return led_rgb;
-+}
-+
-+static void ally_rgb_remove(struct hid_device *hdev)
-+{
-+ struct ally_rgb_leds *led_rgb = drvdata.led_rgb;
-+ unsigned long flags;
-+
-+ spin_lock_irqsave(&led_rgb->lock, flags);
-+ led_rgb->removed = true;
-+ spin_unlock_irqrestore(&led_rgb->lock, flags);
-+ cancel_work_sync(&led_rgb->work);
-+}
-+
-+/**************************************************************************************************/
-+/* ROG Ally driver init */
-+/**************************************************************************************************/
-+static int ally_raw_event(struct hid_device *hdev, struct hid_report *report, u8 *data,
-+ int size)
-+{
-+ struct ally_gamepad_cfg *cfg = drvdata.gamepad_cfg;
-+ struct ally_x_device *ally_x = drvdata.ally_x;
-+
-+ if (ally_x) {
-+ if ((hdev->bus == BUS_USB && report->id == ALLY_X_INPUT_REPORT_USB &&
-+ size == ALLY_X_INPUT_REPORT_USB_SIZE) ||
-+ (cfg && data[0] == 0x5A)) {
-+ ally_x_raw_event(ally_x, report, data, size);
-+ } else {
-+ return -1;
-+ }
-+ }
-+ if (cfg && !ally_x) {
-+ input_report_key(cfg->input, KEY_PROG1, data[1] == 0x38);
-+ input_report_key(cfg->input, KEY_F16, data[1] == 0xA6);
-+ input_report_key(cfg->input, KEY_F17, data[1] == 0xA7);
-+ input_report_key(cfg->input, KEY_F18, data[1] == 0xA8);
-+ input_sync(cfg->input);
-+ }
-+
-+ return 0;
-+}
-+
-+static int ally_gamepad_init(struct hid_device *hdev, u8 report_id)
-+{
-+ const u8 buf[] = { report_id, 0x41, 0x53, 0x55, 0x53, 0x20, 0x54, 0x65,
-+ 0x63, 0x68, 0x2e, 0x49, 0x6e, 0x63, 0x2e, 0x00 };
-+ int ret;
-+
-+ ret = asus_dev_set_report(hdev, buf, sizeof(buf));
-+ if (ret < 0)
-+ hid_err(hdev, "Ally failed to send init command: %d\n", ret);
-+
-+ return ret;
-+}
-+
-+static int ally_probe(struct hid_device *hdev, const struct hid_device_id *id)
-+{
-+ struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
-+ struct usb_host_endpoint *ep = intf->cur_altsetting->endpoint;
-+ int ret;
-+
-+ if (ep->desc.bEndpointAddress != ALLY_CFG_INTF_IN_ADDRESS &&
-+ ep->desc.bEndpointAddress != ALLY_X_INTERFACE_ADDRESS)
-+ return -ENODEV;
-+
-+ ret = hid_parse(hdev);
-+ if (ret) {
-+ hid_err(hdev, "Parse failed\n");
-+ return ret;
-+ }
-+
-+ ret = hid_hw_start(hdev, HID_CONNECT_HIDRAW);
-+ if (ret) {
-+ hid_err(hdev, "Failed to start HID device\n");
-+ return ret;
-+ }
-+
-+ ret = hid_hw_open(hdev);
-+ if (ret) {
-+ hid_err(hdev, "Failed to open HID device\n");
-+ goto err_stop;
-+ }
-+
-+ /* Initialize MCU even before alloc */
-+ ret = ally_gamepad_init(hdev, FEATURE_REPORT_ID);
-+ if (ret < 0)
-+ return ret;
-+
-+ ret = ally_gamepad_init(hdev, FEATURE_KBD_LED_REPORT_ID1);
-+ if (ret < 0)
-+ return ret;
-+
-+ ret = ally_gamepad_init(hdev, FEATURE_KBD_LED_REPORT_ID2);
-+ if (ret < 0)
-+ return ret;
-+
-+ drvdata.hdev = hdev;
-+ hid_set_drvdata(hdev, &drvdata);
-+
-+ /* This should almost always exist */
-+ if (ep->desc.bEndpointAddress == ALLY_CFG_INTF_IN_ADDRESS) {
-+ drvdata.led_rgb = ally_gamepad_rgb_create(hdev);
-+ if (IS_ERR(drvdata.led_rgb))
-+ hid_err(hdev, "Failed to create Ally gamepad LEDs.\n");
-+ else
-+ hid_info(hdev, "Created Ally RGB LED controls.\n");
-+
-+ ally_gamepad_cfg_create(hdev); // assigns self
-+ if (IS_ERR(drvdata.gamepad_cfg))
-+ hid_err(hdev, "Failed to create Ally gamepad attributes.\n");
-+ else
-+ hid_info(hdev, "Created Ally gamepad attributes.\n");
-+
-+ if (IS_ERR(drvdata.led_rgb) && IS_ERR(drvdata.gamepad_cfg))
-+ goto err_close;
-+ }
-+
-+ /* May or may not exist */
-+ if (ep->desc.bEndpointAddress == ALLY_X_INTERFACE_ADDRESS) {
-+ drvdata.ally_x = ally_x_create(hdev);
-+ if (IS_ERR(drvdata.ally_x)) {
-+ hid_err(hdev, "Failed to create Ally X gamepad.\n");
-+ drvdata.ally_x = NULL;
-+ goto err_close;
-+ }
-+ hid_info(hdev, "Created Ally X controller.\n");
-+
-+ // Not required since we send this inputs ep through the gamepad input dev
-+ if (drvdata.gamepad_cfg && drvdata.gamepad_cfg->input) {
-+ input_unregister_device(drvdata.gamepad_cfg->input);
-+ hid_info(hdev, "Ally X removed unrequired input dev.\n");
-+ }
-+ }
-+
-+ return 0;
-+
-+err_close:
-+ hid_hw_close(hdev);
-+err_stop:
-+ hid_hw_stop(hdev);
-+ return ret;
-+}
-+
-+static void ally_remove(struct hid_device *hdev)
-+{
-+ if (drvdata.ally_x)
-+ ally_x_remove(hdev);
-+ if (drvdata.led_rgb)
-+ ally_rgb_remove(hdev);
-+ if (drvdata.gamepad_cfg)
-+ ally_cfg_remove(hdev);
-+ hid_hw_close(hdev);
-+ hid_hw_stop(hdev);
-+}
-+
-+static int ally_resume(struct hid_device *hdev)
-+{
-+ int ret;
-+
-+ ret = ally_gamepad_init(hdev, FEATURE_REPORT_ID);
-+ if (ret < 0)
-+ return ret;
-+
-+ ret = ally_gamepad_init(hdev, FEATURE_KBD_LED_REPORT_ID1);
-+ if (ret < 0)
-+ return ret;
-+
-+ ret = ally_gamepad_init(hdev, FEATURE_KBD_LED_REPORT_ID2);
-+ if (ret < 0)
-+ return ret;
-+
-+ if (drvdata.ally_x && drvdata.ally_x->output_worker_initialized)
-+ schedule_work(&drvdata.ally_x->output_worker);
-+
-+ return ret;
-+}
-+
-+MODULE_DEVICE_TABLE(hid, rog_ally_devices);
-+
-+static struct hid_driver rog_ally_cfg = {
-+ .name = "asus_rog_ally",
-+ .id_table = rog_ally_devices,
-+ .probe = ally_probe,
-+ .remove = ally_remove,
-+ .raw_event = ally_raw_event,
-+ .resume = ally_resume,
-+};
-+
-+static int __init rog_ally_cfg_init(void)
-+{
-+ return hid_register_driver(&rog_ally_cfg);
-+}
-+
-+static void __exit rog_ally_cfg_exit(void)
-+{
-+ hid_unregister_driver(&rog_ally_cfg);
-+}
-+
-+module_init(rog_ally_cfg_init);
-+module_exit(rog_ally_cfg_exit);
-+
-+MODULE_AUTHOR("Luke D. Jones");
-+MODULE_DESCRIPTION("HID Driver for ASUS ROG Ally gamepad configuration.");
-+MODULE_LICENSE("GPL");
-diff --git a/drivers/hid/hid-asus-ally.h b/drivers/hid/hid-asus-ally.h
-new file mode 100644
-index 000000000000..252d9f126e32
---- /dev/null
-+++ b/drivers/hid/hid-asus-ally.h
-@@ -0,0 +1,544 @@
-+/* SPDX-License-Identifier: GPL-2.0-or-later
-+ *
-+ * HID driver for Asus ROG laptops and Ally
-+ *
-+ * Copyright (c) 2023 Luke Jones <luke@ljones.dev>
-+ */
-+
-+#include <linux/hid.h>
-+#include <linux/types.h>
-+
-+#define ALLY_X_INTERFACE_ADDRESS 0x87
-+
-+#define BTN_CODE_LEN 11
-+#define MAPPING_BLOCK_LEN 44
-+
-+#define TURBO_BLOCK_LEN 32
-+#define TURBO_BLOCK_STEP 2
-+
-+#define PAD_A "pad_a"
-+#define PAD_B "pad_b"
-+#define PAD_X "pad_x"
-+#define PAD_Y "pad_y"
-+#define PAD_LB "pad_lb"
-+#define PAD_RB "pad_rb"
-+#define PAD_LS "pad_ls"
-+#define PAD_RS "pad_rs"
-+#define PAD_DPAD_UP "pad_dpad_up"
-+#define PAD_DPAD_DOWN "pad_dpad_down"
-+#define PAD_DPAD_LEFT "pad_dpad_left"
-+#define PAD_DPAD_RIGHT "pad_dpad_right"
-+#define PAD_VIEW "pad_view"
-+#define PAD_MENU "pad_menu"
-+#define PAD_XBOX "pad_xbox"
-+
-+#define KB_M1 "kb_m1"
-+#define KB_M2 "kb_m2"
-+#define KB_ESC "kb_esc"
-+#define KB_F1 "kb_f1"
-+#define KB_F2 "kb_f2"
-+#define KB_F3 "kb_f3"
-+#define KB_F4 "kb_f4"
-+#define KB_F5 "kb_f5"
-+#define KB_F6 "kb_f6"
-+#define KB_F7 "kb_f7"
-+#define KB_F8 "kb_f8"
-+#define KB_F9 "kb_f9"
-+#define KB_F10 "kb_f10"
-+#define KB_F11 "kb_f11"
-+#define KB_F12 "kb_f12"
-+#define KB_F14 "kb_f14"
-+#define KB_F15 "kb_f15"
-+
-+#define KB_BACKTICK "kb_backtick"
-+#define KB_1 "kb_1"
-+#define KB_2 "kb_2"
-+#define KB_3 "kb_3"
-+#define KB_4 "kb_4"
-+#define KB_5 "kb_5"
-+#define KB_6 "kb_6"
-+#define KB_7 "kb_7"
-+#define KB_8 "kb_8"
-+#define KB_9 "kb_9"
-+#define KB_0 "kb_0"
-+#define KB_HYPHEN "kb_hyphen"
-+#define KB_EQUALS "kb_equals"
-+#define KB_BACKSPACE "kb_backspace"
-+
-+#define KB_TAB "kb_tab"
-+#define KB_Q "kb_q"
-+#define KB_W "kb_w"
-+#define KB_E "kb_e"
-+#define KB_R "kb_r"
-+#define KB_T "kb_t"
-+#define KB_Y "kb_y"
-+#define KB_U "kb_u"
-+#define KB_I "kb_i"
-+#define KB_O "kb_o"
-+#define KB_P "kb_p"
-+#define KB_LBRACKET "kb_lbracket"
-+#define KB_RBRACKET "kb_rbracket"
-+#define KB_BACKSLASH "kb_bkslash"
-+
-+#define KB_CAPS "kb_caps"
-+#define KB_A "kb_a"
-+#define KB_S "kb_s"
-+#define KB_D "kb_d"
-+#define KB_F "kb_f"
-+#define KB_G "kb_g"
-+#define KB_H "kb_h"
-+#define KB_J "kb_j"
-+#define KB_K "kb_k"
-+#define KB_L "kb_l"
-+#define KB_SEMI "kb_semicolon"
-+#define KB_QUOTE "kb_quote"
-+#define KB_RET "kb_enter"
-+
-+#define KB_LSHIFT "kb_lshift"
-+#define KB_Z "kb_z"
-+#define KB_X "kb_x"
-+#define KB_C "kb_c"
-+#define KB_V "kb_v"
-+#define KB_B "kb_b"
-+#define KB_N "kb_n"
-+#define KB_M "kb_m"
-+#define KB_COMMA "kb_comma"
-+#define KB_PERIOD "kb_period"
-+#define KB_FWDSLASH "kb_fwdslash"
-+#define KB_RSHIFT "kb_rshift"
-+
-+#define KB_LCTL "kb_lctl"
-+#define KB_META "kb_meta"
-+#define KB_LALT "kb_lalt"
-+#define KB_SPACE "kb_space"
-+#define KB_RALT "kb_ralt"
-+#define KB_MENU "kb_menu"
-+#define KB_RCTL "kb_rctl"
-+
-+#define KB_PRNTSCN "kb_prntscn"
-+#define KB_SCRLCK "kb_scrlck"
-+#define KB_PAUSE "kb_pause"
-+#define KB_INS "kb_ins"
-+#define KB_HOME "kb_home"
-+#define KB_PGUP "kb_pgup"
-+#define KB_DEL "kb_del"
-+#define KB_END "kb_end"
-+#define KB_PGDWN "kb_pgdwn"
-+
-+#define KB_UP_ARROW "kb_up_arrow"
-+#define KB_DOWN_ARROW "kb_down_arrow"
-+#define KB_LEFT_ARROW "kb_left_arrow"
-+#define KB_RIGHT_ARROW "kb_right_arrow"
-+
-+#define NUMPAD_LOCK "numpad_lock"
-+#define NUMPAD_FWDSLASH "numpad_fwdslash"
-+#define NUMPAD_ASTERISK "numpad_asterisk"
-+#define NUMPAD_HYPHEN "numpad_hyphen"
-+#define NUMPAD_0 "numpad_0"
-+#define NUMPAD_1 "numpad_1"
-+#define NUMPAD_2 "numpad_2"
-+#define NUMPAD_3 "numpad_3"
-+#define NUMPAD_4 "numpad_4"
-+#define NUMPAD_5 "numpad_5"
-+#define NUMPAD_6 "numpad_6"
-+#define NUMPAD_7 "numpad_7"
-+#define NUMPAD_8 "numpad_8"
-+#define NUMPAD_9 "numpad_9"
-+#define NUMPAD_PLUS "numpad_plus"
-+#define NUMPAD_ENTER "numpad_enter"
-+#define NUMPAD_PERIOD "numpad_."
-+
-+#define MOUSE_LCLICK "rat_lclick"
-+#define MOUSE_RCLICK "rat_rclick"
-+#define MOUSE_MCLICK "rat_mclick"
-+#define MOUSE_WHEEL_UP "rat_wheel_up"
-+#define MOUSE_WHEEL_DOWN "rat_wheel_down"
-+
-+#define MEDIA_SCREENSHOT "media_screenshot"
-+#define MEDIA_SHOW_KEYBOARD "media_show_keyboard"
-+#define MEDIA_SHOW_DESKTOP "media_show_desktop"
-+#define MEDIA_START_RECORDING "media_start_recording"
-+#define MEDIA_MIC_OFF "media_mic_off"
-+#define MEDIA_VOL_DOWN "media_vol_down"
-+#define MEDIA_VOL_UP "media_vol_up"
-+
-+/* required so we can have nested attributes with same name but different functions */
-+#define ALLY_DEVICE_ATTR_RW(_name, _sysfs_name) \
-+ struct device_attribute dev_attr_##_name = \
-+ __ATTR(_sysfs_name, 0644, _name##_show, _name##_store)
-+
-+#define ALLY_DEVICE_ATTR_RO(_name, _sysfs_name) \
-+ struct device_attribute dev_attr_##_name = \
-+ __ATTR(_sysfs_name, 0444, _name##_show, NULL)
-+
-+#define ALLY_DEVICE_ATTR_WO(_name, _sysfs_name) \
-+ struct device_attribute dev_attr_##_name = \
-+ __ATTR(_sysfs_name, 0200, NULL, _name##_store)
-+
-+/* response curve macros */
-+#define ALLY_RESP_CURVE_SHOW(_name, _point_n) \
-+ static ssize_t _name##_show(struct device *dev, \
-+ struct device_attribute *attr, char *buf) \
-+ { \
-+ struct ally_gamepad_cfg *ally_cfg = drvdata.gamepad_cfg; \
-+ int idx = (_point_n - 1) * 2; \
-+ if (!drvdata.gamepad_cfg) \
-+ return -ENODEV; \
-+ return sysfs_emit( \
-+ buf, "%d %d\n", \
-+ ally_cfg->response_curve[ally_cfg->mode] \
-+ [btn_pair_side_left][idx], \
-+ ally_cfg->response_curve[ally_cfg->mode] \
-+ [btn_pair_side_right] \
-+ [idx + 1]); \
-+ }
-+
-+#define ALLY_RESP_CURVE_STORE(_name, _side, _point_n) \
-+ static ssize_t _name##_store(struct device *dev, \
-+ struct device_attribute *attr, \
-+ const char *buf, size_t count) \
-+ { \
-+ int ret = __gamepad_store_response_curve( \
-+ dev, buf, btn_pair_side_##_side, _point_n); \
-+ if (ret < 0) \
-+ return ret; \
-+ return count; \
-+ }
-+
-+/* _point_n must start at 1 */
-+#define ALLY_JS_RC_POINT(_side, _point_n, _sysfs_label) \
-+ ALLY_RESP_CURVE_SHOW(rc_point_##_side##_##_point_n, _point_n); \
-+ ALLY_RESP_CURVE_STORE(rc_point_##_side##_##_point_n, _side, _point_n); \
-+ ALLY_DEVICE_ATTR_RW(rc_point_##_side##_##_point_n, \
-+ _sysfs_label##_point_n)
-+
-+/* deadzone macros */
-+#define ALLY_AXIS_DEADZONE_SHOW(_axis) \
-+ static ssize_t _axis##_deadzone_show( \
-+ struct device *dev, struct device_attribute *attr, char *buf) \
-+ { \
-+ struct ally_gamepad_cfg *ally_cfg = drvdata.gamepad_cfg; \
-+ int side, is_tr; \
-+ if (!drvdata.gamepad_cfg) \
-+ return -ENODEV; \
-+ is_tr = _axis > xpad_axis_xy_right; \
-+ side = _axis == xpad_axis_xy_right || \
-+ _axis == xpad_axis_z_right ? \
-+ 2 : \
-+ 0; \
-+ return sysfs_emit( \
-+ buf, "%d %d\n", \
-+ ally_cfg->deadzones[ally_cfg->mode][is_tr][side], \
-+ ally_cfg->deadzones[ally_cfg->mode][is_tr][side + 1]); \
-+ }
-+
-+#define ALLY_AXIS_DEADZONE_STORE(_axis) \
-+ static ssize_t _axis##_deadzone_store(struct device *dev, \
-+ struct device_attribute *attr, \
-+ const char *buf, size_t count) \
-+ { \
-+ struct ally_gamepad_cfg *ally_cfg = drvdata.gamepad_cfg; \
-+ if (!drvdata.gamepad_cfg) \
-+ return -ENODEV; \
-+ int ret = __gamepad_store_deadzones(ally_cfg, _axis, buf); \
-+ if (ret < 0) \
-+ return ret; \
-+ return count; \
-+ }
-+
-+#define ALLY_AXIS_DEADZONE(_axis, _sysfs_label) \
-+ ALLY_AXIS_DEADZONE_SHOW(_axis); \
-+ ALLY_AXIS_DEADZONE_STORE(_axis); \
-+ ALLY_DEVICE_ATTR_RW(_axis##_deadzone, _sysfs_label)
-+
-+/* button specific macros */
-+#define ALLY_BTN_SHOW(_fname, _pair, _side, _secondary) \
-+ static ssize_t _fname##_show(struct device *dev, \
-+ struct device_attribute *attr, char *buf) \
-+ { \
-+ struct ally_gamepad_cfg *ally_cfg = drvdata.gamepad_cfg; \
-+ if (!drvdata.gamepad_cfg) \
-+ return -ENODEV; \
-+ return sysfs_emit(buf, "%s\n", \
-+ __btn_map_to_string(ally_cfg, _pair, _side, \
-+ _secondary)); \
-+ }
-+
-+#define ALLY_BTN_STORE(_fname, _pair, _side, _secondary) \
-+ static ssize_t _fname##_store(struct device *dev, \
-+ struct device_attribute *attr, \
-+ const char *buf, size_t count) \
-+ { \
-+ struct ally_gamepad_cfg *ally_cfg = drvdata.gamepad_cfg; \
-+ if (!drvdata.gamepad_cfg) \
-+ return -ENODEV; \
-+ int ret = __gamepad_mapping_store(ally_cfg, buf, _pair, _side, \
-+ _secondary); \
-+ if (ret < 0) \
-+ return ret; \
-+ return count; \
-+ }
-+
-+#define ALLY_BTN_TURBO_SHOW(_fname, _pair, _side) \
-+ static ssize_t _fname##_turbo_show( \
-+ struct device *dev, struct device_attribute *attr, char *buf) \
-+ { \
-+ return sysfs_emit(buf, "%d\n", \
-+ __gamepad_turbo_show(dev, _pair, _side)); \
-+ }
-+
-+#define ALLY_BTN_TURBO_STORE(_fname, _pair, _side) \
-+ static ssize_t _fname##_turbo_store(struct device *dev, \
-+ struct device_attribute *attr, \
-+ const char *buf, size_t count) \
-+ { \
-+ int ret = __gamepad_turbo_store(dev, buf, _pair, _side); \
-+ if (ret < 0) \
-+ return ret; \
-+ return count; \
-+ }
-+
-+#define ALLY_BTN_ATTRS_GROUP(_name, _fname) \
-+ static struct attribute *_fname##_attrs[] = { \
-+ &dev_attr_##_fname.attr, &dev_attr_##_fname##_macro.attr, \
-+ &dev_attr_##_fname##_turbo.attr, NULL \
-+ }; \
-+ static const struct attribute_group _fname##_attr_group = { \
-+ .name = __stringify(_name), \
-+ .attrs = _fname##_attrs, \
-+ }
-+
-+#define ALLY_BTN_MAPPING(_fname, _pair, _side) \
-+ ALLY_BTN_SHOW(btn_mapping_##_fname, _pair, _side, false); \
-+ ALLY_BTN_STORE(btn_mapping_##_fname, _pair, _side, false); \
-+ ALLY_BTN_SHOW(btn_mapping_##_fname##_macro, _pair, _side, true); \
-+ ALLY_BTN_STORE(btn_mapping_##_fname##_macro, _pair, _side, true); \
-+ ALLY_BTN_TURBO_SHOW(btn_mapping_##_fname, _pair, _side); \
-+ ALLY_BTN_TURBO_STORE(btn_mapping_##_fname, _pair, _side); \
-+ ALLY_DEVICE_ATTR_RW(btn_mapping_##_fname, remap); \
-+ ALLY_DEVICE_ATTR_RW(btn_mapping_##_fname##_macro, macro_remap); \
-+ ALLY_DEVICE_ATTR_RW(btn_mapping_##_fname##_turbo, turbo); \
-+ ALLY_BTN_ATTRS_GROUP(btn_##_fname, btn_mapping_##_fname)
-+
-+/* calibration macros */
-+#define ALLY_CAL_STORE(_fname, _axis) \
-+ static ssize_t _fname##_store(struct device *dev, \
-+ struct device_attribute *attr, \
-+ const char *buf, size_t count) \
-+ { \
-+ int ret = __gamepad_cal_store(dev, buf, _axis); \
-+ if (ret < 0) \
-+ return ret; \
-+ return count; \
-+ }
-+
-+#define ALLY_CAL_SHOW(_fname, _axis) \
-+ static ssize_t _fname##_show(struct device *dev, \
-+ struct device_attribute *attr, char *buf) \
-+ { \
-+ return __gamepad_cal_show(dev, buf, _axis); \
-+ }
-+
-+#define ALLY_CAL_ATTR(_fname, _axis, _sysfs_label) \
-+ ALLY_CAL_STORE(_fname, _axis); \
-+ ALLY_CAL_SHOW(_fname, _axis); \
-+ ALLY_DEVICE_ATTR_RW(_fname, _sysfs_label)
-+
-+#define ALLY_CAL_RESET_STORE(_fname, _axis) \
-+ static ssize_t _fname##_store(struct device *dev, \
-+ struct device_attribute *attr, \
-+ const char *buf, size_t count) \
-+ { \
-+ int ret = __gamepad_cal_reset(dev, buf, _axis); \
-+ if (ret < 0) \
-+ return ret; \
-+ return count; \
-+ }
-+
-+#define ALLY_CAL_RESET_ATTR(_fname, _axis, _sysfs_label) \
-+ ALLY_CAL_RESET_STORE(_fname, _axis); \
-+ ALLY_DEVICE_ATTR_WO(_fname, _sysfs_label)
-+
-+/*
-+ * The following blocks of packets exist to make setting a default boot config
-+ * easier. They were directly captured from setting the gamepad up.
-+ */
-+
-+/* Default blocks for the xpad mode */
-+static const u8 XPAD_DEF1[MAPPING_BLOCK_LEN] = {
-+ 0x01, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x05, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x01, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x04, 0x00, 0x00, 0x00, 0x00, 0x03, 0x8c, 0x88, 0x76, 0x00, 0x00
-+};
-+static const u8 XPAD_DEF2[MAPPING_BLOCK_LEN] = {
-+ 0x01, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x04, 0x00, 0x00, 0x00, 0x00, 0x02, 0x82, 0x23, 0x00, 0x00, 0x00,
-+ 0x01, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x04, 0x00, 0x00, 0x00, 0x00, 0x02, 0x82, 0x0d, 0x00, 0x00, 0x00
-+};
-+static const u8 XPAD_DEF3[MAPPING_BLOCK_LEN] = {
-+ 0x01, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
-+};
-+static const u8 XPAD_DEF4[MAPPING_BLOCK_LEN] = {
-+ 0x01, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x01, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
-+};
-+static const u8 XPAD_DEF5[MAPPING_BLOCK_LEN] = {
-+ 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x05, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x04, 0x00, 0x00, 0x00, 0x00, 0x02, 0x82, 0x31, 0x00, 0x00, 0x00
-+};
-+static const u8 XPAD_DEF6[MAPPING_BLOCK_LEN] = {
-+ 0x01, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x04, 0x00, 0x00, 0x00, 0x00, 0x02, 0x82, 0x4d, 0x00, 0x00, 0x00,
-+ 0x01, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x05, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
-+};
-+static const u8 XPAD_DEF7[MAPPING_BLOCK_LEN] = {
-+ 0x01, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x01, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
-+};
-+static const u8 XPAD_DEF8[MAPPING_BLOCK_LEN] = {
-+ 0x02, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x02, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x02, 0x00, 0x8f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x02, 0x00, 0x8f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
-+};
-+static const u8 XPAD_DEF9[MAPPING_BLOCK_LEN] = {
-+ 0x01, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x01, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
-+};
-+
-+/* default blocks for the wasd mode */
-+static const u8 WASD_DEF1[MAPPING_BLOCK_LEN] = {
-+ 0x02, 0x00, 0x98, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x05, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x02, 0x00, 0x99, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x04, 0x00, 0x00, 0x00, 0x00, 0x03, 0x8c, 0x88, 0x76, 0x00, 0x00
-+};
-+static const u8 WASD_DEF2[MAPPING_BLOCK_LEN] = {
-+ 0x02, 0x00, 0x9a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x04, 0x00, 0x00, 0x00, 0x00, 0x02, 0x82, 0x23, 0x00, 0x00, 0x00,
-+ 0x02, 0x00, 0x9b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x04, 0x00, 0x00, 0x00, 0x00, 0x02, 0x82, 0x0d, 0x00, 0x00, 0x00
-+};
-+static const u8 WASD_DEF3[MAPPING_BLOCK_LEN] = {
-+ 0x02, 0x00, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
-+};
-+static const u8 WASD_DEF4[MAPPING_BLOCK_LEN] = {
-+ 0x02, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
-+};
-+static const u8 WASD_DEF5[MAPPING_BLOCK_LEN] = {
-+ 0x02, 0x00, 0x5a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x05, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x02, 0x00, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x04, 0x00, 0x00, 0x00, 0x00, 0x02, 0x82, 0x31, 0x00, 0x00, 0x00
-+};
-+static const u8 WASD_DEF6[MAPPING_BLOCK_LEN] = {
-+ 0x02, 0x00, 0x97, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x04, 0x00, 0x00, 0x00, 0x00, 0x02, 0x82, 0x4d, 0x00, 0x00, 0x00,
-+ 0x02, 0x00, 0x96, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x05, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
-+};
-+static const u8 WASD_DEF7[MAPPING_BLOCK_LEN] = {
-+ 0x01, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x01, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
-+};
-+static const u8 WASD_DEF8[MAPPING_BLOCK_LEN] = {
-+ 0x02, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x02, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x02, 0x00, 0x8f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x02, 0x00, 0x8f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
-+};
-+static const u8 WASD_DEF9[MAPPING_BLOCK_LEN] = {
-+ 0x04, 0x00, 0x00, 0x00, 0x00, 0x02, 0x88, 0x0d, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
-+};
-+
-+/*
-+ * the xpad_mode is used inside the mode setting packet and is used
-+ * for indexing (xpad_mode - 1)
-+ */
-+enum xpad_mode {
-+ xpad_mode_game = 0x01,
-+ xpad_mode_wasd = 0x02,
-+ xpad_mode_mouse = 0x03,
-+};
-+
-+/* the xpad_cmd determines which feature is set or queried */
-+enum xpad_cmd {
-+ xpad_cmd_set_mode = 0x01,
-+ xpad_cmd_set_mapping = 0x02,
-+ xpad_cmd_set_js_dz = 0x04, /* deadzones */
-+ xpad_cmd_set_tr_dz = 0x05, /* deadzones */
-+ xpad_cmd_set_vibe_intensity = 0x06,
-+ xpad_cmd_set_leds = 0x08,
-+ xpad_cmd_check_ready = 0x0A,
-+ xpad_cmd_set_calibration = 0x0D,
-+ xpad_cmd_set_turbo = 0x0F,
-+ xpad_cmd_set_response_curve = 0x13,
-+ xpad_cmd_set_adz = 0x18,
-+};
-+
-+/* the xpad_cmd determines which feature is set or queried */
-+enum xpad_cmd_len {
-+ xpad_cmd_len_mode = 0x01,
-+ xpad_cmd_len_mapping = 0x2c,
-+ xpad_cmd_len_deadzone = 0x04,
-+ xpad_cmd_len_vibe_intensity = 0x02,
-+ xpad_cmd_len_leds = 0x0C,
-+ xpad_cmd_len_calibration2 = 0x01,
-+ xpad_cmd_len_calibration3 = 0x01,
-+ xpad_cmd_len_turbo = 0x20,
-+ xpad_cmd_len_response_curve = 0x09,
-+ xpad_cmd_len_adz = 0x02,
-+};
-+
-+/*
-+ * the xpad_mode is used in various set and query HID packets and is
-+ * used for indexing (xpad_axis - 1)
-+ */
-+enum xpad_axis {
-+ xpad_axis_xy_left = 0x01,
-+ xpad_axis_xy_right = 0x02,
-+ xpad_axis_z_left = 0x03,
-+ xpad_axis_z_right = 0x04,
-+};
-+
-+enum btn_pair {
-+ btn_pair_dpad_u_d = 0x01,
-+ btn_pair_dpad_l_r = 0x02,
-+ btn_pair_ls_rs = 0x03,
-+ btn_pair_lb_rb = 0x04,
-+ btn_pair_a_b = 0x05,
-+ btn_pair_x_y = 0x06,
-+ btn_pair_view_menu = 0x07,
-+ btn_pair_m1_m2 = 0x08,
-+ btn_pair_lt_rt = 0x09,
-+};
-+
-+enum btn_pair_side {
-+ btn_pair_side_left = 0x00,
-+ btn_pair_side_right = 0x01,
-+};
-diff --git a/drivers/hid/hid-asus.c b/drivers/hid/hid-asus.c
-index 37e6d25593c2..9f83a770de8d 100644
---- a/drivers/hid/hid-asus.c
-+++ b/drivers/hid/hid-asus.c
-@@ -52,6 +52,10 @@ MODULE_DESCRIPTION("Asus HID Keyboard and TouchPad");
- #define FEATURE_KBD_LED_REPORT_ID1 0x5d
- #define FEATURE_KBD_LED_REPORT_ID2 0x5e
-
-+#define ALLY_CFG_INTF_IN_ADDRESS 0x83
-+#define ALLY_CFG_INTF_OUT_ADDRESS 0x04
-+#define ALLY_X_INTERFACE_ADDRESS 0x87
-+
- #define SUPPORT_KBD_BACKLIGHT BIT(0)
-
- #define MAX_TOUCH_MAJOR 8
-@@ -84,6 +88,7 @@ MODULE_DESCRIPTION("Asus HID Keyboard and TouchPad");
- #define QUIRK_MEDION_E1239T BIT(10)
- #define QUIRK_ROG_NKEY_KEYBOARD BIT(11)
- #define QUIRK_ROG_CLAYMORE_II_KEYBOARD BIT(12)
-+#define QUIRK_ROG_ALLY_XPAD BIT(13)
-
- #define I2C_KEYBOARD_QUIRKS (QUIRK_FIX_NOTEBOOK_REPORT | \
- QUIRK_NO_INIT_REPORTS | \
-@@ -492,12 +497,19 @@ static void asus_kbd_backlight_work(struct work_struct *work)
- */
- static bool asus_kbd_wmi_led_control_present(struct hid_device *hdev)
- {
-+ struct asus_drvdata *drvdata = hid_get_drvdata(hdev);
- u32 value;
- int ret;
-
- if (!IS_ENABLED(CONFIG_ASUS_WMI))
- return false;
-
-+ if (drvdata->quirks & QUIRK_ROG_NKEY_KEYBOARD &&
-+ dmi_check_system(asus_use_hid_led_dmi_ids)) {
-+ hid_info(hdev, "using HID for asus::kbd_backlight\n");
-+ return false;
-+ }
-+
- ret = asus_wmi_evaluate_method(ASUS_WMI_METHODID_DSTS,
- ASUS_WMI_DEVID_KBD_BACKLIGHT, 0, &value);
- hid_dbg(hdev, "WMI backlight check: rc %d value %x", ret, value);
-@@ -996,6 +1008,17 @@ static int asus_probe(struct hid_device *hdev, const struct hid_device_id *id)
-
- drvdata->quirks = id->driver_data;
-
-+ /* Ignore these endpoints as they will be used by other drivers */
-+ if (drvdata->quirks & QUIRK_ROG_ALLY_XPAD) {
-+ struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
-+ struct usb_host_endpoint *ep = intf->cur_altsetting->endpoint;
-+
-+ if (ep->desc.bEndpointAddress == ALLY_X_INTERFACE_ADDRESS ||
-+ ep->desc.bEndpointAddress == ALLY_CFG_INTF_IN_ADDRESS ||
-+ ep->desc.bEndpointAddress == ALLY_CFG_INTF_OUT_ADDRESS)
-+ return -ENODEV;
-+ }
-+
- /*
- * T90CHI's keyboard dock returns same ID values as T100CHI's dock.
- * Thus, identify T90CHI dock with product name string.
-@@ -1247,6 +1270,12 @@ static const struct hid_device_id asus_devices[] = {
- QUIRK_USE_KBD_BACKLIGHT | QUIRK_ROG_NKEY_KEYBOARD },
- { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK,
- USB_DEVICE_ID_ASUSTEK_ROG_NKEY_ALLY),
-+ QUIRK_USE_KBD_BACKLIGHT | QUIRK_ROG_NKEY_KEYBOARD | QUIRK_ROG_ALLY_XPAD},
-+ { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK,
-+ USB_DEVICE_ID_ASUSTEK_ROG_NKEY_ALLY_X),
-+ QUIRK_USE_KBD_BACKLIGHT | QUIRK_ROG_NKEY_KEYBOARD | QUIRK_ROG_ALLY_XPAD },
-+ { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK,
-+ USB_DEVICE_ID_ASUSTEK_ROG_AZOTH_KEYBOARD),
- QUIRK_USE_KBD_BACKLIGHT | QUIRK_ROG_NKEY_KEYBOARD },
- { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK,
- USB_DEVICE_ID_ASUSTEK_ROG_CLAYMORE_II_KEYBOARD),
-diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
-index 72d56ee7ce1b..57f1f1bc5eb6 100644
---- a/drivers/hid/hid-ids.h
-+++ b/drivers/hid/hid-ids.h
-@@ -209,7 +209,10 @@
- #define USB_DEVICE_ID_ASUSTEK_ROG_NKEY_KEYBOARD2 0x19b6
- #define USB_DEVICE_ID_ASUSTEK_ROG_NKEY_KEYBOARD3 0x1a30
- #define USB_DEVICE_ID_ASUSTEK_ROG_Z13_LIGHTBAR 0x18c6
-+#define USB_DEVICE_ID_ASUSTEK_ROG_RAIKIRI_PAD 0x1abb
- #define USB_DEVICE_ID_ASUSTEK_ROG_NKEY_ALLY 0x1abe
-+#define USB_DEVICE_ID_ASUSTEK_ROG_AZOTH_KEYBOARD 0x1a83
-+#define USB_DEVICE_ID_ASUSTEK_ROG_NKEY_ALLY_X 0x1b4c
- #define USB_DEVICE_ID_ASUSTEK_ROG_CLAYMORE_II_KEYBOARD 0x196b
- #define USB_DEVICE_ID_ASUSTEK_FX503VD_KEYBOARD 0x1869
-
-diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
-index ddfccc226751..d13c4085c228 100644
---- a/drivers/platform/x86/Kconfig
-+++ b/drivers/platform/x86/Kconfig
-@@ -265,6 +265,19 @@ config ASUS_WIRELESS
- If you choose to compile this driver as a module the module will be
- called asus-wireless.
-
-+config ASUS_ARMOURY
-+ tristate "ASUS Armoury (firmware) Driver"
-+ depends on ACPI_WMI
-+ depends on ASUS_WMI
-+ select FW_ATTR_CLASS
-+ help
-+ Say Y here if you have a WMI aware Asus laptop and would like to use the
-+ firmware_attributes API to control various settings typically exposed in
-+ the ASUS Armoury Crate application available on Windows.
-+
-+ To compile this driver as a module, choose M here: the module will
-+ be called asus-armoury.
-+
- config ASUS_WMI
- tristate "ASUS WMI Driver"
- depends on ACPI_WMI
-@@ -276,6 +289,7 @@ config ASUS_WMI
- depends on HOTPLUG_PCI
- depends on ACPI_VIDEO || ACPI_VIDEO = n
- depends on SERIO_I8042 || SERIO_I8042 = n
-+ select ASUS_ARMOURY
- select INPUT_SPARSEKMAP
- select LEDS_CLASS
- select NEW_LEDS
-diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile
-index e1b142947067..fe3e7e7dede8 100644
---- a/drivers/platform/x86/Makefile
-+++ b/drivers/platform/x86/Makefile
-@@ -32,6 +32,7 @@ obj-$(CONFIG_APPLE_GMUX) += apple-gmux.o
- # ASUS
- obj-$(CONFIG_ASUS_LAPTOP) += asus-laptop.o
- obj-$(CONFIG_ASUS_WIRELESS) += asus-wireless.o
-+obj-$(CONFIG_ASUS_ARMOURY) += asus-armoury.o
- obj-$(CONFIG_ASUS_WMI) += asus-wmi.o
- obj-$(CONFIG_ASUS_NB_WMI) += asus-nb-wmi.o
- obj-$(CONFIG_ASUS_TF103C_DOCK) += asus-tf103c-dock.o
-diff --git a/drivers/platform/x86/amd/pmf/pmf-quirks.c b/drivers/platform/x86/amd/pmf/pmf-quirks.c
-index 0b2eb0ae85fe..460444cda1b2 100644
---- a/drivers/platform/x86/amd/pmf/pmf-quirks.c
-+++ b/drivers/platform/x86/amd/pmf/pmf-quirks.c
-@@ -29,6 +29,14 @@ static const struct dmi_system_id fwbug_list[] = {
- },
- .driver_data = &quirk_no_sps_bug,
- },
-+ {
-+ .ident = "ROG Ally X",
-+ .matches = {
-+ DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
-+ DMI_MATCH(DMI_PRODUCT_NAME, "RC72LA"),
-+ },
-+ .driver_data = &quirk_no_sps_bug,
-+ },
- {}
- };
-
-@@ -48,4 +56,3 @@ void amd_pmf_quirks_init(struct amd_pmf_dev *dev)
- dmi_id->ident);
- }
- }
--
-diff --git a/drivers/platform/x86/asus-armoury.c b/drivers/platform/x86/asus-armoury.c
-new file mode 100644
-index 000000000000..aa784b6b9483
---- /dev/null
-+++ b/drivers/platform/x86/asus-armoury.c
-@@ -0,0 +1,1049 @@
-+// SPDX-License-Identifier: GPL-2.0-or-later
-+/*
-+ * Asus Armoury (WMI) attributes driver. This driver uses the fw_attributes
-+ * class to expose the various WMI functions that many gaming and some
-+ * non-gaming ASUS laptops have available.
-+ * These typically don't fit anywhere else in the sysfs such as under LED class,
-+ * hwmon or other, and are set in Windows using the ASUS Armoury Crate tool.
-+ *
-+ * Copyright(C) 2010 Intel Corporation.
-+ * Copyright(C) 2024-2024 Luke Jones <luke@ljones.dev>
-+ */
-+
-+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-+
-+#include <linux/platform_data/x86/asus-wmi.h>
-+#include <linux/errno.h>
-+#include <linux/fs.h>
-+#include <linux/types.h>
-+#include <linux/dmi.h>
-+#include <linux/device.h>
-+#include <linux/kmod.h>
-+#include <linux/kobject.h>
-+#include <linux/module.h>
-+#include <linux/mutex.h>
-+#include <linux/kernel.h>
-+#include "asus-armoury.h"
-+#include "firmware_attributes_class.h"
-+
-+#define ASUS_NB_WMI_EVENT_GUID "0B3CBB35-E3C2-45ED-91C2-4C5A6D195D1C"
-+
-+#define ASUS_MINI_LED_MODE_MASK 0x03
-+/* Standard modes for devices with only on/off */
-+#define ASUS_MINI_LED_OFF 0x00
-+#define ASUS_MINI_LED_ON 0x01
-+/* New mode on some devices, define here to clarify remapping later */
-+#define ASUS_MINI_LED_STRONG_MODE 0x02
-+/* New modes for devices with 3 mini-led mode types */
-+#define ASUS_MINI_LED_2024_WEAK 0x00
-+#define ASUS_MINI_LED_2024_STRONG 0x01
-+#define ASUS_MINI_LED_2024_OFF 0x02
-+
-+enum cpu_core_type {
-+ CPU_CORE_PERF = 0,
-+ CPU_CORE_POWER,
-+};
-+
-+enum cpu_core_value {
-+ CPU_CORE_DEFAULT = 0,
-+ CPU_CORE_MIN,
-+ CPU_CORE_MAX,
-+ CPU_CORE_CURRENT,
-+};
-+
-+/* Default limits for tunables available on ASUS ROG laptops */
-+#define PPT_CPU_LIMIT_MIN 5
-+#define PPT_CPU_LIMIT_MAX 150
-+#define PPT_CPU_LIMIT_DEFAULT 80
-+#define PPT_PLATFORM_MIN 5
-+#define PPT_PLATFORM_MAX 100
-+#define PPT_PLATFORM_DEFAULT 80
-+#define NVIDIA_BOOST_MIN 5
-+#define NVIDIA_BOOST_MAX 25
-+#define NVIDIA_TEMP_MIN 75
-+#define NVIDIA_TEMP_MAX 87
-+#define NVIDIA_POWER_MIN 0
-+#define NVIDIA_POWER_MAX 70
-+#define NVIDIA_POWER_DEFAULT 70
-+
-+/* Tunables provided by ASUS for gaming laptops */
-+struct rog_tunables {
-+ u32 cpu_default;
-+ u32 cpu_min;
-+ u32 cpu_max;
-+
-+ u32 platform_default;
-+ u32 platform_min;
-+ u32 platform_max;
-+
-+ u32 ppt_pl1_spl; // cpu
-+ u32 ppt_pl2_sppt; // cpu
-+ u32 ppt_apu_sppt; // plat
-+ u32 ppt_platform_sppt; // plat
-+ u32 ppt_fppt; // cpu
-+
-+ u32 nv_boost_default;
-+ u32 nv_boost_min;
-+ u32 nv_boost_max;
-+ u32 nv_dynamic_boost;
-+
-+ u32 nv_temp_default;
-+ u32 nv_temp_min;
-+ u32 nv_temp_max;
-+ u32 nv_temp_target;
-+
-+ u32 dgpu_tgp_default;
-+ u32 dgpu_tgp_min;
-+ u32 dgpu_tgp_max;
-+ u32 dgpu_tgp;
-+
-+ u32 min_perf_cores;
-+ u32 max_perf_cores;
-+ u32 max_power_cores;
-+};
-+
-+static const struct class *fw_attr_class;
-+
-+struct asus_armoury_priv {
-+ struct device *fw_attr_dev;
-+ struct kset *fw_attr_kset;
-+
-+ struct rog_tunables *rog_tunables;
-+ u32 mini_led_dev_id;
-+ u32 gpu_mux_dev_id;
-+
-+ struct mutex mutex;
-+};
-+
-+static struct asus_armoury_priv asus_armoury = {
-+ .mutex = __MUTEX_INITIALIZER(asus_armoury.mutex)
-+};
-+
-+struct fw_attrs_group {
-+ u32 pending_reboot;
-+};
-+
-+static struct fw_attrs_group fw_attrs = {
-+ .pending_reboot = 0,
-+};
-+
-+struct asus_attr_group {
-+ const struct attribute_group *attr_group;
-+ u32 wmi_devid;
-+};
-+
-+/**
-+ * asus_wmi_is_present() - determine if a WMI interface is available.
-+ * @dev_id: The WMI function ID to use.
-+ *
-+ * Returns: Boolean state. Note that an error will also return false.
-+ */
-+static bool asus_wmi_is_present(u32 dev_id)
-+{
-+ u32 retval;
-+ int status;
-+
-+ status = asus_wmi_get_devstate_dsts(dev_id, &retval);
-+ pr_debug("%s called (0x%08x), retval: 0x%08x\n", __func__, dev_id, retval);
-+
-+ return status == 0 && (retval & ASUS_WMI_DSTS_PRESENCE_BIT);
-+}
-+
-+static void asus_set_reboot_and_signal_event(void)
-+{
-+ fw_attrs.pending_reboot = 1;
-+ kobject_uevent(&asus_armoury.fw_attr_dev->kobj, KOBJ_CHANGE);
-+}
-+
-+static ssize_t pending_reboot_show(struct kobject *kobj,
-+ struct kobj_attribute *attr,
-+ char *buf)
-+{
-+ return sysfs_emit(buf, "%u\n", fw_attrs.pending_reboot);
-+}
-+
-+static struct kobj_attribute pending_reboot = __ATTR_RO(pending_reboot);
-+
-+static bool asus_bios_requires_reboot(struct kobj_attribute *attr)
-+{
-+ return !strcmp(attr->attr.name, "gpu_mux_mode") ||
-+ !strcmp(attr->attr.name, "cores_performance") ||
-+ !strcmp(attr->attr.name, "cores_efficiency") ||
-+ !strcmp(attr->attr.name, "panel_hd_mode");
-+}
-+
-+/**
-+ * attr_int_store() - Generic store function for use with most WMI functions.
-+ * @kobj: Pointer to the driver object.
-+ * @kobj_attribute: Pointer the the attribute calling this function.
-+ * @buf: The buffer to read from, this is parsed to `int` type.
-+ * @count:
-+ * @min: Minimum accepted value. Below this returns -EINVAL.
-+ * @max: Maximum accepted value. Above this returns -EINVAL.
-+ * @store_value: Pointer to where the parsed value should be stored.
-+ * @wmi_dev: The WMI function ID to use.
-+ *
-+ * The WMI functions available on most ASUS laptops return a 1 as "success", and
-+ * a 0 as failed. However some functions can return n > 1 for additional errors.
-+ * attr_int_store() currently treats all values which are not 1 as errors, ignoring
-+ * the possible differences in WMI error returns.
-+ *
-+ * Returns: Either count, or an error.
-+ */
-+static ssize_t attr_int_store(struct kobject *kobj,
-+ struct kobj_attribute *attr,
-+ const char *buf, size_t count,
-+ u32 min, u32 max, u32 *store_value, u32 wmi_dev)
-+{
-+ u32 result, value;
-+ int err;
-+
-+ err = kstrtouint(buf, 10, &value);
-+ if (err)
-+ return err;
-+
-+ if (value < min || value > max)
-+ return -EINVAL;
-+
-+ err = asus_wmi_set_devstate(wmi_dev, value, &result);
-+ if (err) {
-+ pr_err("Failed to set %s: %d\n", attr->attr.name, err);
-+ return err;
-+ }
-+
-+ if (result != 1) {
-+ pr_err("Failed to set %s (result): 0x%x\n", attr->attr.name, result);
-+ return -EIO;
-+ }
-+
-+ if (store_value != NULL)
-+ *store_value = value;
-+ sysfs_notify(kobj, NULL, attr->attr.name);
-+
-+ if (asus_bios_requires_reboot(attr))
-+ asus_set_reboot_and_signal_event();
-+
-+ return count;
-+}
-+
-+/* Mini-LED mode **************************************************************/
-+static ssize_t mini_led_mode_current_value_show(struct kobject *kobj,
-+ struct kobj_attribute *attr, char *buf)
-+{
-+ u32 value;
-+ int err;
-+
-+ err = asus_wmi_get_devstate_dsts(asus_armoury.mini_led_dev_id, &value);
-+ if (err)
-+ return err;
-+
-+ value = value & ASUS_MINI_LED_MODE_MASK;
-+
-+ /*
-+ * Remap the mode values to match previous generation mini-led. The last gen
-+ * WMI 0 == off, while on this version WMI 2 ==off (flipped).
-+ */
-+ if (asus_armoury.mini_led_dev_id == ASUS_WMI_DEVID_MINI_LED_MODE2) {
-+ switch (value) {
-+ case ASUS_MINI_LED_2024_WEAK:
-+ value = ASUS_MINI_LED_ON;
-+ break;
-+ case ASUS_MINI_LED_2024_STRONG:
-+ value = ASUS_MINI_LED_STRONG_MODE;
-+ break;
-+ case ASUS_MINI_LED_2024_OFF:
-+ value = ASUS_MINI_LED_OFF;
-+ break;
-+ }
-+ }
-+
-+ return sysfs_emit(buf, "%u\n", value);
-+}
-+
-+static ssize_t mini_led_mode_current_value_store(struct kobject *kobj,
-+ struct kobj_attribute *attr,
-+ const char *buf, size_t count)
-+{
-+ int result, err;
-+ u32 mode;
-+
-+ err = kstrtou32(buf, 10, &mode);
-+ if (err)
-+ return err;
-+
-+ if (asus_armoury.mini_led_dev_id == ASUS_WMI_DEVID_MINI_LED_MODE &&
-+ mode > ASUS_MINI_LED_ON)
-+ return -EINVAL;
-+ if (asus_armoury.mini_led_dev_id == ASUS_WMI_DEVID_MINI_LED_MODE2 &&
-+ mode > ASUS_MINI_LED_STRONG_MODE)
-+ return -EINVAL;
-+
-+ /*
-+ * Remap the mode values so expected behaviour is the same as the last
-+ * generation of mini-LED with 0 == off, 1 == on.
-+ */
-+ if (asus_armoury.mini_led_dev_id == ASUS_WMI_DEVID_MINI_LED_MODE2) {
-+ switch (mode) {
-+ case ASUS_MINI_LED_OFF:
-+ mode = ASUS_MINI_LED_2024_OFF;
-+ break;
-+ case ASUS_MINI_LED_ON:
-+ mode = ASUS_MINI_LED_2024_WEAK;
-+ break;
-+ case ASUS_MINI_LED_STRONG_MODE:
-+ mode = ASUS_MINI_LED_2024_STRONG;
-+ break;
-+ }
-+ }
-+
-+ err = asus_wmi_set_devstate(asus_armoury.mini_led_dev_id, mode, &result);
-+ if (err) {
-+ pr_warn("Failed to set mini-LED: %d\n", err);
-+ return err;
-+ }
-+
-+ if (result != 1) {
-+ pr_warn("Failed to set mini-LED mode (result): 0x%x\n", result);
-+ return -EIO;
-+ }
-+
-+ sysfs_notify(kobj, NULL, attr->attr.name);
-+
-+ return count;
-+}
-+
-+static ssize_t mini_led_mode_possible_values_show(struct kobject *kobj,
-+ struct kobj_attribute *attr, char *buf)
-+{
-+ switch (asus_armoury.mini_led_dev_id) {
-+ case ASUS_WMI_DEVID_MINI_LED_MODE:
-+ return sysfs_emit(buf, "0;1\n");
-+ case ASUS_WMI_DEVID_MINI_LED_MODE2:
-+ return sysfs_emit(buf, "0;1;2\n");
-+ }
-+
-+ return sysfs_emit(buf, "0\n");
-+}
-+
-+ATTR_GROUP_ENUM_CUSTOM(mini_led_mode, "mini_led_mode", "Set the mini-LED backlight mode");
-+
-+static ssize_t gpu_mux_mode_current_value_store(struct kobject *kobj,
-+ struct kobj_attribute *attr,
-+ const char *buf, size_t count)
-+{
-+ int result, err;
-+ u32 optimus;
-+
-+ err = kstrtou32(buf, 10, &optimus);
-+ if (err)
-+ return err;
-+
-+ if (optimus > 1)
-+ return -EINVAL;
-+
-+ if (asus_wmi_is_present(ASUS_WMI_DEVID_DGPU)) {
-+ err = asus_wmi_get_devstate_dsts(ASUS_WMI_DEVID_DGPU, &result);
-+ if (err)
-+ return err;
-+ if (result && !optimus) {
-+ err = -ENODEV;
-+ pr_warn("Can not switch MUX to dGPU mode when dGPU is disabled: %d\n", err);
-+ return err;
-+ }
-+ }
-+
-+ if (asus_wmi_is_present(ASUS_WMI_DEVID_EGPU)) {
-+ err = asus_wmi_get_devstate_dsts(ASUS_WMI_DEVID_EGPU, &result);
-+ if (err)
-+ return err;
-+ if (result && !optimus) {
-+ err = -ENODEV;
-+ pr_warn("Can not switch MUX to dGPU mode when eGPU is enabled: %d\n", err);
-+ return err;
-+ }
-+ }
-+
-+ err = asus_wmi_set_devstate(asus_armoury.gpu_mux_dev_id, optimus, &result);
-+ if (err) {
-+ pr_err("Failed to set GPU MUX mode: %d\nn", err);
-+ return err;
-+ }
-+ /* !1 is considered a fail by ASUS */
-+ if (result != 1) {
-+ pr_warn("Failed to set GPU MUX mode (result): 0x%x\n", result);
-+ return -EIO;
-+ }
-+
-+ sysfs_notify(kobj, NULL, attr->attr.name);
-+
-+ return count;
-+}
-+WMI_SHOW_INT(gpu_mux_mode_current_value, "%d\n", asus_armoury.gpu_mux_dev_id);
-+ATTR_GROUP_BOOL_CUSTOM(gpu_mux_mode, "gpu_mux_mode", "Set the GPU display MUX mode");
-+
-+/*
-+ * A user may be required to store the value twice, typcial store first, then
-+ * rescan PCI bus to activate power, then store a second time to save correctly.
-+ * The reason for this is that an extra code path in the ACPI is enabled when
-+ * the device and bus are powered.
-+ */
-+static ssize_t dgpu_disable_current_value_store(struct kobject *kobj,
-+ struct kobj_attribute *attr,
-+ const char *buf, size_t count)
-+{
-+ int result, err;
-+ u32 disable;
-+
-+ err = kstrtou32(buf, 10, &disable);
-+ if (err)
-+ return err;
-+
-+ if (disable > 1)
-+ return -EINVAL;
-+
-+ if (asus_armoury.gpu_mux_dev_id) {
-+ err = asus_wmi_get_devstate_dsts(asus_armoury.gpu_mux_dev_id, &result);
-+ if (err)
-+ return err;
-+ if (!result && disable) {
-+ err = -ENODEV;
-+ pr_warn("Can not disable dGPU when the MUX is in dGPU mode: %d\n", err);
-+ return err;
-+ }
-+ }
-+
-+ err = asus_wmi_set_devstate(ASUS_WMI_DEVID_DGPU, disable, &result);
-+ if (err) {
-+ pr_warn("Failed to set dgpu disable: %d\n", err);
-+ return err;
-+ }
-+
-+ if (result != 1) {
-+ pr_warn("Failed to set dgpu disable (result): 0x%x\n", result);
-+ return -EIO;
-+ }
-+
-+ sysfs_notify(kobj, NULL, attr->attr.name);
-+
-+ return count;
-+}
-+WMI_SHOW_INT(dgpu_disable_current_value, "%d\n", ASUS_WMI_DEVID_DGPU);
-+ATTR_GROUP_BOOL_CUSTOM(dgpu_disable, "dgpu_disable", "Disable the dGPU");
-+
-+/* The ACPI call to enable the eGPU also disables the internal dGPU */
-+static ssize_t egpu_enable_current_value_store(struct kobject *kobj,
-+ struct kobj_attribute *attr,
-+ const char *buf, size_t count)
-+{
-+ int result, err;
-+ u32 enable;
-+
-+ err = kstrtou32(buf, 10, &enable);
-+ if (err)
-+ return err;
-+
-+ if (enable > 1)
-+ return -EINVAL;
-+
-+ err = asus_wmi_get_devstate_dsts(ASUS_WMI_DEVID_EGPU_CONNECTED, &result);
-+ if (err) {
-+ pr_warn("Failed to get egpu connection status: %d\n", err);
-+ return err;
-+ }
-+
-+ if (asus_armoury.gpu_mux_dev_id) {
-+ err = asus_wmi_get_devstate_dsts(asus_armoury.gpu_mux_dev_id, &result);
-+ if (err) {
-+ pr_warn("Failed to get gpu mux status: %d\n", result);
-+ return result;
-+ }
-+ if (!result && enable) {
-+ err = -ENODEV;
-+ pr_warn("Can not enable eGPU when the MUX is in dGPU mode: %d\n", err);
-+ return err;
-+ }
-+ }
-+
-+ err = asus_wmi_set_devstate(ASUS_WMI_DEVID_EGPU, enable, &result);
-+ if (err) {
-+ pr_warn("Failed to set egpu state: %d\n", err);
-+ return err;
-+ }
-+
-+ if (result != 1) {
-+ pr_warn("Failed to set egpu state (retval): 0x%x\n", result);
-+ return -EIO;
-+ }
-+
-+ sysfs_notify(kobj, NULL, attr->attr.name);
-+
-+ return count;
-+}
-+WMI_SHOW_INT(egpu_enable_current_value, "%d\n", ASUS_WMI_DEVID_EGPU);
-+ATTR_GROUP_BOOL_CUSTOM(egpu_enable, "egpu_enable", "Enable the eGPU (also disables dGPU)");
-+
-+/* Device memory available to APU */
-+
-+static ssize_t apu_mem_current_value_show(struct kobject *kobj,
-+ struct kobj_attribute *attr, char *buf)
-+{
-+ int err;
-+ u32 mem;
-+
-+ err = asus_wmi_get_devstate_dsts(ASUS_WMI_DEVID_APU_MEM, &mem);
-+ if (err)
-+ return err;
-+
-+ switch (mem) {
-+ case 256:
-+ mem = 0;
-+ break;
-+ case 258:
-+ mem = 1;
-+ break;
-+ case 259:
-+ mem = 2;
-+ break;
-+ case 260:
-+ mem = 3;
-+ break;
-+ case 261:
-+ mem = 4;
-+ break;
-+ case 262:
-+ /* This is out of order and looks wrong but is correct */
-+ mem = 8;
-+ break;
-+ case 263:
-+ mem = 5;
-+ break;
-+ case 264:
-+ mem = 6;
-+ break;
-+ case 265:
-+ mem = 7;
-+ break;
-+ default:
-+ mem = 4;
-+ break;
-+ }
-+
-+ return sysfs_emit(buf, "%d\n", mem);
-+}
-+
-+static ssize_t apu_mem_current_value_store(struct kobject *kobj,
-+ struct kobj_attribute *attr,
-+ const char *buf, size_t count)
-+{
-+ int result, err;
-+ u32 requested, mem;
-+
-+ result = kstrtou32(buf, 10, &requested);
-+ if (result)
-+ return result;
-+
-+ switch (requested) {
-+ case 0:
-+ mem = 0;
-+ break;
-+ case 1:
-+ mem = 258;
-+ break;
-+ case 2:
-+ mem = 259;
-+ break;
-+ case 3:
-+ mem = 260;
-+ break;
-+ case 4:
-+ mem = 261;
-+ break;
-+ case 5:
-+ mem = 263;
-+ break;
-+ case 6:
-+ mem = 264;
-+ break;
-+ case 7:
-+ mem = 265;
-+ break;
-+ case 8:
-+ /* This is outof order and looks wrong but is correct */
-+ mem = 262;
-+ break;
-+ default:
-+ return -EIO;
-+ }
-+
-+ err = asus_wmi_set_devstate(ASUS_WMI_DEVID_APU_MEM, mem, &result);
-+ if (err) {
-+ pr_warn("Failed to set apu_mem: %d\n", err);
-+ return err;
-+ }
-+
-+ pr_info("APU memory changed to %dGB, reboot required\n", requested);
-+ sysfs_notify(kobj, NULL, attr->attr.name);
-+
-+ asus_set_reboot_and_signal_event();
-+
-+ return count;
-+}
-+
-+static ssize_t apu_mem_possible_values_show(struct kobject *kobj,
-+ struct kobj_attribute *attr, char *buf)
-+{
-+ return sysfs_emit(buf, "0;1;2;3;4;5;6;7;8\n");
-+}
-+ATTR_GROUP_ENUM_CUSTOM(apu_mem, "apu_mem", "Set the available system memory for the APU to use");
-+
-+static int init_max_cpu_cores(void)
-+{
-+ u32 cores;
-+ int err;
-+
-+ asus_armoury.rog_tunables->min_perf_cores = 4;
-+ asus_armoury.rog_tunables->max_perf_cores = 4;
-+ asus_armoury.rog_tunables->max_power_cores = 8;
-+
-+ err = asus_wmi_get_devstate_dsts(ASUS_WMI_DEVID_CORES_MAX, &cores);
-+ if (err)
-+ return err;
-+
-+ cores &= ~ASUS_WMI_DSTS_PRESENCE_BIT;
-+ asus_armoury.rog_tunables->max_power_cores = (cores & 0xff00) >> 8;
-+ asus_armoury.rog_tunables->max_perf_cores = cores & 0xff;
-+
-+ return 0;
-+}
-+
-+static ssize_t cores_value_show(struct kobject *kobj,
-+ struct kobj_attribute *attr, char *buf,
-+ enum cpu_core_type core_type,
-+ enum cpu_core_value core_value)
-+{
-+ u32 cores;
-+ int err;
-+
-+ switch (core_value) {
-+ case CPU_CORE_DEFAULT:
-+ case CPU_CORE_MAX:
-+ if (core_type == CPU_CORE_PERF)
-+ return sysfs_emit(buf, "%d\n", asus_armoury.rog_tunables->max_perf_cores);
-+ else
-+ return sysfs_emit(buf, "%d\n", asus_armoury.rog_tunables->max_power_cores);
-+ case CPU_CORE_MIN:
-+ if (core_type == CPU_CORE_PERF)
-+ return sysfs_emit(buf, "%d\n", asus_armoury.rog_tunables->min_perf_cores);
-+ else
-+ return sysfs_emit(buf, "%d\n", 0);
-+ default:
-+ break;
-+ }
-+
-+ err = asus_wmi_get_devstate_dsts(ASUS_WMI_DEVID_CORES, &cores);
-+ if (err)
-+ return err;
-+
-+ cores &= ~ASUS_WMI_DSTS_PRESENCE_BIT;
-+ if (core_type == CPU_CORE_PERF)
-+ cores &= 0xff;
-+ else
-+ cores = (cores & 0xff00) >> 8;
-+ return sysfs_emit(buf, "%d\n", cores);
-+}
-+
-+static ssize_t cores_current_value_store(struct kobject *kobj,
-+ struct kobj_attribute *attr, const char *buf,
-+ enum cpu_core_type core_type)
-+{
-+ int result, err;
-+ u32 cores, currentv, min, max;
-+
-+ result = kstrtou32(buf, 10, &cores);
-+ if (result)
-+ return result;
-+
-+ if (core_type == CPU_CORE_PERF) {
-+ min = asus_armoury.rog_tunables->min_perf_cores;
-+ max = asus_armoury.rog_tunables->max_perf_cores;
-+ } else {
-+ min = 0;
-+ max = asus_armoury.rog_tunables->max_power_cores;
-+ }
-+ if (cores < min || cores > max)
-+ return -EINVAL;
-+
-+ err = asus_wmi_get_devstate_dsts(ASUS_WMI_DEVID_CORES, &currentv);
-+ if (err)
-+ return err;
-+
-+ if (core_type == CPU_CORE_PERF)
-+ cores |= (currentv & 0xff00);
-+ else
-+ cores |= currentv & 0xff;
-+
-+ if (cores == currentv)
-+ return 0;
-+
-+ err = asus_wmi_set_devstate(ASUS_WMI_DEVID_CORES, cores, &result);
-+ if (err) {
-+ pr_warn("Failed to set CPU core count: %d\n", err);
-+ return err;
-+ }
-+
-+ if (result > 1) {
-+ pr_warn("Failed to set CPU core count (result): 0x%x\n", result);
-+ return -EIO;
-+ }
-+
-+ pr_info("CPU core count changed, reboot required\n");
-+ sysfs_notify(kobj, NULL, attr->attr.name);
-+ asus_set_reboot_and_signal_event();
-+
-+ return 0;
-+}
-+
-+static ssize_t cores_performance_min_value_show(struct kobject *kobj,
-+ struct kobj_attribute *attr, char *buf)
-+{
-+ return cores_value_show(kobj, attr, buf, CPU_CORE_PERF, CPU_CORE_MIN);
-+}
-+
-+static ssize_t cores_performance_max_value_show(struct kobject *kobj,
-+ struct kobj_attribute *attr, char *buf)
-+{
-+ return cores_value_show(kobj, attr, buf, CPU_CORE_PERF, CPU_CORE_MAX);
-+}
-+
-+static ssize_t cores_performance_default_value_show(struct kobject *kobj,
-+ struct kobj_attribute *attr, char *buf)
-+{
-+ return cores_value_show(kobj, attr, buf, CPU_CORE_PERF, CPU_CORE_DEFAULT);
-+}
-+
-+static ssize_t cores_performance_current_value_show(struct kobject *kobj,
-+ struct kobj_attribute *attr, char *buf)
-+{
-+ return cores_value_show(kobj, attr, buf, CPU_CORE_PERF, CPU_CORE_CURRENT);
-+}
-+
-+static ssize_t cores_performance_current_value_store(struct kobject *kobj,
-+ struct kobj_attribute *attr,
-+ const char *buf, size_t count)
-+{
-+ int err;
-+
-+ err = cores_current_value_store(kobj, attr, buf, CPU_CORE_PERF);
-+ if (err)
-+ return err;
-+
-+ return count;
-+}
-+ATTR_GROUP_CORES_RW(cores_performance, "cores_performance",
-+ "Set the max available performance cores");
-+
-+static ssize_t cores_efficiency_min_value_show(struct kobject *kobj,
-+ struct kobj_attribute *attr, char *buf)
-+{
-+ return cores_value_show(kobj, attr, buf, CPU_CORE_POWER, CPU_CORE_MIN);
-+}
-+
-+static ssize_t cores_efficiency_max_value_show(struct kobject *kobj,
-+ struct kobj_attribute *attr, char *buf)
-+{
-+ return cores_value_show(kobj, attr, buf, CPU_CORE_POWER, CPU_CORE_MAX);
-+}
-+
-+static ssize_t cores_efficiency_default_value_show(struct kobject *kobj,
-+ struct kobj_attribute *attr, char *buf)
-+{
-+ return cores_value_show(kobj, attr, buf, CPU_CORE_POWER, CPU_CORE_DEFAULT);
-+}
-+
-+static ssize_t cores_efficiency_current_value_show(struct kobject *kobj,
-+ struct kobj_attribute *attr, char *buf)
-+{
-+ return cores_value_show(kobj, attr, buf, CPU_CORE_POWER, CPU_CORE_CURRENT);
-+}
-+
-+static ssize_t cores_efficiency_current_value_store(struct kobject *kobj,
-+ struct kobj_attribute *attr,
-+ const char *buf, size_t count)
-+{
-+ int err;
-+
-+ err = cores_current_value_store(kobj, attr, buf, CPU_CORE_POWER);
-+ if (err)
-+ return err;
-+
-+ return count;
-+}
-+ATTR_GROUP_CORES_RW(cores_efficiency, "cores_efficiency",
-+ "Set the max available efficiency cores");
-+
-+/* Simple attribute creation */
-+ATTR_GROUP_ROG_TUNABLE(ppt_pl1_spl, "ppt_pl1_spl", ASUS_WMI_DEVID_PPT_PL1_SPL,
-+ cpu_default, cpu_min, cpu_max, 1, "Set the CPU slow package limit");
-+ATTR_GROUP_ROG_TUNABLE(ppt_pl2_sppt, "ppt_pl2_sppt", ASUS_WMI_DEVID_PPT_PL2_SPPT,
-+ cpu_default, cpu_min, cpu_max, 1, "Set the CPU fast package limit");
-+ATTR_GROUP_ROG_TUNABLE(ppt_apu_sppt, "ppt_apu_sppt", ASUS_WMI_DEVID_PPT_APU_SPPT,
-+ platform_default, platform_min, platform_max, 1, "Set the CPU slow package limit");
-+ATTR_GROUP_ROG_TUNABLE(ppt_platform_sppt, "ppt_platform_sppt", ASUS_WMI_DEVID_PPT_PLAT_SPPT,
-+ platform_default, platform_min, platform_max, 1, "Set the CPU slow package limit");
-+ATTR_GROUP_ROG_TUNABLE(ppt_fppt, "ppt_fppt", ASUS_WMI_DEVID_PPT_FPPT,
-+ cpu_default, cpu_min, cpu_max, 1, "Set the CPU slow package limit");
-+
-+ATTR_GROUP_ROG_TUNABLE(nv_dynamic_boost, "nv_dynamic_boost", ASUS_WMI_DEVID_NV_DYN_BOOST,
-+ nv_boost_default, nv_boost_min, nv_boost_max, 1, "Set the Nvidia dynamic boost limit");
-+ATTR_GROUP_ROG_TUNABLE(nv_temp_target, "nv_temp_target", ASUS_WMI_DEVID_NV_THERM_TARGET,
-+ nv_temp_default, nv_boost_min, nv_temp_max, 1, "Set the Nvidia max thermal limit");
-+ATTR_GROUP_INT_VALUE_ONLY_RO(dgpu_base_tgp, "dgpu_base_tgp", ASUS_WMI_DEVID_DGPU_BASE_TGP,
-+ "Read the base TGP value");
-+ATTR_GROUP_ROG_TUNABLE(dgpu_tgp, "dgpu_tgp", ASUS_WMI_DEVID_DGPU_SET_TGP,
-+ dgpu_tgp_default, dgpu_tgp_min, dgpu_tgp_max, 1,
-+ "Set the additional TGP on top of the base TGP");
-+
-+ATTR_GROUP_ENUM_INT_RO(charge_mode, "charge_mode", ASUS_WMI_DEVID_CHARGE_MODE,
-+ "0;1;2", "Show the current mode of charging");
-+ATTR_GROUP_BOOL_RW(boot_sound, "boot_sound", ASUS_WMI_DEVID_BOOT_SOUND,
-+ "Set the boot POST sound");
-+ATTR_GROUP_BOOL_RW(mcu_powersave, "mcu_powersave", ASUS_WMI_DEVID_MCU_POWERSAVE,
-+ "Set MCU powersaving mode");
-+ATTR_GROUP_BOOL_RW(panel_od, "panel_overdrive", ASUS_WMI_DEVID_PANEL_OD,
-+ "Set the panel refresh overdrive");
-+ATTR_GROUP_BOOL_RW(panel_hd_mode, "panel_hd_mode", ASUS_WMI_DEVID_PANEL_HD,
-+ "Set the panel HD mode to UHD<0> or FHD<1>");
-+ATTR_GROUP_BOOL_RO(egpu_connected, "egpu_connected", ASUS_WMI_DEVID_EGPU_CONNECTED,
-+ "Show the eGPU connection status");
-+
-+/* If an attribute does not require any special case handling add it here */
-+static const struct asus_attr_group armoury_attr_groups[] = {
-+ { &egpu_connected_attr_group, ASUS_WMI_DEVID_EGPU_CONNECTED },
-+ { &egpu_enable_attr_group, ASUS_WMI_DEVID_EGPU },
-+ { &dgpu_disable_attr_group, ASUS_WMI_DEVID_DGPU },
-+
-+ { &ppt_pl1_spl_attr_group, ASUS_WMI_DEVID_PPT_PL1_SPL },
-+ { &ppt_pl2_sppt_attr_group, ASUS_WMI_DEVID_PPT_PL2_SPPT },
-+ { &ppt_apu_sppt_attr_group, ASUS_WMI_DEVID_PPT_APU_SPPT },
-+ { &ppt_platform_sppt_attr_group, ASUS_WMI_DEVID_PPT_PLAT_SPPT },
-+ { &ppt_fppt_attr_group, ASUS_WMI_DEVID_PPT_FPPT },
-+ { &nv_dynamic_boost_attr_group, ASUS_WMI_DEVID_NV_DYN_BOOST },
-+ { &nv_temp_target_attr_group, ASUS_WMI_DEVID_NV_THERM_TARGET },
-+ { &dgpu_base_tgp_attr_group, ASUS_WMI_DEVID_DGPU_BASE_TGP },
-+ { &dgpu_tgp_attr_group, ASUS_WMI_DEVID_DGPU_SET_TGP },
-+ { &apu_mem_attr_group, ASUS_WMI_DEVID_APU_MEM },
-+ { &cores_efficiency_attr_group, ASUS_WMI_DEVID_CORES_MAX },
-+ { &cores_performance_attr_group, ASUS_WMI_DEVID_CORES_MAX },
-+
-+ { &charge_mode_attr_group, ASUS_WMI_DEVID_CHARGE_MODE },
-+ { &boot_sound_attr_group, ASUS_WMI_DEVID_BOOT_SOUND },
-+ { &mcu_powersave_attr_group, ASUS_WMI_DEVID_MCU_POWERSAVE },
-+ { &panel_od_attr_group, ASUS_WMI_DEVID_PANEL_OD },
-+ { &panel_hd_mode_attr_group, ASUS_WMI_DEVID_PANEL_HD },
-+};
-+
-+static int asus_fw_attr_add(void)
-+{
-+ int err;
-+
-+ err = fw_attributes_class_get(&fw_attr_class);
-+ if (err)
-+ goto fail_class_created;
-+
-+ asus_armoury.fw_attr_dev = device_create(fw_attr_class, NULL,
-+ MKDEV(0, 0), NULL, "%s", DRIVER_NAME);
-+
-+ if (IS_ERR(asus_armoury.fw_attr_dev)) {
-+ err = PTR_ERR(asus_armoury.fw_attr_dev);
-+ goto fail_class_created;
-+ }
-+
-+ asus_armoury.fw_attr_kset = kset_create_and_add("attributes", NULL,
-+ &asus_armoury.fw_attr_dev->kobj);
-+ if (!asus_armoury.fw_attr_dev) {
-+ err = -ENOMEM;
-+ pr_debug("Failed to create and add attributes\n");
-+ goto err_destroy_classdev;
-+ }
-+
-+ err = sysfs_create_file(&asus_armoury.fw_attr_kset->kobj, &pending_reboot.attr);
-+ if (err) {
-+ pr_warn("Failed to create sysfs level attributes\n");
-+ goto fail_class_created;
-+ }
-+
-+ err = 0;
-+ asus_armoury.mini_led_dev_id = 0;
-+ if (asus_wmi_is_present(ASUS_WMI_DEVID_MINI_LED_MODE)) {
-+ asus_armoury.mini_led_dev_id = ASUS_WMI_DEVID_MINI_LED_MODE;
-+ err = sysfs_create_group(&asus_armoury.fw_attr_kset->kobj,
-+ &mini_led_mode_attr_group);
-+ } else if (asus_wmi_is_present(ASUS_WMI_DEVID_MINI_LED_MODE2)) {
-+ asus_armoury.mini_led_dev_id = ASUS_WMI_DEVID_MINI_LED_MODE2;
-+ err = sysfs_create_group(&asus_armoury.fw_attr_kset->kobj,
-+ &mini_led_mode_attr_group);
-+ }
-+ if (err)
-+ pr_warn("Failed to create sysfs-group for mini_led\n");
-+
-+ err = 0;
-+ asus_armoury.gpu_mux_dev_id = 0;
-+ if (asus_wmi_is_present(ASUS_WMI_DEVID_GPU_MUX)) {
-+ asus_armoury.gpu_mux_dev_id = ASUS_WMI_DEVID_GPU_MUX;
-+ err = sysfs_create_group(&asus_armoury.fw_attr_kset->kobj, &gpu_mux_mode_attr_group);
-+ } else if (asus_wmi_is_present(ASUS_WMI_DEVID_GPU_MUX_VIVO)) {
-+ asus_armoury.gpu_mux_dev_id = ASUS_WMI_DEVID_GPU_MUX_VIVO;
-+ err = sysfs_create_group(&asus_armoury.fw_attr_kset->kobj, &gpu_mux_mode_attr_group);
-+ }
-+ if (err)
-+ pr_warn("Failed to create sysfs-group for gpu_mux\n");
-+
-+ for (int i = 0; i < ARRAY_SIZE(armoury_attr_groups); i++) {
-+ if (!asus_wmi_is_present(armoury_attr_groups[i].wmi_devid))
-+ continue;
-+
-+ err = sysfs_create_group(&asus_armoury.fw_attr_kset->kobj,
-+ armoury_attr_groups[i].attr_group);
-+ if (err)
-+ pr_warn("Failed to create sysfs-group for %s\n",
-+ armoury_attr_groups[i].attr_group->name);
-+ else
-+ pr_debug("Created sysfs-group for %s\n",
-+ armoury_attr_groups[i].attr_group->name);
-+ }
-+
-+ return 0;
-+
-+err_destroy_classdev:
-+ device_destroy(fw_attr_class, MKDEV(0, 0));
-+
-+fail_class_created:
-+ fw_attributes_class_put();
-+ return err;
-+}
-+
-+/* Init / exit ****************************************************************/
-+
-+/* Set up the min/max and defaults for ROG tunables */
-+static void init_rog_tunables(struct rog_tunables *rog)
-+{
-+ const char *product;
-+ u32 max_boost = NVIDIA_BOOST_MAX;
-+ u32 cpu_default = PPT_CPU_LIMIT_DEFAULT;
-+ u32 cpu_max = PPT_CPU_LIMIT_MAX;
-+ u32 platform_default = PPT_PLATFORM_DEFAULT;
-+ u32 platform_max = PPT_PLATFORM_MAX;
-+
-+ /*
-+ * ASUS product_name contains everything required, e.g,
-+ * "ROG Flow X16 GV601VV_GV601VV_00185149B"
-+ */
-+ product = dmi_get_system_info(DMI_PRODUCT_NAME);
-+
-+ if (strstr(product, "GA402R")) {
-+ cpu_default = 125;
-+ } else if (strstr(product, "13QY")) {
-+ cpu_max = 250;
-+ } else if (strstr(product, "X13")) {
-+ cpu_max = 75;
-+ cpu_default = 50;
-+ } else if (strstr(product, "RC71")) {
-+ cpu_max = 50;
-+ cpu_default = 30;
-+ } else if (strstr(product, "G814")
-+ || strstr(product, "G614")
-+ || strstr(product, "G834")
-+ || strstr(product, "G634")) {
-+ cpu_max = 175;
-+ } else if (strstr(product, "GA402X")
-+ || strstr(product, "GA403")
-+ || strstr(product, "FA507N")
-+ || strstr(product, "FA507X")
-+ || strstr(product, "FA707N")
-+ || strstr(product, "FA707X")) {
-+ cpu_max = 90;
-+ }
-+
-+ if (strstr(product, "GZ301ZE"))
-+ max_boost = 5;
-+ else if (strstr(product, "FX507ZC4"))
-+ max_boost = 15;
-+ else if (strstr(product, "GU605"))
-+ max_boost = 20;
-+
-+ /* ensure defaults for tunables */
-+ rog->cpu_default = cpu_default;
-+ rog->cpu_min = PPT_CPU_LIMIT_MIN;
-+ rog->cpu_max = cpu_max;
-+
-+ rog->platform_default = platform_default;
-+ rog->platform_max = PPT_PLATFORM_MIN;
-+ rog->platform_max = platform_max;
-+
-+ rog->ppt_pl1_spl = cpu_default;
-+ rog->ppt_pl2_sppt = cpu_default;
-+ rog->ppt_apu_sppt = cpu_default;
-+
-+ rog->ppt_platform_sppt = platform_default;
-+ rog->ppt_fppt = platform_default;
-+
-+ rog->nv_boost_default = NVIDIA_BOOST_MAX;
-+ rog->nv_boost_max = NVIDIA_BOOST_MIN;
-+ rog->nv_boost_max = max_boost;
-+ rog->nv_dynamic_boost = NVIDIA_BOOST_MIN;
-+
-+ rog->nv_temp_default = NVIDIA_TEMP_MAX;
-+ rog->nv_temp_max = NVIDIA_TEMP_MIN;
-+ rog->nv_temp_max = NVIDIA_TEMP_MAX;
-+ rog->nv_temp_target = NVIDIA_TEMP_MIN;
-+
-+ rog->dgpu_tgp_default = NVIDIA_POWER_DEFAULT;
-+ rog->dgpu_tgp_min = NVIDIA_POWER_MIN;
-+ rog->dgpu_tgp_max = NVIDIA_POWER_MAX;
-+ rog->dgpu_tgp = NVIDIA_POWER_MAX;
-+
-+}
-+
-+static int __init asus_fw_init(void)
-+{
-+ int err;
-+
-+ fw_attrs.pending_reboot = 0;
-+
-+ mutex_lock(&asus_armoury.mutex);
-+
-+ asus_armoury.rog_tunables = kzalloc(sizeof(struct rog_tunables), GFP_KERNEL);
-+ if (!asus_armoury.rog_tunables) {
-+ mutex_unlock(&asus_armoury.mutex);
-+ return -ENOMEM;
-+ }
-+ init_rog_tunables(asus_armoury.rog_tunables);
-+ init_max_cpu_cores();
-+
-+ err = asus_fw_attr_add();
-+ mutex_unlock(&asus_armoury.mutex);
-+ if (err)
-+ return err;
-+
-+ return 0;
-+}
-+
-+static void __exit asus_fw_exit(void)
-+{
-+ mutex_lock(&asus_armoury.mutex);
-+
-+ sysfs_remove_file(&asus_armoury.fw_attr_kset->kobj, &pending_reboot.attr);
-+ kset_unregister(asus_armoury.fw_attr_kset);
-+ device_destroy(fw_attr_class, MKDEV(0, 0));
-+ fw_attributes_class_put();
-+
-+ mutex_unlock(&asus_armoury.mutex);
-+}
-+
-+module_init(asus_fw_init);
-+module_exit(asus_fw_exit);
-+
-+MODULE_AUTHOR("Luke Jones <luke@ljones.dev>");
-+MODULE_DESCRIPTION("ASUS BIOS Configuration Driver");
-+MODULE_LICENSE("GPL");
-+MODULE_ALIAS("wmi:"ASUS_NB_WMI_EVENT_GUID);
-diff --git a/drivers/platform/x86/asus-armoury.h b/drivers/platform/x86/asus-armoury.h
-new file mode 100644
-index 000000000000..25b2c055930e
---- /dev/null
-+++ b/drivers/platform/x86/asus-armoury.h
-@@ -0,0 +1,259 @@
-+/* SPDX-License-Identifier: GPL-2.0
-+ *
-+ * Definitions for kernel modules using asus-armoury driver
-+ *
-+ * Copyright (c) 2024 Luke Jones <luke@ljones.dev>
-+ */
-+
-+#ifndef _ASUS_BIOSCFG_H_
-+#define _ASUS_BIOSCFG_H_
-+
-+#include "firmware_attributes_class.h"
-+#include <linux/types.h>
-+
-+#define DRIVER_NAME "asus-armoury"
-+
-+static ssize_t attr_int_store(struct kobject *kobj, struct kobj_attribute *attr,
-+ const char *buf, size_t count,
-+ u32 min, u32 max, u32 *store_value, u32 wmi_dev);
-+
-+
-+static ssize_t int_type_show(struct kobject *kobj, struct kobj_attribute *attr,
-+ char *buf)
-+{
-+ return sysfs_emit(buf, "integer\n");
-+}
-+
-+static ssize_t enum_type_show(struct kobject *kobj, struct kobj_attribute *attr,
-+ char *buf)
-+{
-+ return sysfs_emit(buf, "enumeration\n");
-+}
-+
-+#define __ASUS_ATTR_RO(_func, _name) { \
-+ .attr = { .name = __stringify(_name), .mode = 0444 }, \
-+ .show = _func##_##_name##_show, \
-+}
-+
-+#define __ASUS_ATTR_RO_AS(_name, _show) { \
-+ .attr = { .name = __stringify(_name), .mode = 0444 }, \
-+ .show = _show, \
-+}
-+
-+#define __ASUS_ATTR_RW(_func, _name) __ATTR(_name, 0644, \
-+ _func##_##_name##_show, _func##_##_name##_store)
-+
-+#define __WMI_STORE_INT(_attr, _min, _max, _wmi) \
-+static ssize_t _attr##_store(struct kobject *kobj, \
-+ struct kobj_attribute *attr, \
-+ const char *buf, size_t count) \
-+{ \
-+ return attr_int_store(kobj, attr, buf, count, _min, _max, NULL, _wmi); \
-+}
-+
-+#define WMI_SHOW_INT(_attr, _fmt, _wmi) \
-+static ssize_t _attr##_show(struct kobject *kobj, \
-+ struct kobj_attribute *attr, char *buf) \
-+{ \
-+ u32 result; \
-+ int err; \
-+ err = asus_wmi_get_devstate_dsts(_wmi, &result); \
-+ if (err) \
-+ return err; \
-+ return sysfs_emit(buf, _fmt, \
-+ result & ~ASUS_WMI_DSTS_PRESENCE_BIT); \
-+}
-+
-+/* Create functions and attributes for use in other macros or on their own */
-+
-+#define __ATTR_CURRENT_INT_RO(_attr, _wmi) \
-+WMI_SHOW_INT(_attr##_current_value, "%d\n", _wmi); \
-+static struct kobj_attribute attr_##_attr##_current_value = \
-+ __ASUS_ATTR_RO(_attr, current_value)
-+
-+#define __ATTR_CURRENT_INT_RW(_attr, _minv, _maxv, _wmi) \
-+__WMI_STORE_INT(_attr##_current_value, _minv, _maxv, _wmi); \
-+WMI_SHOW_INT(_attr##_current_value, "%d\n", _wmi); \
-+static struct kobj_attribute attr_##_attr##_current_value = \
-+ __ASUS_ATTR_RW(_attr, current_value)
-+
-+/* Shows a formatted static variable */
-+#define __ATTR_SHOW_FMT(_prop, _attrname, _fmt, _val) \
-+static ssize_t _attrname##_##_prop##_show(struct kobject *kobj, \
-+ struct kobj_attribute *attr, char *buf) \
-+{ \
-+ return sysfs_emit(buf, _fmt, _val); \
-+} \
-+static struct kobj_attribute attr_##_attrname##_##_prop = \
-+ __ASUS_ATTR_RO(_attrname, _prop)
-+
-+/* Requires current_value show&|store */
-+#define __ATTR_GROUP_INT_VALUE_ONLY(_attrname, _fsname, _dispname) \
-+__ATTR_SHOW_FMT(display_name, _attrname, "%s\n", _dispname); \
-+static struct kobj_attribute attr_##_attrname##_type = \
-+ __ASUS_ATTR_RO_AS(type, int_type_show); \
-+static struct attribute *_attrname##_attrs[] = { \
-+ &attr_##_attrname##_current_value.attr, \
-+ &attr_##_attrname##_display_name.attr, \
-+ &attr_##_attrname##_type.attr, \
-+ NULL \
-+}; \
-+static const struct attribute_group _attrname##_attr_group = { \
-+ .name = _fsname, \
-+ .attrs = _attrname##_attrs \
-+}
-+
-+/* Boolean style enumeration, base macro. Requires adding show/store */
-+#define __ATTR_GROUP_ENUM(_attrname, _fsname, _possible, _dispname) \
-+__ATTR_SHOW_FMT(display_name, _attrname, "%s\n", _dispname); \
-+__ATTR_SHOW_FMT(possible_values, _attrname, "%s\n", _possible); \
-+static struct kobj_attribute attr_##_attrname##_type = \
-+ __ASUS_ATTR_RO_AS(type, enum_type_show); \
-+static struct attribute *_attrname##_attrs[] = { \
-+ &attr_##_attrname##_current_value.attr, \
-+ &attr_##_attrname##_display_name.attr, \
-+ &attr_##_attrname##_possible_values.attr, \
-+ &attr_##_attrname##_type.attr, \
-+ NULL \
-+}; \
-+static const struct attribute_group _attrname##_attr_group = { \
-+ .name = _fsname, \
-+ .attrs = _attrname##_attrs \
-+}
-+
-+#define ATTR_GROUP_INT_VALUE_ONLY_RO(_attrname, _fsname, _wmi, _dispname) \
-+ __ATTR_CURRENT_INT_RO(_attrname, _wmi); \
-+ __ATTR_GROUP_INT_VALUE_ONLY(_attrname, _fsname, _dispname)
-+
-+#define ATTR_GROUP_BOOL_RO(_attrname, _fsname, _wmi, _dispname) \
-+ __ATTR_CURRENT_INT_RO(_attrname, _wmi); \
-+ __ATTR_GROUP_ENUM(_attrname, _fsname, "0;1", _dispname)
-+
-+#define ATTR_GROUP_BOOL_RW(_attrname, _fsname, _wmi, _dispname) \
-+ __ATTR_CURRENT_INT_RW(_attrname, 0, 1, _wmi); \
-+ __ATTR_GROUP_ENUM(_attrname, _fsname, "0;1", _dispname)
-+
-+/*
-+ * Requires <name>_current_value_show(), <name>_current_value_show()
-+ */
-+#define ATTR_GROUP_BOOL_CUSTOM(_attrname, _fsname, _dispname) \
-+static struct kobj_attribute attr_##_attrname##_current_value = \
-+ __ASUS_ATTR_RW(_attrname, current_value); \
-+ __ATTR_GROUP_ENUM(_attrname, _fsname, "0;1", _dispname)
-+
-+#define ATTR_GROUP_ENUM_INT_RO(_attrname, _fsname, _wmi, \
-+ _possible, _dispname) \
-+ __ATTR_CURRENT_INT_RO(_attrname, _wmi); \
-+ __ATTR_GROUP_ENUM(_attrname, _fsname, _possible, _dispname)
-+
-+/*
-+ * Requires <name>_current_value_show(), <name>_current_value_show()
-+ * and <name>_possible_values_show()
-+ */
-+#define ATTR_GROUP_ENUM_CUSTOM(_attrname, _fsname, _dispname) \
-+__ATTR_SHOW_FMT(display_name, _attrname, "%s\n", _dispname); \
-+static struct kobj_attribute attr_##_attrname##_current_value = \
-+ __ASUS_ATTR_RW(_attrname, current_value); \
-+static struct kobj_attribute attr_##_attrname##_possible_values = \
-+ __ASUS_ATTR_RO(_attrname, possible_values); \
-+static struct kobj_attribute attr_##_attrname##_type = \
-+ __ASUS_ATTR_RO_AS(type, enum_type_show); \
-+static struct attribute *_attrname##_attrs[] = { \
-+ &attr_##_attrname##_current_value.attr, \
-+ &attr_##_attrname##_display_name.attr, \
-+ &attr_##_attrname##_possible_values.attr, \
-+ &attr_##_attrname##_type.attr, \
-+ NULL \
-+}; \
-+static const struct attribute_group _attrname##_attr_group = { \
-+ .name = _fsname, \
-+ .attrs = _attrname##_attrs \
-+}
-+
-+/* CPU core attributes need a little different in setup */
-+#define ATTR_GROUP_CORES_RW(_attrname, _fsname, _dispname) \
-+__ATTR_SHOW_FMT(scalar_increment, _attrname, "%d\n", 1); \
-+__ATTR_SHOW_FMT(display_name, _attrname, "%s\n", _dispname); \
-+static struct kobj_attribute attr_##_attrname##_current_value = \
-+ __ASUS_ATTR_RW(_attrname, current_value); \
-+static struct kobj_attribute attr_##_attrname##_default_value = \
-+ __ASUS_ATTR_RO(_attrname, default_value); \
-+static struct kobj_attribute attr_##_attrname##_min_value = \
-+ __ASUS_ATTR_RO(_attrname, min_value); \
-+static struct kobj_attribute attr_##_attrname##_max_value = \
-+ __ASUS_ATTR_RO(_attrname, max_value); \
-+static struct kobj_attribute attr_##_attrname##_type = \
-+ __ASUS_ATTR_RO_AS(type, int_type_show); \
-+static struct attribute *_attrname##_attrs[] = { \
-+ &attr_##_attrname##_current_value.attr, \
-+ &attr_##_attrname##_default_value.attr, \
-+ &attr_##_attrname##_min_value.attr, \
-+ &attr_##_attrname##_max_value.attr, \
-+ &attr_##_attrname##_scalar_increment.attr, \
-+ &attr_##_attrname##_display_name.attr, \
-+ &attr_##_attrname##_type.attr, \
-+ NULL \
-+}; \
-+static const struct attribute_group _attrname##_attr_group = { \
-+ .name = _fsname, \
-+ .attrs = _attrname##_attrs \
-+}
-+
-+/*
-+ * ROG PPT attributes need a little different in setup as they
-+ * require rog_tunables members.
-+ */
-+
-+#define __ROG_TUNABLE_RW(_attr, _min, _max, _wmi) \
-+static ssize_t _attr##_current_value_store(struct kobject *kobj, \
-+ struct kobj_attribute *attr, \
-+ const char *buf, size_t count) \
-+{ \
-+ return attr_int_store(kobj, attr, buf, count, \
-+ asus_armoury.rog_tunables->_min, \
-+ asus_armoury.rog_tunables->_max, \
-+ &asus_armoury.rog_tunables->_attr, _wmi); \
-+} \
-+static ssize_t _attr##_current_value_show(struct kobject *kobj, \
-+ struct kobj_attribute *attr, char *buf) \
-+{ \
-+ return sysfs_emit(buf, "%u\n", asus_armoury.rog_tunables->_attr);\
-+} \
-+static struct kobj_attribute attr_##_attr##_current_value = \
-+ __ASUS_ATTR_RW(_attr, current_value)
-+
-+#define __ROG_TUNABLE_SHOW(_prop, _attrname, _val) \
-+static ssize_t _attrname##_##_prop##_show(struct kobject *kobj, \
-+ struct kobj_attribute *attr, char *buf) \
-+{ \
-+ return sysfs_emit(buf, "%d\n", asus_armoury.rog_tunables->_val);\
-+} \
-+static struct kobj_attribute attr_##_attrname##_##_prop = \
-+ __ASUS_ATTR_RO(_attrname, _prop)
-+
-+#define ATTR_GROUP_ROG_TUNABLE(_attrname, _fsname, _wmi, _default, \
-+ _min, _max, _incstep, _dispname) \
-+__ROG_TUNABLE_SHOW(default_value, _attrname, _default); \
-+__ROG_TUNABLE_RW(_attrname, _min, _max, _wmi); \
-+__ROG_TUNABLE_SHOW(min_value, _attrname, _min); \
-+__ROG_TUNABLE_SHOW(max_value, _attrname, _max); \
-+__ATTR_SHOW_FMT(scalar_increment, _attrname, "%d\n", _incstep); \
-+__ATTR_SHOW_FMT(display_name, _attrname, "%s\n", _dispname); \
-+static struct kobj_attribute attr_##_attrname##_type = \
-+ __ASUS_ATTR_RO_AS(type, int_type_show); \
-+static struct attribute *_attrname##_attrs[] = { \
-+ &attr_##_attrname##_current_value.attr, \
-+ &attr_##_attrname##_default_value.attr, \
-+ &attr_##_attrname##_min_value.attr, \
-+ &attr_##_attrname##_max_value.attr, \
-+ &attr_##_attrname##_scalar_increment.attr, \
-+ &attr_##_attrname##_display_name.attr, \
-+ &attr_##_attrname##_type.attr, \
-+ NULL \
-+}; \
-+static const struct attribute_group _attrname##_attr_group = { \
-+ .name = _fsname, \
-+ .attrs = _attrname##_attrs \
-+}
-+
-+#endif /* _ASUS_BIOSCFG_H_ */
-diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c
-index bc9c5db38324..9faebd12bd49 100644
---- a/drivers/platform/x86/asus-wmi.c
-+++ b/drivers/platform/x86/asus-wmi.c
-@@ -97,6 +97,12 @@ module_param(fnlock_default, bool, 0444);
- #define ASUS_THROTTLE_THERMAL_POLICY_OVERBOOST 1
- #define ASUS_THROTTLE_THERMAL_POLICY_SILENT 2
-
-+#define ASUS_THROTTLE_THERMAL_POLICY_DEFAULT_VIVO 0
-+#define ASUS_THROTTLE_THERMAL_POLICY_SILENT_VIVO 1
-+#define ASUS_THROTTLE_THERMAL_POLICY_OVERBOOST_VIVO 2
-+
-+#define PLATFORM_PROFILE_MAX 2
-+
- #define USB_INTEL_XUSB2PR 0xD0
- #define PCI_DEVICE_ID_INTEL_LYNXPOINT_LP_XHCI 0x9c31
-
-@@ -146,6 +152,20 @@ static const char * const ashs_ids[] = { "ATK4001", "ATK4002", NULL };
-
- static int throttle_thermal_policy_write(struct asus_wmi *);
-
-+static const struct dmi_system_id asus_ally_mcu_quirk[] = {
-+ {
-+ .matches = {
-+ DMI_MATCH(DMI_BOARD_NAME, "RC71L"),
-+ },
-+ },
-+ {
-+ .matches = {
-+ DMI_MATCH(DMI_BOARD_NAME, "RC72L"),
-+ },
-+ },
-+ { },
-+};
-+
- static bool ashs_present(void)
- {
- int i = 0;
-@@ -285,8 +305,8 @@ struct asus_wmi {
- u32 kbd_rgb_dev;
- bool kbd_rgb_state_available;
-
-- bool throttle_thermal_policy_available;
- u8 throttle_thermal_policy_mode;
-+ u32 throttle_thermal_policy_dev;
-
- bool cpu_fan_curve_available;
- bool gpu_fan_curve_available;
-@@ -334,20 +354,29 @@ static int asus_wmi_evaluate_method3(u32 method_id,
- status = wmi_evaluate_method(ASUS_WMI_MGMT_GUID, 0, method_id,
- &input, &output);
-
-- if (ACPI_FAILURE(status))
-+ pr_debug("%s called (0x%08x) with args: 0x%08x, 0x%08x, 0x%08x\n",
-+ __func__, method_id, arg0, arg1, arg2);
-+ if (ACPI_FAILURE(status)) {
-+ pr_debug("%s, (0x%08x), arg 0x%08x failed: %d\n",
-+ __func__, method_id, arg0, -EIO);
- return -EIO;
-+ }
-
- obj = (union acpi_object *)output.pointer;
- if (obj && obj->type == ACPI_TYPE_INTEGER)
- tmp = (u32) obj->integer.value;
-
-+ pr_debug("Result: 0x%08x\n", tmp);
- if (retval)
- *retval = tmp;
-
- kfree(obj);
-
-- if (tmp == ASUS_WMI_UNSUPPORTED_METHOD)
-+ if (tmp == ASUS_WMI_UNSUPPORTED_METHOD) {
-+ pr_debug("%s, (0x%08x), arg 0x%08x failed: %d\n",
-+ __func__, method_id, arg0, -ENODEV);
- return -ENODEV;
-+ }
-
- return 0;
- }
-@@ -377,20 +406,29 @@ static int asus_wmi_evaluate_method5(u32 method_id,
- status = wmi_evaluate_method(ASUS_WMI_MGMT_GUID, 0, method_id,
- &input, &output);
-
-- if (ACPI_FAILURE(status))
-+ pr_debug("%s called (0x%08x) with args: 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x\n",
-+ __func__, method_id, arg0, arg1, arg2, arg3, arg4);
-+ if (ACPI_FAILURE(status)) {
-+ pr_debug("%s, (0x%08x), arg 0x%08x failed: %d\n",
-+ __func__, method_id, arg0, -EIO);
- return -EIO;
-+ }
-
- obj = (union acpi_object *)output.pointer;
- if (obj && obj->type == ACPI_TYPE_INTEGER)
- tmp = (u32) obj->integer.value;
-
-+ pr_debug("Result: %x\n", tmp);
- if (retval)
- *retval = tmp;
-
- kfree(obj);
-
-- if (tmp == ASUS_WMI_UNSUPPORTED_METHOD)
-+ if (tmp == ASUS_WMI_UNSUPPORTED_METHOD) {
-+ pr_debug("%s, (0x%08x), arg 0x%08x failed: %d\n",
-+ __func__, method_id, arg0, -ENODEV);
- return -ENODEV;
-+ }
-
- return 0;
- }
-@@ -416,8 +454,13 @@ static int asus_wmi_evaluate_method_buf(u32 method_id,
- status = wmi_evaluate_method(ASUS_WMI_MGMT_GUID, 0, method_id,
- &input, &output);
-
-- if (ACPI_FAILURE(status))
-+ pr_debug("%s called (0x%08x) with args: 0x%08x, 0x%08x\n",
-+ __func__, method_id, arg0, arg1);
-+ if (ACPI_FAILURE(status)) {
-+ pr_debug("%s, (0x%08x), arg 0x%08x failed: %d\n",
-+ __func__, method_id, arg0, -EIO);
- return -EIO;
-+ }
-
- obj = (union acpi_object *)output.pointer;
-
-@@ -453,8 +496,11 @@ static int asus_wmi_evaluate_method_buf(u32 method_id,
-
- kfree(obj);
-
-- if (err)
-+ if (err) {
-+ pr_debug("%s, (0x%08x), arg 0x%08x failed: %d\n",
-+ __func__, method_id, arg0, err);
- return err;
-+ }
-
- return 0;
- }
-@@ -503,12 +549,56 @@ static int asus_wmi_get_devstate(struct asus_wmi *asus, u32 dev_id, u32 *retval)
- return 0;
- }
-
--static int asus_wmi_set_devstate(u32 dev_id, u32 ctrl_param,
-- u32 *retval)
-+/**
-+ * asus_wmi_get_devstate_dsts() - Get the WMI function state.
-+ * @dev_id: The WMI function to call.
-+ * @retval: A pointer to where to store the value returned from WMI.
-+ *
-+ * The returned WMI function state can also be used to determine if the WMI
-+ * function is supported by checking if the asus_wmi_get_devstate_dsts()
-+ * returns an error.
-+ *
-+ * On success the return value is 0, and the retval is a valid value returned
-+ * by the successful WMI function call. An error value is returned only if the
-+ * WMI function failed, or if it returns "unsupported" which is typically a 0
-+ * (no return, and no 'supported' bit set), or a 0xFFFFFFFE (~1) which if not
-+ * caught here can result in unexpected behaviour later.
-+ */
-+int asus_wmi_get_devstate_dsts(u32 dev_id, u32 *retval)
-+{
-+ int err;
-+
-+ err = asus_wmi_evaluate_method(ASUS_WMI_METHODID_DSTS, dev_id, 0, retval);
-+ if (err)
-+ return err;
-+ /* Be explicit about retval */
-+ if (*retval == 0xFFFFFFFE || *retval == 0)
-+ return -ENODEV;
-+
-+ return 0;
-+}
-+EXPORT_SYMBOL_GPL(asus_wmi_get_devstate_dsts);
-+
-+/**
-+ * asus_wmi_set_devstate() - Set the WMI function state.
-+ * @dev_id: The WMI function to call.
-+ * @ctrl_param: The argument to be used for this WMI function.
-+ * @retval: A pointer to where to store the value returned from WMI.
-+ *
-+ * The returned WMI function state if not checked here for error as
-+ * asus_wmi_set_devstate() is not called unless first paired with a call to
-+ * asus_wmi_get_devstate_dsts() to check that the WMI function is supported.
-+ *
-+ * On success the return value is 0, and the retval is a valid value returned
-+ * by the successful WMI function call. An error value is returned only if the
-+ * WMI function failed.
-+ */
-+int asus_wmi_set_devstate(u32 dev_id, u32 ctrl_param, u32 *retval)
- {
- return asus_wmi_evaluate_method(ASUS_WMI_METHODID_DEVS, dev_id,
- ctrl_param, retval);
- }
-+EXPORT_SYMBOL_GPL(asus_wmi_set_devstate);
-
- /* Helper for special devices with magic return codes */
- static int asus_wmi_get_devstate_bits(struct asus_wmi *asus,
-@@ -542,6 +632,7 @@ static bool asus_wmi_dev_is_present(struct asus_wmi *asus, u32 dev_id)
- {
- u32 retval;
- int status = asus_wmi_get_devstate(asus, dev_id, &retval);
-+ pr_debug("%s called (0x%08x), retval: 0x%08x\n", __func__, dev_id, retval);
-
- return status == 0 && (retval & ASUS_WMI_DSTS_PRESENCE_BIT);
- }
-@@ -1685,7 +1776,8 @@ static int asus_wmi_led_init(struct asus_wmi *asus)
- goto error;
- }
-
-- if (!kbd_led_read(asus, &led_val, NULL)) {
-+ if (!kbd_led_read(asus, &led_val, NULL) && !dmi_check_system(asus_use_hid_led_dmi_ids)) {
-+ pr_info("using asus-wmi for asus::kbd_backlight\n");
- asus->kbd_led_wk = led_val;
- asus->kbd_led.name = "asus::kbd_backlight";
- asus->kbd_led.flags = LED_BRIGHT_HW_CHANGED;
-@@ -3127,7 +3219,7 @@ static int fan_curve_get_factory_default(struct asus_wmi *asus, u32 fan_dev)
- int err, fan_idx;
- u8 mode = 0;
-
-- if (asus->throttle_thermal_policy_available)
-+ if (asus->throttle_thermal_policy_dev)
- mode = asus->throttle_thermal_policy_mode;
- /* DEVID_<C/G>PU_FAN_CURVE is switched for OVERBOOST vs SILENT */
- if (mode == 2)
-@@ -3334,7 +3426,7 @@ static ssize_t fan_curve_enable_store(struct device *dev,
- * For machines with throttle this is the only way to reset fans
- * to default mode of operation (does not erase curve data).
- */
-- if (asus->throttle_thermal_policy_available) {
-+ if (asus->throttle_thermal_policy_dev) {
- err = throttle_thermal_policy_write(asus);
- if (err)
- return err;
-@@ -3551,8 +3643,8 @@ static const struct attribute_group asus_fan_curve_attr_group = {
- __ATTRIBUTE_GROUPS(asus_fan_curve_attr);
-
- /*
-- * Must be initialised after throttle_thermal_policy_check_present() as
-- * we check the status of throttle_thermal_policy_available during init.
-+ * Must be initialised after throttle_thermal_policy_dev is set as
-+ * we check the status of throttle_thermal_policy_dev during init.
- */
- static int asus_wmi_custom_fan_curve_init(struct asus_wmi *asus)
- {
-@@ -3562,18 +3654,27 @@ static int asus_wmi_custom_fan_curve_init(struct asus_wmi *asus)
-
- err = fan_curve_check_present(asus, &asus->cpu_fan_curve_available,
- ASUS_WMI_DEVID_CPU_FAN_CURVE);
-- if (err)
-+ if (err) {
-+ pr_err("%s, checked 0x%08x, failed: %d\n",
-+ __func__, ASUS_WMI_DEVID_CPU_FAN_CURVE, err);
- return err;
-+ }
-
- err = fan_curve_check_present(asus, &asus->gpu_fan_curve_available,
- ASUS_WMI_DEVID_GPU_FAN_CURVE);
-- if (err)
-+ if (err) {
-+ pr_err("%s, checked 0x%08x, failed: %d\n",
-+ __func__, ASUS_WMI_DEVID_GPU_FAN_CURVE, err);
- return err;
-+ }
-
- err = fan_curve_check_present(asus, &asus->mid_fan_curve_available,
- ASUS_WMI_DEVID_MID_FAN_CURVE);
-- if (err)
-+ if (err) {
-+ pr_err("%s, checked 0x%08x, failed: %d\n",
-+ __func__, ASUS_WMI_DEVID_MID_FAN_CURVE, err);
- return err;
-+ }
-
- if (!asus->cpu_fan_curve_available
- && !asus->gpu_fan_curve_available
-@@ -3593,38 +3694,13 @@ static int asus_wmi_custom_fan_curve_init(struct asus_wmi *asus)
- }
-
- /* Throttle thermal policy ****************************************************/
--
--static int throttle_thermal_policy_check_present(struct asus_wmi *asus)
--{
-- u32 result;
-- int err;
--
-- asus->throttle_thermal_policy_available = false;
--
-- err = asus_wmi_get_devstate(asus,
-- ASUS_WMI_DEVID_THROTTLE_THERMAL_POLICY,
-- &result);
-- if (err) {
-- if (err == -ENODEV)
-- return 0;
-- return err;
-- }
--
-- if (result & ASUS_WMI_DSTS_PRESENCE_BIT)
-- asus->throttle_thermal_policy_available = true;
--
-- return 0;
--}
--
- static int throttle_thermal_policy_write(struct asus_wmi *asus)
- {
-- int err;
-- u8 value;
-+ u8 value = asus->throttle_thermal_policy_mode;
- u32 retval;
-+ int err;
-
-- value = asus->throttle_thermal_policy_mode;
--
-- err = asus_wmi_set_devstate(ASUS_WMI_DEVID_THROTTLE_THERMAL_POLICY,
-+ err = asus_wmi_set_devstate(asus->throttle_thermal_policy_dev,
- value, &retval);
-
- sysfs_notify(&asus->platform_device->dev.kobj, NULL,
-@@ -3654,7 +3730,7 @@ static int throttle_thermal_policy_write(struct asus_wmi *asus)
-
- static int throttle_thermal_policy_set_default(struct asus_wmi *asus)
- {
-- if (!asus->throttle_thermal_policy_available)
-+ if (!asus->throttle_thermal_policy_dev)
- return 0;
-
- asus->throttle_thermal_policy_mode = ASUS_THROTTLE_THERMAL_POLICY_DEFAULT;
-@@ -3666,7 +3742,7 @@ static int throttle_thermal_policy_switch_next(struct asus_wmi *asus)
- u8 new_mode = asus->throttle_thermal_policy_mode + 1;
- int err;
-
-- if (new_mode > ASUS_THROTTLE_THERMAL_POLICY_SILENT)
-+ if (new_mode > PLATFORM_PROFILE_MAX)
- new_mode = ASUS_THROTTLE_THERMAL_POLICY_DEFAULT;
-
- asus->throttle_thermal_policy_mode = new_mode;
-@@ -3705,7 +3781,7 @@ static ssize_t throttle_thermal_policy_store(struct device *dev,
- if (result < 0)
- return result;
-
-- if (new_mode > ASUS_THROTTLE_THERMAL_POLICY_SILENT)
-+ if (new_mode > PLATFORM_PROFILE_MAX)
- return -EINVAL;
-
- asus->throttle_thermal_policy_mode = new_mode;
-@@ -3722,10 +3798,52 @@ static ssize_t throttle_thermal_policy_store(struct device *dev,
- return count;
- }
-
--// Throttle thermal policy: 0 - default, 1 - overboost, 2 - silent
-+/*
-+ * Throttle thermal policy: 0 - default, 1 - overboost, 2 - silent
-+ */
- static DEVICE_ATTR_RW(throttle_thermal_policy);
-
- /* Platform profile ***********************************************************/
-+static int asus_wmi_platform_profile_to_vivo(struct asus_wmi *asus, int mode)
-+{
-+ bool vivo;
-+
-+ vivo = asus->throttle_thermal_policy_dev == ASUS_WMI_DEVID_THROTTLE_THERMAL_POLICY_VIVO;
-+
-+ if (vivo) {
-+ switch (mode) {
-+ case ASUS_THROTTLE_THERMAL_POLICY_DEFAULT:
-+ return ASUS_THROTTLE_THERMAL_POLICY_DEFAULT_VIVO;
-+ case ASUS_THROTTLE_THERMAL_POLICY_OVERBOOST:
-+ return ASUS_THROTTLE_THERMAL_POLICY_OVERBOOST_VIVO;
-+ case ASUS_THROTTLE_THERMAL_POLICY_SILENT:
-+ return ASUS_THROTTLE_THERMAL_POLICY_SILENT_VIVO;
-+ }
-+ }
-+
-+ return mode;
-+}
-+
-+static int asus_wmi_platform_profile_mode_from_vivo(struct asus_wmi *asus, int mode)
-+{
-+ bool vivo;
-+
-+ vivo = asus->throttle_thermal_policy_dev == ASUS_WMI_DEVID_THROTTLE_THERMAL_POLICY_VIVO;
-+
-+ if (vivo) {
-+ switch (mode) {
-+ case ASUS_THROTTLE_THERMAL_POLICY_DEFAULT_VIVO:
-+ return ASUS_THROTTLE_THERMAL_POLICY_DEFAULT;
-+ case ASUS_THROTTLE_THERMAL_POLICY_OVERBOOST_VIVO:
-+ return ASUS_THROTTLE_THERMAL_POLICY_OVERBOOST;
-+ case ASUS_THROTTLE_THERMAL_POLICY_SILENT_VIVO:
-+ return ASUS_THROTTLE_THERMAL_POLICY_SILENT;
-+ }
-+ }
-+
-+ return mode;
-+}
-+
- static int asus_wmi_platform_profile_get(struct platform_profile_handler *pprof,
- enum platform_profile_option *profile)
- {
-@@ -3733,10 +3851,9 @@ static int asus_wmi_platform_profile_get(struct platform_profile_handler *pprof,
- int tp;
-
- asus = container_of(pprof, struct asus_wmi, platform_profile_handler);
--
- tp = asus->throttle_thermal_policy_mode;
-
-- switch (tp) {
-+ switch (asus_wmi_platform_profile_mode_from_vivo(asus, tp)) {
- case ASUS_THROTTLE_THERMAL_POLICY_DEFAULT:
- *profile = PLATFORM_PROFILE_BALANCED;
- break;
-@@ -3775,7 +3892,7 @@ static int asus_wmi_platform_profile_set(struct platform_profile_handler *pprof,
- return -EOPNOTSUPP;
- }
-
-- asus->throttle_thermal_policy_mode = tp;
-+ asus->throttle_thermal_policy_mode = asus_wmi_platform_profile_to_vivo(asus, tp);
- return throttle_thermal_policy_write(asus);
- }
-
-@@ -3788,7 +3905,7 @@ static int platform_profile_setup(struct asus_wmi *asus)
- * Not an error if a component platform_profile relies on is unavailable
- * so early return, skipping the setup of platform_profile.
- */
-- if (!asus->throttle_thermal_policy_available)
-+ if (!asus->throttle_thermal_policy_dev)
- return 0;
-
- dev_info(dev, "Using throttle_thermal_policy for platform_profile support\n");
-@@ -3803,8 +3920,13 @@ static int platform_profile_setup(struct asus_wmi *asus)
- asus->platform_profile_handler.choices);
-
- err = platform_profile_register(&asus->platform_profile_handler);
-- if (err)
-+ if (err == -EEXIST) {
-+ pr_warn("%s, a platform_profile handler is already registered\n", __func__);
-+ return 0;
-+ } else if (err) {
-+ pr_err("%s, failed at platform_profile_register: %d\n", __func__, err);
- return err;
-+ }
-
- asus->platform_profile_support = true;
- return 0;
-@@ -4203,7 +4325,7 @@ static void asus_wmi_handle_event_code(int code, struct asus_wmi *asus)
- if (code == NOTIFY_KBD_FBM || code == NOTIFY_KBD_TTP) {
- if (asus->fan_boost_mode_available)
- fan_boost_mode_switch_next(asus);
-- if (asus->throttle_thermal_policy_available)
-+ if (asus->throttle_thermal_policy_dev)
- throttle_thermal_policy_switch_next(asus);
- return;
-
-@@ -4375,7 +4497,7 @@ static umode_t asus_sysfs_is_visible(struct kobject *kobj,
- else if (attr == &dev_attr_fan_boost_mode.attr)
- ok = asus->fan_boost_mode_available;
- else if (attr == &dev_attr_throttle_thermal_policy.attr)
-- ok = asus->throttle_thermal_policy_available;
-+ ok = asus->throttle_thermal_policy_dev != 0;
- else if (attr == &dev_attr_ppt_pl2_sppt.attr)
- devid = ASUS_WMI_DEVID_PPT_PL2_SPPT;
- else if (attr == &dev_attr_ppt_pl1_spl.attr)
-@@ -4401,8 +4523,10 @@ static umode_t asus_sysfs_is_visible(struct kobject *kobj,
- else if (attr == &dev_attr_available_mini_led_mode.attr)
- ok = asus->mini_led_dev_id != 0;
-
-- if (devid != -1)
-+ if (devid != -1) {
- ok = !(asus_wmi_get_devstate_simple(asus, devid) < 0);
-+ pr_debug("%s called 0x%08x, ok: %x\n", __func__, devid, ok);
-+ }
-
- return ok ? attr->mode : 0;
- }
-@@ -4650,7 +4774,7 @@ static int asus_wmi_add(struct platform_device *pdev)
- asus->dgpu_disable_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_DGPU);
- asus->kbd_rgb_state_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_TUF_RGB_STATE);
- asus->ally_mcu_usb_switch = acpi_has_method(NULL, ASUS_USB0_PWR_EC0_CSEE)
-- && dmi_match(DMI_BOARD_NAME, "RC71L");
-+ && dmi_check_system(asus_ally_mcu_quirk);
-
- if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_MINI_LED_MODE))
- asus->mini_led_dev_id = ASUS_WMI_DEVID_MINI_LED_MODE;
-@@ -4667,18 +4791,17 @@ static int asus_wmi_add(struct platform_device *pdev)
- else if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_TUF_RGB_MODE2))
- asus->kbd_rgb_dev = ASUS_WMI_DEVID_TUF_RGB_MODE2;
-
-+ if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_THROTTLE_THERMAL_POLICY))
-+ asus->throttle_thermal_policy_dev = ASUS_WMI_DEVID_THROTTLE_THERMAL_POLICY;
-+ else if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_THROTTLE_THERMAL_POLICY_VIVO))
-+ asus->throttle_thermal_policy_dev = ASUS_WMI_DEVID_THROTTLE_THERMAL_POLICY_VIVO;
-+
- err = fan_boost_mode_check_present(asus);
- if (err)
- goto fail_fan_boost_mode;
-
-- err = throttle_thermal_policy_check_present(asus);
-- if (err)
-- goto fail_throttle_thermal_policy;
-- else
-- throttle_thermal_policy_set_default(asus);
--
- err = platform_profile_setup(asus);
-- if (err)
-+ if (err && err != -EEXIST)
- goto fail_platform_profile_setup;
-
- err = asus_wmi_sysfs_init(asus->platform_device);
-@@ -4771,7 +4894,6 @@ static int asus_wmi_add(struct platform_device *pdev)
- fail_input:
- asus_wmi_sysfs_exit(asus->platform_device);
- fail_sysfs:
--fail_throttle_thermal_policy:
- fail_custom_fan_curve:
- fail_platform_profile_setup:
- if (asus->platform_profile_support)
-diff --git a/drivers/platform/x86/intel/int3472/Makefile b/drivers/platform/x86/intel/int3472/Makefile
-index 9f16cb514397..a8aba07bf1dc 100644
---- a/drivers/platform/x86/intel/int3472/Makefile
-+++ b/drivers/platform/x86/intel/int3472/Makefile
-@@ -1,4 +1,7 @@
- obj-$(CONFIG_INTEL_SKL_INT3472) += intel_skl_int3472_discrete.o \
-- intel_skl_int3472_tps68470.o
--intel_skl_int3472_discrete-y := discrete.o clk_and_regulator.o led.o common.o
--intel_skl_int3472_tps68470-y := tps68470.o tps68470_board_data.o common.o
-+ intel_skl_int3472_tps68470.o \
-+ intel_skl_int3472_common.o
-+intel_skl_int3472_discrete-y := discrete.o clk_and_regulator.o led.o
-+intel_skl_int3472_tps68470-y := tps68470.o tps68470_board_data.o
-+
-+intel_skl_int3472_common-y += common.o
-diff --git a/drivers/platform/x86/intel/int3472/common.c b/drivers/platform/x86/intel/int3472/common.c
-index 9db2bb0bbba4..b3a2578e06c1 100644
---- a/drivers/platform/x86/intel/int3472/common.c
-+++ b/drivers/platform/x86/intel/int3472/common.c
-@@ -29,6 +29,7 @@ union acpi_object *skl_int3472_get_acpi_buffer(struct acpi_device *adev, char *i
-
- return obj;
- }
-+EXPORT_SYMBOL_GPL(skl_int3472_get_acpi_buffer);
-
- int skl_int3472_fill_cldb(struct acpi_device *adev, struct int3472_cldb *cldb)
- {
-@@ -52,6 +53,7 @@ int skl_int3472_fill_cldb(struct acpi_device *adev, struct int3472_cldb *cldb)
- kfree(obj);
- return ret;
- }
-+EXPORT_SYMBOL_GPL(skl_int3472_fill_cldb);
-
- /* sensor_adev_ret may be NULL, name_ret must not be NULL */
- int skl_int3472_get_sensor_adev_and_name(struct device *dev,
-@@ -80,3 +82,8 @@ int skl_int3472_get_sensor_adev_and_name(struct device *dev,
-
- return ret;
- }
-+EXPORT_SYMBOL_GPL(skl_int3472_get_sensor_adev_and_name);
-+
-+MODULE_DESCRIPTION("Intel SkyLake INT3472 ACPI Device Driver library");
-+MODULE_AUTHOR("Daniel Scally <djrscally@gmail.com>");
-+MODULE_LICENSE("GPL");
-diff --git a/include/linux/platform_data/x86/asus-wmi.h b/include/linux/platform_data/x86/asus-wmi.h
-index 3eb5cd6773ad..a23cc8624218 100644
---- a/include/linux/platform_data/x86/asus-wmi.h
-+++ b/include/linux/platform_data/x86/asus-wmi.h
-@@ -4,6 +4,7 @@
-
- #include <linux/errno.h>
- #include <linux/types.h>
-+#include <linux/dmi.h>
-
- /* WMI Methods */
- #define ASUS_WMI_METHODID_SPEC 0x43455053 /* BIOS SPECification */
-@@ -64,8 +65,10 @@
- #define ASUS_WMI_DEVID_SCREENPAD_LIGHT 0x00050032
- #define ASUS_WMI_DEVID_FAN_BOOST_MODE 0x00110018
- #define ASUS_WMI_DEVID_THROTTLE_THERMAL_POLICY 0x00120075
-+#define ASUS_WMI_DEVID_THROTTLE_THERMAL_POLICY_VIVO 0x00110019
-
- /* Misc */
-+#define ASUS_WMI_DEVID_PANEL_HD 0x0005001C
- #define ASUS_WMI_DEVID_PANEL_OD 0x00050019
- #define ASUS_WMI_DEVID_CAMERA 0x00060013
- #define ASUS_WMI_DEVID_LID_FLIP 0x00060062
-@@ -126,6 +129,14 @@
- /* dgpu on/off */
- #define ASUS_WMI_DEVID_DGPU 0x00090020
-
-+/* Intel E-core and P-core configuration in a format 0x0[E]0[P] */
-+#define ASUS_WMI_DEVID_CORES 0x001200D2
-+ /* Maximum Intel E-core and P-core availability */
-+#define ASUS_WMI_DEVID_CORES_MAX 0x001200D3
-+#define ASUS_WMI_DEVID_DGPU_BASE_TGP 0x00120099
-+#define ASUS_WMI_DEVID_DGPU_SET_TGP 0x00120098
-+#define ASUS_WMI_DEVID_APU_MEM 0x000600C1
-+
- /* gpu mux switch, 0 = dGPU, 1 = Optimus */
- #define ASUS_WMI_DEVID_GPU_MUX 0x00090016
- #define ASUS_WMI_DEVID_GPU_MUX_VIVO 0x00090026
-@@ -151,8 +162,18 @@
- #define ASUS_WMI_DSTS_LIGHTBAR_MASK 0x0000000F
-
- #if IS_REACHABLE(CONFIG_ASUS_WMI)
-+int asus_wmi_get_devstate_dsts(u32 dev_id, u32 *retval);
-+int asus_wmi_set_devstate(u32 dev_id, u32 ctrl_param, u32 *retval);
- int asus_wmi_evaluate_method(u32 method_id, u32 arg0, u32 arg1, u32 *retval);
- #else
-+static int asus_wmi_get_devstate_dsts(u32 dev_id, u32 *retval)
-+{
-+ return -ENODEV;
-+}
-+static int asus_wmi_set_devstate(u32 dev_id, u32 ctrl_param, u32 *retval)
-+{
-+ return -ENODEV;
-+}
- static inline int asus_wmi_evaluate_method(u32 method_id, u32 arg0, u32 arg1,
- u32 *retval)
- {
-@@ -160,4 +181,39 @@ static inline int asus_wmi_evaluate_method(u32 method_id, u32 arg0, u32 arg1,
- }
- #endif
-
-+/* To be used by both hid-asus and asus-wmi to determine which controls kbd_brightness */
-+static const struct dmi_system_id asus_use_hid_led_dmi_ids[] = {
-+ {
-+ .matches = {
-+ DMI_MATCH(DMI_PRODUCT_FAMILY, "ROG Zephyrus"),
-+ },
-+ },
-+ {
-+ .matches = {
-+ DMI_MATCH(DMI_PRODUCT_FAMILY, "ROG Strix"),
-+ },
-+ },
-+ {
-+ .matches = {
-+ DMI_MATCH(DMI_PRODUCT_FAMILY, "ROG Flow"),
-+ },
-+ },
-+ {
-+ .matches = {
-+ DMI_MATCH(DMI_BOARD_NAME, "GA403U"),
-+ },
-+ },
-+ {
-+ .matches = {
-+ DMI_MATCH(DMI_BOARD_NAME, "GU605M"),
-+ },
-+ },
-+ {
-+ .matches = {
-+ DMI_MATCH(DMI_BOARD_NAME, "RC71L"),
-+ },
-+ },
-+ { },
-+};
-+
- #endif /* __PLATFORM_DATA_X86_ASUS_WMI_H */
-diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
-index 3840565ef8b0..5641b40b9cdc 100644
---- a/sound/pci/hda/patch_realtek.c
-+++ b/sound/pci/hda/patch_realtek.c
-@@ -7409,6 +7409,7 @@ enum {
- ALC285_FIXUP_THINKPAD_X1_GEN7,
- ALC285_FIXUP_THINKPAD_HEADSET_JACK,
- ALC294_FIXUP_ASUS_ALLY,
-+ ALC294_FIXUP_ASUS_ALLY_X,
- ALC294_FIXUP_ASUS_ALLY_PINS,
- ALC294_FIXUP_ASUS_ALLY_VERBS,
- ALC294_FIXUP_ASUS_ALLY_SPEAKER,
-@@ -8875,6 +8876,12 @@ static const struct hda_fixup alc269_fixups[] = {
- .chained = true,
- .chain_id = ALC294_FIXUP_ASUS_ALLY_PINS
- },
-+ [ALC294_FIXUP_ASUS_ALLY_X] = {
-+ .type = HDA_FIXUP_FUNC,
-+ .v.func = tas2781_fixup_i2c,
-+ .chained = true,
-+ .chain_id = ALC294_FIXUP_ASUS_ALLY_PINS
-+ },
- [ALC294_FIXUP_ASUS_ALLY_PINS] = {
- .type = HDA_FIXUP_PINS,
- .v.pins = (const struct hda_pintbl[]) {
-@@ -10307,6 +10314,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
- SND_PCI_QUIRK(0x1043, 0x1740, "ASUS UX430UA", ALC295_FIXUP_ASUS_DACS),
- SND_PCI_QUIRK(0x1043, 0x17d1, "ASUS UX431FL", ALC294_FIXUP_ASUS_DUAL_SPK),
- SND_PCI_QUIRK(0x1043, 0x17f3, "ROG Ally NR2301L/X", ALC294_FIXUP_ASUS_ALLY),
-+ SND_PCI_QUIRK(0x1043, 0x1eb3, "ROG Ally X RC72LA", ALC294_FIXUP_ASUS_ALLY_X),
- SND_PCI_QUIRK(0x1043, 0x1863, "ASUS UX6404VI/VV", ALC245_FIXUP_CS35L41_SPI_2),
- SND_PCI_QUIRK(0x1043, 0x1881, "ASUS Zephyrus S/M", ALC294_FIXUP_ASUS_GX502_PINS),
- SND_PCI_QUIRK(0x1043, 0x18b1, "Asus MJ401TA", ALC256_FIXUP_ASUS_HEADSET_MIC),
diff --git a/SOURCES/kernel-s390x-debug-fedora.config b/SOURCES/kernel-s390x-debug-fedora.config
index 59ccfe6..08be104 100644
--- a/SOURCES/kernel-s390x-debug-fedora.config
+++ b/SOURCES/kernel-s390x-debug-fedora.config
@@ -5148,6 +5148,7 @@ CONFIG_RADIO_WL1273=m
CONFIG_RAID_ATTRS=m
CONFIG_RANDOM32_SELFTEST=y
CONFIG_RANDOMIZE_BASE=y
+# CONFIG_RANDOMIZE_IDENTITY_BASE is not set
CONFIG_RANDOMIZE_KSTACK_OFFSET_DEFAULT=y
CONFIG_RANDOMIZE_KSTACK_OFFSET=y
CONFIG_RANDOMIZE_MEMORY_PHYSICAL_PADDING=0xa
diff --git a/SOURCES/kernel-s390x-debug-rhel.config b/SOURCES/kernel-s390x-debug-rhel.config
index f47ccc6..dba2e6e 100644
--- a/SOURCES/kernel-s390x-debug-rhel.config
+++ b/SOURCES/kernel-s390x-debug-rhel.config
@@ -4725,6 +4725,7 @@ CONFIG_RADIO_TEA575X=m
CONFIG_RAID_ATTRS=m
CONFIG_RANDOM32_SELFTEST=y
CONFIG_RANDOMIZE_BASE=y
+# CONFIG_RANDOMIZE_IDENTITY_BASE is not set
CONFIG_RANDOMIZE_KSTACK_OFFSET_DEFAULT=y
CONFIG_RANDOMIZE_KSTACK_OFFSET=y
CONFIG_RANDOMIZE_MEMORY_PHYSICAL_PADDING=0xa
diff --git a/SOURCES/kernel-s390x-fedora.config b/SOURCES/kernel-s390x-fedora.config
index dd3adc9..2ab7209 100644
--- a/SOURCES/kernel-s390x-fedora.config
+++ b/SOURCES/kernel-s390x-fedora.config
@@ -5119,6 +5119,7 @@ CONFIG_RADIO_WL1273=m
CONFIG_RAID_ATTRS=m
# CONFIG_RANDOM32_SELFTEST is not set
CONFIG_RANDOMIZE_BASE=y
+# CONFIG_RANDOMIZE_IDENTITY_BASE is not set
CONFIG_RANDOMIZE_KSTACK_OFFSET_DEFAULT=y
CONFIG_RANDOMIZE_KSTACK_OFFSET=y
CONFIG_RANDOMIZE_MEMORY_PHYSICAL_PADDING=0xa
diff --git a/SOURCES/kernel-s390x-rhel.config b/SOURCES/kernel-s390x-rhel.config
index 20d1a61..893cdd0 100644
--- a/SOURCES/kernel-s390x-rhel.config
+++ b/SOURCES/kernel-s390x-rhel.config
@@ -4704,6 +4704,7 @@ CONFIG_RADIO_TEA575X=m
CONFIG_RAID_ATTRS=m
# CONFIG_RANDOM32_SELFTEST is not set
CONFIG_RANDOMIZE_BASE=y
+# CONFIG_RANDOMIZE_IDENTITY_BASE is not set
CONFIG_RANDOMIZE_KSTACK_OFFSET_DEFAULT=y
CONFIG_RANDOMIZE_KSTACK_OFFSET=y
CONFIG_RANDOMIZE_MEMORY_PHYSICAL_PADDING=0xa
diff --git a/SOURCES/kernel-s390x-zfcpdump-rhel.config b/SOURCES/kernel-s390x-zfcpdump-rhel.config
index 582dc9b..93c6e5f 100644
--- a/SOURCES/kernel-s390x-zfcpdump-rhel.config
+++ b/SOURCES/kernel-s390x-zfcpdump-rhel.config
@@ -4716,6 +4716,7 @@ CONFIG_RADIO_TEA575X=m
# CONFIG_RAID_ATTRS is not set
# CONFIG_RANDOM32_SELFTEST is not set
CONFIG_RANDOMIZE_BASE=y
+# CONFIG_RANDOMIZE_IDENTITY_BASE is not set
CONFIG_RANDOMIZE_KSTACK_OFFSET_DEFAULT=y
CONFIG_RANDOMIZE_KSTACK_OFFSET=y
CONFIG_RANDOMIZE_MEMORY_PHYSICAL_PADDING=0xa
diff --git a/SOURCES/kernel.changelog b/SOURCES/kernel.changelog
index 31d659f..4771116 100644
--- a/SOURCES/kernel.changelog
+++ b/SOURCES/kernel.changelog
@@ -1,3 +1,22 @@
+* Mon Sep 30 2024 Augusto Caringi <acaringi@redhat.com> [6.10.12-0]
+- Linux v6.10.12
+Resolves:
+
+* Wed Sep 18 2024 Augusto Caringi <acaringi@redhat.com> [6.10.11-0]
+- New config for 6.10.11 (Augusto Caringi)
+- Linux v6.10.11
+Resolves:
+
+* Thu Sep 12 2024 Augusto Caringi <acaringi@redhat.com> [6.10.10-0]
+- Add entry for BugsFixed (Justin M. Forbes)
+- drm/nouveau/fb: restore init() for ramgp102 (Ben Skeggs)
+- Linux v6.10.10
+Resolves:
+
+* Sun Sep 08 2024 Justin M. Forbes <jforbes@fedoraproject.org> [6.10.9-0]
+- Linux v6.10.9
+Resolves:
+
* Wed Sep 04 2024 Augusto Caringi <acaringi@redhat.com> [6.10.8-0]
- Add to BugsFixed (Augusto Caringi)
- xfs: xfs_finobt_count_blocks() walks the wrong btree (Dave Chinner)
diff --git a/SOURCES/linux-surface.patch b/SOURCES/linux-surface.patch
index 303c347..9d19868 100644
--- a/SOURCES/linux-surface.patch
+++ b/SOURCES/linux-surface.patch
@@ -1,4 +1,4 @@
-From 252c5b2e65865a2a3aa6a5400f204c47d22490ee Mon Sep 17 00:00:00 2001
+From 2dd7c57b604b7cae49efcebc5fb6e46f7401a69b Mon Sep 17 00:00:00 2001
From: Maximilian Luz <luzmaximilian@gmail.com>
Date: Sun, 9 Jun 2024 19:48:58 +0200
Subject: [PATCH] Revert "efi/x86: Set the PE/COFF header's NX compat flag
@@ -33,9 +33,84 @@ index b5c79f43359b..a1bbedd989e4 100644
.long 0 # SizeOfStackReserve
.long 0 # SizeOfStackCommit
--
-2.46.0
+2.46.1
-From 1146270e92aee0b612dfe695bcf8f7131a19bcf3 Mon Sep 17 00:00:00 2001
+From 8c63d9f68dff804be41fcf71b725a1e28c78118f Mon Sep 17 00:00:00 2001
+From: "J. Eduardo" <j.eduardo@gmail.com>
+Date: Sun, 25 Aug 2024 14:17:45 +0200
+Subject: [PATCH] PM: hibernate: Add a lockdown_hibernate parameter
+
+This allows the user to tell the kernel that they know better (namely,
+they secured their swap properly), and that it can enable hibernation.
+
+Signed-off-by: Kelvie Wong <kelvie@kelvie.ca>
+Link: https://github.com/linux-surface/kernel/pull/158
+Link: https://gist.github.com/brknkfr/95d1925ccdbb7a2d18947c168dfabbee
+Patchset: secureboot
+---
+ Documentation/admin-guide/kernel-parameters.txt | 5 +++++
+ kernel/power/hibernate.c | 10 +++++++++-
+ 2 files changed, 14 insertions(+), 1 deletion(-)
+
+diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
+index c82446cef8e2..2ae1a6fda7f9 100644
+--- a/Documentation/admin-guide/kernel-parameters.txt
++++ b/Documentation/admin-guide/kernel-parameters.txt
+@@ -3000,6 +3000,11 @@
+ to extract confidential information from the kernel
+ are also disabled.
+
++ lockdown_hibernate [HIBERNATION]
++ Enable hibernation even if lockdown is enabled. Enable this only if
++ your swap is encrypted and secured properly, as an attacker can
++ modify the kernel offline during hibernation.
++
+ locktorture.acq_writer_lim= [KNL]
+ Set the time limit in jiffies for a lock
+ acquisition. Acquisitions exceeding this limit
+diff --git a/kernel/power/hibernate.c b/kernel/power/hibernate.c
+index 0a213f69a9e4..8e4f9dcc9f4c 100644
+--- a/kernel/power/hibernate.c
++++ b/kernel/power/hibernate.c
+@@ -37,6 +37,7 @@
+ #include "power.h"
+
+
++static int lockdown_hibernate;
+ static int nocompress;
+ static int noresume;
+ static int nohibernate;
+@@ -92,7 +93,7 @@ void hibernate_release(void)
+ bool hibernation_available(void)
+ {
+ return nohibernate == 0 &&
+- !security_locked_down(LOCKDOWN_HIBERNATION) &&
++ (lockdown_hibernate || !security_locked_down(LOCKDOWN_HIBERNATION)) &&
+ !secretmem_active() && !cxl_mem_active();
+ }
+
+@@ -1422,6 +1423,12 @@ static int __init nohibernate_setup(char *str)
+ return 1;
+ }
+
++static int __init lockdown_hibernate_setup(char *str)
++{
++ lockdown_hibernate = 1;
++ return 1;
++}
++
+ static const char * const comp_alg_enabled[] = {
+ #if IS_ENABLED(CONFIG_CRYPTO_LZO)
+ COMPRESSION_ALGO_LZO,
+@@ -1480,3 +1487,4 @@ __setup("hibernate=", hibernate_setup);
+ __setup("resumewait", resumewait_setup);
+ __setup("resumedelay=", resumedelay_setup);
+ __setup("nohibernate", nohibernate_setup);
++__setup("lockdown_hibernate", lockdown_hibernate_setup);
+--
+2.46.1
+
+From 3d3aec0cd78fd07d406486dd140daa7baf1fba7c Mon Sep 17 00:00:00 2001
From: Tsuchiya Yuto <kitakar@gmail.com>
Date: Sun, 18 Oct 2020 16:42:44 +0900
Subject: [PATCH] (surface3-oemb) add DMI matches for Surface 3 with broken DMI
@@ -134,9 +209,9 @@ index 5e2ec60e2954..207868c699f2 100644
};
--
-2.46.0
+2.46.1
-From 800e9cfe84a3eadd4dc9ae700940068e77fa8a12 Mon Sep 17 00:00:00 2001
+From a50739a5e7b0ca9f6bca85606f2b9389a9dd6bec Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= <verdre@v0yd.nl>
Date: Tue, 3 Nov 2020 13:28:04 +0100
Subject: [PATCH] mwifiex: Add quirk resetting the PCI bridge on MS Surface
@@ -301,9 +376,9 @@ index d6ff964aec5b..5d30ae39d65e 100644
void mwifiex_initialize_quirks(struct pcie_service_card *card);
int mwifiex_pcie_reset_d3cold_quirk(struct pci_dev *pdev);
--
-2.46.0
+2.46.1
-From d51c5a356fee57c99a8d181825f8f941f34749d7 Mon Sep 17 00:00:00 2001
+From 883ef69235ff8daa9653576dd6104460f60b7bde Mon Sep 17 00:00:00 2001
From: Tsuchiya Yuto <kitakar@gmail.com>
Date: Sun, 4 Oct 2020 00:11:49 +0900
Subject: [PATCH] mwifiex: pcie: disable bridge_d3 for Surface gen4+
@@ -456,9 +531,9 @@ index 5d30ae39d65e..c14eb56eb911 100644
void mwifiex_initialize_quirks(struct pcie_service_card *card);
int mwifiex_pcie_reset_d3cold_quirk(struct pci_dev *pdev);
--
-2.46.0
+2.46.1
-From 317cde3654592dcb3e072d0d2fe7b4e5598cc078 Mon Sep 17 00:00:00 2001
+From 9e1720f0132e61bc6f738284080c6925941e1a91 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= <verdre@v0yd.nl>
Date: Thu, 25 Mar 2021 11:33:02 +0100
Subject: [PATCH] Bluetooth: btusb: Lower passive lescan interval on Marvell
@@ -494,7 +569,7 @@ Patchset: mwifiex
1 file changed, 15 insertions(+)
diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
-index 789c492df6fa..1e766b6c1f9a 100644
+index 0927f51867c2..3d3573829631 100644
--- a/drivers/bluetooth/btusb.c
+++ b/drivers/bluetooth/btusb.c
@@ -65,6 +65,7 @@ static struct usb_driver btusb_driver;
@@ -534,9 +609,9 @@ index 789c492df6fa..1e766b6c1f9a 100644
(id->driver_info & BTUSB_MEDIATEK)) {
hdev->setup = btusb_mtk_setup;
--
-2.46.0
+2.46.1
-From 268a79fb66862ef22294397a425fd074fc336c34 Mon Sep 17 00:00:00 2001
+From 68efac8fe5bd9af5e3c3e1d3cf7d9d2a3a5f4248 Mon Sep 17 00:00:00 2001
From: Maximilian Luz <luzmaximilian@gmail.com>
Date: Sat, 27 Feb 2021 00:45:52 +0100
Subject: [PATCH] ath10k: Add module parameters to override board files
@@ -654,9 +729,9 @@ index bdf0552cd1c3..e062cc687689 100644
snprintf(filename, sizeof(filename), "%s/%s/%s",
dir, ar->board_name, file);
--
-2.46.0
+2.46.1
-From 9904c59dbdd422b811974893bab69fc5b4bc9a03 Mon Sep 17 00:00:00 2001
+From 7e608ebdf188a298503111e503a4cc2fc3880f7c Mon Sep 17 00:00:00 2001
From: Dorian Stoll <dorian.stoll@tmsp.io>
Date: Thu, 30 Jul 2020 13:21:53 +0200
Subject: [PATCH] mei: me: Add Icelake device ID for iTouch
@@ -693,9 +768,9 @@ index 6589635f8ba3..a1df48a434e2 100644
{MEI_PCI_DEVICE(MEI_DEV_ID_TGP_LP, MEI_ME_PCH15_CFG)},
--
-2.46.0
+2.46.1
-From b0d9ceae2f95a4e4093b07580bedc10821374555 Mon Sep 17 00:00:00 2001
+From 8b12cf7a1fe199057c7a39087d233f62fd4d6a93 Mon Sep 17 00:00:00 2001
From: Liban Hannan <liban.p@gmail.com>
Date: Tue, 12 Apr 2022 23:31:12 +0100
Subject: [PATCH] iommu: Use IOMMU passthrough mode for IPTS
@@ -719,7 +794,7 @@ Patchset: ipts
1 file changed, 29 insertions(+)
diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c
-index f55ec1fd7942..8d95579436a9 100644
+index e9bea0305c26..6ee97bf7b6a9 100644
--- a/drivers/iommu/intel/iommu.c
+++ b/drivers/iommu/intel/iommu.c
@@ -40,6 +40,11 @@
@@ -800,9 +875,9 @@ index f55ec1fd7942..8d95579436a9 100644
{
if (risky_device(dev))
--
-2.46.0
+2.46.1
-From ee1ebc3f9ec7a8418f418902817b5c5f4b51c21d Mon Sep 17 00:00:00 2001
+From fd63fc042c6554c75134e4dab8e4a1d74c495d05 Mon Sep 17 00:00:00 2001
From: Dorian Stoll <dorian.stoll@tmsp.io>
Date: Sun, 11 Dec 2022 12:00:59 +0100
Subject: [PATCH] hid: Add support for Intel Precise Touch and Stylus
@@ -3895,9 +3970,9 @@ index 000000000000..1f966b8b32c4
+
+#endif /* IPTS_THREAD_H */
--
-2.46.0
+2.46.1
-From 0d0e07366b425e953d6dab698d62dbe9a7546994 Mon Sep 17 00:00:00 2001
+From dc65c76763207057a6797b0ef844c3f58e6a6e15 Mon Sep 17 00:00:00 2001
From: Dorian Stoll <dorian.stoll@tmsp.io>
Date: Sun, 11 Dec 2022 12:03:38 +0100
Subject: [PATCH] iommu: intel: Disable source id verification for ITHC
@@ -3936,9 +4011,9 @@ index e4a70886678c..961a33b87c24 100644
* DMA alias provides us with a PCI device and alias. The only case
* where the it will return an alias on a different bus than the
--
-2.46.0
+2.46.1
-From 19a947aa5cc417bd43656cf9d8bf010abdc6bc3f Mon Sep 17 00:00:00 2001
+From c3ddc02f7b0e27c09233022d7bbfd6b72ca12d2e Mon Sep 17 00:00:00 2001
From: quo <tuple@list.ru>
Date: Sun, 11 Dec 2022 12:10:54 +0100
Subject: [PATCH] hid: Add support for Intel Touch Host Controller
@@ -6666,169 +6741,9 @@ index 000000000000..aec320d4e945
+int ithc_reset(struct ithc *ithc);
+
--
-2.46.0
-
-From 00b833401e8060eb50db269e0681383454a74848 Mon Sep 17 00:00:00 2001
-From: Maximilian Luz <luzmaximilian@gmail.com>
-Date: Sun, 22 Oct 2023 14:57:11 +0200
-Subject: [PATCH] platform/surface: aggregator_registry: Add support for
- Surface Laptop Go 3
-
-Add SAM client device nodes for the Surface Laptop Go 3. It seems to use
-the same SAM client devices as the Surface Laptop Go 1 and 2, so re-use
-their node group.
-
-Signed-off-by: Maximilian Luz <luzmaximilian@gmail.com>
-Patchset: surface-sam
----
- drivers/platform/surface/surface_aggregator_registry.c | 3 +++
- 1 file changed, 3 insertions(+)
-
-diff --git a/drivers/platform/surface/surface_aggregator_registry.c b/drivers/platform/surface/surface_aggregator_registry.c
-index 1c4d74db08c9..f826489dc69d 100644
---- a/drivers/platform/surface/surface_aggregator_registry.c
-+++ b/drivers/platform/surface/surface_aggregator_registry.c
-@@ -395,6 +395,9 @@ static const struct acpi_device_id ssam_platform_hub_match[] = {
- /* Surface Laptop Go 2 */
- { "MSHW0290", (unsigned long)ssam_node_group_slg1 },
-
-+ /* Surface Laptop Go 3 */
-+ { "MSHW0440", (unsigned long)ssam_node_group_slg1 },
-+
- /* Surface Laptop Studio */
- { "MSHW0123", (unsigned long)ssam_node_group_sls },
-
---
-2.46.0
-
-From 9e13165394bf1898d05c7d5a4a5adb1767d2307e Mon Sep 17 00:00:00 2001
-From: Maximilian Luz <luzmaximilian@gmail.com>
-Date: Mon, 20 Nov 2023 19:47:00 +0100
-Subject: [PATCH] platform/surface: aggregator_registry: Add support for
- Surface Laptop Studio 2
-
-Add SAM client device nodes for the Surface Laptop Studio 2 (SLS2). The
-SLS2 is quite similar to the SLS1, but it does not provide the touchpad
-as a SAM-HID device. Therefore, add a new node group for the SLS2 and
-update the comments accordingly
-
-Signed-off-by: Maximilian Luz <luzmaximilian@gmail.com>
-Patchset: surface-sam
----
- .../surface/surface_aggregator_registry.c | 25 ++++++++++++++++---
- 1 file changed, 21 insertions(+), 4 deletions(-)
-
-diff --git a/drivers/platform/surface/surface_aggregator_registry.c b/drivers/platform/surface/surface_aggregator_registry.c
-index f826489dc69d..ef59a7b66667 100644
---- a/drivers/platform/surface/surface_aggregator_registry.c
-+++ b/drivers/platform/surface/surface_aggregator_registry.c
-@@ -273,8 +273,8 @@ static const struct software_node *ssam_node_group_sl5[] = {
- NULL,
- };
-
--/* Devices for Surface Laptop Studio. */
--static const struct software_node *ssam_node_group_sls[] = {
-+/* Devices for Surface Laptop Studio 1. */
-+static const struct software_node *ssam_node_group_sls1[] = {
- &ssam_node_root,
- &ssam_node_bat_ac,
- &ssam_node_bat_main,
-@@ -289,6 +289,20 @@ static const struct software_node *ssam_node_group_sls[] = {
- NULL,
- };
-
-+/* Devices for Surface Laptop Studio 2. */
-+static const struct software_node *ssam_node_group_sls2[] = {
-+ &ssam_node_root,
-+ &ssam_node_bat_ac,
-+ &ssam_node_bat_main,
-+ &ssam_node_tmp_pprof,
-+ &ssam_node_pos_tablet_switch,
-+ &ssam_node_hid_sam_keyboard,
-+ &ssam_node_hid_sam_penstash,
-+ &ssam_node_hid_sam_sensors,
-+ &ssam_node_hid_sam_ucm_ucsi,
-+ NULL,
-+};
-+
- /* Devices for Surface Laptop Go. */
- static const struct software_node *ssam_node_group_slg1[] = {
- &ssam_node_root,
-@@ -398,8 +412,11 @@ static const struct acpi_device_id ssam_platform_hub_match[] = {
- /* Surface Laptop Go 3 */
- { "MSHW0440", (unsigned long)ssam_node_group_slg1 },
-
-- /* Surface Laptop Studio */
-- { "MSHW0123", (unsigned long)ssam_node_group_sls },
-+ /* Surface Laptop Studio 1 */
-+ { "MSHW0123", (unsigned long)ssam_node_group_sls1 },
-+
-+ /* Surface Laptop Studio 2 */
-+ { "MSHW0360", (unsigned long)ssam_node_group_sls2 },
-
- { },
- };
---
-2.46.0
-
-From 83719d2cd70ad6ac1df993782e757ded15e881cc Mon Sep 17 00:00:00 2001
-From: Maximilian Luz <luzmaximilian@gmail.com>
-Date: Sun, 9 Jun 2024 20:05:57 +0200
-Subject: [PATCH] platform/surface: aggregator_registry: Add support for
- Surface Laptop 6
-
-Add SAM client device nodes for the Surface Laptop Studio 6 (SL6). The
-SL6 is similar to the SL5, with the typical battery/AC, platform
-profile, and HID nodes. It also has support for the newly supported fan
-interface.
-
-Signed-off-by: Maximilian Luz <luzmaximilian@gmail.com>
-Patchset: surface-sam
----
- .../surface/surface_aggregator_registry.c | 19 +++++++++++++++++++
- 1 file changed, 19 insertions(+)
-
-diff --git a/drivers/platform/surface/surface_aggregator_registry.c b/drivers/platform/surface/surface_aggregator_registry.c
-index ef59a7b66667..70a2ea5a1957 100644
---- a/drivers/platform/surface/surface_aggregator_registry.c
-+++ b/drivers/platform/surface/surface_aggregator_registry.c
-@@ -273,6 +273,22 @@ static const struct software_node *ssam_node_group_sl5[] = {
- NULL,
- };
-
-+/* Devices for Surface Laptop 6. */
-+static const struct software_node *ssam_node_group_sl6[] = {
-+ &ssam_node_root,
-+ &ssam_node_bat_ac,
-+ &ssam_node_bat_main,
-+ &ssam_node_tmp_perf_profile_with_fan,
-+ &ssam_node_tmp_sensors,
-+ &ssam_node_fan_speed,
-+ &ssam_node_hid_main_keyboard,
-+ &ssam_node_hid_main_touchpad,
-+ &ssam_node_hid_main_iid5,
-+ &ssam_node_hid_sam_sensors,
-+ &ssam_node_hid_sam_ucm_ucsi,
-+ NULL,
-+};
-+
- /* Devices for Surface Laptop Studio 1. */
- static const struct software_node *ssam_node_group_sls1[] = {
- &ssam_node_root,
-@@ -403,6 +419,9 @@ static const struct acpi_device_id ssam_platform_hub_match[] = {
- /* Surface Laptop 5 */
- { "MSHW0350", (unsigned long)ssam_node_group_sl5 },
-
-+ /* Surface Laptop 6 */
-+ { "MSHW0530", (unsigned long)ssam_node_group_sl5 },
-+
- /* Surface Laptop Go 1 */
- { "MSHW0118", (unsigned long)ssam_node_group_slg1 },
-
---
-2.46.0
+2.46.1
-From c188646846cc6e9db1134eb62208d088ce615312 Mon Sep 17 00:00:00 2001
+From 3e6733db885b3a91339039897cbf0f3e05cda2a5 Mon Sep 17 00:00:00 2001
From: Maximilian Luz <luzmaximilian@gmail.com>
Date: Sat, 30 Dec 2023 18:07:54 +0100
Subject: [PATCH] hwmon: Add thermal sensor driver for Surface Aggregator
@@ -7054,9 +6969,9 @@ index 000000000000..48c3e826713f
+MODULE_DESCRIPTION("Thermal sensor subsystem driver for Surface System Aggregator Module");
+MODULE_LICENSE("GPL");
--
-2.46.0
+2.46.1
-From 31d334453ebc65b7868bf33b1963553586e64fa3 Mon Sep 17 00:00:00 2001
+From 3e4479ac556ff21b45485822edb0980bbb27fdba Mon Sep 17 00:00:00 2001
From: Maximilian Luz <luzmaximilian@gmail.com>
Date: Sat, 30 Dec 2023 18:12:23 +0100
Subject: [PATCH] hwmon: surface_temp: Add support for sensor names
@@ -7249,121 +7164,9 @@ index 48c3e826713f..4c08926139db 100644
"surface_thermal", ssam_temp, &ssam_temp_hwmon_chip_info,
NULL);
--
-2.46.0
-
-From 36174000616d130e9b4655d69eb3bd5b07adbecb Mon Sep 17 00:00:00 2001
-From: Maximilian Luz <luzmaximilian@gmail.com>
-Date: Mon, 10 Jun 2024 21:47:47 +0200
-Subject: [PATCH] platform/surface: aggregator_registry: Add fan and thermal
- sensor support for Surface Laptop 5
-
-Patchset: surface-sam
----
- drivers/platform/surface/surface_aggregator_registry.c | 4 +++-
- 1 file changed, 3 insertions(+), 1 deletion(-)
-
-diff --git a/drivers/platform/surface/surface_aggregator_registry.c b/drivers/platform/surface/surface_aggregator_registry.c
-index 70a2ea5a1957..6b568804f70b 100644
---- a/drivers/platform/surface/surface_aggregator_registry.c
-+++ b/drivers/platform/surface/surface_aggregator_registry.c
-@@ -265,7 +265,9 @@ static const struct software_node *ssam_node_group_sl5[] = {
- &ssam_node_root,
- &ssam_node_bat_ac,
- &ssam_node_bat_main,
-- &ssam_node_tmp_perf_profile,
-+ &ssam_node_tmp_perf_profile_with_fan,
-+ &ssam_node_tmp_sensors,
-+ &ssam_node_fan_speed,
- &ssam_node_hid_main_keyboard,
- &ssam_node_hid_main_touchpad,
- &ssam_node_hid_main_iid5,
---
-2.46.0
-
-From e32f317be4ad620fb6683b62ad9e883f37e17f57 Mon Sep 17 00:00:00 2001
-From: Maximilian Luz <luzmaximilian@gmail.com>
-Date: Mon, 10 Jun 2024 21:48:02 +0200
-Subject: [PATCH] platform/surface: aggregator_registry: Add fan and thermal
- sensor support for Surface Laptop Studio 2
-
-Patchset: surface-sam
----
- drivers/platform/surface/surface_aggregator_registry.c | 4 +++-
- 1 file changed, 3 insertions(+), 1 deletion(-)
-
-diff --git a/drivers/platform/surface/surface_aggregator_registry.c b/drivers/platform/surface/surface_aggregator_registry.c
-index 6b568804f70b..9046df95c043 100644
---- a/drivers/platform/surface/surface_aggregator_registry.c
-+++ b/drivers/platform/surface/surface_aggregator_registry.c
-@@ -312,7 +312,9 @@ static const struct software_node *ssam_node_group_sls2[] = {
- &ssam_node_root,
- &ssam_node_bat_ac,
- &ssam_node_bat_main,
-- &ssam_node_tmp_pprof,
-+ &ssam_node_tmp_perf_profile_with_fan,
-+ &ssam_node_tmp_sensors,
-+ &ssam_node_fan_speed,
- &ssam_node_pos_tablet_switch,
- &ssam_node_hid_sam_keyboard,
- &ssam_node_hid_sam_penstash,
---
-2.46.0
-
-From ebf64f6dcf1bdf0dbe80b5ec5e3d4b8a6cfab41e Mon Sep 17 00:00:00 2001
-From: Maximilian Luz <luzmaximilian@gmail.com>
-Date: Fri, 28 Jun 2024 22:31:37 +0200
-Subject: [PATCH] platform/surface: aggregator_registry: Add Support for
- Surface Pro 10
-
-Patchset: surface-sam
----
- .../surface/surface_aggregator_registry.c | 22 +++++++++++++++++++
- 1 file changed, 22 insertions(+)
-
-diff --git a/drivers/platform/surface/surface_aggregator_registry.c b/drivers/platform/surface/surface_aggregator_registry.c
-index 9046df95c043..058f4edd8b66 100644
---- a/drivers/platform/surface/surface_aggregator_registry.c
-+++ b/drivers/platform/surface/surface_aggregator_registry.c
-@@ -377,6 +377,25 @@ static const struct software_node *ssam_node_group_sp9[] = {
- NULL,
- };
-
-+/* Devices for Surface Pro 10 */
-+static const struct software_node *ssam_node_group_sp10[] = {
-+ &ssam_node_root,
-+ &ssam_node_hub_kip,
-+ &ssam_node_bat_ac,
-+ &ssam_node_bat_main,
-+ &ssam_node_tmp_perf_profile_with_fan,
-+ &ssam_node_tmp_sensors,
-+ &ssam_node_fan_speed,
-+ &ssam_node_pos_tablet_switch,
-+ &ssam_node_hid_kip_keyboard,
-+ &ssam_node_hid_kip_penstash,
-+ &ssam_node_hid_kip_touchpad,
-+ &ssam_node_hid_kip_fwupd,
-+ &ssam_node_hid_sam_sensors,
-+ &ssam_node_hid_sam_ucm_ucsi,
-+ NULL,
-+};
-+
-
- /* -- SSAM platform/meta-hub driver. ---------------------------------------- */
-
-@@ -399,6 +418,9 @@ static const struct acpi_device_id ssam_platform_hub_match[] = {
- /* Surface Pro 9 */
- { "MSHW0343", (unsigned long)ssam_node_group_sp9 },
-
-+ /* Surface Pro 10 */
-+ { "MSHW0510", (unsigned long)ssam_node_group_sp10 },
-+
- /* Surface Book 2 */
- { "MSHW0107", (unsigned long)ssam_node_group_gen5 },
-
---
-2.46.0
+2.46.1
-From 8dac7a369f2f1c461750a3c3f6d93caae9566ace Mon Sep 17 00:00:00 2001
+From 134830c02674d93c2433bb898de34d1b84467f86 Mon Sep 17 00:00:00 2001
From: Maximilian Luz <luzmaximilian@gmail.com>
Date: Sat, 25 Jul 2020 17:19:53 +0200
Subject: [PATCH] i2c: acpi: Implement RawBytes read access
@@ -7416,14 +7219,14 @@ quirk-like interface into the I2C core.
Signed-off-by: Maximilian Luz <luzmaximilian@gmail.com>
Patchset: surface-sam-over-hid
---
- drivers/i2c/i2c-core-acpi.c | 35 +++++++++++++++++++++++++++++++++++
- 1 file changed, 35 insertions(+)
+ drivers/i2c/i2c-core-acpi.c | 34 ++++++++++++++++++++++++++++++++++
+ 1 file changed, 34 insertions(+)
diff --git a/drivers/i2c/i2c-core-acpi.c b/drivers/i2c/i2c-core-acpi.c
-index 14ae0cfc325e..a3a9f81fb47f 100644
+index 14ae0cfc325e..6197c5252d2a 100644
--- a/drivers/i2c/i2c-core-acpi.c
+++ b/drivers/i2c/i2c-core-acpi.c
-@@ -639,6 +639,28 @@ static int acpi_gsb_i2c_write_bytes(struct i2c_client *client,
+@@ -639,6 +639,27 @@ static int acpi_gsb_i2c_write_bytes(struct i2c_client *client,
return (ret == 1) ? 0 : -EIO;
}
@@ -7431,7 +7234,7 @@ index 14ae0cfc325e..a3a9f81fb47f 100644
+ u8 *data, u8 data_len)
+{
+ struct i2c_msg msgs[1];
-+ int ret = AE_OK;
++ int ret;
+
+ msgs[0].addr = client->addr;
+ msgs[0].flags = client->flags;
@@ -7439,7 +7242,6 @@ index 14ae0cfc325e..a3a9f81fb47f 100644
+ msgs[0].buf = data;
+
+ ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
-+
+ if (ret < 0) {
+ dev_err(&client->adapter->dev, "i2c write failed: %d\n", ret);
+ return ret;
@@ -7452,7 +7254,7 @@ index 14ae0cfc325e..a3a9f81fb47f 100644
static acpi_status
i2c_acpi_space_handler(u32 function, acpi_physical_address command,
u32 bits, u64 *value64,
-@@ -740,6 +762,19 @@ i2c_acpi_space_handler(u32 function, acpi_physical_address command,
+@@ -740,6 +761,19 @@ i2c_acpi_space_handler(u32 function, acpi_physical_address command,
}
break;
@@ -7473,9 +7275,9 @@ index 14ae0cfc325e..a3a9f81fb47f 100644
dev_warn(&adapter->dev, "protocol 0x%02x not supported for client 0x%02x\n",
accessor_type, client->addr);
--
-2.46.0
+2.46.1
-From fe964119c511036a560d1dfcbec1196ae4ed1621 Mon Sep 17 00:00:00 2001
+From 61af2c864646d5582463f9e5fbf06a96e0c4300d Mon Sep 17 00:00:00 2001
From: Maximilian Luz <luzmaximilian@gmail.com>
Date: Sat, 13 Feb 2021 16:41:18 +0100
Subject: [PATCH] platform/surface: Add driver for Surface Book 1 dGPU switch
@@ -7493,8 +7295,8 @@ Patchset: surface-sam-over-hid
---
drivers/platform/surface/Kconfig | 7 +
drivers/platform/surface/Makefile | 1 +
- .../surface/surfacebook1_dgpu_switch.c | 162 ++++++++++++++++++
- 3 files changed, 170 insertions(+)
+ .../surface/surfacebook1_dgpu_switch.c | 136 ++++++++++++++++++
+ 3 files changed, 144 insertions(+)
create mode 100644 drivers/platform/surface/surfacebook1_dgpu_switch.c
diff --git a/drivers/platform/surface/Kconfig b/drivers/platform/surface/Kconfig
@@ -7529,35 +7331,28 @@ index 53344330939b..7efcd0cdb532 100644
obj-$(CONFIG_SURFACE_HOTPLUG) += surface_hotplug.o
diff --git a/drivers/platform/surface/surfacebook1_dgpu_switch.c b/drivers/platform/surface/surfacebook1_dgpu_switch.c
new file mode 100644
-index 000000000000..8b816ed8f35c
+index 000000000000..68db237734a1
--- /dev/null
+++ b/drivers/platform/surface/surfacebook1_dgpu_switch.c
-@@ -0,0 +1,162 @@
+@@ -0,0 +1,136 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
-+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/acpi.h>
+#include <linux/platform_device.h>
+
-+
-+#ifdef pr_fmt
-+#undef pr_fmt
-+#endif
-+#define pr_fmt(fmt) "%s:%s: " fmt, KBUILD_MODNAME, __func__
-+
-+
-+static const guid_t dgpu_sw_guid = GUID_INIT(0x6fd05c69, 0xcde3, 0x49f4,
-+ 0x95, 0xed, 0xab, 0x16, 0x65, 0x49, 0x80, 0x35);
++/* MSHW0040/VGBI DSM UUID: 6fd05c69-cde3-49f4-95ed-ab1665498035 */
++static const guid_t dgpu_sw_guid =
++ GUID_INIT(0x6fd05c69, 0xcde3, 0x49f4,
++ 0x95, 0xed, 0xab, 0x16, 0x65, 0x49, 0x80, 0x35);
+
+#define DGPUSW_ACPI_PATH_DSM "\\_SB_.PCI0.LPCB.EC0_.VGBI"
+#define DGPUSW_ACPI_PATH_HGON "\\_SB_.PCI0.RP05.HGON"
+#define DGPUSW_ACPI_PATH_HGOF "\\_SB_.PCI0.RP05.HGOF"
+
-+
+static int sb1_dgpu_sw_dsmcall(void)
+{
-+ union acpi_object *ret;
++ union acpi_object *obj;
+ acpi_handle handle;
+ acpi_status status;
+
@@ -7565,67 +7360,66 @@ index 000000000000..8b816ed8f35c
+ if (status)
+ return -EINVAL;
+
-+ ret = acpi_evaluate_dsm_typed(handle, &dgpu_sw_guid, 1, 1, NULL, ACPI_TYPE_BUFFER);
-+ if (!ret)
++ obj = acpi_evaluate_dsm_typed(handle, &dgpu_sw_guid, 1, 1, NULL, ACPI_TYPE_BUFFER);
++ if (!obj)
+ return -EINVAL;
+
-+ ACPI_FREE(ret);
++ ACPI_FREE(obj);
+ return 0;
+}
+
-+static int sb1_dgpu_sw_hgon(void)
++static int sb1_dgpu_sw_hgon(struct device *dev)
+{
+ struct acpi_buffer buf = {ACPI_ALLOCATE_BUFFER, NULL};
+ acpi_status status;
+
+ status = acpi_evaluate_object(NULL, DGPUSW_ACPI_PATH_HGON, NULL, &buf);
+ if (status) {
-+ pr_err("failed to run HGON: %d\n", status);
++ dev_err(dev, "failed to run HGON: %d\n", status);
+ return -EINVAL;
+ }
+
-+ if (buf.pointer)
-+ ACPI_FREE(buf.pointer);
++ ACPI_FREE(buf.pointer);
+
-+ pr_info("turned-on dGPU via HGON\n");
++ dev_info(dev, "turned-on dGPU via HGON\n");
+ return 0;
+}
+
-+static int sb1_dgpu_sw_hgof(void)
++static int sb1_dgpu_sw_hgof(struct device *dev)
+{
+ struct acpi_buffer buf = {ACPI_ALLOCATE_BUFFER, NULL};
+ acpi_status status;
+
+ status = acpi_evaluate_object(NULL, DGPUSW_ACPI_PATH_HGOF, NULL, &buf);
+ if (status) {
-+ pr_err("failed to run HGOF: %d\n", status);
++ dev_err(dev, "failed to run HGOF: %d\n", status);
+ return -EINVAL;
+ }
+
-+ if (buf.pointer)
-+ ACPI_FREE(buf.pointer);
++ ACPI_FREE(buf.pointer);
+
-+ pr_info("turned-off dGPU via HGOF\n");
++ dev_info(dev, "turned-off dGPU via HGOF\n");
+ return 0;
+}
+
-+
+static ssize_t dgpu_dsmcall_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t len)
+{
-+ int status, value;
++ bool value;
++ int status;
+
-+ status = kstrtoint(buf, 0, &value);
++ status = kstrtobool(buf, &value);
+ if (status < 0)
+ return status;
+
-+ if (value != 1)
-+ return -EINVAL;
++ if (!value)
++ return 0;
+
+ status = sb1_dgpu_sw_dsmcall();
+
+ return status < 0 ? status : len;
+}
++static DEVICE_ATTR_WO(dgpu_dsmcall);
+
+static ssize_t dgpu_power_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t len)
@@ -7638,37 +7432,20 @@ index 000000000000..8b816ed8f35c
+ return status;
+
+ if (power)
-+ status = sb1_dgpu_sw_hgon();
++ status = sb1_dgpu_sw_hgon(dev);
+ else
-+ status = sb1_dgpu_sw_hgof();
++ status = sb1_dgpu_sw_hgof(dev);
+
+ return status < 0 ? status : len;
+}
-+
-+static DEVICE_ATTR_WO(dgpu_dsmcall);
+static DEVICE_ATTR_WO(dgpu_power);
+
+static struct attribute *sb1_dgpu_sw_attrs[] = {
+ &dev_attr_dgpu_dsmcall.attr,
+ &dev_attr_dgpu_power.attr,
-+ NULL,
-+};
-+
-+static const struct attribute_group sb1_dgpu_sw_attr_group = {
-+ .attrs = sb1_dgpu_sw_attrs,
++ NULL
+};
-+
-+
-+static int sb1_dgpu_sw_probe(struct platform_device *pdev)
-+{
-+ return sysfs_create_group(&pdev->dev.kobj, &sb1_dgpu_sw_attr_group);
-+}
-+
-+static int sb1_dgpu_sw_remove(struct platform_device *pdev)
-+{
-+ sysfs_remove_group(&pdev->dev.kobj, &sb1_dgpu_sw_attr_group);
-+ return 0;
-+}
++ATTRIBUTE_GROUPS(sb1_dgpu_sw);
+
+/*
+ * The dGPU power seems to be actually handled by MSHW0040. However, that is
@@ -7677,17 +7454,16 @@ index 000000000000..8b816ed8f35c
+ */
+static const struct acpi_device_id sb1_dgpu_sw_match[] = {
+ { "MSHW0041", },
-+ { },
++ { }
+};
+MODULE_DEVICE_TABLE(acpi, sb1_dgpu_sw_match);
+
+static struct platform_driver sb1_dgpu_sw = {
-+ .probe = sb1_dgpu_sw_probe,
-+ .remove = sb1_dgpu_sw_remove,
+ .driver = {
+ .name = "surfacebook1_dgpu_switch",
+ .acpi_match_table = sb1_dgpu_sw_match,
+ .probe_type = PROBE_PREFER_ASYNCHRONOUS,
++ .dev_groups = sb1_dgpu_sw_groups,
+ },
+};
+module_platform_driver(sb1_dgpu_sw);
@@ -7696,9 +7472,9 @@ index 000000000000..8b816ed8f35c
+MODULE_DESCRIPTION("Discrete GPU Power-Switch for Surface Book 1");
+MODULE_LICENSE("GPL");
--
-2.46.0
+2.46.1
-From d811fb8e32e1327baf131c85522aee281f4281af Mon Sep 17 00:00:00 2001
+From 02f4deefe4c0ab63cd6771198cd05d5798fcc80f Mon Sep 17 00:00:00 2001
From: Sachi King <nakato@nakato.io>
Date: Tue, 5 Oct 2021 00:05:09 +1100
Subject: [PATCH] Input: soc_button_array - support AMD variant Surface devices
@@ -7773,9 +7549,9 @@ index f6d060377d18..b8603f74eb28 100644
/*
--
-2.46.0
+2.46.1
-From e21138766921f4a22e710b4858f75f98e308c61d Mon Sep 17 00:00:00 2001
+From fbdda31b4a3ce2a7113fa831056830b6b46cf0df Mon Sep 17 00:00:00 2001
From: Sachi King <nakato@nakato.io>
Date: Tue, 5 Oct 2021 00:22:57 +1100
Subject: [PATCH] platform/surface: surfacepro3_button: don't load on amd
@@ -7845,9 +7621,9 @@ index 2755601f979c..4240c98ca226 100644
--
-2.46.0
+2.46.1
-From a19b7328ccb6c090354593fa039e5283140a5e69 Mon Sep 17 00:00:00 2001
+From edc26a9d993aca624b164989945d6bbcc5c7a856 Mon Sep 17 00:00:00 2001
From: Maximilian Luz <luzmaximilian@gmail.com>
Date: Sat, 18 Feb 2023 01:02:49 +0100
Subject: [PATCH] USB: quirks: Add USB_QUIRK_DELAY_INIT for Surface Go 3
@@ -7886,9 +7662,9 @@ index 13171454f959..a83beefd25f3 100644
{ USB_DEVICE(0x046a, 0x0023), .driver_info = USB_QUIRK_RESET_RESUME },
--
-2.46.0
+2.46.1
-From 99fb371b3a11e3c3d67d29673508911b81a1408c Mon Sep 17 00:00:00 2001
+From 43bac5cac64c45b423509196acdb2261c3f0a7ba Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= <verdre@v0yd.nl>
Date: Thu, 5 Nov 2020 13:09:45 +0100
Subject: [PATCH] hid/multitouch: Turn off Type Cover keyboard backlight when
@@ -7924,7 +7700,7 @@ Patchset: surface-typecover
1 file changed, 98 insertions(+), 2 deletions(-)
diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c
-index 56fc78841f24..a266449065a0 100644
+index 99812c0f830b..0b3b51e37149 100644
--- a/drivers/hid/hid-multitouch.c
+++ b/drivers/hid/hid-multitouch.c
@@ -34,7 +34,10 @@
@@ -7996,7 +7772,7 @@ index 56fc78841f24..a266449065a0 100644
{ }
};
-@@ -1720,6 +1740,69 @@ static void mt_expired_timeout(struct timer_list *t)
+@@ -1744,6 +1764,69 @@ static void mt_expired_timeout(struct timer_list *t)
clear_bit_unlock(MT_IO_FLAGS_RUNNING, &td->mt_io_flags);
}
@@ -8066,7 +7842,7 @@ index 56fc78841f24..a266449065a0 100644
static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
{
int ret, i;
-@@ -1743,6 +1826,9 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
+@@ -1767,6 +1850,9 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
td->inputmode_value = MT_INPUTMODE_TOUCHSCREEN;
hid_set_drvdata(hdev, td);
@@ -8076,7 +7852,7 @@ index 56fc78841f24..a266449065a0 100644
INIT_LIST_HEAD(&td->applications);
INIT_LIST_HEAD(&td->reports);
-@@ -1781,15 +1867,19 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
+@@ -1805,15 +1891,19 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
timer_setup(&td->release_timer, mt_expired_timeout, 0);
ret = hid_parse(hdev);
@@ -8098,7 +7874,7 @@ index 56fc78841f24..a266449065a0 100644
ret = sysfs_create_group(&hdev->dev.kobj, &mt_attribute_group);
if (ret)
-@@ -1839,6 +1929,7 @@ static void mt_remove(struct hid_device *hdev)
+@@ -1863,6 +1953,7 @@ static void mt_remove(struct hid_device *hdev)
{
struct mt_device *td = hid_get_drvdata(hdev);
@@ -8106,7 +7882,7 @@ index 56fc78841f24..a266449065a0 100644
del_timer_sync(&td->release_timer);
sysfs_remove_group(&hdev->dev.kobj, &mt_attribute_group);
-@@ -2235,6 +2326,11 @@ static const struct hid_device_id mt_devices[] = {
+@@ -2267,6 +2358,11 @@ static const struct hid_device_id mt_devices[] = {
MT_USB_DEVICE(USB_VENDOR_ID_XIROKU,
USB_DEVICE_ID_XIROKU_CSR2) },
@@ -8119,9 +7895,9 @@ index 56fc78841f24..a266449065a0 100644
{ .driver_data = MT_CLS_GOOGLE,
HID_DEVICE(HID_BUS_ANY, HID_GROUP_ANY, USB_VENDOR_ID_GOOGLE,
--
-2.46.0
+2.46.1
-From 7b797164a3f2ecf402b8f24d5123e74914b09064 Mon Sep 17 00:00:00 2001
+From 41478ba3be0680c18610cb66f5344abadff1b82d Mon Sep 17 00:00:00 2001
From: PJungkamp <p.jungkamp@gmail.com>
Date: Fri, 25 Feb 2022 12:04:25 +0100
Subject: [PATCH] hid/multitouch: Add support for surface pro type cover tablet
@@ -8150,7 +7926,7 @@ Patchset: surface-typecover
1 file changed, 122 insertions(+), 26 deletions(-)
diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c
-index a266449065a0..060c706e936a 100644
+index 0b3b51e37149..481b97dce830 100644
--- a/drivers/hid/hid-multitouch.c
+++ b/drivers/hid/hid-multitouch.c
@@ -77,6 +77,7 @@ MODULE_LICENSE("GPL");
@@ -8260,7 +8036,7 @@ index a266449065a0..060c706e936a 100644
return 0;
}
-@@ -1610,6 +1656,42 @@ static void mt_post_parse(struct mt_device *td, struct mt_application *app)
+@@ -1634,6 +1680,42 @@ static void mt_post_parse(struct mt_device *td, struct mt_application *app)
app->quirks &= ~MT_QUIRK_CONTACT_CNT_ACCURATE;
}
@@ -8303,7 +8079,7 @@ index a266449065a0..060c706e936a 100644
static int mt_input_configured(struct hid_device *hdev, struct hid_input *hi)
{
struct mt_device *td = hid_get_drvdata(hdev);
-@@ -1658,6 +1740,13 @@ static int mt_input_configured(struct hid_device *hdev, struct hid_input *hi)
+@@ -1682,6 +1764,13 @@ static int mt_input_configured(struct hid_device *hdev, struct hid_input *hi)
/* force BTN_STYLUS to allow tablet matching in udev */
__set_bit(BTN_STYLUS, hi->input->keybit);
break;
@@ -8317,7 +8093,7 @@ index a266449065a0..060c706e936a 100644
default:
suffix = "UNKNOWN";
break;
-@@ -1740,30 +1829,6 @@ static void mt_expired_timeout(struct timer_list *t)
+@@ -1764,30 +1853,6 @@ static void mt_expired_timeout(struct timer_list *t)
clear_bit_unlock(MT_IO_FLAGS_RUNNING, &td->mt_io_flags);
}
@@ -8348,7 +8124,7 @@ index a266449065a0..060c706e936a 100644
static void update_keyboard_backlight(struct hid_device *hdev, bool enabled)
{
struct usb_device *udev = hid_to_usb_dev(hdev);
-@@ -1772,8 +1837,9 @@ static void update_keyboard_backlight(struct hid_device *hdev, bool enabled)
+@@ -1796,8 +1861,9 @@ static void update_keyboard_backlight(struct hid_device *hdev, bool enabled)
/* Wake up the device in case it's already suspended */
pm_runtime_get_sync(&udev->dev);
@@ -8360,7 +8136,7 @@ index a266449065a0..060c706e936a 100644
hid_err(hdev, "couldn't find backlight field\n");
goto out;
}
-@@ -1907,13 +1973,24 @@ static int mt_suspend(struct hid_device *hdev, pm_message_t state)
+@@ -1931,13 +1997,24 @@ static int mt_suspend(struct hid_device *hdev, pm_message_t state)
static int mt_reset_resume(struct hid_device *hdev)
{
@@ -8385,7 +8161,7 @@ index a266449065a0..060c706e936a 100644
/* Some Elan legacy devices require SET_IDLE to be set on resume.
* It should be safe to send it to other devices too.
* Tested on 3M, Stantum, Cypress, Zytronic, eGalax, and Elan panels. */
-@@ -1922,12 +1999,31 @@ static int mt_resume(struct hid_device *hdev)
+@@ -1946,12 +2023,31 @@ static int mt_resume(struct hid_device *hdev)
mt_set_modes(hdev, HID_LATENCY_NORMAL, true, true);
@@ -8418,9 +8194,9 @@ index a266449065a0..060c706e936a 100644
unregister_pm_notifier(&td->pm_notifier);
del_timer_sync(&td->release_timer);
--
-2.46.0
+2.46.1
-From e26e0570db9e2dbb37e075ef7a88270fe793fb94 Mon Sep 17 00:00:00 2001
+From fe6c6b6e8d581aeca114902ec5f962a44a0ee3ff Mon Sep 17 00:00:00 2001
From: Maximilian Luz <luzmaximilian@gmail.com>
Date: Sun, 19 Feb 2023 22:12:24 +0100
Subject: [PATCH] PCI: Add quirk to prevent calling shutdown mehtod
@@ -8515,9 +8291,9 @@ index cafc5ab1cbcb..64bb5aca2c13 100644
atomic_t enable_cnt; /* pci_enable_device has been called */
--
-2.46.0
+2.46.1
-From bed56a2a67db8c5934008ed83fa0bbd71360ab02 Mon Sep 17 00:00:00 2001
+From d0443743ccc9c4d76192f7bbf0152990e461945e Mon Sep 17 00:00:00 2001
From: Maximilian Luz <luzmaximilian@gmail.com>
Date: Sun, 12 Mar 2023 01:41:57 +0100
Subject: [PATCH] platform/surface: gpe: Add support for Surface Pro 9
@@ -8566,9 +8342,9 @@ index 62fd4004db31..103fc4468262 100644
.ident = "Surface Book 1",
.matches = {
--
-2.46.0
+2.46.1
-From 0a70aafbfa7ad39054c0974e428935c9d9e48cf1 Mon Sep 17 00:00:00 2001
+From e7b32369a9dc01221dc44a1250c425d8ebc9b28b Mon Sep 17 00:00:00 2001
From: Hans de Goede <hdegoede@redhat.com>
Date: Sun, 10 Oct 2021 20:56:57 +0200
Subject: [PATCH] ACPI: delay enumeration of devices with a _DEP pointing to an
@@ -8628,7 +8404,7 @@ Patchset: cameras
1 file changed, 3 insertions(+)
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
-index 503773707e01..a292a20c4315 100644
+index cdc5a74092c7..e3a16c14a29e 100644
--- a/drivers/acpi/scan.c
+++ b/drivers/acpi/scan.c
@@ -2176,6 +2176,9 @@ static acpi_status acpi_bus_check_add_2(acpi_handle handle, u32 lvl_not_used,
@@ -8642,9 +8418,9 @@ index 503773707e01..a292a20c4315 100644
* Do not enumerate devices with enumeration_by_parent flag set as
* they will be enumerated by their respective parents.
--
-2.46.0
+2.46.1
-From bdae5b6a0e462398fa6035a2f0de8efae144abe4 Mon Sep 17 00:00:00 2001
+From aa71d469b9000984bfbd4ee4f596517db89bcb46 Mon Sep 17 00:00:00 2001
From: zouxiaoh <xiaohong.zou@intel.com>
Date: Fri, 25 Jun 2021 08:52:59 +0800
Subject: [PATCH] iommu: intel-ipu: use IOMMU passthrough mode for Intel IPUs
@@ -8670,7 +8446,7 @@ Patchset: cameras
1 file changed, 30 insertions(+)
diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c
-index 8d95579436a9..cbfb59ed5985 100644
+index 6ee97bf7b6a9..a1f86bde277a 100644
--- a/drivers/iommu/intel/iommu.c
+++ b/drivers/iommu/intel/iommu.c
@@ -45,6 +45,13 @@
@@ -8752,9 +8528,9 @@ index 8d95579436a9..cbfb59ed5985 100644
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x9D3E, quirk_iommu_ipts);
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x34E4, quirk_iommu_ipts);
--
-2.46.0
+2.46.1
-From aa044fab288ddf51ad963effe090d0b548d83243 Mon Sep 17 00:00:00 2001
+From fb1981ea8427c311f08860ddbb2ea1b7e1ddd313 Mon Sep 17 00:00:00 2001
From: Daniel Scally <djrscally@gmail.com>
Date: Sun, 10 Oct 2021 20:57:02 +0200
Subject: [PATCH] platform/x86: int3472: Enable I2c daisy chain
@@ -8789,9 +8565,9 @@ index 1e107fd49f82..e3e1696e7f0e 100644
return 0;
--
-2.46.0
+2.46.1
-From 12da0a015e6d71071561668950a4fb5e33220af8 Mon Sep 17 00:00:00 2001
+From ae05619486ea72603af63628e7f7a0c3b4f045ac Mon Sep 17 00:00:00 2001
From: Daniel Scally <dan.scally@ideasonboard.com>
Date: Thu, 2 Mar 2023 12:59:39 +0000
Subject: [PATCH] platform/x86: int3472: Remap reset GPIO for INT347E
@@ -8809,19 +8585,20 @@ polarity of the pin to match the driver's expectation.
Signed-off-by: Daniel Scally <dan.scally@ideasonboard.com>
Patchset: cameras
---
- drivers/platform/x86/intel/int3472/discrete.c | 14 ++++++++++++++
- 1 file changed, 14 insertions(+)
+ drivers/platform/x86/intel/int3472/discrete.c | 15 +++++++++++++++
+ 1 file changed, 15 insertions(+)
diff --git a/drivers/platform/x86/intel/int3472/discrete.c b/drivers/platform/x86/intel/int3472/discrete.c
-index 07b302e09340..1d3097bc7e48 100644
+index 07b302e09340..baad1e50ca81 100644
--- a/drivers/platform/x86/intel/int3472/discrete.c
+++ b/drivers/platform/x86/intel/int3472/discrete.c
-@@ -83,12 +83,26 @@ static int skl_int3472_map_gpio_to_sensor(struct int3472_discrete_device *int347
+@@ -83,12 +83,27 @@ static int skl_int3472_map_gpio_to_sensor(struct int3472_discrete_device *int347
const char *func, u32 polarity)
{
int ret;
+ const struct acpi_device_id ov7251_ids[] = {
+ { "INT347E" },
++ { }
+ };
if (int3472->n_sensor_gpios >= INT3472_MAX_SENSOR_GPIOS) {
@@ -8837,16 +8614,16 @@ index 07b302e09340..1d3097bc7e48 100644
+ */
+ if (!strcmp(func, "reset") && !acpi_match_device_ids(int3472->sensor, ov7251_ids)) {
+ func = "enable";
-+ polarity = GPIO_ACTIVE_HIGH;
++ polarity ^= GPIO_ACTIVE_LOW;
+ }
+
ret = skl_int3472_fill_gpiod_lookup(&int3472->gpios.table[int3472->n_sensor_gpios],
agpio, func, polarity);
if (ret)
--
-2.46.0
+2.46.1
-From ddc65d1014592b1fe4d6e16c9badcc928e577b3b Mon Sep 17 00:00:00 2001
+From 7066acd9423a7eecc94d22397095e04f4a47aba8 Mon Sep 17 00:00:00 2001
From: Daniel Scally <dan.scally@ideasonboard.com>
Date: Tue, 21 Mar 2023 13:45:26 +0000
Subject: [PATCH] media: i2c: Clarify that gain is Analogue gain in OV7251
@@ -8883,9 +8660,9 @@ index 30f61e04ecaf..9c1292ca8552 100644
V4L2_CID_TEST_PATTERN,
ARRAY_SIZE(ov7251_test_pattern_menu) - 1,
--
-2.46.0
+2.46.1
-From ea560c5a7e55695438ac99fbd363352991fe62af Mon Sep 17 00:00:00 2001
+From 9feb537c1c69e0d01ad3ed713959fcf371dc2db6 Mon Sep 17 00:00:00 2001
From: Daniel Scally <dan.scally@ideasonboard.com>
Date: Wed, 22 Mar 2023 11:01:42 +0000
Subject: [PATCH] media: v4l2-core: Acquire privacy led in
@@ -8934,9 +8711,9 @@ index 89c7192148df..44eca113e772 100644
if (ret < 0)
goto out_cleanup;
--
-2.46.0
+2.46.1
-From 0c59f9eee1c8dc8ea4d99f8b1a07b342ef5e425d Mon Sep 17 00:00:00 2001
+From 580ca92681c7c6bafa132b81043fbd0857b5da6b Mon Sep 17 00:00:00 2001
From: Kate Hsuan <hpa@redhat.com>
Date: Tue, 21 Mar 2023 23:37:16 +0800
Subject: [PATCH] platform: x86: int3472: Add MFD cell for tps68470 LED
@@ -8975,9 +8752,9 @@ index e3e1696e7f0e..423dc555093f 100644
for (i = 0; i < board_data->n_gpiod_lookups; i++)
gpiod_add_lookup_table(board_data->tps68470_gpio_lookup_tables[i]);
--
-2.46.0
+2.46.1
-From 8f69fe36b3d6052c7f41182041fc59ea84515066 Mon Sep 17 00:00:00 2001
+From ef863c4385da78967765505ccd3702371a32d70e Mon Sep 17 00:00:00 2001
From: Kate Hsuan <hpa@redhat.com>
Date: Tue, 21 Mar 2023 23:37:17 +0800
Subject: [PATCH] include: mfd: tps68470: Add masks for LEDA and LEDB
@@ -9016,9 +8793,9 @@ index 7807fa329db0..2d2abb25b944 100644
+
#endif /* __LINUX_MFD_TPS68470_H */
--
-2.46.0
+2.46.1
-From 457ccb4dad651a58bc24e4c49fcc95a81e3762bb Mon Sep 17 00:00:00 2001
+From e81fa0ec83149cf15d779fea0ba7435f8fd28898 Mon Sep 17 00:00:00 2001
From: Kate Hsuan <hpa@redhat.com>
Date: Tue, 21 Mar 2023 23:37:18 +0800
Subject: [PATCH] leds: tps68470: Add LED control for tps68470
@@ -9267,9 +9044,9 @@ index 000000000000..35aeb5db89c8
+MODULE_DESCRIPTION("LED driver for TPS68470 PMIC");
+MODULE_LICENSE("GPL v2");
--
-2.46.0
+2.46.1
-From 281dcaef04abcc6a75b34c6f69f8f608b68912cf Mon Sep 17 00:00:00 2001
+From afce9fb83bf7355d5ceb4a6958023dd07e00cfdf Mon Sep 17 00:00:00 2001
From: mojyack <mojyack@gmail.com>
Date: Sat, 3 Feb 2024 12:59:53 +0900
Subject: [PATCH] media: staging: ipu3-imgu: Fix multiple calls of s_stream on
@@ -9314,9 +9091,9 @@ index 3df58eb3e882..81aff2d5d898 100644
r = imgu_s_stream(imgu, false);
if (!r)
--
-2.46.0
+2.46.1
-From f1d09776b3c5026bfd4d035bbca5be3f8e41b247 Mon Sep 17 00:00:00 2001
+From 10cc9e54fa6067a0c08dc4f2c0f5bf029e3a4ed1 Mon Sep 17 00:00:00 2001
From: mojyack <mojyack@gmail.com>
Date: Tue, 26 Mar 2024 05:55:44 +0900
Subject: [PATCH] media: i2c: dw9719: fix probe error on surface go 2
@@ -9346,9 +9123,9 @@ index c626ed845928..0094cfda57ea 100644
cci_write(dw9719->regmap, DW9719_CONTROL, 1, &ret);
--
-2.46.0
+2.46.1
-From 29121bd1e5b235572d56645abdb8f54a31bf476e Mon Sep 17 00:00:00 2001
+From 04f1ce03393e660c6275004e0ccda0f1e4481f8b Mon Sep 17 00:00:00 2001
From: Sachi King <nakato@nakato.io>
Date: Sat, 29 May 2021 17:47:38 +1000
Subject: [PATCH] ACPI: Add quirk for Surface Laptop 4 AMD missing irq 7
@@ -9413,9 +9190,9 @@ index 4bf82dbd2a6b..7a8cb090c656 100644
mp_config_acpi_legacy_irqs();
--
-2.46.0
+2.46.1
-From f8d58835a76ce8ea016c0fcd75ddb93a95ca14c6 Mon Sep 17 00:00:00 2001
+From a05e3240a282702699117da0e657a46bc960a944 Mon Sep 17 00:00:00 2001
From: Maximilian Luz <luzmaximilian@gmail.com>
Date: Thu, 3 Jun 2021 14:04:26 +0200
Subject: [PATCH] ACPI: Add AMD 13" Surface Laptop 4 model to irq 7 override
@@ -9455,9 +9232,9 @@ index 7a8cb090c656..0faafc323e67 100644
};
--
-2.46.0
+2.46.1
-From 5c662b210790b2b297457de3e84274cc062b215e Mon Sep 17 00:00:00 2001
+From 4e5c87c48625f80729705e6ca756b289dace0452 Mon Sep 17 00:00:00 2001
From: "Bart Groeneveld | GPX Solutions B.V" <bart@gpxbv.nl>
Date: Mon, 5 Dec 2022 16:08:46 +0100
Subject: [PATCH] acpi: allow usage of acpi_tad on HW-reduced platforms
@@ -9565,5 +9342,5 @@ index 1d670dbe4d1d..71c9e375ca1c 100644
ret = sysfs_create_group(&dev->kobj, &acpi_tad_dc_attr_group);
if (ret)
--
-2.46.0
+2.46.1
diff --git a/SOURCES/patch-6.10-redhat.patch b/SOURCES/patch-6.10-redhat.patch
index 86a5055..207bf7f 100644
--- a/SOURCES/patch-6.10-redhat.patch
+++ b/SOURCES/patch-6.10-redhat.patch
@@ -32,7 +32,6 @@
drivers/pci/quirks.c | 24 ++++
drivers/scsi/sd.c | 10 ++
drivers/usb/core/hub.c | 7 +
- fs/xfs/libxfs/xfs_ialloc_btree.c | 2 +-
include/linux/crypto.h | 1 +
include/linux/efi.h | 22 ++-
include/linux/lsm_hook_defs.h | 2 +
@@ -46,10 +45,10 @@
security/lockdown/Kconfig | 13 ++
security/lockdown/lockdown.c | 1 +
security/security.c | 12 ++
- 48 files changed, 828 insertions(+), 257 deletions(-)
+ 47 files changed, 827 insertions(+), 256 deletions(-)
diff --git a/Documentation/virt/kvm/api.rst b/Documentation/virt/kvm/api.rst
-index eec8df1dde06..88f49dd10cd0 100644
+index eec8df1dde06a..88f49dd10cd06 100644
--- a/Documentation/virt/kvm/api.rst
+++ b/Documentation/virt/kvm/api.rst
@@ -2445,8 +2445,11 @@ registers, find a list below:
@@ -65,7 +64,7 @@ index eec8df1dde06..88f49dd10cd0 100644
...
PPC KVM_REG_PPC_TM_GPR31 64
diff --git a/Makefile b/Makefile
-index 2e5ac6ab3d47..838301b19917 100644
+index 175d7f27ea32a..52eef3d589e67 100644
--- a/Makefile
+++ b/Makefile
@@ -22,6 +22,18 @@ $(if $(filter __%, $(MAKECMDGOALS)), \
@@ -88,7 +87,7 @@ index 2e5ac6ab3d47..838301b19917 100644
# to get the ordering right.
#
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
-index ee5115252aac..7f3796df8404 100644
+index ee5115252aac4..7f3796df84041 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -1224,9 +1224,9 @@ config HIGHMEM
@@ -104,7 +103,7 @@ index ee5115252aac..7f3796df8404 100644
The VM uses one page of physical memory for each page table.
For systems with a lot of processes, this can use a lot of
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
-index 11bbdc15c6e5..9cecc1448e3c 100644
+index 11bbdc15c6e5e..9cecc1448e3c6 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -1364,7 +1364,7 @@ endchoice
@@ -117,7 +116,7 @@ index 11bbdc15c6e5..9cecc1448e3c 100644
For systems with 52-bit userspace VAs enabled, the kernel will attempt
to maintain compatibility with older software by providing 48-bit VAs
diff --git a/arch/powerpc/include/asm/kvm_host.h b/arch/powerpc/include/asm/kvm_host.h
-index 8abac532146e..6a0c771d3ce8 100644
+index 8abac532146e7..6a0c771d3ce89 100644
--- a/arch/powerpc/include/asm/kvm_host.h
+++ b/arch/powerpc/include/asm/kvm_host.h
@@ -599,6 +599,9 @@ struct kvm_vcpu_arch {
@@ -131,7 +130,7 @@ index 8abac532146e..6a0c771d3ce8 100644
ulong cfar;
ulong ppr;
diff --git a/arch/powerpc/include/uapi/asm/kvm.h b/arch/powerpc/include/uapi/asm/kvm.h
-index 1691297a766a..eaeda001784e 100644
+index 1691297a766a9..eaeda001784eb 100644
--- a/arch/powerpc/include/uapi/asm/kvm.h
+++ b/arch/powerpc/include/uapi/asm/kvm.h
@@ -645,6 +645,9 @@ struct kvm_ppc_cpu_char {
@@ -145,7 +144,7 @@ index 1691297a766a..eaeda001784e 100644
/* Transactional Memory checkpointed state:
* This is all GPRs, all VSX regs and a subset of SPRs
diff --git a/arch/powerpc/kvm/book3s_hv.c b/arch/powerpc/kvm/book3s_hv.c
-index d8352e4d9cdc..36068c3ed8a7 100644
+index d8352e4d9cdc7..36068c3ed8a76 100644
--- a/arch/powerpc/kvm/book3s_hv.c
+++ b/arch/powerpc/kvm/book3s_hv.c
@@ -2349,6 +2349,15 @@ static int kvmppc_get_one_reg_hv(struct kvm_vcpu *vcpu, u64 id,
@@ -181,7 +180,7 @@ index d8352e4d9cdc..36068c3ed8a7 100644
kvmppc_set_ciabr_hv(vcpu, set_reg_val(id, *val));
/* Don't allow setting breakpoints in hypervisor code */
diff --git a/arch/powerpc/kvm/book3s_hv.h b/arch/powerpc/kvm/book3s_hv.h
-index 47b2c815641e..a404c9b221c1 100644
+index 47b2c815641e4..a404c9b221c1a 100644
--- a/arch/powerpc/kvm/book3s_hv.h
+++ b/arch/powerpc/kvm/book3s_hv.h
@@ -116,6 +116,9 @@ KVMPPC_BOOK3S_HV_VCPU_ACCESSOR(dawr0, 64, KVMPPC_GSID_DAWR0)
@@ -195,7 +194,7 @@ index 47b2c815641e..a404c9b221c1 100644
KVMPPC_BOOK3S_HV_VCPU_ACCESSOR(wort, 64, KVMPPC_GSID_WORT)
KVMPPC_BOOK3S_HV_VCPU_ACCESSOR(ppr, 64, KVMPPC_GSID_PPR)
diff --git a/arch/powerpc/kvm/book3s_hv_nestedv2.c b/arch/powerpc/kvm/book3s_hv_nestedv2.c
-index 342f58314770..eeecea8f202b 100644
+index 342f583147709..eeecea8f202b3 100644
--- a/arch/powerpc/kvm/book3s_hv_nestedv2.c
+++ b/arch/powerpc/kvm/book3s_hv_nestedv2.c
@@ -193,6 +193,15 @@ static int gs_msg_ops_vcpu_fill_info(struct kvmppc_gs_buff *gsb,
@@ -231,7 +230,7 @@ index 342f58314770..eeecea8f202b 100644
vcpu->arch.ciabr = kvmppc_gse_get_u64(gse);
break;
diff --git a/arch/s390/include/asm/ipl.h b/arch/s390/include/asm/ipl.h
-index b0d00032479d..afb9544fb007 100644
+index b0d00032479d6..afb9544fb0074 100644
--- a/arch/s390/include/asm/ipl.h
+++ b/arch/s390/include/asm/ipl.h
@@ -139,6 +139,7 @@ int ipl_report_add_component(struct ipl_report *report, struct kexec_buf *kbuf,
@@ -243,7 +242,7 @@ index b0d00032479d..afb9544fb007 100644
/*
* DIAG 308 support
diff --git a/arch/s390/kernel/ipl.c b/arch/s390/kernel/ipl.c
-index 3a7d6e172211..8163a2173247 100644
+index 3a7d6e1722112..8163a2173247e 100644
--- a/arch/s390/kernel/ipl.c
+++ b/arch/s390/kernel/ipl.c
@@ -2479,3 +2479,8 @@ int ipl_report_free(struct ipl_report *report)
@@ -256,7 +255,7 @@ index 3a7d6e172211..8163a2173247 100644
+ return !!ipl_secure_flag;
+}
diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c
-index 610e6f794511..4fc7aca3f572 100644
+index 610e6f794511a..4fc7aca3f572c 100644
--- a/arch/s390/kernel/setup.c
+++ b/arch/s390/kernel/setup.c
@@ -49,6 +49,7 @@
@@ -278,7 +277,7 @@ index 610e6f794511..4fc7aca3f572 100644
/* boot_command_line has been already set up in early.c */
*cmdline_p = boot_command_line;
diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c
-index 05c5aa951da7..da521c6f1cf2 100644
+index 05c5aa951da74..da521c6f1cf2d 100644
--- a/arch/x86/kernel/setup.c
+++ b/arch/x86/kernel/setup.c
@@ -21,6 +21,7 @@
@@ -325,7 +324,7 @@ index 05c5aa951da7..da521c6f1cf2 100644
reserve_initrd();
diff --git a/certs/extract-cert.c b/certs/extract-cert.c
-index 70e9ec89d87d..f5fb74916cee 100644
+index 70e9ec89d87d3..f5fb74916cee4 100644
--- a/certs/extract-cert.c
+++ b/certs/extract-cert.c
@@ -21,7 +21,6 @@
@@ -368,7 +367,7 @@ index 70e9ec89d87d..f5fb74916cee 100644
BIO *b;
X509 *x509;
diff --git a/crypto/drbg.c b/crypto/drbg.c
-index 3addce90930c..730b03de596a 100644
+index 3addce90930c3..730b03de596a3 100644
--- a/crypto/drbg.c
+++ b/crypto/drbg.c
@@ -1494,13 +1494,14 @@ static int drbg_generate(struct drbg_state *drbg,
@@ -423,7 +422,7 @@ index 3addce90930c..730b03de596a 100644
/*
diff --git a/crypto/rng.c b/crypto/rng.c
-index 9d8804e46422..5ccb0485ff4b 100644
+index 9d8804e464226..5ccb0485ff4b2 100644
--- a/crypto/rng.c
+++ b/crypto/rng.c
@@ -12,10 +12,13 @@
@@ -642,7 +641,7 @@ index 9d8804e46422..5ccb0485ff4b 100644
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Random Number Generator");
diff --git a/drivers/acpi/apei/hest.c b/drivers/acpi/apei/hest.c
-index 20d757687e3d..90a13f20f052 100644
+index 20d757687e3d9..90a13f20f052b 100644
--- a/drivers/acpi/apei/hest.c
+++ b/drivers/acpi/apei/hest.c
@@ -142,6 +142,14 @@ static int apei_hest_parse(apei_hest_func_t func, void *data)
@@ -661,7 +660,7 @@ index 20d757687e3d..90a13f20f052 100644
for (i = 0; i < hest_tab->error_source_count; i++) {
len = hest_esrc_len(hest_hdr);
diff --git a/drivers/acpi/irq.c b/drivers/acpi/irq.c
-index 1687483ff319..390b67f19181 100644
+index 1687483ff319e..390b67f19181a 100644
--- a/drivers/acpi/irq.c
+++ b/drivers/acpi/irq.c
@@ -143,6 +143,7 @@ struct acpi_irq_parse_one_ctx {
@@ -704,7 +703,7 @@ index 1687483ff319..390b67f19181 100644
return ctx.rc;
}
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
-index cdc5a74092c7..45679565878f 100644
+index cdc5a74092c77..45679565878f1 100644
--- a/drivers/acpi/scan.c
+++ b/drivers/acpi/scan.c
@@ -1793,6 +1793,15 @@ static bool acpi_device_enumeration_by_parent(struct acpi_device *device)
@@ -724,7 +723,7 @@ index cdc5a74092c7..45679565878f 100644
acpi_dev_get_resources(device, &resource_list,
acpi_check_serial_bus_slave,
diff --git a/drivers/ata/libahci.c b/drivers/ata/libahci.c
-index 83431aae74d8..f2a9c0d644af 100644
+index 83431aae74d8b..f2a9c0d644af2 100644
--- a/drivers/ata/libahci.c
+++ b/drivers/ata/libahci.c
@@ -729,6 +729,24 @@ int ahci_stop_engine(struct ata_port *ap)
@@ -753,7 +752,7 @@ index 83431aae74d8..f2a9c0d644af 100644
tmp = ata_wait_register(ap, port_mmio + PORT_CMD,
PORT_CMD_LIST_ON, PORT_CMD_LIST_ON, 1, 500);
diff --git a/drivers/char/ipmi/ipmi_dmi.c b/drivers/char/ipmi/ipmi_dmi.c
-index bbf7029e224b..cf7faa970dd6 100644
+index bbf7029e224be..cf7faa970dd65 100644
--- a/drivers/char/ipmi/ipmi_dmi.c
+++ b/drivers/char/ipmi/ipmi_dmi.c
@@ -215,6 +215,21 @@ static int __init scan_for_dmi_ipmi(void)
@@ -779,7 +778,7 @@ index bbf7029e224b..cf7faa970dd6 100644
dmi_decode_ipmi((const struct dmi_header *) dev->device_data);
diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c
-index e12b531f5c2f..082707f8dff8 100644
+index e12b531f5c2f3..082707f8dff8c 100644
--- a/drivers/char/ipmi/ipmi_msghandler.c
+++ b/drivers/char/ipmi/ipmi_msghandler.c
@@ -35,6 +35,7 @@
@@ -814,7 +813,7 @@ index e12b531f5c2f..082707f8dff8 100644
rv = ipmi_register_driver();
mutex_unlock(&ipmi_interfaces_mutex);
diff --git a/drivers/char/random.c b/drivers/char/random.c
-index 2597cb43f438..d860f4f6ba2c 100644
+index 2597cb43f4387..d860f4f6ba2c7 100644
--- a/drivers/char/random.c
+++ b/drivers/char/random.c
@@ -51,6 +51,7 @@
@@ -1011,7 +1010,7 @@ index 2597cb43f438..d860f4f6ba2c 100644
/********************************************************************
*
diff --git a/drivers/firmware/efi/Makefile b/drivers/firmware/efi/Makefile
-index a2d0009560d0..4f3486e6a84b 100644
+index a2d0009560d0f..4f3486e6a84b2 100644
--- a/drivers/firmware/efi/Makefile
+++ b/drivers/firmware/efi/Makefile
@@ -25,6 +25,7 @@ subdir-$(CONFIG_EFI_STUB) += libstub
@@ -1023,7 +1022,7 @@ index a2d0009560d0..4f3486e6a84b 100644
obj-$(CONFIG_EFI_RCI2_TABLE) += rci2-table.o
obj-$(CONFIG_EFI_EMBEDDED_FIRMWARE) += embedded-firmware.o
diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c
-index fdf07dd6f459..cfd2b58a3494 100644
+index fdf07dd6f4591..cfd2b58a34940 100644
--- a/drivers/firmware/efi/efi.c
+++ b/drivers/firmware/efi/efi.c
@@ -33,6 +33,7 @@
@@ -1169,7 +1168,7 @@ index fdf07dd6f459..cfd2b58a3494 100644
diff --git a/drivers/firmware/efi/secureboot.c b/drivers/firmware/efi/secureboot.c
new file mode 100644
-index 000000000000..de0a3714a5d4
+index 0000000000000..de0a3714a5d44
--- /dev/null
+++ b/drivers/firmware/efi/secureboot.c
@@ -0,0 +1,38 @@
@@ -1212,7 +1211,7 @@ index 000000000000..de0a3714a5d4
+ }
+}
diff --git a/drivers/hid/hid-rmi.c b/drivers/hid/hid-rmi.c
-index d4af17fdba46..154f0403cbf4 100644
+index d4af17fdba467..154f0403cbf4c 100644
--- a/drivers/hid/hid-rmi.c
+++ b/drivers/hid/hid-rmi.c
@@ -321,21 +321,12 @@ static int rmi_input_event(struct hid_device *hdev, u8 *data, int size)
@@ -1314,7 +1313,7 @@ index d4af17fdba46..154f0403cbf4 100644
data->xport.ops = &hid_rmi_ops;
diff --git a/drivers/hwtracing/coresight/coresight-etm4x-core.c b/drivers/hwtracing/coresight/coresight-etm4x-core.c
-index bf01f01964cf..703896981e8a 100644
+index bf01f01964cf9..703896981e8ae 100644
--- a/drivers/hwtracing/coresight/coresight-etm4x-core.c
+++ b/drivers/hwtracing/coresight/coresight-etm4x-core.c
@@ -10,6 +10,7 @@
@@ -1365,7 +1364,7 @@ index bf01f01964cf..703896981e8a 100644
platform_driver_unregister(&etm4_platform_driver);
etm4_pm_clear();
diff --git a/drivers/input/rmi4/rmi_driver.c b/drivers/input/rmi4/rmi_driver.c
-index ef9ea295f9e0..0103334e8f32 100644
+index ef9ea295f9e03..0103334e8f32c 100644
--- a/drivers/input/rmi4/rmi_driver.c
+++ b/drivers/input/rmi4/rmi_driver.c
@@ -182,34 +182,47 @@ void rmi_set_attn_data(struct rmi_device *rmi_dev, unsigned long irq_status,
@@ -1557,7 +1556,7 @@ index ef9ea295f9e0..0103334e8f32 100644
if (data->f01_container->dev.driver) {
/* Driver already bound, so enable ATTN now. */
diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
-index 9df7cc75c1bc..60d541ae39e8 100644
+index 9df7cc75c1bc5..60d541ae39e8d 100644
--- a/drivers/iommu/iommu.c
+++ b/drivers/iommu/iommu.c
@@ -8,6 +8,7 @@
@@ -1597,7 +1596,7 @@ index 9df7cc75c1bc..60d541ae39e8 100644
* iommu_setup_default_domain - Set the default_domain for the group
* @group: Group to change
diff --git a/drivers/media/pci/intel/ipu-bridge.c b/drivers/media/pci/intel/ipu-bridge.c
-index 61750cc98d70..a0e9a71580b5 100644
+index 61750cc98d705..a0e9a71580b5d 100644
--- a/drivers/media/pci/intel/ipu-bridge.c
+++ b/drivers/media/pci/intel/ipu-bridge.c
@@ -43,28 +43,46 @@
@@ -1659,7 +1658,7 @@ index 61750cc98d70..a0e9a71580b5 100644
static const struct ipu_property_names prop_names = {
diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
-index 568410e64ce6..6afbaee83950 100644
+index 568410e64ce64..6afbaee839503 100644
--- a/drivers/pci/quirks.c
+++ b/drivers/pci/quirks.c
@@ -4433,6 +4433,30 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_BROADCOM, 0x9000,
@@ -1694,7 +1693,7 @@ index 568410e64ce6..6afbaee83950 100644
* Intersil/Techwell TW686[4589]-based video capture cards have an empty (zero)
* class code. Fix it.
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
-index 7d2a294ebc3d..c2536099932b 100644
+index 7d2a294ebc3d7..c2536099932b6 100644
--- a/drivers/scsi/sd.c
+++ b/drivers/scsi/sd.c
@@ -120,6 +120,14 @@ static const char *sd_cache_types[] = {
@@ -1722,7 +1721,7 @@ index 7d2a294ebc3d..c2536099932b 100644
if (err)
goto err_out_driver;
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
-index 4b93c0bd1d4b..b98906237306 100644
+index 4b93c0bd1d4bc..b98906237306d 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -5844,6 +5844,13 @@ static void hub_event(struct work_struct *work)
@@ -1739,21 +1738,8 @@ index 4b93c0bd1d4b..b98906237306 100644
/* Lock the device, then check to see if we were
* disconnected while waiting for the lock to succeed. */
usb_lock_device(hdev);
-diff --git a/fs/xfs/libxfs/xfs_ialloc_btree.c b/fs/xfs/libxfs/xfs_ialloc_btree.c
-index 42e9fd47f6c7..ffef1c75dd57 100644
---- a/fs/xfs/libxfs/xfs_ialloc_btree.c
-+++ b/fs/xfs/libxfs/xfs_ialloc_btree.c
-@@ -749,7 +749,7 @@ xfs_finobt_count_blocks(
- if (error)
- return error;
-
-- cur = xfs_inobt_init_cursor(pag, tp, agbp);
-+ cur = xfs_finobt_init_cursor(pag, tp, agbp);
- error = xfs_btree_count_blocks(cur, tree_blocks);
- xfs_btree_del_cursor(cur, error);
- xfs_trans_brelse(tp, agbp);
diff --git a/include/linux/crypto.h b/include/linux/crypto.h
-index b164da5e129e..59021b8609a7 100644
+index b164da5e129e8..59021b8609a70 100644
--- a/include/linux/crypto.h
+++ b/include/linux/crypto.h
@@ -133,6 +133,7 @@
@@ -1765,7 +1751,7 @@ index b164da5e129e..59021b8609a7 100644
/*
* Miscellaneous stuff.
diff --git a/include/linux/efi.h b/include/linux/efi.h
-index 418e555459da..fdd941287ae1 100644
+index 418e555459da7..fdd941287ae1d 100644
--- a/include/linux/efi.h
+++ b/include/linux/efi.h
@@ -45,6 +45,8 @@ struct screen_info;
@@ -1833,7 +1819,7 @@ index 418e555459da..fdd941287ae1 100644
enum efi_secureboot_mode efi_get_secureboot_mode(efi_get_variable_t *get_var)
{
diff --git a/include/linux/lsm_hook_defs.h b/include/linux/lsm_hook_defs.h
-index 855db460e08b..7a8c28cd7510 100644
+index 855db460e08bc..7a8c28cd7510d 100644
--- a/include/linux/lsm_hook_defs.h
+++ b/include/linux/lsm_hook_defs.h
@@ -438,6 +438,8 @@ LSM_HOOK(int, 0, bpf_token_capable, const struct bpf_token *token, int cap)
@@ -1846,7 +1832,7 @@ index 855db460e08b..7a8c28cd7510 100644
#ifdef CONFIG_PERF_EVENTS
LSM_HOOK(int, 0, perf_event_open, struct perf_event_attr *attr, int type)
diff --git a/include/linux/random.h b/include/linux/random.h
-index b0a940af4fff..8a52424fd0d5 100644
+index b0a940af4fff5..8a52424fd0d50 100644
--- a/include/linux/random.h
+++ b/include/linux/random.h
@@ -9,6 +9,13 @@
@@ -1874,7 +1860,7 @@ index b0a940af4fff..8a52424fd0d5 100644
extern const struct file_operations random_fops, urandom_fops;
#endif
diff --git a/include/linux/rmi.h b/include/linux/rmi.h
-index ab7eea01ab42..fff7c5f737fc 100644
+index ab7eea01ab427..fff7c5f737fc8 100644
--- a/include/linux/rmi.h
+++ b/include/linux/rmi.h
@@ -364,6 +364,7 @@ struct rmi_driver_data {
@@ -1886,7 +1872,7 @@ index ab7eea01ab42..fff7c5f737fc 100644
int rmi_register_transport_device(struct rmi_transport_dev *xport);
diff --git a/include/linux/security.h b/include/linux/security.h
-index de3af33e6ff5..0a37270070e4 100644
+index de3af33e6ff50..0a37270070e4c 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -507,6 +507,7 @@ int security_inode_notifysecctx(struct inode *inode, void *ctx, u32 ctxlen);
@@ -1909,7 +1895,7 @@ index de3af33e6ff5..0a37270070e4 100644
u32 *uctx_len, void *val, size_t val_len,
u64 id, u64 flags)
diff --git a/kernel/module/signing.c b/kernel/module/signing.c
-index a2ff4242e623..f0d2be1ee4f1 100644
+index a2ff4242e623d..f0d2be1ee4f1c 100644
--- a/kernel/module/signing.c
+++ b/kernel/module/signing.c
@@ -61,10 +61,17 @@ int mod_verify_sig(const void *mod, struct load_info *info)
@@ -1932,7 +1918,7 @@ index a2ff4242e623..f0d2be1ee4f1 100644
int module_sig_check(struct load_info *info, int flags)
diff --git a/scripts/sign-file.c b/scripts/sign-file.c
-index 3edb156ae52c..0114ae1dbf7f 100644
+index 3edb156ae52c3..0114ae1dbf7ff 100644
--- a/scripts/sign-file.c
+++ b/scripts/sign-file.c
@@ -27,7 +27,6 @@
@@ -1986,7 +1972,7 @@ index 3edb156ae52c..0114ae1dbf7f 100644
BIO *b;
diff --git a/scripts/tags.sh b/scripts/tags.sh
-index 191e0461d6d5..e6f418b3e948 100755
+index 191e0461d6d5b..e6f418b3e948b 100755
--- a/scripts/tags.sh
+++ b/scripts/tags.sh
@@ -16,6 +16,8 @@ fi
@@ -1999,7 +1985,7 @@ index 191e0461d6d5..e6f418b3e948 100755
# ignore arbitrary directories
if [ -n "${IGNORE_DIRS}" ]; then
diff --git a/security/integrity/platform_certs/load_uefi.c b/security/integrity/platform_certs/load_uefi.c
-index d1fdd113450a..182e8090cfe8 100644
+index d1fdd113450a6..182e8090cfe85 100644
--- a/security/integrity/platform_certs/load_uefi.c
+++ b/security/integrity/platform_certs/load_uefi.c
@@ -74,7 +74,8 @@ static __init void *get_cert_list(efi_char16_t *name, efi_guid_t *guid,
@@ -2023,7 +2009,7 @@ index d1fdd113450a..182e8090cfe8 100644
}
diff --git a/security/lockdown/Kconfig b/security/lockdown/Kconfig
-index e84ddf484010..d0501353a4b9 100644
+index e84ddf4840101..d0501353a4b95 100644
--- a/security/lockdown/Kconfig
+++ b/security/lockdown/Kconfig
@@ -16,6 +16,19 @@ config SECURITY_LOCKDOWN_LSM_EARLY
@@ -2047,7 +2033,7 @@ index e84ddf484010..d0501353a4b9 100644
prompt "Kernel default lockdown mode"
default LOCK_DOWN_KERNEL_FORCE_NONE
diff --git a/security/lockdown/lockdown.c b/security/lockdown/lockdown.c
-index cd84d8ea1dfb..e4c70a0312bc 100644
+index cd84d8ea1dfbf..e4c70a0312bc8 100644
--- a/security/lockdown/lockdown.c
+++ b/security/lockdown/lockdown.c
@@ -74,6 +74,7 @@ static int lockdown_is_locked_down(enum lockdown_reason what)
@@ -2059,7 +2045,7 @@ index cd84d8ea1dfb..e4c70a0312bc 100644
const struct lsm_id lockdown_lsmid = {
diff --git a/security/security.c b/security/security.c
-index 8cee5b6c6e6d..489e25946bf9 100644
+index 8cee5b6c6e6d5..489e25946bf96 100644
--- a/security/security.c
+++ b/security/security.c
@@ -5596,6 +5596,18 @@ int security_locked_down(enum lockdown_reason what)
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
-
diff --git a/SOURCES/tkg-misc-additions.patch b/SOURCES/tkg-misc-additions.patch
index 938ddf3..3056a1c 100644
--- a/SOURCES/tkg-misc-additions.patch
+++ b/SOURCES/tkg-misc-additions.patch
@@ -98,19 +98,6 @@ index f4b210ab061291..837d0dbb28ea08 100644
help
This value can be used to select the number of bits to use to
-diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_state.c b/drivers/gpu/drm/amd/display/dc/core/dc_state.c
-index 180ac47868c2..42bf097b36b7 100644
---- a/drivers/gpu/drm/amd/display/dc/core/dc_state.c
-+++ b/drivers/gpu/drm/amd/display/dc/core/dc_state.c
-@@ -300,7 +300,6 @@ void dc_state_destruct(struct dc_state *state)
- state->phantom_plane_count = 0;
-
- state->stream_mask = 0;
-- memset(&state->res_ctx, 0, sizeof(state->res_ctx));
- memset(&state->pp_display_cfg, 0, sizeof(state->pp_display_cfg));
- memset(&state->dcn_bw_vars, 0, sizeof(state->dcn_bw_vars));
- state->clk_mgr = NULL;
-
From 299b81f3e619aea3ceda77d7c42842a496b34a53 Mon Sep 17 00:00:00 2001
From: Peter Jung <admin@ptr1337.dev>
Date: Thu, 21 Mar 2024 19:00:50 +0100
@@ -151,9 +138,9 @@ index 59d2eee72a3297..0a4e75de95c257 100644
-#ifdef AMD_PRIVATE_COLOR
+#ifdef CONFIG_AMD_PRIVATE_COLOR
- if (amdgpu_dm_create_color_properties(adev))
- return -ENOMEM;
- #endif
+ if (amdgpu_dm_create_color_properties(adev)) {
+ dc_state_release(state->context);
+ kfree(state);
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
index c87b64e464ed5c..6fe07243adc3d5 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
diff --git a/SOURCES/v0-speaker-multifix.patch b/SOURCES/v0-speaker-multifix.patch
index 724fa59..014985e 100644
--- a/SOURCES/v0-speaker-multifix.patch
+++ b/SOURCES/v0-speaker-multifix.patch
@@ -20277,7 +20277,7 @@ diff --git a/sound/soc/codecs/aw87xxx/aw87xxx.c b/sound/soc/codecs/aw87xxx/aw87x
index eddb01695..7f44d9b9d 100644
--- a/sound/soc/codecs/aw87xxx/aw87xxx.c
+++ b/sound/soc/codecs/aw87xxx/aw87xxx.c
-@@ -1,1457 +1,1467 @@
+@@ -1,1457 +1,1466 @@
-/*
- * aw87xxx.c aw87xxx pa module
- *
@@ -21779,7 +21779,6 @@ index eddb01695..7f44d9b9d 100644
+#include <linux/hrtimer.h>
+#include <linux/ktime.h>
+#include <linux/kthread.h>
-+#include <linux/vmalloc.h>
+#include <uapi/sound/asound.h>
+#include <sound/control.h>
+#include <sound/soc.h>
@@ -23669,8 +23668,8 @@ index f2be4b102..928202b1a 100644
ALC269_FIXUP_HEADSET_MODE_NO_HP_MIC,
ALC269_FIXUP_ASPIRE_HEADSET_MIC,
ALC269_FIXUP_ASUS_X101_FUNC,
-@@ -7528,6 +7528,30 @@
- ALC287_FIXUP_LENOVO_SSID_17AA3820,
+@@ -7555,6 +7555,30 @@
+ ALC245_FIXUP_CLEVO_NOISY_MIC,
};
+/* A special fixup for AYN and AYANEO handhelds as both