diff options
-rw-r--r-- | SOURCES/0001-Set-amdgpu.ppfeaturemask-0xffffffff-as-default.patch | 25 | ||||
-rw-r--r-- | SOURCES/0001-bump-the-sensitivity-of-AMD-SFH.patch | 450 | ||||
-rw-r--r-- | SOURCES/0001-drm-i915-quirks-disable-async-flipping-on-specific-d.patch | 8 | ||||
-rw-r--r-- | SOURCES/Patchlist.changelog | 3 | ||||
-rw-r--r-- | SOURCES/asus-linux.patch | 5069 | ||||
-rw-r--r-- | SOURCES/kernel-s390x-debug-fedora.config | 1 | ||||
-rw-r--r-- | SOURCES/kernel-s390x-debug-rhel.config | 1 | ||||
-rw-r--r-- | SOURCES/kernel-s390x-fedora.config | 1 | ||||
-rw-r--r-- | SOURCES/kernel-s390x-rhel.config | 1 | ||||
-rw-r--r-- | SOURCES/kernel-s390x-zfcpdump-rhel.config | 1 | ||||
-rw-r--r-- | SOURCES/kernel.changelog | 19 | ||||
-rw-r--r-- | SOURCES/linux-surface.patch | 639 | ||||
-rw-r--r-- | SOURCES/patch-6.10-redhat.patch | 110 | ||||
-rw-r--r-- | SOURCES/t2linux.patch | 10707 | ||||
-rw-r--r-- | SOURCES/tkg-misc-additions.patch | 19 | ||||
-rw-r--r-- | SOURCES/v0-speaker-multifix.patch | 7 | ||||
-rw-r--r-- | SPECS/kernel.spec | 43 |
17 files changed, 314 insertions, 16790 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, ¤tv); -+ 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 = ¶ms->bgr888_result; -+ size_t dst_size; -+ u8 *buf = NULL; -+ __le32 *xrgb8888 = NULL; -+ struct iosys_map dst, src; -+ -+ struct drm_framebuffer fb = { -+ .format = drm_format_info(DRM_FORMAT_XRGB8888), -+ .pitches = { params->pitch, 0, 0 }, -+ }; -+ -+ dst_size = conversion_buf_size(DRM_FORMAT_BGR888, result->dst_pitch, -+ ¶ms->clip, 0); -+ KUNIT_ASSERT_GT(test, dst_size, 0); -+ -+ buf = kunit_kzalloc(test, dst_size, GFP_KERNEL); -+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, buf); -+ iosys_map_set_vaddr(&dst, buf); -+ -+ xrgb8888 = cpubuf_to_le32(test, params->xrgb8888, TEST_BUF_SIZE); -+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, xrgb8888); -+ iosys_map_set_vaddr(&src, xrgb8888); -+ -+ /* -+ * BGR888 expected results are already in little-endian -+ * order, so there's no need to convert the test output. -+ */ -+ drm_fb_xrgb8888_to_bgr888(&dst, &result->dst_pitch, &src, &fb, ¶ms->clip, -+ &fmtcnv_state); -+ KUNIT_EXPECT_MEMEQ(test, buf, result->expected, dst_size); -+ -+ buf = dst.vaddr; /* restore original value of buf */ -+ memset(buf, 0, dst_size); -+ -+ int blit_result = 0; -+ -+ blit_result = drm_fb_blit(&dst, &result->dst_pitch, DRM_FORMAT_BGR888, &src, &fb, ¶ms->clip, -+ &fmtcnv_state); -+ -+ KUNIT_EXPECT_FALSE(test, blit_result); -+ KUNIT_EXPECT_MEMEQ(test, buf, result->expected, dst_size); -+} -+ - static void drm_test_fb_xrgb8888_to_argb8888(struct kunit *test) - { - const struct convert_xrgb8888_case *params = test->param_value; -@@ -1851,6 +1931,7 @@ static struct kunit_case drm_format_helper_test_cases[] = { - KUNIT_CASE_PARAM(drm_test_fb_xrgb8888_to_argb1555, convert_xrgb8888_gen_params), - KUNIT_CASE_PARAM(drm_test_fb_xrgb8888_to_rgba5551, convert_xrgb8888_gen_params), - KUNIT_CASE_PARAM(drm_test_fb_xrgb8888_to_rgb888, convert_xrgb8888_gen_params), -+ KUNIT_CASE_PARAM(drm_test_fb_xrgb8888_to_bgr888, convert_xrgb8888_gen_params), - KUNIT_CASE_PARAM(drm_test_fb_xrgb8888_to_argb8888, convert_xrgb8888_gen_params), - KUNIT_CASE_PARAM(drm_test_fb_xrgb8888_to_xrgb2101010, convert_xrgb8888_gen_params), - KUNIT_CASE_PARAM(drm_test_fb_xrgb8888_to_argb2101010, convert_xrgb8888_gen_params), -diff --git a/drivers/gpu/drm/tiny/Kconfig b/drivers/gpu/drm/tiny/Kconfig -index f6889f649bc1..559a97bce12c 100644 ---- a/drivers/gpu/drm/tiny/Kconfig -+++ b/drivers/gpu/drm/tiny/Kconfig -@@ -1,5 +1,17 @@ - # SPDX-License-Identifier: GPL-2.0-only - -+config DRM_APPLETBDRM -+ tristate "DRM support for Apple Touch Bars" -+ depends on DRM && USB && MMU -+ select DRM_KMS_HELPER -+ select DRM_GEM_SHMEM_HELPER -+ help -+ Say Y here if you want support for the display of Touch Bars on x86 -+ MacBook Pros. -+ -+ To compile this driver as a module, choose M here: the -+ module will be called appletbdrm. -+ - config DRM_ARCPGU - tristate "ARC PGU" - depends on DRM && OF -diff --git a/drivers/gpu/drm/tiny/Makefile b/drivers/gpu/drm/tiny/Makefile -index 76dde89a044b..9a1b412e764a 100644 ---- a/drivers/gpu/drm/tiny/Makefile -+++ b/drivers/gpu/drm/tiny/Makefile -@@ -1,5 +1,6 @@ - # SPDX-License-Identifier: GPL-2.0-only - -+obj-$(CONFIG_DRM_APPLETBDRM) += appletbdrm.o - obj-$(CONFIG_DRM_ARCPGU) += arcpgu.o - obj-$(CONFIG_DRM_BOCHS) += bochs.o - obj-$(CONFIG_DRM_CIRRUS_QEMU) += cirrus.o -diff --git a/drivers/gpu/drm/tiny/appletbdrm.c b/drivers/gpu/drm/tiny/appletbdrm.c -new file mode 100644 -index 000000000000..b9440ce0064e ---- /dev/null -+++ b/drivers/gpu/drm/tiny/appletbdrm.c -@@ -0,0 +1,624 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * Apple Touch Bar DRM Driver -+ * -+ * Copyright (c) 2023 Kerem Karabay <kekrby@gmail.com> -+ */ -+ -+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt -+ -+#include <asm/unaligned.h> -+ -+#include <linux/usb.h> -+#include <linux/module.h> -+ -+#include <drm/drm_drv.h> -+#include <drm/drm_fourcc.h> -+#include <drm/drm_probe_helper.h> -+#include <drm/drm_atomic_helper.h> -+#include <drm/drm_damage_helper.h> -+#include <drm/drm_format_helper.h> -+#include <drm/drm_gem_shmem_helper.h> -+#include <drm/drm_gem_atomic_helper.h> -+#include <drm/drm_simple_kms_helper.h> -+#include <drm/drm_gem_framebuffer_helper.h> -+ -+#define _APPLETBDRM_FOURCC(s) (((s)[0] << 24) | ((s)[1] << 16) | ((s)[2] << 8) | (s)[3]) -+#define APPLETBDRM_FOURCC(s) _APPLETBDRM_FOURCC(#s) -+ -+#define APPLETBDRM_PIXEL_FORMAT APPLETBDRM_FOURCC(RGBA) /* The actual format is BGR888 */ -+#define APPLETBDRM_BITS_PER_PIXEL 24 -+ -+#define APPLETBDRM_MSG_CLEAR_DISPLAY APPLETBDRM_FOURCC(CLRD) -+#define APPLETBDRM_MSG_GET_INFORMATION APPLETBDRM_FOURCC(GINF) -+#define APPLETBDRM_MSG_UPDATE_COMPLETE APPLETBDRM_FOURCC(UDCL) -+#define APPLETBDRM_MSG_SIGNAL_READINESS APPLETBDRM_FOURCC(REDY) -+ -+#define APPLETBDRM_BULK_MSG_TIMEOUT 1000 -+ -+#define drm_to_adev(_drm) container_of(_drm, struct appletbdrm_device, drm) -+#define adev_to_udev(adev) interface_to_usbdev(to_usb_interface(adev->dev)) -+ -+struct appletbdrm_device { -+ struct device *dev; -+ -+ u8 in_ep; -+ u8 out_ep; -+ -+ u32 width; -+ u32 height; -+ -+ struct drm_device drm; -+ struct drm_display_mode mode; -+ struct drm_connector connector; -+ struct drm_simple_display_pipe pipe; -+ -+ bool readiness_signal_received; -+}; -+ -+struct appletbdrm_request_header { -+ __le16 unk_00; -+ __le16 unk_02; -+ __le32 unk_04; -+ __le32 unk_08; -+ __le32 size; -+} __packed; -+ -+struct appletbdrm_response_header { -+ u8 unk_00[16]; -+ u32 msg; -+} __packed; -+ -+struct appletbdrm_simple_request { -+ struct appletbdrm_request_header header; -+ u32 msg; -+ u8 unk_14[8]; -+ __le32 size; -+} __packed; -+ -+struct appletbdrm_information { -+ struct appletbdrm_response_header header; -+ u8 unk_14[12]; -+ __le32 width; -+ __le32 height; -+ u8 bits_per_pixel; -+ __le32 bytes_per_row; -+ __le32 orientation; -+ __le32 bitmap_info; -+ u32 pixel_format; -+ __le32 width_inches; /* floating point */ -+ __le32 height_inches; /* floating point */ -+} __packed; -+ -+struct appletbdrm_frame { -+ __le16 begin_x; -+ __le16 begin_y; -+ __le16 width; -+ __le16 height; -+ __le32 buf_size; -+ u8 buf[]; -+} __packed; -+ -+struct appletbdrm_fb_request_footer { -+ u8 unk_00[12]; -+ __le32 unk_0c; -+ u8 unk_10[12]; -+ __le32 unk_1c; -+ __le64 timestamp; -+ u8 unk_28[12]; -+ __le32 unk_34; -+ u8 unk_38[20]; -+ __le32 unk_4c; -+} __packed; -+ -+struct appletbdrm_fb_request { -+ struct appletbdrm_request_header header; -+ __le16 unk_10; -+ u8 msg_id; -+ u8 unk_13[29]; -+ /* -+ * Contents of `data`: -+ * - struct appletbdrm_frame frames[]; -+ * - struct appletbdrm_fb_request_footer footer; -+ * - padding to make the total size a multiple of 16 -+ */ -+ u8 data[]; -+} __packed; -+ -+struct appletbdrm_fb_request_response { -+ struct appletbdrm_response_header header; -+ u8 unk_14[12]; -+ __le64 timestamp; -+} __packed; -+ -+static int appletbdrm_send_request(struct appletbdrm_device *adev, -+ struct appletbdrm_request_header *request, size_t size) -+{ -+ struct usb_device *udev = adev_to_udev(adev); -+ struct drm_device *drm = &adev->drm; -+ int ret, actual_size; -+ -+ ret = usb_bulk_msg(udev, usb_sndbulkpipe(udev, adev->out_ep), -+ request, size, &actual_size, APPLETBDRM_BULK_MSG_TIMEOUT); -+ if (ret) { -+ drm_err(drm, "Failed to send message (%pe)\n", ERR_PTR(ret)); -+ return ret; -+ } -+ -+ if (actual_size != size) { -+ drm_err(drm, "Actual size (%d) doesn't match expected size (%lu)\n", -+ actual_size, size); -+ return -EIO; -+ } -+ -+ return ret; -+} -+ -+static int appletbdrm_read_response(struct appletbdrm_device *adev, -+ struct appletbdrm_response_header *response, -+ size_t size, u32 expected_response) -+{ -+ struct usb_device *udev = adev_to_udev(adev); -+ struct drm_device *drm = &adev->drm; -+ int ret, actual_size; -+ -+retry: -+ ret = usb_bulk_msg(udev, usb_rcvbulkpipe(udev, adev->in_ep), -+ response, size, &actual_size, APPLETBDRM_BULK_MSG_TIMEOUT); -+ if (ret) { -+ drm_err(drm, "Failed to read response (%pe)\n", ERR_PTR(ret)); -+ return ret; -+ } -+ -+ /* -+ * The device responds to the first request sent in a particular -+ * timeframe after the USB device configuration is set with a readiness -+ * signal, in which case the response should be read again -+ */ -+ if (response->msg == APPLETBDRM_MSG_SIGNAL_READINESS) { -+ if (!adev->readiness_signal_received) { -+ adev->readiness_signal_received = true; -+ goto retry; -+ } -+ -+ drm_err(drm, "Encountered unexpected readiness signal\n"); -+ return -EIO; -+ } -+ -+ if (actual_size != size) { -+ drm_err(drm, "Actual size (%d) doesn't match expected size (%lu)\n", -+ actual_size, size); -+ return -EIO; -+ } -+ -+ if (response->msg != expected_response) { -+ drm_err(drm, "Unexpected response from device (expected %p4ch found %p4ch)\n", -+ &expected_response, &response->msg); -+ return -EIO; -+ } -+ -+ return 0; -+} -+ -+static int appletbdrm_send_msg(struct appletbdrm_device *adev, u32 msg) -+{ -+ struct appletbdrm_simple_request *request; -+ int ret; -+ -+ request = kzalloc(sizeof(*request), GFP_KERNEL); -+ if (!request) -+ return -ENOMEM; -+ -+ request->header.unk_00 = cpu_to_le16(2); -+ request->header.unk_02 = cpu_to_le16(0x1512); -+ request->header.size = cpu_to_le32(sizeof(*request) - sizeof(request->header)); -+ request->msg = msg; -+ request->size = request->header.size; -+ -+ ret = appletbdrm_send_request(adev, &request->header, sizeof(*request)); -+ -+ kfree(request); -+ -+ return ret; -+} -+ -+static int appletbdrm_clear_display(struct appletbdrm_device *adev) -+{ -+ return appletbdrm_send_msg(adev, APPLETBDRM_MSG_CLEAR_DISPLAY); -+} -+ -+static int appletbdrm_signal_readiness(struct appletbdrm_device *adev) -+{ -+ return appletbdrm_send_msg(adev, APPLETBDRM_MSG_SIGNAL_READINESS); -+} -+ -+static int appletbdrm_get_information(struct appletbdrm_device *adev) -+{ -+ struct appletbdrm_information *info; -+ struct drm_device *drm = &adev->drm; -+ u8 bits_per_pixel; -+ u32 pixel_format; -+ int ret; -+ -+ info = kzalloc(sizeof(*info), GFP_KERNEL); -+ if (!info) -+ return -ENOMEM; -+ -+ ret = appletbdrm_send_msg(adev, APPLETBDRM_MSG_GET_INFORMATION); -+ if (ret) -+ return ret; -+ -+ ret = appletbdrm_read_response(adev, &info->header, sizeof(*info), -+ APPLETBDRM_MSG_GET_INFORMATION); -+ if (ret) -+ goto free_info; -+ -+ bits_per_pixel = info->bits_per_pixel; -+ pixel_format = get_unaligned(&info->pixel_format); -+ -+ adev->width = get_unaligned_le32(&info->width); -+ adev->height = get_unaligned_le32(&info->height); -+ -+ if (bits_per_pixel != APPLETBDRM_BITS_PER_PIXEL) { -+ drm_err(drm, "Encountered unexpected bits per pixel value (%d)\n", bits_per_pixel); -+ ret = -EINVAL; -+ goto free_info; -+ } -+ -+ if (pixel_format != APPLETBDRM_PIXEL_FORMAT) { -+ drm_err(drm, "Encountered unknown pixel format (%p4ch)\n", &pixel_format); -+ ret = -EINVAL; -+ goto free_info; -+ } -+ -+free_info: -+ kfree(info); -+ -+ return ret; -+} -+ -+static u32 rect_size(struct drm_rect *rect) -+{ -+ return drm_rect_width(rect) * drm_rect_height(rect) * (APPLETBDRM_BITS_PER_PIXEL / 8); -+} -+ -+static int appletbdrm_flush_damage(struct appletbdrm_device *adev, -+ struct drm_plane_state *old_state, -+ struct drm_plane_state *state) -+{ -+ struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(state); -+ struct appletbdrm_fb_request_response *response; -+ struct appletbdrm_fb_request_footer *footer; -+ struct drm_atomic_helper_damage_iter iter; -+ struct drm_framebuffer *fb = state->fb; -+ struct appletbdrm_fb_request *request; -+ struct drm_device *drm = &adev->drm; -+ struct appletbdrm_frame *frame; -+ u64 timestamp = ktime_get_ns(); -+ struct drm_rect damage; -+ size_t frames_size = 0; -+ size_t request_size; -+ int ret; -+ -+ drm_atomic_helper_damage_iter_init(&iter, old_state, state); -+ drm_atomic_for_each_plane_damage(&iter, &damage) { -+ frames_size += struct_size(frame, buf, rect_size(&damage)); -+ } -+ -+ if (!frames_size) -+ return 0; -+ -+ request_size = ALIGN(sizeof(*request) + frames_size + sizeof(*footer), 16); -+ -+ request = kzalloc(request_size, GFP_KERNEL); -+ if (!request) -+ return -ENOMEM; -+ -+ response = kzalloc(sizeof(*response), GFP_KERNEL); -+ if (!response) { -+ ret = -ENOMEM; -+ goto free_request; -+ } -+ -+ ret = drm_gem_fb_begin_cpu_access(fb, DMA_FROM_DEVICE); -+ if (ret) { -+ drm_err(drm, "Failed to start CPU framebuffer access (%pe)\n", ERR_PTR(ret)); -+ goto free_response; -+ } -+ -+ request->header.unk_00 = cpu_to_le16(2); -+ request->header.unk_02 = cpu_to_le16(0x12); -+ request->header.unk_04 = cpu_to_le32(9); -+ request->header.size = cpu_to_le32(request_size - sizeof(request->header)); -+ request->unk_10 = cpu_to_le16(1); -+ request->msg_id = timestamp & 0xff; -+ -+ frame = (struct appletbdrm_frame *)request->data; -+ -+ drm_atomic_helper_damage_iter_init(&iter, old_state, state); -+ drm_atomic_for_each_plane_damage(&iter, &damage) { -+ struct iosys_map dst = IOSYS_MAP_INIT_VADDR(frame->buf); -+ u32 buf_size = rect_size(&damage); -+ -+ /* -+ * The coordinates need to be translated to the coordinate -+ * system the device expects, see the comment in -+ * appletbdrm_setup_mode_config -+ */ -+ frame->begin_x = cpu_to_le16(damage.y1); -+ frame->begin_y = cpu_to_le16(adev->height - damage.x2); -+ frame->width = cpu_to_le16(drm_rect_height(&damage)); -+ frame->height = cpu_to_le16(drm_rect_width(&damage)); -+ frame->buf_size = cpu_to_le32(buf_size); -+ -+ ret = drm_fb_blit(&dst, NULL, DRM_FORMAT_BGR888, -+ &shadow_plane_state->data[0], fb, &damage, &shadow_plane_state->fmtcnv_state); -+ if (ret) { -+ drm_err(drm, "Failed to copy damage clip (%pe)\n", ERR_PTR(ret)); -+ goto end_fb_cpu_access; -+ } -+ -+ frame = (void *)frame + struct_size(frame, buf, buf_size); -+ } -+ -+ footer = (struct appletbdrm_fb_request_footer *)&request->data[frames_size]; -+ -+ footer->unk_0c = cpu_to_le32(0xfffe); -+ footer->unk_1c = cpu_to_le32(0x80001); -+ footer->unk_34 = cpu_to_le32(0x80002); -+ footer->unk_4c = cpu_to_le32(0xffff); -+ footer->timestamp = cpu_to_le64(timestamp); -+ -+ ret = appletbdrm_send_request(adev, &request->header, request_size); -+ if (ret) -+ goto end_fb_cpu_access; -+ -+ ret = appletbdrm_read_response(adev, &response->header, sizeof(*response), -+ APPLETBDRM_MSG_UPDATE_COMPLETE); -+ if (ret) -+ goto end_fb_cpu_access; -+ -+ if (response->timestamp != footer->timestamp) { -+ drm_err(drm, "Response timestamp (%llu) doesn't match request timestamp (%llu)\n", -+ le64_to_cpu(response->timestamp), timestamp); -+ goto end_fb_cpu_access; -+ } -+ -+end_fb_cpu_access: -+ drm_gem_fb_end_cpu_access(fb, DMA_FROM_DEVICE); -+free_response: -+ kfree(response); -+free_request: -+ kfree(request); -+ -+ return ret; -+} -+ -+static int appletbdrm_connector_helper_get_modes(struct drm_connector *connector) -+{ -+ struct appletbdrm_device *adev = drm_to_adev(connector->dev); -+ -+ return drm_connector_helper_get_modes_fixed(connector, &adev->mode); -+} -+ -+static enum drm_mode_status appletbdrm_pipe_mode_valid(struct drm_simple_display_pipe *pipe, -+ const struct drm_display_mode *mode) -+{ -+ struct drm_crtc *crtc = &pipe->crtc; -+ struct appletbdrm_device *adev = drm_to_adev(crtc->dev); -+ -+ return drm_crtc_helper_mode_valid_fixed(crtc, mode, &adev->mode); -+} -+ -+static void appletbdrm_pipe_disable(struct drm_simple_display_pipe *pipe) -+{ -+ struct appletbdrm_device *adev = drm_to_adev(pipe->crtc.dev); -+ int idx; -+ -+ if (!drm_dev_enter(&adev->drm, &idx)) -+ return; -+ -+ appletbdrm_clear_display(adev); -+ -+ drm_dev_exit(idx); -+} -+ -+static void appletbdrm_pipe_update(struct drm_simple_display_pipe *pipe, -+ struct drm_plane_state *old_state) -+{ -+ struct drm_crtc *crtc = &pipe->crtc; -+ struct appletbdrm_device *adev = drm_to_adev(crtc->dev); -+ int idx; -+ -+ if (!crtc->state->active || !drm_dev_enter(&adev->drm, &idx)) -+ return; -+ -+ appletbdrm_flush_damage(adev, old_state, pipe->plane.state); -+ -+ drm_dev_exit(idx); -+} -+ -+static const u32 appletbdrm_formats[] = { -+ DRM_FORMAT_BGR888, -+ DRM_FORMAT_XRGB8888, /* emulated */ -+}; -+ -+static const struct drm_mode_config_funcs appletbdrm_mode_config_funcs = { -+ .fb_create = drm_gem_fb_create_with_dirty, -+ .atomic_check = drm_atomic_helper_check, -+ .atomic_commit = drm_atomic_helper_commit, -+}; -+ -+static const struct drm_connector_funcs appletbdrm_connector_funcs = { -+ .reset = drm_atomic_helper_connector_reset, -+ .destroy = drm_connector_cleanup, -+ .fill_modes = drm_helper_probe_single_connector_modes, -+ .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, -+ .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, -+}; -+ -+static const struct drm_connector_helper_funcs appletbdrm_connector_helper_funcs = { -+ .get_modes = appletbdrm_connector_helper_get_modes, -+}; -+ -+static const struct drm_simple_display_pipe_funcs appletbdrm_pipe_funcs = { -+ DRM_GEM_SIMPLE_DISPLAY_PIPE_SHADOW_PLANE_FUNCS, -+ .update = appletbdrm_pipe_update, -+ .disable = appletbdrm_pipe_disable, -+ .mode_valid = appletbdrm_pipe_mode_valid, -+}; -+ -+DEFINE_DRM_GEM_FOPS(appletbdrm_drm_fops); -+ -+static const struct drm_driver appletbdrm_drm_driver = { -+ DRM_GEM_SHMEM_DRIVER_OPS, -+ .name = "appletbdrm", -+ .desc = "Apple Touch Bar DRM Driver", -+ .date = "20230910", -+ .major = 1, -+ .minor = 0, -+ .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_ATOMIC, -+ .fops = &appletbdrm_drm_fops, -+}; -+ -+static int appletbdrm_setup_mode_config(struct appletbdrm_device *adev) -+{ -+ struct drm_connector *connector = &adev->connector; -+ struct drm_device *drm = &adev->drm; -+ struct device *dev = adev->dev; -+ int ret; -+ -+ ret = drmm_mode_config_init(drm); -+ if (ret) -+ return dev_err_probe(dev, ret, "Failed to initialize mode configuration\n"); -+ -+ /* -+ * The coordinate system used by the device is different from the -+ * coordinate system of the framebuffer in that the x and y axes are -+ * swapped, and that the y axis is inverted; so what the device reports -+ * as the height is actually the width of the framebuffer and vice -+ * versa -+ */ -+ drm->mode_config.min_width = 0; -+ drm->mode_config.min_height = 0; -+ drm->mode_config.max_width = max(adev->height, DRM_SHADOW_PLANE_MAX_WIDTH); -+ drm->mode_config.max_height = max(adev->width, DRM_SHADOW_PLANE_MAX_HEIGHT); -+ drm->mode_config.preferred_depth = APPLETBDRM_BITS_PER_PIXEL; -+ drm->mode_config.funcs = &appletbdrm_mode_config_funcs; -+ -+ adev->mode = (struct drm_display_mode) { -+ DRM_MODE_INIT(60, adev->height, adev->width, -+ DRM_MODE_RES_MM(adev->height, 218), -+ DRM_MODE_RES_MM(adev->width, 218)) -+ }; -+ -+ ret = drm_connector_init(drm, connector, -+ &appletbdrm_connector_funcs, DRM_MODE_CONNECTOR_USB); -+ if (ret) -+ return dev_err_probe(dev, ret, "Failed to initialize connector\n"); -+ -+ drm_connector_helper_add(connector, &appletbdrm_connector_helper_funcs); -+ -+ ret = drm_connector_set_panel_orientation(connector, -+ DRM_MODE_PANEL_ORIENTATION_RIGHT_UP); -+ if (ret) -+ return dev_err_probe(dev, ret, "Failed to set panel orientation\n"); -+ -+ connector->display_info.non_desktop = true; -+ ret = drm_object_property_set_value(&connector->base, -+ drm->mode_config.non_desktop_property, true); -+ if (ret) -+ return dev_err_probe(dev, ret, "Failed to set non-desktop property\n"); -+ -+ ret = drm_simple_display_pipe_init(drm, &adev->pipe, &appletbdrm_pipe_funcs, -+ appletbdrm_formats, ARRAY_SIZE(appletbdrm_formats), -+ NULL, &adev->connector); -+ if (ret) -+ return dev_err_probe(dev, ret, "Failed to initialize simple display pipe\n"); -+ -+ drm_plane_enable_fb_damage_clips(&adev->pipe.plane); -+ -+ drm_mode_config_reset(drm); -+ -+ ret = drm_dev_register(drm, 0); -+ if (ret) -+ return dev_err_probe(dev, ret, "Failed to register DRM device\n"); -+ -+ return 0; -+} -+ -+static int appletbdrm_probe(struct usb_interface *intf, -+ const struct usb_device_id *id) -+{ -+ struct usb_endpoint_descriptor *bulk_in, *bulk_out; -+ struct device *dev = &intf->dev; -+ struct appletbdrm_device *adev; -+ int ret; -+ -+ ret = usb_find_common_endpoints(intf->cur_altsetting, &bulk_in, &bulk_out, NULL, NULL); -+ if (ret) -+ return dev_err_probe(dev, ret, "Failed to find bulk endpoints\n"); -+ -+ adev = devm_drm_dev_alloc(dev, &appletbdrm_drm_driver, struct appletbdrm_device, drm); -+ if (IS_ERR(adev)) -+ return PTR_ERR(adev); -+ -+ adev->dev = dev; -+ adev->in_ep = bulk_in->bEndpointAddress; -+ adev->out_ep = bulk_out->bEndpointAddress; -+ -+ usb_set_intfdata(intf, adev); -+ -+ ret = appletbdrm_get_information(adev); -+ if (ret) -+ return dev_err_probe(dev, ret, "Failed to get display information\n"); -+ -+ ret = appletbdrm_signal_readiness(adev); -+ if (ret) -+ return dev_err_probe(dev, ret, "Failed to signal readiness\n"); -+ -+ ret = appletbdrm_clear_display(adev); -+ if (ret) -+ return dev_err_probe(dev, ret, "Failed to clear display\n"); -+ -+ return appletbdrm_setup_mode_config(adev); -+} -+ -+static void appletbdrm_disconnect(struct usb_interface *intf) -+{ -+ struct appletbdrm_device *adev = usb_get_intfdata(intf); -+ struct drm_device *drm = &adev->drm; -+ -+ drm_dev_unplug(drm); -+ drm_atomic_helper_shutdown(drm); -+} -+ -+static void appletbdrm_shutdown(struct usb_interface *intf) -+{ -+ struct appletbdrm_device *adev = usb_get_intfdata(intf); -+ -+ /* -+ * The framebuffer needs to be cleared on shutdown since its content -+ * persists across boots -+ */ -+ drm_atomic_helper_shutdown(&adev->drm); -+} -+ -+static const struct usb_device_id appletbdrm_usb_id_table[] = { -+ { USB_DEVICE_INTERFACE_CLASS(0x05ac, 0x8302, USB_CLASS_AUDIO_VIDEO) }, -+ {} -+}; -+MODULE_DEVICE_TABLE(usb, appletbdrm_usb_id_table); -+ -+static struct usb_driver appletbdrm_usb_driver = { -+ .name = "appletbdrm", -+ .probe = appletbdrm_probe, -+ .disconnect = appletbdrm_disconnect, -+ .shutdown = appletbdrm_shutdown, -+ .id_table = appletbdrm_usb_id_table, -+}; -+module_usb_driver(appletbdrm_usb_driver); -+ -+MODULE_AUTHOR("Kerem Karabay <kekrby@gmail.com>"); -+MODULE_DESCRIPTION("Apple Touch Bar DRM Driver"); -+MODULE_LICENSE("GPL"); -diff --git a/drivers/gpu/vga/vga_switcheroo.c b/drivers/gpu/vga/vga_switcheroo.c -index 365e6ddbe90f..cf357cd3389d 100644 ---- a/drivers/gpu/vga/vga_switcheroo.c -+++ b/drivers/gpu/vga/vga_switcheroo.c -@@ -438,12 +438,7 @@ find_active_client(struct list_head *head) - bool vga_switcheroo_client_probe_defer(struct pci_dev *pdev) - { - if ((pdev->class >> 16) == PCI_BASE_CLASS_DISPLAY) { -- /* -- * apple-gmux is needed on pre-retina MacBook Pro -- * to probe the panel if pdev is the inactive GPU. -- */ -- if (apple_gmux_present() && pdev != vga_default_device() && -- !vgasr_priv.handler_flags) -+ if (apple_gmux_present() && !vgasr_priv.handler_flags) - return true; - } - -diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig -index 08446c89eff6..35ef5d4ef068 100644 ---- a/drivers/hid/Kconfig -+++ b/drivers/hid/Kconfig -@@ -148,6 +148,27 @@ config HID_APPLEIR - - Say Y here if you want support for Apple infrared remote control. - -+config HID_APPLETB_BL -+ tristate "Apple Touch Bar Backlight" -+ depends on BACKLIGHT_CLASS_DEVICE -+ help -+ Say Y here if you want support for the backlight of Touch Bars on x86 -+ MacBook Pros. -+ -+ To compile this driver as a module, choose M here: the -+ module will be called hid-appletb-bl. -+ -+config HID_APPLETB_KBD -+ tristate "Apple Touch Bar Keyboard Mode" -+ depends on USB_HID -+ help -+ Say Y here if you want support for the keyboard mode (escape, -+ function, media and brightness keys) of Touch Bars on x86 MacBook -+ Pros. -+ -+ To compile this driver as a module, choose M here: the -+ module will be called hid-appletb-kbd. -+ - config HID_ASUS - tristate "Asus" - depends on USB_HID -@@ -723,6 +744,7 @@ config HID_MULTITOUCH - Say Y here if you have one of the following devices: - - 3M PCT touch screens - - ActionStar dual touch panels -+ - Touch Bars on x86 MacBook Pros - - Atmel panels - - Cando dual touch panels - - Chunghwa panels -diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile -index ce71b53ea6c5..fecec1d61393 100644 ---- a/drivers/hid/Makefile -+++ b/drivers/hid/Makefile -@@ -29,6 +29,8 @@ - obj-$(CONFIG_HID_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, ×tamp, &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 diff --git a/SPECS/kernel.spec b/SPECS/kernel.spec index ff6d004..eda7e35 100644 --- a/SPECS/kernel.spec +++ b/SPECS/kernel.spec @@ -160,18 +160,18 @@ Summary: The Linux kernel # the --with-release option overrides this setting.) %define debugbuildsenabled 1 %define buildid .fsync -%define specrpmversion 6.10.8 -%define specversion 6.10.8 +%define specrpmversion 6.10.12 +%define specversion 6.10.12 %define patchversion 6.10 %define pkgrelease 200 %define kversion 6 -%define tarfile_release 6.10.8 +%define tarfile_release 6.10.12 # This is needed to do merge window version magic %define patchlevel 10 # This allows pkg_release to have configurable %%{?dist} tag %define specrelease 201%{?buildid}%{?dist} # This defines the kabi tarball version -%define kabiversion 6.10.8 +%define kabiversion 6.10.12 # If this variable is set to 1, a bpf selftests build failure will cause a # fatal kernel package build error @@ -1006,13 +1006,10 @@ Patch215: cachy-bbr3.patch # device specific patches Patch300: linux-surface.patch -Patch302: asus-linux.patch Patch303: lenovo-legion-laptop.patch # workaround for i915 getting stuck during async page flips on Nvidia PRIME systems Patch308: 0001-drm-i915-quirks-disable-async-flipping-on-specific-d.patch Patch309: 0002-drm-i915-add-kernel-parameter-to-disable-async-page-.patch -# improve AMD SFH 1.1 gyro and accel sensitivity -Patch324: 0001-bump-the-sensitivity-of-AMD-SFH.patch # ROG Ally Patch316: rog-ally-audio-fix.patch Patch317: ROG-ALLY-NCT6775-PLATFORM.patch @@ -1039,17 +1036,12 @@ Patch312: steamdeck-oled-audio.patch Patch313: steamdeck-oled-hw-quirks.patch Patch315: steamdeck-oled-legion-go-bluetooth-hang.patch -# t2 macbook patches -Patch332: t2linux.patch - # temporary patches Patch401: 0001-Revert-PCI-Add-a-REBAR-size-quirk-for-Sapphire-RX-56.patch Patch405: mt76:-mt7921:-Disable-powersave-features-by-default.patch Patch408: 0001-acpi-proc-idle-skip-dummy-wait.patch # Fixes the steam deck not coming back from hibernation Patch411: 0001-Revert-nvme-pci-drop-redundant-pci_enable_pcie_error.patch -# Allows corectl to work out of the box -Patch412: 0001-Set-amdgpu.ppfeaturemask-0xffffffff-as-default.patch # fix https://gitlab.freedesktop.org/drm/amd/-/issues/3183 Patch413: amdgpu-ignore-min-pcap.patch # improve controller hiding @@ -1902,13 +1894,10 @@ ApplyOptionalPatch cachy-bbr3.patch # device specific patches ApplyOptionalPatch linux-surface.patch -ApplyOptionalPatch asus-linux.patch ApplyOptionalPatch lenovo-legion-laptop.patch # workaround for i915 getting stuck during async page flips on Nvidia PRIME systems ApplyOptionalPatch 0001-drm-i915-quirks-disable-async-flipping-on-specific-d.patch ApplyOptionalPatch 0002-drm-i915-add-kernel-parameter-to-disable-async-page-.patch -# improve AMD SFH 1.1 gyro and accel sensitivity -ApplyOptionalPatch 0001-bump-the-sensitivity-of-AMD-SFH.patch # ROG Ally- ApplyOptionalPatch rog-ally-audio-fix.patch ApplyOptionalPatch ROG-ALLY-NCT6775-PLATFORM.patch @@ -1935,9 +1924,6 @@ ApplyOptionalPatch steamdeck-oled-audio.patch ApplyOptionalPatch steamdeck-oled-hw-quirks.patch ApplyOptionalPatch steamdeck-oled-legion-go-bluetooth-hang.patch -# t2 macbook patches -ApplyOptionalPatch t2linux.patch - # temporary patches ApplyOptionalPatch 0001-Revert-PCI-Add-a-REBAR-size-quirk-for-Sapphire-RX-56.patch # mediatek fixups @@ -1945,8 +1931,6 @@ ApplyOptionalPatch mt76:-mt7921:-Disable-powersave-features-by-default.patch ApplyOptionalPatch 0001-acpi-proc-idle-skip-dummy-wait.patch # Fixes the steam deck not coming back from hibernation ApplyOptionalPatch 0001-Revert-nvme-pci-drop-redundant-pci_enable_pcie_error.patch -# enable full amd power control by default -ApplyOptionalPatch 0001-Set-amdgpu.ppfeaturemask-0xffffffff-as-default.patch # fix https://gitlab.freedesktop.org/drm/amd/-/issues/3183 ApplyOptionalPatch amdgpu-ignore-min-pcap.patch # improve controller hiding @@ -4198,8 +4182,23 @@ fi\ # # %changelog -* Sat Sep 07 2024 Jan200101 <sentrycraft123@gmail.com> - 6.10.8-201.fsync -- kernel-fsync v6.10.8 +* Sat Oct 05 2024 Jan200101 <sentrycraft123@gmail.com> - 6.10.12-201.fsync +- kernel-fsync v6.10.12 + +* Mon Sep 30 2024 Augusto Caringi <acaringi@redhat.com> [6.10.12-0] +- Linux v6.10.12 + +* 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 + +* 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 + +* Sun Sep 08 2024 Justin M. Forbes <jforbes@fedoraproject.org> [6.10.9-0] +- Linux v6.10.9 * Wed Sep 04 2024 Augusto Caringi <acaringi@redhat.com> [6.10.8-0] - Add to BugsFixed (Augusto Caringi) |