summaryrefslogtreecommitdiff
path: root/drivers/hid
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/hid')
-rw-r--r--drivers/hid/Kconfig1
-rw-r--r--drivers/hid/amd-sfh-hid/amd_sfh_client.c23
-rw-r--r--drivers/hid/amd-sfh-hid/amd_sfh_hid.h2
-rw-r--r--drivers/hid/amd-sfh-hid/amd_sfh_pcie.c4
-rw-r--r--drivers/hid/amd-sfh-hid/amd_sfh_pcie.h1
-rw-r--r--drivers/hid/hid-apple.c244
-rw-r--r--drivers/hid/hid-core.c17
-rw-r--r--drivers/hid/hid-debug.c2
-rw-r--r--drivers/hid/hid-ids.h30
-rw-r--r--drivers/hid/hid-lg4ff.c6
-rw-r--r--drivers/hid/hid-magicmouse.c66
-rw-r--r--drivers/hid/hid-mcp2221.c108
-rw-r--r--drivers/hid/hid-multitouch.c62
-rw-r--r--drivers/hid/hid-quirks.c9
-rw-r--r--drivers/hid/hid-roccat-arvo.c2
-rw-r--r--drivers/hid/hid-roccat-common.h8
-rw-r--r--drivers/hid/hid-roccat-isku.c10
-rw-r--r--drivers/hid/hid-roccat-kone.c6
-rw-r--r--drivers/hid/hid-roccat-koneplus.c14
-rw-r--r--drivers/hid/hid-roccat-konepure.c2
-rw-r--r--drivers/hid/hid-roccat-kovaplus.c12
-rw-r--r--drivers/hid/hid-roccat-lua.c4
-rw-r--r--drivers/hid/hid-roccat-pyra.c14
-rw-r--r--drivers/hid/hid-roccat-ryos.c2
-rw-r--r--drivers/hid/hid-roccat-savu.c2
-rw-r--r--drivers/hid/hid-uclogic-core.c66
-rw-r--r--drivers/hid/hid-uclogic-params.c134
-rw-r--r--drivers/hid/hid-uclogic-params.h5
-rw-r--r--drivers/hid/hid-uclogic-rdesc.c44
-rw-r--r--drivers/hid/hid-uclogic-rdesc.h4
-rw-r--r--drivers/hid/hid-universal-pidff.c5
-rw-r--r--drivers/hid/intel-thc-hid/Makefile1
-rw-r--r--drivers/hid/intel-thc-hid/intel-quicki2c/pci-quicki2c.c218
-rw-r--r--drivers/hid/intel-thc-hid/intel-quicki2c/quicki2c-dev.h55
-rw-r--r--drivers/hid/intel-thc-hid/intel-quickspi/pci-quickspi.c15
-rw-r--r--drivers/hid/intel-thc-hid/intel-thc/intel-thc-dev.c140
-rw-r--r--drivers/hid/intel-thc-hid/intel-thc/intel-thc-dev.h33
-rw-r--r--drivers/hid/intel-thc-hid/intel-thc/intel-thc-dma.c40
-rw-r--r--drivers/hid/intel-thc-hid/intel-thc/intel-thc-dma.h38
-rw-r--r--drivers/hid/intel-thc-hid/intel-thc/intel-thc-hw.h5
-rw-r--r--drivers/hid/intel-thc-hid/intel-thc/intel-thc-wot.c94
-rw-r--r--drivers/hid/intel-thc-hid/intel-thc/intel-thc-wot.h26
-rw-r--r--drivers/hid/usbhid/hid-pidff.c46
-rw-r--r--drivers/hid/usbhid/hid-pidff.h3
44 files changed, 1264 insertions, 359 deletions
diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
index 43859fc75747..a57901203aeb 100644
--- a/drivers/hid/Kconfig
+++ b/drivers/hid/Kconfig
@@ -771,6 +771,7 @@ config HID_MULTITOUCH
Say Y here if you have one of the following devices:
- 3M PCT touch screens
- ActionStar dual touch panels
+ - Apple Touch Bar on x86 MacBook Pros
- Atmel panels
- Cando dual touch panels
- Chunghwa panels
diff --git a/drivers/hid/amd-sfh-hid/amd_sfh_client.c b/drivers/hid/amd-sfh-hid/amd_sfh_client.c
index 3438d392920f..0f2cbae39b2b 100644
--- a/drivers/hid/amd-sfh-hid/amd_sfh_client.c
+++ b/drivers/hid/amd-sfh-hid/amd_sfh_client.c
@@ -146,6 +146,8 @@ static const char *get_sensor_name(int idx)
return "gyroscope";
case mag_idx:
return "magnetometer";
+ case op_idx:
+ return "operating-mode";
case als_idx:
case ACS_IDX: /* ambient color sensor */
return "ALS";
@@ -243,6 +245,20 @@ int amd_sfh_hid_client_init(struct amd_mp2_dev *privdata)
rc = -ENOMEM;
goto cleanup;
}
+
+ if (cl_data->sensor_idx[i] == op_idx) {
+ info.period = AMD_SFH_IDLE_LOOP;
+ info.sensor_idx = cl_data->sensor_idx[i];
+ info.dma_address = cl_data->sensor_dma_addr[i];
+ mp2_ops->start(privdata, info);
+ cl_data->sensor_sts[i] = amd_sfh_wait_for_response(privdata,
+ cl_data->sensor_idx[i],
+ SENSOR_ENABLED);
+ if (cl_data->sensor_sts[i] == SENSOR_ENABLED)
+ cl_data->is_any_sensor_enabled = true;
+ continue;
+ }
+
cl_data->sensor_sts[i] = SENSOR_DISABLED;
cl_data->sensor_requested_cnt[i] = 0;
cl_data->cur_hid_dev = i;
@@ -303,6 +319,13 @@ int amd_sfh_hid_client_init(struct amd_mp2_dev *privdata)
for (i = 0; i < cl_data->num_hid_devices; i++) {
cl_data->cur_hid_dev = i;
+ if (cl_data->sensor_idx[i] == op_idx) {
+ dev_dbg(dev, "sid 0x%x (%s) status 0x%x\n",
+ cl_data->sensor_idx[i], get_sensor_name(cl_data->sensor_idx[i]),
+ cl_data->sensor_sts[i]);
+ continue;
+ }
+
if (cl_data->sensor_sts[i] == SENSOR_ENABLED) {
rc = amdtp_hid_probe(i, cl_data);
if (rc)
diff --git a/drivers/hid/amd-sfh-hid/amd_sfh_hid.h b/drivers/hid/amd-sfh-hid/amd_sfh_hid.h
index 1c91be8daedd..7452b0302953 100644
--- a/drivers/hid/amd-sfh-hid/amd_sfh_hid.h
+++ b/drivers/hid/amd-sfh-hid/amd_sfh_hid.h
@@ -11,7 +11,7 @@
#ifndef AMDSFH_HID_H
#define AMDSFH_HID_H
-#define MAX_HID_DEVICES 6
+#define MAX_HID_DEVICES 7
#define AMD_SFH_HID_VENDOR 0x1022
#define AMD_SFH_HID_PRODUCT 0x0001
diff --git a/drivers/hid/amd-sfh-hid/amd_sfh_pcie.c b/drivers/hid/amd-sfh-hid/amd_sfh_pcie.c
index 1c1fd63330c9..2983af969579 100644
--- a/drivers/hid/amd-sfh-hid/amd_sfh_pcie.c
+++ b/drivers/hid/amd-sfh-hid/amd_sfh_pcie.c
@@ -29,6 +29,7 @@
#define ACEL_EN BIT(0)
#define GYRO_EN BIT(1)
#define MAGNO_EN BIT(2)
+#define OP_EN BIT(15)
#define HPD_EN BIT(16)
#define ALS_EN BIT(19)
#define ACS_EN BIT(22)
@@ -232,6 +233,9 @@ int amd_mp2_get_sensor_num(struct amd_mp2_dev *privdata, u8 *sensor_id)
if (MAGNO_EN & activestatus)
sensor_id[num_of_sensors++] = mag_idx;
+ if (OP_EN & activestatus)
+ sensor_id[num_of_sensors++] = op_idx;
+
if (ALS_EN & activestatus)
sensor_id[num_of_sensors++] = als_idx;
diff --git a/drivers/hid/amd-sfh-hid/amd_sfh_pcie.h b/drivers/hid/amd-sfh-hid/amd_sfh_pcie.h
index 05e400a4a83e..2eb61f4e8434 100644
--- a/drivers/hid/amd-sfh-hid/amd_sfh_pcie.h
+++ b/drivers/hid/amd-sfh-hid/amd_sfh_pcie.h
@@ -79,6 +79,7 @@ enum sensor_idx {
accel_idx = 0,
gyro_idx = 1,
mag_idx = 2,
+ op_idx = 15,
als_idx = 19
};
diff --git a/drivers/hid/hid-apple.c b/drivers/hid/hid-apple.c
index 0639b1f43d88..61404d7a43ee 100644
--- a/drivers/hid/hid-apple.c
+++ b/drivers/hid/hid-apple.c
@@ -30,7 +30,7 @@
#include "hid-ids.h"
#define APPLE_RDESC_JIS BIT(0)
-#define APPLE_IGNORE_MOUSE BIT(1)
+/* BIT(1) reserved, was: APPLE_IGNORE_MOUSE */
#define APPLE_HAS_FN BIT(2)
/* BIT(3) reserved, was: APPLE_HIDDEV */
#define APPLE_ISO_TILDE_QUIRK BIT(4)
@@ -42,11 +42,13 @@
#define APPLE_BACKLIGHT_CTL BIT(10)
#define APPLE_IS_NON_APPLE BIT(11)
#define APPLE_MAGIC_BACKLIGHT BIT(12)
+#define APPLE_DISABLE_FKEYS BIT(13)
-#define APPLE_FLAG_FKEY 0x01
+#define APPLE_FLAG_FKEY BIT(0)
+#define APPLE_FLAG_TB_FKEY BIT(1)
#define HID_COUNTRY_INTERNATIONAL_ISO 13
-#define APPLE_BATTERY_TIMEOUT_MS 60000
+#define APPLE_BATTERY_TIMEOUT_SEC 60
#define HID_USAGE_MAGIC_BL 0xff00000f
#define APPLE_MAGIC_REPORT_ID_POWER 3
@@ -55,7 +57,7 @@
static unsigned int fnmode = 3;
module_param(fnmode, uint, 0644);
MODULE_PARM_DESC(fnmode, "Mode of fn key on Apple keyboards (0 = disabled, "
- "1 = fkeyslast, 2 = fkeysfirst, [3] = auto)");
+ "1 = fkeyslast, 2 = fkeysfirst, [3] = auto, 4 = fkeysdisabled)");
static int iso_layout = -1;
module_param(iso_layout, int, 0644);
@@ -89,6 +91,19 @@ struct apple_sc_backlight {
struct hid_device *hdev;
};
+struct apple_backlight_config_report {
+ u8 report_id;
+ u8 version;
+ u16 backlight_off, backlight_on_min, backlight_on_max;
+};
+
+struct apple_backlight_set_report {
+ u8 report_id;
+ u8 version;
+ u16 backlight;
+ u16 rate;
+};
+
struct apple_magic_backlight {
struct led_classdev cdev;
struct hid_report *brightness;
@@ -108,7 +123,7 @@ struct apple_sc {
struct apple_key_translation {
u16 from;
u16 to;
- u8 flags;
+ unsigned long flags;
};
static const struct apple_key_translation magic_keyboard_alu_fn_keys[] = {
@@ -152,21 +167,7 @@ static const struct apple_key_translation magic_keyboard_2015_fn_keys[] = {
{ }
};
-struct apple_backlight_config_report {
- u8 report_id;
- u8 version;
- u16 backlight_off, backlight_on_min, backlight_on_max;
-};
-
-struct apple_backlight_set_report {
- u8 report_id;
- u8 version;
- u16 backlight;
- u16 rate;
-};
-
-
-static const struct apple_key_translation apple2021_fn_keys[] = {
+static const struct apple_key_translation magic_keyboard_2021_and_2024_fn_keys[] = {
{ KEY_BACKSPACE, KEY_DELETE },
{ KEY_ENTER, KEY_INSERT },
{ KEY_F1, KEY_BRIGHTNESSDOWN, APPLE_FLAG_FKEY },
@@ -212,19 +213,19 @@ static const struct apple_key_translation macbookair_fn_keys[] = {
static const struct apple_key_translation macbookpro_no_esc_fn_keys[] = {
{ KEY_BACKSPACE, KEY_DELETE },
{ KEY_ENTER, KEY_INSERT },
- { KEY_GRAVE, KEY_ESC },
- { KEY_1, KEY_F1 },
- { KEY_2, KEY_F2 },
- { KEY_3, KEY_F3 },
- { KEY_4, KEY_F4 },
- { KEY_5, KEY_F5 },
- { KEY_6, KEY_F6 },
- { KEY_7, KEY_F7 },
- { KEY_8, KEY_F8 },
- { KEY_9, KEY_F9 },
- { KEY_0, KEY_F10 },
- { KEY_MINUS, KEY_F11 },
- { KEY_EQUAL, KEY_F12 },
+ { KEY_GRAVE, KEY_ESC, APPLE_FLAG_TB_FKEY },
+ { KEY_1, KEY_F1, APPLE_FLAG_TB_FKEY },
+ { KEY_2, KEY_F2, APPLE_FLAG_TB_FKEY },
+ { KEY_3, KEY_F3, APPLE_FLAG_TB_FKEY },
+ { KEY_4, KEY_F4, APPLE_FLAG_TB_FKEY },
+ { KEY_5, KEY_F5, APPLE_FLAG_TB_FKEY },
+ { KEY_6, KEY_F6, APPLE_FLAG_TB_FKEY },
+ { KEY_7, KEY_F7, APPLE_FLAG_TB_FKEY },
+ { KEY_8, KEY_F8, APPLE_FLAG_TB_FKEY },
+ { KEY_9, KEY_F9, APPLE_FLAG_TB_FKEY },
+ { KEY_0, KEY_F10, APPLE_FLAG_TB_FKEY },
+ { KEY_MINUS, KEY_F11, APPLE_FLAG_TB_FKEY },
+ { KEY_EQUAL, KEY_F12, APPLE_FLAG_TB_FKEY },
{ KEY_UP, KEY_PAGEUP },
{ KEY_DOWN, KEY_PAGEDOWN },
{ KEY_LEFT, KEY_HOME },
@@ -235,18 +236,18 @@ static const struct apple_key_translation macbookpro_no_esc_fn_keys[] = {
static const struct apple_key_translation macbookpro_dedicated_esc_fn_keys[] = {
{ KEY_BACKSPACE, KEY_DELETE },
{ KEY_ENTER, KEY_INSERT },
- { KEY_1, KEY_F1 },
- { KEY_2, KEY_F2 },
- { KEY_3, KEY_F3 },
- { KEY_4, KEY_F4 },
- { KEY_5, KEY_F5 },
- { KEY_6, KEY_F6 },
- { KEY_7, KEY_F7 },
- { KEY_8, KEY_F8 },
- { KEY_9, KEY_F9 },
- { KEY_0, KEY_F10 },
- { KEY_MINUS, KEY_F11 },
- { KEY_EQUAL, KEY_F12 },
+ { KEY_1, KEY_F1, APPLE_FLAG_TB_FKEY },
+ { KEY_2, KEY_F2, APPLE_FLAG_TB_FKEY },
+ { KEY_3, KEY_F3, APPLE_FLAG_TB_FKEY },
+ { KEY_4, KEY_F4, APPLE_FLAG_TB_FKEY },
+ { KEY_5, KEY_F5, APPLE_FLAG_TB_FKEY },
+ { KEY_6, KEY_F6, APPLE_FLAG_TB_FKEY },
+ { KEY_7, KEY_F7, APPLE_FLAG_TB_FKEY },
+ { KEY_8, KEY_F8, APPLE_FLAG_TB_FKEY },
+ { KEY_9, KEY_F9, APPLE_FLAG_TB_FKEY },
+ { KEY_0, KEY_F10, APPLE_FLAG_TB_FKEY },
+ { KEY_MINUS, KEY_F11, APPLE_FLAG_TB_FKEY },
+ { KEY_EQUAL, KEY_F12, APPLE_FLAG_TB_FKEY },
{ KEY_UP, KEY_PAGEUP },
{ KEY_DOWN, KEY_PAGEDOWN },
{ KEY_LEFT, KEY_HOME },
@@ -425,7 +426,12 @@ static int hidinput_apple_event(struct hid_device *hid, struct input_dev *input,
unsigned int real_fnmode;
if (fnmode == 3) {
- real_fnmode = (asc->quirks & APPLE_IS_NON_APPLE) ? 2 : 1;
+ if (asc->quirks & APPLE_DISABLE_FKEYS)
+ real_fnmode = 4;
+ else if (asc->quirks & APPLE_IS_NON_APPLE)
+ real_fnmode = 2;
+ else
+ real_fnmode = 1;
} else {
real_fnmode = fnmode;
}
@@ -466,42 +472,54 @@ static int hidinput_apple_event(struct hid_device *hid, struct input_dev *input,
asc->fn_on = !!value;
if (real_fnmode) {
- if (hid->product == USB_DEVICE_ID_APPLE_ALU_WIRELESS_ANSI ||
- hid->product == USB_DEVICE_ID_APPLE_ALU_WIRELESS_ISO ||
- hid->product == USB_DEVICE_ID_APPLE_ALU_WIRELESS_JIS ||
- hid->product == USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ANSI ||
- hid->product == USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ISO ||
- hid->product == USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_JIS ||
- hid->product == USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ANSI ||
- hid->product == USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ISO ||
- hid->product == USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_JIS)
+ switch (hid->product) {
+ case USB_DEVICE_ID_APPLE_ALU_WIRELESS_ANSI:
+ case USB_DEVICE_ID_APPLE_ALU_WIRELESS_ISO:
+ case USB_DEVICE_ID_APPLE_ALU_WIRELESS_JIS:
+ case USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ANSI:
+ case USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ISO:
+ case USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_JIS:
+ case USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ANSI:
+ case USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ISO:
+ case USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_JIS:
table = magic_keyboard_alu_fn_keys;
- else if (hid->product == USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_2015 ||
- hid->product == USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_NUMPAD_2015)
+ break;
+ case USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_2015:
+ case USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_NUMPAD_2015:
table = magic_keyboard_2015_fn_keys;
- else if (hid->product == USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_2021 ||
- hid->product == USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_2024 ||
- hid->product == USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_FINGERPRINT_2021 ||
- hid->product == USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_NUMPAD_2021)
- table = apple2021_fn_keys;
- else if (hid->product == USB_DEVICE_ID_APPLE_WELLSPRINGT2_J132 ||
- hid->product == USB_DEVICE_ID_APPLE_WELLSPRINGT2_J680 ||
- hid->product == USB_DEVICE_ID_APPLE_WELLSPRINGT2_J213)
- table = macbookpro_no_esc_fn_keys;
- else if (hid->product == USB_DEVICE_ID_APPLE_WELLSPRINGT2_J214K ||
- hid->product == USB_DEVICE_ID_APPLE_WELLSPRINGT2_J223 ||
- hid->product == USB_DEVICE_ID_APPLE_WELLSPRINGT2_J152F)
- table = macbookpro_dedicated_esc_fn_keys;
- else if (hid->product == USB_DEVICE_ID_APPLE_WELLSPRINGT2_J140K ||
- hid->product == USB_DEVICE_ID_APPLE_WELLSPRINGT2_J230K)
- table = apple_fn_keys;
- else if (hid->product >= USB_DEVICE_ID_APPLE_WELLSPRING4_ANSI &&
- hid->product <= USB_DEVICE_ID_APPLE_WELLSPRING4A_JIS)
- table = macbookair_fn_keys;
- else if (hid->product < 0x21d || hid->product >= 0x300)
- table = powerbook_fn_keys;
- else
+ break;
+ case USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_2021:
+ case USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_FINGERPRINT_2021:
+ case USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_NUMPAD_2021:
+ case USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_2024:
+ case USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_FINGERPRINT_2024:
+ case USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_NUMPAD_2024:
+ table = magic_keyboard_2021_and_2024_fn_keys;
+ break;
+ case USB_DEVICE_ID_APPLE_WELLSPRINGT2_J132:
+ case USB_DEVICE_ID_APPLE_WELLSPRINGT2_J213:
+ case USB_DEVICE_ID_APPLE_WELLSPRINGT2_J680:
+ case USB_DEVICE_ID_APPLE_WELLSPRINGT2_J680_ALT:
+ table = macbookpro_no_esc_fn_keys;
+ break;
+ case USB_DEVICE_ID_APPLE_WELLSPRINGT2_J152F:
+ case USB_DEVICE_ID_APPLE_WELLSPRINGT2_J214K:
+ case USB_DEVICE_ID_APPLE_WELLSPRINGT2_J223:
+ table = macbookpro_dedicated_esc_fn_keys;
+ break;
+ case USB_DEVICE_ID_APPLE_WELLSPRINGT2_J140K:
+ case USB_DEVICE_ID_APPLE_WELLSPRINGT2_J230K:
table = apple_fn_keys;
+ break;
+ default:
+ if (hid->product >= USB_DEVICE_ID_APPLE_WELLSPRING4_ANSI &&
+ hid->product <= USB_DEVICE_ID_APPLE_WELLSPRING4A_JIS)
+ table = macbookair_fn_keys;
+ else if (hid->product < 0x21d || hid->product >= 0x300)
+ table = powerbook_fn_keys;
+ else
+ table = apple_fn_keys;
+ }
trans = apple_find_translation(table, code);
@@ -524,8 +542,16 @@ static int hidinput_apple_event(struct hid_device *hid, struct input_dev *input,
do_translate = asc->fn_on;
break;
default:
- /* should never happen */
+ /* case 4 */
+ do_translate = false;
+ }
+ } else if (trans->flags & APPLE_FLAG_TB_FKEY) {
+ switch (real_fnmode) {
+ case 4:
do_translate = false;
+ break;
+ default:
+ do_translate = asc->fn_on;
}
} else {
do_translate = asc->fn_on;
@@ -619,7 +645,7 @@ static void apple_battery_timer_tick(struct timer_list *t)
if (apple_fetch_battery(hdev) == 0) {
mod_timer(&asc->battery_timer,
- jiffies + msecs_to_jiffies(APPLE_BATTERY_TIMEOUT_MS));
+ jiffies + secs_to_jiffies(APPLE_BATTERY_TIMEOUT_SEC));
}
}
@@ -682,7 +708,7 @@ static void apple_setup_input(struct input_dev *input)
apple_setup_key_translation(input, apple_iso_keyboard);
apple_setup_key_translation(input, magic_keyboard_alu_fn_keys);
apple_setup_key_translation(input, magic_keyboard_2015_fn_keys);
- apple_setup_key_translation(input, apple2021_fn_keys);
+ apple_setup_key_translation(input, magic_keyboard_2021_and_2024_fn_keys);
apple_setup_key_translation(input, macbookpro_no_esc_fn_keys);
apple_setup_key_translation(input, macbookpro_dedicated_esc_fn_keys);
}
@@ -890,7 +916,8 @@ static int apple_magic_backlight_init(struct hid_device *hdev)
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)
+ if (!backlight->brightness || backlight->brightness->maxfield < 2 ||
+ !backlight->power || backlight->power->maxfield < 2)
return -ENODEV;
backlight->cdev.name = ":white:" LED_FUNCTION_KBD_BACKLIGHT;
@@ -933,10 +960,12 @@ static int apple_probe(struct hid_device *hdev,
return ret;
}
- timer_setup(&asc->battery_timer, apple_battery_timer_tick, 0);
- mod_timer(&asc->battery_timer,
- jiffies + msecs_to_jiffies(APPLE_BATTERY_TIMEOUT_MS));
- apple_fetch_battery(hdev);
+ if (quirks & APPLE_RDESC_BATTERY) {
+ timer_setup(&asc->battery_timer, apple_battery_timer_tick, 0);
+ mod_timer(&asc->battery_timer,
+ jiffies + secs_to_jiffies(APPLE_BATTERY_TIMEOUT_SEC));
+ apple_fetch_battery(hdev);
+ }
if (quirks & APPLE_BACKLIGHT_CTL)
apple_backlight_init(hdev);
@@ -950,7 +979,9 @@ static int apple_probe(struct hid_device *hdev,
return 0;
out_err:
- timer_delete_sync(&asc->battery_timer);
+ if (quirks & APPLE_RDESC_BATTERY)
+ timer_delete_sync(&asc->battery_timer);
+
hid_hw_stop(hdev);
return ret;
}
@@ -959,7 +990,8 @@ static void apple_remove(struct hid_device *hdev)
{
struct apple_sc *asc = hid_get_drvdata(hdev);
- timer_delete_sync(&asc->battery_timer);
+ if (asc->quirks & APPLE_RDESC_BATTERY)
+ timer_delete_sync(&asc->battery_timer);
hid_hw_stop(hdev);
}
@@ -1129,19 +1161,25 @@ static const struct hid_device_id apple_devices[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRINGT2_J140K),
.driver_data = APPLE_HAS_FN | APPLE_BACKLIGHT_CTL | APPLE_ISO_TILDE_QUIRK },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRINGT2_J132),
- .driver_data = APPLE_HAS_FN | APPLE_BACKLIGHT_CTL | APPLE_ISO_TILDE_QUIRK },
+ .driver_data = APPLE_HAS_FN | APPLE_BACKLIGHT_CTL | APPLE_ISO_TILDE_QUIRK |
+ APPLE_DISABLE_FKEYS },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRINGT2_J680),
- .driver_data = APPLE_HAS_FN | APPLE_BACKLIGHT_CTL | APPLE_ISO_TILDE_QUIRK },
+ .driver_data = APPLE_HAS_FN | APPLE_BACKLIGHT_CTL | APPLE_ISO_TILDE_QUIRK |
+ APPLE_DISABLE_FKEYS },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRINGT2_J680_ALT),
+ .driver_data = APPLE_HAS_FN | APPLE_BACKLIGHT_CTL | APPLE_ISO_TILDE_QUIRK |
+ APPLE_DISABLE_FKEYS },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRINGT2_J213),
- .driver_data = APPLE_HAS_FN | APPLE_BACKLIGHT_CTL | APPLE_ISO_TILDE_QUIRK },
+ .driver_data = APPLE_HAS_FN | APPLE_BACKLIGHT_CTL | APPLE_ISO_TILDE_QUIRK |
+ APPLE_DISABLE_FKEYS },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRINGT2_J214K),
- .driver_data = APPLE_HAS_FN | APPLE_ISO_TILDE_QUIRK },
+ .driver_data = APPLE_HAS_FN | APPLE_ISO_TILDE_QUIRK | APPLE_DISABLE_FKEYS },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRINGT2_J223),
- .driver_data = APPLE_HAS_FN | APPLE_ISO_TILDE_QUIRK },
+ .driver_data = APPLE_HAS_FN | APPLE_ISO_TILDE_QUIRK | APPLE_DISABLE_FKEYS },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRINGT2_J230K),
.driver_data = APPLE_HAS_FN | APPLE_ISO_TILDE_QUIRK },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRINGT2_J152F),
- .driver_data = APPLE_HAS_FN | APPLE_ISO_TILDE_QUIRK },
+ .driver_data = APPLE_HAS_FN | APPLE_ISO_TILDE_QUIRK | APPLE_DISABLE_FKEYS },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ANSI),
.driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ISO),
@@ -1157,10 +1195,6 @@ 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_2021),
.driver_data = APPLE_HAS_FN | APPLE_ISO_TILDE_QUIRK },
- { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_2024),
- .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_2024),
- .driver_data = APPLE_HAS_FN | APPLE_ISO_TILDE_QUIRK },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_FINGERPRINT_2021),
.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_FINGERPRINT_2021),
@@ -1169,6 +1203,18 @@ 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_MAGIC_KEYBOARD_2024),
+ .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_2024),
+ .driver_data = APPLE_HAS_FN | APPLE_ISO_TILDE_QUIRK },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_FINGERPRINT_2024),
+ .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_FINGERPRINT_2024),
+ .driver_data = APPLE_HAS_FN | APPLE_ISO_TILDE_QUIRK },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_NUMPAD_2024),
+ .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_2024),
+ .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-core.c b/drivers/hid/hid-core.c
index b31b8a2fd540..5419a6c10907 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -66,8 +66,12 @@ static s32 snto32(__u32 value, unsigned int n)
static u32 s32ton(__s32 value, unsigned int n)
{
- s32 a = value >> (n - 1);
+ s32 a;
+ if (!value || !n)
+ return 0;
+
+ a = value >> (n - 1);
if (a && a != -1)
return value < 0 ? 1 << (n - 1) : (1 << (n - 1)) - 1;
return value & ((1 << n) - 1);
@@ -659,9 +663,9 @@ static int hid_parser_main(struct hid_parser *parser, struct hid_item *item)
default:
if (item->tag >= HID_MAIN_ITEM_TAG_RESERVED_MIN &&
item->tag <= HID_MAIN_ITEM_TAG_RESERVED_MAX)
- hid_warn(parser->device, "reserved main item tag 0x%x\n", item->tag);
+ hid_warn_ratelimited(parser->device, "reserved main item tag 0x%x\n", item->tag);
else
- hid_warn(parser->device, "unknown main item tag 0x%x\n", item->tag);
+ hid_warn_ratelimited(parser->device, "unknown main item tag 0x%x\n", item->tag);
ret = 0;
}
@@ -2303,6 +2307,9 @@ int hid_connect(struct hid_device *hdev, unsigned int connect_mask)
case BUS_I2C:
bus = "I2C";
break;
+ case BUS_SDW:
+ bus = "SOUNDWIRE";
+ break;
case BUS_VIRTUAL:
bus = "VIRTUAL";
break;
@@ -2806,7 +2813,7 @@ static ssize_t modalias_show(struct device *dev, struct device_attribute *a,
{
struct hid_device *hdev = container_of(dev, struct hid_device, dev);
- return scnprintf(buf, PAGE_SIZE, "hid:b%04Xg%04Xv%08Xp%08X\n",
+ return sysfs_emit(buf, "hid:b%04Xg%04Xv%08Xp%08X\n",
hdev->bus, hdev->group, hdev->vendor, hdev->product);
}
static DEVICE_ATTR_RO(modalias);
@@ -2821,7 +2828,7 @@ static const struct bin_attribute *hid_dev_bin_attrs[] = {
};
static const struct attribute_group hid_dev_group = {
.attrs = hid_dev_attrs,
- .bin_attrs_new = hid_dev_bin_attrs,
+ .bin_attrs = hid_dev_bin_attrs,
};
__ATTRIBUTE_GROUPS(hid_dev);
diff --git a/drivers/hid/hid-debug.c b/drivers/hid/hid-debug.c
index 4424c0512bae..e86bda0dab9b 100644
--- a/drivers/hid/hid-debug.c
+++ b/drivers/hid/hid-debug.c
@@ -3726,7 +3726,7 @@ static ssize_t hid_debug_events_read(struct file *file, char __user *buffer,
*/
if (!list->hdev || !list->hdev->debug) {
ret = -EIO;
- set_current_state(TASK_RUNNING);
+ __set_current_state(TASK_RUNNING);
goto out;
}
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
index 33cc5820f2be..5a1096283855 100644
--- a/drivers/hid/hid-ids.h
+++ b/drivers/hid/hid-ids.h
@@ -167,20 +167,27 @@
#define USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_JIS 0x0257
#define USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_2015 0x0267
#define USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_NUMPAD_2015 0x026c
+#define USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_2021 0x029c
+#define USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_FINGERPRINT_2021 0x029a
+#define USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_NUMPAD_2021 0x029f
+#define USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_2024 0x0320
+#define USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_FINGERPRINT_2024 0x0321
+#define USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_NUMPAD_2024 0x0322
#define USB_DEVICE_ID_APPLE_WELLSPRING8_ANSI 0x0290
#define USB_DEVICE_ID_APPLE_WELLSPRING8_ISO 0x0291
#define USB_DEVICE_ID_APPLE_WELLSPRING8_JIS 0x0292
#define USB_DEVICE_ID_APPLE_WELLSPRING9_ANSI 0x0272
#define USB_DEVICE_ID_APPLE_WELLSPRING9_ISO 0x0273
#define USB_DEVICE_ID_APPLE_WELLSPRING9_JIS 0x0274
-#define USB_DEVICE_ID_APPLE_WELLSPRINGT2_J140K 0x027a
-#define USB_DEVICE_ID_APPLE_WELLSPRINGT2_J132 0x027b
-#define USB_DEVICE_ID_APPLE_WELLSPRINGT2_J680 0x027c
-#define USB_DEVICE_ID_APPLE_WELLSPRINGT2_J213 0x027d
-#define USB_DEVICE_ID_APPLE_WELLSPRINGT2_J214K 0x027e
-#define USB_DEVICE_ID_APPLE_WELLSPRINGT2_J223 0x027f
-#define USB_DEVICE_ID_APPLE_WELLSPRINGT2_J230K 0x0280
-#define USB_DEVICE_ID_APPLE_WELLSPRINGT2_J152F 0x0340
+#define USB_DEVICE_ID_APPLE_WELLSPRINGT2_J140K 0x027a
+#define USB_DEVICE_ID_APPLE_WELLSPRINGT2_J132 0x027b
+#define USB_DEVICE_ID_APPLE_WELLSPRINGT2_J680 0x027c
+#define USB_DEVICE_ID_APPLE_WELLSPRINGT2_J680_ALT 0x0278
+#define USB_DEVICE_ID_APPLE_WELLSPRINGT2_J213 0x027d
+#define USB_DEVICE_ID_APPLE_WELLSPRINGT2_J214K 0x027e
+#define USB_DEVICE_ID_APPLE_WELLSPRINGT2_J223 0x027f
+#define USB_DEVICE_ID_APPLE_WELLSPRINGT2_J230K 0x0280
+#define USB_DEVICE_ID_APPLE_WELLSPRINGT2_J152F 0x0340
#define USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY 0x030a
#define USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY 0x030b
#define USB_DEVICE_ID_APPLE_IRCONTROL 0x8240
@@ -188,10 +195,6 @@
#define USB_DEVICE_ID_APPLE_IRCONTROL3 0x8241
#define USB_DEVICE_ID_APPLE_IRCONTROL4 0x8242
#define USB_DEVICE_ID_APPLE_IRCONTROL5 0x8243
-#define USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_2021 0x029c
-#define USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_2024 0x0320
-#define USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_FINGERPRINT_2021 0x029a
-#define USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_NUMPAD_2021 0x029f
#define USB_DEVICE_ID_APPLE_TOUCHBAR_BACKLIGHT 0x8102
#define USB_DEVICE_ID_APPLE_TOUCHBAR_DISPLAY 0x8302
@@ -846,7 +849,7 @@
#define USB_DEVICE_ID_PXN_V12 0x1212
#define USB_DEVICE_ID_PXN_V12_LITE 0x1112
#define USB_DEVICE_ID_PXN_V12_LITE_2 0x1211
-#define USB_DEVICE_LITE_STAR_GT987_FF 0x2141
+#define USB_DEVICE_ID_LITE_STAR_GT987 0x2141
#define USB_VENDOR_ID_LOGITECH 0x046d
#define USB_DEVICE_ID_LOGITECH_Z_10_SPK 0x0a07
@@ -1406,6 +1409,7 @@
#define USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO_PRO_S 0x0909
#define USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO_PRO_SW 0x0933
#define USB_DEVICE_ID_UGEE_XPPEN_TABLET_STAR06 0x0078
+#define USB_DEVICE_ID_UGEE_XPPEN_TABLET_22R_PRO 0x091b
#define USB_DEVICE_ID_UGEE_TABLET_G5 0x0074
#define USB_DEVICE_ID_UGEE_TABLET_EX07S 0x0071
#define USB_DEVICE_ID_UGEE_TABLET_RAINBOW_CV720 0x0055
diff --git a/drivers/hid/hid-lg4ff.c b/drivers/hid/hid-lg4ff.c
index 445623dd1bd6..32b711723f2a 100644
--- a/drivers/hid/hid-lg4ff.c
+++ b/drivers/hid/hid-lg4ff.c
@@ -956,7 +956,7 @@ static ssize_t lg4ff_combine_show(struct device *dev, struct device_attribute *a
return 0;
}
- count = scnprintf(buf, PAGE_SIZE, "%u\n", entry->wdata.combine);
+ count = sysfs_emit(buf, "%u\n", entry->wdata.combine);
return count;
}
@@ -1009,7 +1009,7 @@ static ssize_t lg4ff_range_show(struct device *dev, struct device_attribute *att
return 0;
}
- count = scnprintf(buf, PAGE_SIZE, "%u\n", entry->wdata.range);
+ count = sysfs_emit(buf, "%u\n", entry->wdata.range);
return count;
}
@@ -1073,7 +1073,7 @@ static ssize_t lg4ff_real_id_show(struct device *dev, struct device_attribute *a
return 0;
}
- count = scnprintf(buf, PAGE_SIZE, "%s: %s\n", entry->wdata.real_tag, entry->wdata.real_name);
+ count = sysfs_emit(buf, "%s: %s\n", entry->wdata.real_tag, entry->wdata.real_name);
return count;
}
diff --git a/drivers/hid/hid-magicmouse.c b/drivers/hid/hid-magicmouse.c
index 36f034ac605d..7d4a25c6de0e 100644
--- a/drivers/hid/hid-magicmouse.c
+++ b/drivers/hid/hid-magicmouse.c
@@ -60,7 +60,7 @@ MODULE_PARM_DESC(report_undeciphered, "Report undeciphered multi-touch state fie
#define MOUSE_REPORT_ID 0x29
#define MOUSE2_REPORT_ID 0x12
#define DOUBLE_REPORT_ID 0xf7
-#define USB_BATTERY_TIMEOUT_MS 60000
+#define USB_BATTERY_TIMEOUT_SEC 60
/* These definitions are not precise, but they're close enough. (Bits
* 0x03 seem to indicate the aspect ratio of the touch, bits 0x70 seem
@@ -791,17 +791,31 @@ static void magicmouse_enable_mt_work(struct work_struct *work)
hid_err(msc->hdev, "unable to request touch data (%d)\n", ret);
}
+static bool is_usb_magicmouse2(__u32 vendor, __u32 product)
+{
+ if (vendor != USB_VENDOR_ID_APPLE)
+ return false;
+ return product == USB_DEVICE_ID_APPLE_MAGICMOUSE2 ||
+ product == USB_DEVICE_ID_APPLE_MAGICMOUSE2_USBC;
+}
+
+static bool is_usb_magictrackpad2(__u32 vendor, __u32 product)
+{
+ if (vendor != USB_VENDOR_ID_APPLE)
+ return false;
+ return product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2 ||
+ product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2_USBC;
+}
+
static int magicmouse_fetch_battery(struct hid_device *hdev)
{
#ifdef CONFIG_HID_BATTERY_STRENGTH
struct hid_report_enum *report_enum;
struct hid_report *report;
- if (!hdev->battery || hdev->vendor != USB_VENDOR_ID_APPLE ||
- (hdev->product != USB_DEVICE_ID_APPLE_MAGICMOUSE2 &&
- hdev->product != USB_DEVICE_ID_APPLE_MAGICMOUSE2_USBC &&
- hdev->product != USB_DEVICE_ID_APPLE_MAGICTRACKPAD2 &&
- hdev->product != USB_DEVICE_ID_APPLE_MAGICTRACKPAD2_USBC))
+ if (!hdev->battery ||
+ (!is_usb_magicmouse2(hdev->vendor, hdev->product) &&
+ !is_usb_magictrackpad2(hdev->vendor, hdev->product)))
return -1;
report_enum = &hdev->report_enum[hdev->battery_report_type];
@@ -827,7 +841,7 @@ static void magicmouse_battery_timer_tick(struct timer_list *t)
if (magicmouse_fetch_battery(hdev) == 0) {
mod_timer(&msc->battery_timer,
- jiffies + msecs_to_jiffies(USB_BATTERY_TIMEOUT_MS));
+ jiffies + secs_to_jiffies(USB_BATTERY_TIMEOUT_SEC));
}
}
@@ -863,17 +877,17 @@ static int magicmouse_probe(struct hid_device *hdev,
return ret;
}
- timer_setup(&msc->battery_timer, magicmouse_battery_timer_tick, 0);
- mod_timer(&msc->battery_timer,
- jiffies + msecs_to_jiffies(USB_BATTERY_TIMEOUT_MS));
- magicmouse_fetch_battery(hdev);
-
- if (id->vendor == USB_VENDOR_ID_APPLE &&
- (id->product == USB_DEVICE_ID_APPLE_MAGICMOUSE2 ||
- id->product == USB_DEVICE_ID_APPLE_MAGICMOUSE2_USBC ||
- ((id->product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2 ||
- id->product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2_USBC) &&
- hdev->type != HID_TYPE_USBMOUSE)))
+ if (is_usb_magicmouse2(id->vendor, id->product) ||
+ is_usb_magictrackpad2(id->vendor, id->product)) {
+ timer_setup(&msc->battery_timer, magicmouse_battery_timer_tick, 0);
+ mod_timer(&msc->battery_timer,
+ jiffies + secs_to_jiffies(USB_BATTERY_TIMEOUT_SEC));
+ magicmouse_fetch_battery(hdev);
+ }
+
+ if (is_usb_magicmouse2(id->vendor, id->product) ||
+ (is_usb_magictrackpad2(id->vendor, id->product) &&
+ hdev->type != HID_TYPE_USBMOUSE))
return 0;
if (!msc->input) {
@@ -936,7 +950,10 @@ static int magicmouse_probe(struct hid_device *hdev,
return 0;
err_stop_hw:
- timer_delete_sync(&msc->battery_timer);
+ if (is_usb_magicmouse2(id->vendor, id->product) ||
+ is_usb_magictrackpad2(id->vendor, id->product))
+ timer_delete_sync(&msc->battery_timer);
+
hid_hw_stop(hdev);
return ret;
}
@@ -947,7 +964,9 @@ static void magicmouse_remove(struct hid_device *hdev)
if (msc) {
cancel_delayed_work_sync(&msc->work);
- timer_delete_sync(&msc->battery_timer);
+ if (is_usb_magicmouse2(hdev->vendor, hdev->product) ||
+ is_usb_magictrackpad2(hdev->vendor, hdev->product))
+ timer_delete_sync(&msc->battery_timer);
}
hid_hw_stop(hdev);
@@ -964,11 +983,8 @@ static const __u8 *magicmouse_report_fixup(struct hid_device *hdev, __u8 *rdesc,
* 0x05, 0x01, // Usage Page (Generic Desktop) 0
* 0x09, 0x02, // Usage (Mouse) 2
*/
- if (hdev->vendor == USB_VENDOR_ID_APPLE &&
- (hdev->product == USB_DEVICE_ID_APPLE_MAGICMOUSE2 ||
- hdev->product == USB_DEVICE_ID_APPLE_MAGICMOUSE2_USBC ||
- hdev->product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2 ||
- hdev->product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2_USBC) &&
+ if ((is_usb_magicmouse2(hdev->vendor, hdev->product) ||
+ is_usb_magictrackpad2(hdev->vendor, hdev->product)) &&
*rsize == 83 && rdesc[46] == 0x84 && rdesc[58] == 0x85) {
hid_info(hdev,
"fixing up magicmouse battery report descriptor\n");
diff --git a/drivers/hid/hid-mcp2221.c b/drivers/hid/hid-mcp2221.c
index 6c0ac14f11a6..fcfe9370a887 100644
--- a/drivers/hid/hid-mcp2221.c
+++ b/drivers/hid/hid-mcp2221.c
@@ -18,6 +18,7 @@
#include <linux/i2c.h>
#include <linux/gpio/driver.h>
#include <linux/iio/iio.h>
+#include <linux/minmax.h>
#include "hid-ids.h"
/* Commands codes in a raw output report */
@@ -55,6 +56,27 @@ enum {
MCP2221_ALT_F_NOT_GPIOD = 0xEF,
};
+/* MCP SRAM read offsets cmd: MCP2221_GET_SRAM_SETTINGS */
+enum {
+ MCP2221_SRAM_RD_GP0 = 22,
+ MCP2221_SRAM_RD_GP1 = 23,
+ MCP2221_SRAM_RD_GP2 = 24,
+ MCP2221_SRAM_RD_GP3 = 25,
+};
+
+/* MCP SRAM write offsets cmd: MCP2221_SET_SRAM_SETTINGS */
+enum {
+ MCP2221_SRAM_WR_GP_ENA_ALTER = 7,
+ MCP2221_SRAM_WR_GP0 = 8,
+ MCP2221_SRAM_WR_GP1 = 9,
+ MCP2221_SRAM_WR_GP2 = 10,
+ MCP2221_SRAM_WR_GP3 = 11,
+};
+
+#define MCP2221_SRAM_GP_DESIGN_MASK 0x07
+#define MCP2221_SRAM_GP_DIRECTION_MASK 0x08
+#define MCP2221_SRAM_GP_VALUE_MASK 0x10
+
/* MCP GPIO direction encoding */
enum {
MCP2221_DIR_OUT = 0x00,
@@ -241,10 +263,7 @@ static int mcp_i2c_write(struct mcp2221 *mcp,
idx = 0;
sent = 0;
- if (msg->len < 60)
- len = msg->len;
- else
- len = 60;
+ len = min(msg->len, 60);
do {
mcp->txbuf[0] = type;
@@ -271,10 +290,7 @@ static int mcp_i2c_write(struct mcp2221 *mcp,
break;
idx = idx + len;
- if ((msg->len - sent) < 60)
- len = msg->len - sent;
- else
- len = 60;
+ len = min(msg->len - sent, 60);
/*
* Testing shows delay is needed between successive writes
@@ -607,6 +623,80 @@ static const struct i2c_algorithm mcp_i2c_algo = {
};
#if IS_REACHABLE(CONFIG_GPIOLIB)
+static int mcp_gpio_read_sram(struct mcp2221 *mcp)
+{
+ int ret;
+
+ memset(mcp->txbuf, 0, 64);
+ mcp->txbuf[0] = MCP2221_GET_SRAM_SETTINGS;
+
+ mutex_lock(&mcp->lock);
+ ret = mcp_send_data_req_status(mcp, mcp->txbuf, 64);
+ mutex_unlock(&mcp->lock);
+
+ return ret;
+}
+
+/*
+ * If CONFIG_IIO is not enabled, check for the gpio pins
+ * if they are in gpio mode. For the ones which are not
+ * in gpio mode, set them into gpio mode.
+ */
+static int mcp2221_check_gpio_pinfunc(struct mcp2221 *mcp)
+{
+ int i;
+ int needgpiofix = 0;
+ int ret;
+
+ if (IS_ENABLED(CONFIG_IIO))
+ return 0;
+
+ ret = mcp_gpio_read_sram(mcp);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < MCP_NGPIO; i++) {
+ if ((mcp->mode[i] & MCP2221_SRAM_GP_DESIGN_MASK) != 0x0) {
+ dev_warn(&mcp->hdev->dev,
+ "GPIO %d not in gpio mode\n", i);
+ needgpiofix = 1;
+ }
+ }
+
+ if (!needgpiofix)
+ return 0;
+
+ /*
+ * Set all bytes to 0, so Bit 7 is not set. The chip
+ * only changes content of a register when bit 7 is set.
+ */
+ memset(mcp->txbuf, 0, 64);
+ mcp->txbuf[0] = MCP2221_SET_SRAM_SETTINGS;
+
+ /*
+ * Set bit 7 in MCP2221_SRAM_WR_GP_ENA_ALTER to enable
+ * loading of a new set of gpio settings to GP SRAM
+ */
+ mcp->txbuf[MCP2221_SRAM_WR_GP_ENA_ALTER] = 0x80;
+ for (i = 0; i < MCP_NGPIO; i++) {
+ if ((mcp->mode[i] & MCP2221_SRAM_GP_DESIGN_MASK) == 0x0) {
+ /* write current GPIO mode */
+ mcp->txbuf[MCP2221_SRAM_WR_GP0 + i] = mcp->mode[i];
+ } else {
+ /* pin is not in gpio mode, set it to input mode */
+ mcp->txbuf[MCP2221_SRAM_WR_GP0 + i] = 0x08;
+ dev_warn(&mcp->hdev->dev,
+ "Set GPIO mode for gpio pin %d!\n", i);
+ }
+ }
+
+ mutex_lock(&mcp->lock);
+ ret = mcp_send_data_req_status(mcp, mcp->txbuf, 64);
+ mutex_unlock(&mcp->lock);
+
+ return ret;
+}
+
static int mcp_gpio_get(struct gpio_chip *gc,
unsigned int offset)
{
@@ -1218,6 +1308,8 @@ static int mcp2221_probe(struct hid_device *hdev,
ret = devm_gpiochip_add_data(&hdev->dev, mcp->gc, mcp);
if (ret)
return ret;
+
+ mcp2221_check_gpio_pinfunc(mcp);
#endif
#if IS_REACHABLE(CONFIG_IIO)
diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c
index a1c54ffe02b4..294516a8f541 100644
--- a/drivers/hid/hid-multitouch.c
+++ b/drivers/hid/hid-multitouch.c
@@ -73,6 +73,7 @@ MODULE_LICENSE("GPL");
#define MT_QUIRK_FORCE_MULTI_INPUT BIT(20)
#define MT_QUIRK_DISABLE_WAKEUP BIT(21)
#define MT_QUIRK_ORIENTATION_INVERT BIT(22)
+#define MT_QUIRK_APPLE_TOUCHBAR BIT(23)
#define MT_INPUTMODE_TOUCHSCREEN 0x02
#define MT_INPUTMODE_TOUCHPAD 0x03
@@ -220,6 +221,7 @@ static void mt_post_parse(struct mt_device *td, struct mt_application *app);
#define MT_CLS_GOOGLE 0x0111
#define MT_CLS_RAZER_BLADE_STEALTH 0x0112
#define MT_CLS_SMART_TECH 0x0113
+#define MT_CLS_APPLE_TOUCHBAR 0x0114
#define MT_CLS_SIS 0x0457
#define MT_DEFAULT_MAXCONTACT 10
@@ -405,6 +407,12 @@ static const struct mt_class mt_classes[] = {
MT_QUIRK_CONTACT_CNT_ACCURATE |
MT_QUIRK_SEPARATE_APP_REPORT,
},
+ { .name = MT_CLS_APPLE_TOUCHBAR,
+ .quirks = MT_QUIRK_HOVERING |
+ MT_QUIRK_SLOT_IS_CONTACTID_MINUS_ONE |
+ MT_QUIRK_APPLE_TOUCHBAR,
+ .maxcontacts = 11,
+ },
{ .name = MT_CLS_SIS,
.quirks = MT_QUIRK_NOT_SEEN_MEANS_UP |
MT_QUIRK_ALWAYS_VALID |
@@ -625,6 +633,7 @@ static struct mt_application *mt_find_application(struct mt_device *td,
static struct mt_report_data *mt_allocate_report_data(struct mt_device *td,
struct hid_report *report)
{
+ struct mt_class *cls = &td->mtclass;
struct mt_report_data *rdata;
struct hid_field *field;
int r, n;
@@ -649,7 +658,11 @@ 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 ||
+ (cls->quirks & MT_QUIRK_APPLE_TOUCHBAR &&
+ hid == HID_DG_TRANSDUCER_INDEX)) {
rdata->is_mt_collection = true;
break;
}
@@ -821,12 +834,31 @@ 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.
+ * One special case here is of the Apple Touch Bars.
+ * In these devices, the tip state is contained in
+ * fields with the HID_DG_TOUCH usage.
+ * Let's just ignore this field for other devices.
+ */
+ if (!(cls->quirks & MT_QUIRK_APPLE_TOUCHBAR))
+ return -1;
+ fallthrough;
case HID_DG_TIPSWITCH:
if (field->application != HID_GD_SYSTEM_MULTIAXIS)
input_set_capability(hi->input,
EV_KEY, BTN_TOUCH);
MT_STORE_FIELD(tip_state);
return 1;
+ case HID_DG_TRANSDUCER_INDEX:
+ /*
+ * Contact ID in case of Apple Touch Bars is contained
+ * in fields with HID_DG_TRANSDUCER_INDEX usage.
+ */
+ if (!(cls->quirks & MT_QUIRK_APPLE_TOUCHBAR))
+ return 0;
+ fallthrough;
case HID_DG_CONTACTID:
MT_STORE_FIELD(contactid);
app->touches_by_report++;
@@ -883,10 +915,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;
@@ -1314,6 +1342,13 @@ static int mt_touch_input_configured(struct hid_device *hdev,
struct input_dev *input = hi->input;
int ret;
+ /*
+ * HID_DG_CONTACTMAX field is not present on Apple Touch Bars,
+ * but the maximum contact count is greater than the default.
+ */
+ if (cls->quirks & MT_QUIRK_APPLE_TOUCHBAR && cls->maxcontacts)
+ td->maxcontacts = cls->maxcontacts;
+
if (!td->maxcontacts)
td->maxcontacts = MT_DEFAULT_MAXCONTACT;
@@ -1321,6 +1356,13 @@ static int mt_touch_input_configured(struct hid_device *hdev,
if (td->serial_maybe)
mt_post_parse_default_settings(td, app);
+ /*
+ * The application for Apple Touch Bars is HID_DG_TOUCHPAD,
+ * but these devices are direct.
+ */
+ if (cls->quirks & MT_QUIRK_APPLE_TOUCHBAR)
+ app->mt_flags |= INPUT_MT_DIRECT;
+
if (cls->is_indirect)
app->mt_flags |= INPUT_MT_POINTER;
@@ -1823,6 +1865,11 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
if (ret != 0)
return ret;
+ if (mtclass->name == MT_CLS_APPLE_TOUCHBAR &&
+ !hid_find_field(hdev, HID_INPUT_REPORT,
+ HID_DG_TOUCHPAD, HID_DG_TRANSDUCER_INDEX))
+ return -ENODEV;
+
if (mtclass->quirks & MT_QUIRK_FIX_CONST_CONTACT_ID)
mt_fix_const_fields(hdev, HID_DG_CONTACTID);
@@ -2320,6 +2367,11 @@ static const struct hid_device_id mt_devices[] = {
MT_USB_DEVICE(USB_VENDOR_ID_XIROKU,
USB_DEVICE_ID_XIROKU_CSR2) },
+ /* Apple Touch Bar */
+ { .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 9bf9ce8dc803..ff11f1ad344d 100644
--- a/drivers/hid/hid-quirks.c
+++ b/drivers/hid/hid-quirks.c
@@ -314,6 +314,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRINGT2_J140K) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRINGT2_J132) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRINGT2_J680) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRINGT2_J680_ALT) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRINGT2_J213) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRINGT2_J214K) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRINGT2_J223) },
@@ -973,14 +974,6 @@ static const struct hid_device_id hid_mouse_ignore_list[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING9_ANSI) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING9_ISO) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING9_JIS) },
- { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRINGT2_J140K) },
- { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRINGT2_J132) },
- { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRINGT2_J680) },
- { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRINGT2_J213) },
- { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRINGT2_J214K) },
- { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRINGT2_J223) },
- { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRINGT2_J230K) },
- { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRINGT2_J152F) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY) },
{ }
diff --git a/drivers/hid/hid-roccat-arvo.c b/drivers/hid/hid-roccat-arvo.c
index 3048297569c5..7b09adfa44a1 100644
--- a/drivers/hid/hid-roccat-arvo.c
+++ b/drivers/hid/hid-roccat-arvo.c
@@ -258,7 +258,7 @@ static const struct bin_attribute *const arvo_bin_attributes[] = {
static const struct attribute_group arvo_group = {
.attrs = arvo_attrs,
- .bin_attrs_new = arvo_bin_attributes,
+ .bin_attrs = arvo_bin_attributes,
};
static const struct attribute_group *arvo_groups[] = {
diff --git a/drivers/hid/hid-roccat-common.h b/drivers/hid/hid-roccat-common.h
index 0f9a2db04df9..e931d0b48efe 100644
--- a/drivers/hid/hid-roccat-common.h
+++ b/drivers/hid/hid-roccat-common.h
@@ -71,8 +71,8 @@ ROCCAT_COMMON2_SYSFS_RW(thingy, COMMAND, SIZE); \
static const struct bin_attribute bin_attr_ ## thingy = { \
.attr = { .name = #thingy, .mode = 0660 }, \
.size = SIZE, \
- .read_new = roccat_common2_sysfs_read_ ## thingy, \
- .write_new = roccat_common2_sysfs_write_ ## thingy \
+ .read = roccat_common2_sysfs_read_ ## thingy, \
+ .write = roccat_common2_sysfs_write_ ## thingy \
}
#define ROCCAT_COMMON2_BIN_ATTRIBUTE_R(thingy, COMMAND, SIZE) \
@@ -80,7 +80,7 @@ ROCCAT_COMMON2_SYSFS_R(thingy, COMMAND, SIZE); \
static const struct bin_attribute bin_attr_ ## thingy = { \
.attr = { .name = #thingy, .mode = 0440 }, \
.size = SIZE, \
- .read_new = roccat_common2_sysfs_read_ ## thingy, \
+ .read = roccat_common2_sysfs_read_ ## thingy, \
}
#define ROCCAT_COMMON2_BIN_ATTRIBUTE_W(thingy, COMMAND, SIZE) \
@@ -88,7 +88,7 @@ ROCCAT_COMMON2_SYSFS_W(thingy, COMMAND, SIZE); \
static const struct bin_attribute bin_attr_ ## thingy = { \
.attr = { .name = #thingy, .mode = 0220 }, \
.size = SIZE, \
- .write_new = roccat_common2_sysfs_write_ ## thingy \
+ .write = roccat_common2_sysfs_write_ ## thingy \
}
#endif
diff --git a/drivers/hid/hid-roccat-isku.c b/drivers/hid/hid-roccat-isku.c
index 65a84bfcc2f8..339378771ed5 100644
--- a/drivers/hid/hid-roccat-isku.c
+++ b/drivers/hid/hid-roccat-isku.c
@@ -181,8 +181,8 @@ ISKU_SYSFS_RW(thingy, THINGY); \
static const struct bin_attribute bin_attr_##thingy = { \
.attr = { .name = #thingy, .mode = 0660 }, \
.size = ISKU_SIZE_ ## THINGY, \
- .read_new = isku_sysfs_read_ ## thingy, \
- .write_new = isku_sysfs_write_ ## thingy \
+ .read = isku_sysfs_read_ ## thingy, \
+ .write = isku_sysfs_write_ ## thingy \
}
#define ISKU_BIN_ATTR_R(thingy, THINGY) \
@@ -190,7 +190,7 @@ ISKU_SYSFS_R(thingy, THINGY); \
static const struct bin_attribute bin_attr_##thingy = { \
.attr = { .name = #thingy, .mode = 0440 }, \
.size = ISKU_SIZE_ ## THINGY, \
- .read_new = isku_sysfs_read_ ## thingy, \
+ .read = isku_sysfs_read_ ## thingy, \
}
#define ISKU_BIN_ATTR_W(thingy, THINGY) \
@@ -198,7 +198,7 @@ ISKU_SYSFS_W(thingy, THINGY); \
static const struct bin_attribute bin_attr_##thingy = { \
.attr = { .name = #thingy, .mode = 0220 }, \
.size = ISKU_SIZE_ ## THINGY, \
- .write_new = isku_sysfs_write_ ## thingy \
+ .write = isku_sysfs_write_ ## thingy \
}
ISKU_BIN_ATTR_RW(macro, MACRO);
@@ -238,7 +238,7 @@ static const struct bin_attribute *const isku_bin_attributes[] = {
static const struct attribute_group isku_group = {
.attrs = isku_attrs,
- .bin_attrs_new = isku_bin_attributes,
+ .bin_attrs = isku_bin_attributes,
};
static const struct attribute_group *isku_groups[] = {
diff --git a/drivers/hid/hid-roccat-kone.c b/drivers/hid/hid-roccat-kone.c
index b3c0242e5a37..fabc08efcfd8 100644
--- a/drivers/hid/hid-roccat-kone.c
+++ b/drivers/hid/hid-roccat-kone.c
@@ -385,8 +385,8 @@ static ssize_t kone_sysfs_write_profilex(struct file *fp,
static const struct bin_attribute bin_attr_profile##number = { \
.attr = { .name = "profile" #number, .mode = 0660 }, \
.size = sizeof(struct kone_profile), \
- .read_new = kone_sysfs_read_profilex, \
- .write_new = kone_sysfs_write_profilex, \
+ .read = kone_sysfs_read_profilex, \
+ .write = kone_sysfs_write_profilex, \
.private = &profile_numbers[number-1], \
}
PROFILE_ATTR(1);
@@ -646,7 +646,7 @@ static const struct bin_attribute *const kone_bin_attributes[] = {
static const struct attribute_group kone_group = {
.attrs = kone_attrs,
- .bin_attrs_new = kone_bin_attributes,
+ .bin_attrs = kone_bin_attributes,
};
static const struct attribute_group *kone_groups[] = {
diff --git a/drivers/hid/hid-roccat-koneplus.c b/drivers/hid/hid-roccat-koneplus.c
index 5d8a5ce88b4c..77d45d36421a 100644
--- a/drivers/hid/hid-roccat-koneplus.c
+++ b/drivers/hid/hid-roccat-koneplus.c
@@ -153,8 +153,8 @@ KONEPLUS_SYSFS_RW(thingy, THINGY); \
static const struct bin_attribute bin_attr_##thingy = { \
.attr = { .name = #thingy, .mode = 0660 }, \
.size = KONEPLUS_SIZE_ ## THINGY, \
- .read_new = koneplus_sysfs_read_ ## thingy, \
- .write_new = koneplus_sysfs_write_ ## thingy \
+ .read = koneplus_sysfs_read_ ## thingy, \
+ .write = koneplus_sysfs_write_ ## thingy \
}
#define KONEPLUS_BIN_ATTRIBUTE_R(thingy, THINGY) \
@@ -162,7 +162,7 @@ KONEPLUS_SYSFS_R(thingy, THINGY); \
static const struct bin_attribute bin_attr_##thingy = { \
.attr = { .name = #thingy, .mode = 0440 }, \
.size = KONEPLUS_SIZE_ ## THINGY, \
- .read_new = koneplus_sysfs_read_ ## thingy, \
+ .read = koneplus_sysfs_read_ ## thingy, \
}
#define KONEPLUS_BIN_ATTRIBUTE_W(thingy, THINGY) \
@@ -170,7 +170,7 @@ KONEPLUS_SYSFS_W(thingy, THINGY); \
static const struct bin_attribute bin_attr_##thingy = { \
.attr = { .name = #thingy, .mode = 0220 }, \
.size = KONEPLUS_SIZE_ ## THINGY, \
- .write_new = koneplus_sysfs_write_ ## thingy \
+ .write = koneplus_sysfs_write_ ## thingy \
}
KONEPLUS_BIN_ATTRIBUTE_W(control, CONTROL);
KONEPLUS_BIN_ATTRIBUTE_W(talk, TALK);
@@ -222,13 +222,13 @@ static ssize_t koneplus_sysfs_read_profilex_buttons(struct file *fp,
static const struct bin_attribute bin_attr_profile##number##_settings = { \
.attr = { .name = "profile" #number "_settings", .mode = 0440 }, \
.size = KONEPLUS_SIZE_PROFILE_SETTINGS, \
- .read_new = koneplus_sysfs_read_profilex_settings, \
+ .read = koneplus_sysfs_read_profilex_settings, \
.private = &profile_numbers[number-1], \
}; \
static const struct bin_attribute bin_attr_profile##number##_buttons = { \
.attr = { .name = "profile" #number "_buttons", .mode = 0440 }, \
.size = KONEPLUS_SIZE_PROFILE_BUTTONS, \
- .read_new = koneplus_sysfs_read_profilex_buttons, \
+ .read = koneplus_sysfs_read_profilex_buttons, \
.private = &profile_numbers[number-1], \
};
PROFILE_ATTR(1);
@@ -346,7 +346,7 @@ static const struct bin_attribute *const koneplus_bin_attributes[] = {
static const struct attribute_group koneplus_group = {
.attrs = koneplus_attrs,
- .bin_attrs_new = koneplus_bin_attributes,
+ .bin_attrs = koneplus_bin_attributes,
};
static const struct attribute_group *koneplus_groups[] = {
diff --git a/drivers/hid/hid-roccat-konepure.c b/drivers/hid/hid-roccat-konepure.c
index 7fb705789d4e..027bfc55ef9c 100644
--- a/drivers/hid/hid-roccat-konepure.c
+++ b/drivers/hid/hid-roccat-konepure.c
@@ -62,7 +62,7 @@ static const struct bin_attribute *const konepure_bin_attrs[] = {
};
static const struct attribute_group konepure_group = {
- .bin_attrs_new = konepure_bin_attrs,
+ .bin_attrs = konepure_bin_attrs,
};
static const struct attribute_group *konepure_groups[] = {
diff --git a/drivers/hid/hid-roccat-kovaplus.c b/drivers/hid/hid-roccat-kovaplus.c
index e31e4a2e62d5..a66f1b4730f3 100644
--- a/drivers/hid/hid-roccat-kovaplus.c
+++ b/drivers/hid/hid-roccat-kovaplus.c
@@ -196,8 +196,8 @@ KOVAPLUS_SYSFS_RW(thingy, THINGY); \
static const struct bin_attribute bin_attr_##thingy = { \
.attr = { .name = #thingy, .mode = 0660 }, \
.size = KOVAPLUS_SIZE_ ## THINGY, \
- .read_new = kovaplus_sysfs_read_ ## thingy, \
- .write_new = kovaplus_sysfs_write_ ## thingy \
+ .read = kovaplus_sysfs_read_ ## thingy, \
+ .write = kovaplus_sysfs_write_ ## thingy \
}
#define KOVAPLUS_BIN_ATTRIBUTE_W(thingy, THINGY) \
@@ -205,7 +205,7 @@ KOVAPLUS_SYSFS_W(thingy, THINGY); \
static const struct bin_attribute bin_attr_##thingy = { \
.attr = { .name = #thingy, .mode = 0220 }, \
.size = KOVAPLUS_SIZE_ ## THINGY, \
- .write_new = kovaplus_sysfs_write_ ## thingy \
+ .write = kovaplus_sysfs_write_ ## thingy \
}
KOVAPLUS_BIN_ATTRIBUTE_W(control, CONTROL);
KOVAPLUS_BIN_ATTRIBUTE_RW(info, INFO);
@@ -252,13 +252,13 @@ static ssize_t kovaplus_sysfs_read_profilex_buttons(struct file *fp,
static const struct bin_attribute bin_attr_profile##number##_settings = { \
.attr = { .name = "profile" #number "_settings", .mode = 0440 }, \
.size = KOVAPLUS_SIZE_PROFILE_SETTINGS, \
- .read_new = kovaplus_sysfs_read_profilex_settings, \
+ .read = kovaplus_sysfs_read_profilex_settings, \
.private = &profile_numbers[number-1], \
}; \
static const struct bin_attribute bin_attr_profile##number##_buttons = { \
.attr = { .name = "profile" #number "_buttons", .mode = 0440 }, \
.size = KOVAPLUS_SIZE_PROFILE_BUTTONS, \
- .read_new = kovaplus_sysfs_read_profilex_buttons, \
+ .read = kovaplus_sysfs_read_profilex_buttons, \
.private = &profile_numbers[number-1], \
};
PROFILE_ATTR(1);
@@ -399,7 +399,7 @@ static const struct bin_attribute *const kovaplus_bin_attributes[] = {
static const struct attribute_group kovaplus_group = {
.attrs = kovaplus_attrs,
- .bin_attrs_new = kovaplus_bin_attributes,
+ .bin_attrs = kovaplus_bin_attributes,
};
static const struct attribute_group *kovaplus_groups[] = {
diff --git a/drivers/hid/hid-roccat-lua.c b/drivers/hid/hid-roccat-lua.c
index 023ec64b4b0e..45e30549c236 100644
--- a/drivers/hid/hid-roccat-lua.c
+++ b/drivers/hid/hid-roccat-lua.c
@@ -88,8 +88,8 @@ LUA_SYSFS_R(thingy, THINGY) \
static const struct bin_attribute lua_ ## thingy ## _attr = { \
.attr = { .name = #thingy, .mode = 0660 }, \
.size = LUA_SIZE_ ## THINGY, \
- .read_new = lua_sysfs_read_ ## thingy, \
- .write_new = lua_sysfs_write_ ## thingy \
+ .read = lua_sysfs_read_ ## thingy, \
+ .write = lua_sysfs_write_ ## thingy \
};
LUA_BIN_ATTRIBUTE_RW(control, CONTROL)
diff --git a/drivers/hid/hid-roccat-pyra.c b/drivers/hid/hid-roccat-pyra.c
index 2b53fbfbb897..de2da6086e0b 100644
--- a/drivers/hid/hid-roccat-pyra.c
+++ b/drivers/hid/hid-roccat-pyra.c
@@ -154,8 +154,8 @@ PYRA_SYSFS_RW(thingy, THINGY); \
static const struct bin_attribute bin_attr_##thingy = { \
.attr = { .name = #thingy, .mode = 0660 }, \
.size = PYRA_SIZE_ ## THINGY, \
- .read_new = pyra_sysfs_read_ ## thingy, \
- .write_new = pyra_sysfs_write_ ## thingy \
+ .read = pyra_sysfs_read_ ## thingy, \
+ .write = pyra_sysfs_write_ ## thingy \
}
#define PYRA_BIN_ATTRIBUTE_R(thingy, THINGY) \
@@ -163,7 +163,7 @@ PYRA_SYSFS_R(thingy, THINGY); \
static const struct bin_attribute bin_attr_##thingy = { \
.attr = { .name = #thingy, .mode = 0440 }, \
.size_new = PYRA_SIZE_ ## THINGY, \
- .read_new = pyra_sysfs_read_ ## thingy, \
+ .read = pyra_sysfs_read_ ## thingy, \
}
#define PYRA_BIN_ATTRIBUTE_W(thingy, THINGY) \
@@ -171,7 +171,7 @@ PYRA_SYSFS_W(thingy, THINGY); \
static const struct bin_attribute bin_attr_##thingy = { \
.attr = { .name = #thingy, .mode = 0220 }, \
.size = PYRA_SIZE_ ## THINGY, \
- .write_new = pyra_sysfs_write_ ## thingy \
+ .write = pyra_sysfs_write_ ## thingy \
}
PYRA_BIN_ATTRIBUTE_W(control, CONTROL);
@@ -219,13 +219,13 @@ static ssize_t pyra_sysfs_read_profilex_buttons(struct file *fp,
static const struct bin_attribute bin_attr_profile##number##_settings = { \
.attr = { .name = "profile" #number "_settings", .mode = 0440 }, \
.size = PYRA_SIZE_PROFILE_SETTINGS, \
- .read_new = pyra_sysfs_read_profilex_settings, \
+ .read = pyra_sysfs_read_profilex_settings, \
.private = &profile_numbers[number-1], \
}; \
static const struct bin_attribute bin_attr_profile##number##_buttons = { \
.attr = { .name = "profile" #number "_buttons", .mode = 0440 }, \
.size = PYRA_SIZE_PROFILE_BUTTONS, \
- .read_new = pyra_sysfs_read_profilex_buttons, \
+ .read = pyra_sysfs_read_profilex_buttons, \
.private = &profile_numbers[number-1], \
};
PROFILE_ATTR(1);
@@ -355,7 +355,7 @@ static const struct bin_attribute *const pyra_bin_attributes[] = {
static const struct attribute_group pyra_group = {
.attrs = pyra_attrs,
- .bin_attrs_new = pyra_bin_attributes,
+ .bin_attrs = pyra_bin_attributes,
};
static const struct attribute_group *pyra_groups[] = {
diff --git a/drivers/hid/hid-roccat-ryos.c b/drivers/hid/hid-roccat-ryos.c
index 902dac1e714e..36911c9da4fe 100644
--- a/drivers/hid/hid-roccat-ryos.c
+++ b/drivers/hid/hid-roccat-ryos.c
@@ -70,7 +70,7 @@ static const struct bin_attribute *const ryos_bin_attrs[] = {
};
static const struct attribute_group ryos_group = {
- .bin_attrs_new = ryos_bin_attrs,
+ .bin_attrs = ryos_bin_attrs,
};
static const struct attribute_group *ryos_groups[] = {
diff --git a/drivers/hid/hid-roccat-savu.c b/drivers/hid/hid-roccat-savu.c
index 7399b8ffb5c7..fb2e464c3ada 100644
--- a/drivers/hid/hid-roccat-savu.c
+++ b/drivers/hid/hid-roccat-savu.c
@@ -42,7 +42,7 @@ static const struct bin_attribute *const savu_bin_attrs[] = {
};
static const struct attribute_group savu_group = {
- .bin_attrs_new = savu_bin_attrs,
+ .bin_attrs = savu_bin_attrs,
};
static const struct attribute_group *savu_groups[] = {
diff --git a/drivers/hid/hid-uclogic-core.c b/drivers/hid/hid-uclogic-core.c
index af98398d9247..34fb03ae8ee2 100644
--- a/drivers/hid/hid-uclogic-core.c
+++ b/drivers/hid/hid-uclogic-core.c
@@ -62,6 +62,30 @@ static const __u8 *uclogic_report_fixup(struct hid_device *hdev, __u8 *rdesc,
return rdesc;
}
+/* Buttons considered valid tablet pad inputs. */
+static const unsigned int uclogic_extra_input_mapping[] = {
+ BTN_0,
+ BTN_1,
+ BTN_2,
+ BTN_3,
+ BTN_4,
+ BTN_5,
+ BTN_6,
+ BTN_7,
+ BTN_8,
+ BTN_RIGHT,
+ BTN_MIDDLE,
+ BTN_SIDE,
+ BTN_EXTRA,
+ BTN_FORWARD,
+ BTN_BACK,
+ BTN_B,
+ BTN_A,
+ BTN_BASE,
+ BTN_BASE2,
+ BTN_X
+};
+
static int uclogic_input_mapping(struct hid_device *hdev,
struct hid_input *hi,
struct hid_field *field,
@@ -72,9 +96,27 @@ static int uclogic_input_mapping(struct hid_device *hdev,
struct uclogic_drvdata *drvdata = hid_get_drvdata(hdev);
struct uclogic_params *params = &drvdata->params;
- /* Discard invalid pen usages */
- if (params->pen.usage_invalid && (field->application == HID_DG_PEN))
- return -1;
+ if (field->application == HID_GD_KEYPAD) {
+ /*
+ * Remap input buttons to sensible ones that are not invalid.
+ * This only affects previous behavior for devices with more than ten or so buttons.
+ */
+ const int key = (usage->hid & HID_USAGE) - 1;
+
+ if (key < ARRAY_SIZE(uclogic_extra_input_mapping)) {
+ hid_map_usage(hi,
+ usage,
+ bit,
+ max,
+ EV_KEY,
+ uclogic_extra_input_mapping[key]);
+ return 1;
+ }
+ } else if (field->application == HID_DG_PEN) {
+ /* Discard invalid pen usages */
+ if (params->pen.usage_invalid)
+ return -1;
+ }
/* Let hid-core decide what to do */
return 0;
@@ -407,8 +449,22 @@ static int uclogic_raw_event_frame(
/* If need to, and can, transform the bitmap dial reports */
if (frame->bitmap_dial_byte > 0 && frame->bitmap_dial_byte < size) {
- if (data[frame->bitmap_dial_byte] == 2)
+ switch (data[frame->bitmap_dial_byte]) {
+ case 2:
data[frame->bitmap_dial_byte] = -1;
+ break;
+
+ /* Everything below here is for tablets that shove multiple dials into 1 byte */
+ case 16:
+ data[frame->bitmap_dial_byte] = 0;
+ data[frame->bitmap_second_dial_destination_byte] = 1;
+ break;
+
+ case 32:
+ data[frame->bitmap_dial_byte] = 0;
+ data[frame->bitmap_second_dial_destination_byte] = -1;
+ break;
+ }
}
return 0;
@@ -546,6 +602,8 @@ static const struct hid_device_id uclogic_devices[] = {
.driver_data = UCLOGIC_MOUSE_FRAME_QUIRK | UCLOGIC_BATTERY_QUIRK },
{ HID_USB_DEVICE(USB_VENDOR_ID_UGEE,
USB_DEVICE_ID_UGEE_XPPEN_TABLET_STAR06) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_UGEE,
+ USB_DEVICE_ID_UGEE_XPPEN_TABLET_22R_PRO) },
{ }
};
MODULE_DEVICE_TABLE(hid, uclogic_devices);
diff --git a/drivers/hid/hid-uclogic-params.c b/drivers/hid/hid-uclogic-params.c
index a6044996abf2..4a17f7332c3f 100644
--- a/drivers/hid/hid-uclogic-params.c
+++ b/drivers/hid/hid-uclogic-params.c
@@ -103,6 +103,8 @@ static void uclogic_params_frame_hid_dbg(
frame->touch_flip_at);
hid_dbg(hdev, "\t\t.bitmap_dial_byte = %u\n",
frame->bitmap_dial_byte);
+ hid_dbg(hdev, "\t\t.bitmap_second_dial_destination_byte = %u\n",
+ frame->bitmap_second_dial_destination_byte);
}
/**
@@ -1341,7 +1343,7 @@ static int uclogic_params_ugee_v2_init_event_hooks(struct hid_device *hdev,
struct uclogic_params *p)
{
struct uclogic_raw_event_hook *event_hook;
- __u8 reconnect_event[] = {
+ static const __u8 reconnect_event[] = {
/* Event received on wireless tablet reconnection */
0x02, 0xF8, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
@@ -1529,6 +1531,126 @@ cleanup:
return rc;
}
+/*
+ * uclogic_params_init_ugee_xppen_pro_22r() - Initializes a UGEE XP-Pen Pro 22R tablet device.
+ *
+ * @hdev: The HID device of the tablet interface to initialize and get
+ * parameters from. Cannot be NULL.
+ * @params: Parameters to fill in (to be cleaned with
+ * uclogic_params_cleanup()). Not modified in case of error.
+ * Cannot be NULL.
+ *
+ * Returns:
+ * Zero, if successful. A negative errno code on error.
+ */
+static int uclogic_params_init_ugee_xppen_pro_22r(struct uclogic_params *params,
+ struct hid_device *hdev,
+ const u8 rdesc_frame_arr[],
+ const size_t rdesc_frame_size)
+{
+ int rc = 0;
+ struct usb_interface *iface;
+ __u8 bInterfaceNumber;
+ const int str_desc_len = 12;
+ u8 *str_desc = NULL;
+ __u8 *rdesc_pen = NULL;
+ s32 desc_params[UCLOGIC_RDESC_PH_ID_NUM];
+ enum uclogic_params_frame_type frame_type;
+ /* The resulting parameters (noop) */
+ struct uclogic_params p = {0, };
+
+ if (!hdev || !params) {
+ rc = -EINVAL;
+ goto cleanup;
+ }
+
+ iface = to_usb_interface(hdev->dev.parent);
+ bInterfaceNumber = iface->cur_altsetting->desc.bInterfaceNumber;
+
+ /* Ignore non-pen interfaces */
+ if (bInterfaceNumber != 2) {
+ rc = -EINVAL;
+ uclogic_params_init_invalid(&p);
+ goto cleanup;
+ }
+
+ /*
+ * Initialize the interface by sending magic data.
+ * This magic data is the same as other UGEE v2 tablets.
+ */
+ rc = uclogic_probe_interface(hdev,
+ uclogic_ugee_v2_probe_arr,
+ uclogic_ugee_v2_probe_size,
+ uclogic_ugee_v2_probe_endpoint);
+ if (rc) {
+ uclogic_params_init_invalid(&p);
+ goto cleanup;
+ }
+
+ /**
+ * Read the string descriptor containing pen and frame parameters.
+ * These are slightly different than typical UGEE v2 devices.
+ */
+ rc = uclogic_params_get_str_desc(&str_desc, hdev, 100, str_desc_len);
+ if (rc != str_desc_len) {
+ rc = (rc < 0) ? rc : -EINVAL;
+ hid_err(hdev, "failed retrieving pen and frame parameters: %d\n", rc);
+ uclogic_params_init_invalid(&p);
+ goto cleanup;
+ }
+
+ rc = uclogic_params_parse_ugee_v2_desc(str_desc, str_desc_len,
+ desc_params,
+ ARRAY_SIZE(desc_params),
+ &frame_type);
+ if (rc)
+ goto cleanup;
+
+ // str_desc doesn't report the correct amount of buttons, so manually fix it
+ desc_params[UCLOGIC_RDESC_FRAME_PH_ID_UM] = 20;
+
+ kfree(str_desc);
+ str_desc = NULL;
+
+ /* Initialize the pen interface */
+ rdesc_pen = uclogic_rdesc_template_apply(
+ uclogic_rdesc_ugee_v2_pen_template_arr,
+ uclogic_rdesc_ugee_v2_pen_template_size,
+ desc_params, ARRAY_SIZE(desc_params));
+ if (!rdesc_pen) {
+ rc = -ENOMEM;
+ goto cleanup;
+ }
+
+ p.pen.desc_ptr = rdesc_pen;
+ p.pen.desc_size = uclogic_rdesc_ugee_v2_pen_template_size;
+ p.pen.id = 0x02;
+ p.pen.subreport_list[0].value = 0xf0;
+ p.pen.subreport_list[0].id = UCLOGIC_RDESC_V1_FRAME_ID;
+
+ /* Initialize the frame interface */
+ rc = uclogic_params_frame_init_with_desc(
+ &p.frame_list[0],
+ rdesc_frame_arr,
+ rdesc_frame_size,
+ UCLOGIC_RDESC_V1_FRAME_ID);
+ if (rc < 0) {
+ hid_err(hdev, "initializing frame params failed: %d\n", rc);
+ goto cleanup;
+ }
+
+ p.frame_list[0].bitmap_dial_byte = 7;
+ p.frame_list[0].bitmap_second_dial_destination_byte = 8;
+
+ /* Output parameters */
+ memcpy(params, &p, sizeof(*params));
+ memset(&p, 0, sizeof(p));
+cleanup:
+ kfree(str_desc);
+ uclogic_params_cleanup(&p);
+ return rc;
+}
+
/**
* uclogic_params_init() - initialize a tablet interface and discover its
* parameters.
@@ -1846,6 +1968,16 @@ int uclogic_params_init(struct uclogic_params *params,
}
break;
+ case VID_PID(USB_VENDOR_ID_UGEE,
+ USB_DEVICE_ID_UGEE_XPPEN_TABLET_22R_PRO):
+ rc = uclogic_params_init_ugee_xppen_pro_22r(&p,
+ hdev,
+ uclogic_rdesc_xppen_artist_22r_pro_frame_arr,
+ uclogic_rdesc_xppen_artist_22r_pro_frame_size);
+ if (rc != 0)
+ goto cleanup;
+
+ break;
}
#undef VID_PID
diff --git a/drivers/hid/hid-uclogic-params.h b/drivers/hid/hid-uclogic-params.h
index 35ff062d09b5..6ec8643d2ee5 100644
--- a/drivers/hid/hid-uclogic-params.h
+++ b/drivers/hid/hid-uclogic-params.h
@@ -175,6 +175,11 @@ struct uclogic_params_frame {
* counterclockwise, as opposed to the normal 1 and -1.
*/
unsigned int bitmap_dial_byte;
+ /*
+ * Destination offset for the second bitmap dial byte, if the tablet
+ * supports a second dial at all.
+ */
+ unsigned int bitmap_second_dial_destination_byte;
};
/*
diff --git a/drivers/hid/hid-uclogic-rdesc.c b/drivers/hid/hid-uclogic-rdesc.c
index 9b9cbc2aae36..08a89c6aae3b 100644
--- a/drivers/hid/hid-uclogic-rdesc.c
+++ b/drivers/hid/hid-uclogic-rdesc.c
@@ -1193,6 +1193,50 @@ const __u8 uclogic_rdesc_xppen_deco01_frame_arr[] = {
const size_t uclogic_rdesc_xppen_deco01_frame_size =
sizeof(uclogic_rdesc_xppen_deco01_frame_arr);
+/* Fixed report descriptor for XP-Pen Arist 22R Pro frame */
+const __u8 uclogic_rdesc_xppen_artist_22r_pro_frame_arr[] = {
+ 0x05, 0x01, /* Usage Page (Desktop), */
+ 0x09, 0x07, /* Usage (Keypad), */
+ 0xA1, 0x01, /* Collection (Application), */
+ 0x85, UCLOGIC_RDESC_V1_FRAME_ID,
+ /* Report ID (Virtual report), */
+ 0x05, 0x0D, /* Usage Page (Digitizer), */
+ 0x09, 0x39, /* Usage (Tablet Function Keys), */
+ 0xA0, /* Collection (Physical), */
+ 0x14, /* Logical Minimum (0), */
+ 0x25, 0x01, /* Logical Maximum (1), */
+ 0x75, 0x01, /* Report Size (1), */
+ 0x95, 0x08, /* Report Count (8), */
+ 0x81, 0x01, /* Input (Constant), */
+ 0x05, 0x09, /* Usage Page (Button), */
+ 0x19, 0x01, /* Usage Minimum (01h), */
+ 0x29, 0x14, /* Usage Maximum (14h), */
+ 0x95, 0x14, /* Report Count (20), */
+ 0x81, 0x02, /* Input (Variable), */
+ 0x95, 0x14, /* Report Count (20), */
+ 0x81, 0x01, /* Input (Constant), */
+ 0x05, 0x01, /* Usage Page (Desktop), */
+ 0x09, 0x38, /* Usage (Wheel), */
+ 0x75, 0x08, /* Report Size (8), */
+ 0x95, 0x01, /* Report Count (1), */
+ 0x15, 0xFF, /* Logical Minimum (-1), */
+ 0x25, 0x08, /* Logical Maximum (8), */
+ 0x81, 0x06, /* Input (Variable, Relative), */
+ 0x05, 0x0C, /* Usage Page (Consumer Devices), */
+ 0x0A, 0x38, 0x02, /* Usage (AC PAN), */
+ 0x95, 0x01, /* Report Count (1), */
+ 0x81, 0x06, /* Input (Variable, Relative), */
+ 0x26, 0xFF, 0x00, /* Logical Maximum (255), */
+ 0x75, 0x08, /* Report Size (8), */
+ 0x95, 0x01, /* Report Count (1), */
+ 0x81, 0x02, /* Input (Variable), */
+ 0xC0, /* End Collection */
+ 0xC0, /* End Collection */
+};
+
+const size_t uclogic_rdesc_xppen_artist_22r_pro_frame_size =
+ sizeof(uclogic_rdesc_xppen_artist_22r_pro_frame_arr);
+
/**
* uclogic_rdesc_template_apply() - apply report descriptor parameters to a
* report descriptor template, creating a report descriptor. Copies the
diff --git a/drivers/hid/hid-uclogic-rdesc.h b/drivers/hid/hid-uclogic-rdesc.h
index 3878a0e8c464..644a35ff12f2 100644
--- a/drivers/hid/hid-uclogic-rdesc.h
+++ b/drivers/hid/hid-uclogic-rdesc.h
@@ -210,4 +210,8 @@ extern const size_t uclogic_rdesc_ugee_g5_frame_size;
/* Least-significant bit of Ugee G5 frame rotary encoder state */
#define UCLOGIC_RDESC_UGEE_G5_FRAME_RE_LSB 38
+/* Fixed report descriptor for XP-Pen Arist 22R Pro frame */
+extern const __u8 uclogic_rdesc_xppen_artist_22r_pro_frame_arr[];
+extern const size_t uclogic_rdesc_xppen_artist_22r_pro_frame_size;
+
#endif /* _HID_UCLOGIC_RDESC_H */
diff --git a/drivers/hid/hid-universal-pidff.c b/drivers/hid/hid-universal-pidff.c
index 001a0f5efb9d..554a6559aeb7 100644
--- a/drivers/hid/hid-universal-pidff.c
+++ b/drivers/hid/hid-universal-pidff.c
@@ -57,6 +57,7 @@ static int universal_pidff_probe(struct hid_device *hdev,
const struct hid_device_id *id)
{
int i, error;
+
error = hid_parse(hdev);
if (error) {
hid_err(hdev, "HID parse failed\n");
@@ -91,8 +92,8 @@ static int universal_pidff_probe(struct hid_device *hdev,
/* Check if HID_PID support is enabled */
int (*init_function)(struct hid_device *, u32);
- init_function = hid_pidff_init_with_quirks;
+ init_function = hid_pidff_init_with_quirks;
if (!init_function) {
hid_warn(hdev, "HID_PID support not enabled!\n");
return 0;
@@ -177,7 +178,7 @@ static const struct hid_device_id universal_pidff_devices[] = {
.driver_data = HID_PIDFF_QUIRK_PERIODIC_SINE_ONLY },
{ HID_USB_DEVICE(USB_VENDOR_ID_LITE_STAR, USB_DEVICE_ID_PXN_V12_LITE_2),
.driver_data = HID_PIDFF_QUIRK_PERIODIC_SINE_ONLY },
- { HID_USB_DEVICE(USB_VENDOR_ID_LITE_STAR, USB_DEVICE_LITE_STAR_GT987_FF),
+ { HID_USB_DEVICE(USB_VENDOR_ID_LITE_STAR, USB_DEVICE_ID_LITE_STAR_GT987),
.driver_data = HID_PIDFF_QUIRK_PERIODIC_SINE_ONLY },
{ HID_USB_DEVICE(USB_VENDOR_ID_ASETEK, USB_DEVICE_ID_ASETEK_INVICTA) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ASETEK, USB_DEVICE_ID_ASETEK_FORTE) },
diff --git a/drivers/hid/intel-thc-hid/Makefile b/drivers/hid/intel-thc-hid/Makefile
index 6f762d87af07..f1182253b5b7 100644
--- a/drivers/hid/intel-thc-hid/Makefile
+++ b/drivers/hid/intel-thc-hid/Makefile
@@ -8,6 +8,7 @@
obj-$(CONFIG_INTEL_THC_HID) += intel-thc.o
intel-thc-objs += intel-thc/intel-thc-dev.o
intel-thc-objs += intel-thc/intel-thc-dma.o
+intel-thc-objs += intel-thc/intel-thc-wot.o
obj-$(CONFIG_INTEL_QUICKSPI) += intel-quickspi.o
intel-quickspi-objs += intel-quickspi/pci-quickspi.o
diff --git a/drivers/hid/intel-thc-hid/intel-quicki2c/pci-quicki2c.c b/drivers/hid/intel-thc-hid/intel-quicki2c/pci-quicki2c.c
index 8a8c4a46f927..e944a6ccb776 100644
--- a/drivers/hid/intel-thc-hid/intel-quicki2c/pci-quicki2c.c
+++ b/drivers/hid/intel-thc-hid/intel-quicki2c/pci-quicki2c.c
@@ -11,13 +11,20 @@
#include <linux/sizes.h>
#include <linux/pm_runtime.h>
+#include <linux/gpio/consumer.h>
+
#include "intel-thc-dev.h"
#include "intel-thc-hw.h"
+#include "intel-thc-wot.h"
#include "quicki2c-dev.h"
#include "quicki2c-hid.h"
#include "quicki2c-protocol.h"
+static struct quicki2c_ddata ptl_ddata = {
+ .max_detect_size = MAX_RX_DETECT_SIZE_PTL,
+};
+
/* THC QuickI2C ACPI method to get device properties */
/* HIDI2C device method */
static guid_t i2c_hid_guid =
@@ -27,19 +34,26 @@ static guid_t i2c_hid_guid =
static guid_t thc_platform_guid =
GUID_INIT(0x84005682, 0x5b71, 0x41a4, 0x8d, 0x66, 0x81, 0x30, 0xf7, 0x87, 0xa1, 0x38);
+/* QuickI2C Wake-on-Touch GPIO resource */
+static const struct acpi_gpio_params wake_gpio = { 0, 0, true };
+
+static const struct acpi_gpio_mapping quicki2c_gpios[] = {
+ { "wake-on-touch", &wake_gpio, 1 },
+ { }
+};
+
/**
* quicki2c_acpi_get_dsm_property - Query device ACPI DSM parameter
- *
- * @adev: point to ACPI device
+ * @adev: Point to ACPI device
* @guid: ACPI method's guid
* @rev: ACPI method's revision
* @func: ACPI method's function number
* @type: ACPI parameter's data type
- * @prop_buf: point to return buffer
+ * @prop_buf: Point to return buffer
*
* This is a helper function for device to query its ACPI DSM parameters.
*
- * Return: 0 if success or ENODEV on failed.
+ * Return: 0 if success or ENODEV on failure.
*/
static int quicki2c_acpi_get_dsm_property(struct acpi_device *adev, const guid_t *guid,
u64 rev, u64 func, acpi_object_type type, void *prop_buf)
@@ -67,11 +81,10 @@ static int quicki2c_acpi_get_dsm_property(struct acpi_device *adev, const guid_t
/**
* quicki2c_acpi_get_dsd_property - Query device ACPI DSD parameter
- *
- * @adev: point to ACPI device
+ * @adev: Point to ACPI device
* @dsd_method_name: ACPI method's property name
* @type: ACPI parameter's data type
- * @prop_buf: point to return buffer
+ * @prop_buf: Point to return buffer
*
* This is a helper function for device to query its ACPI DSD parameters.
*
@@ -100,13 +113,12 @@ static int quicki2c_acpi_get_dsd_property(struct acpi_device *adev, acpi_string
}
/**
- * quicki2c_get_acpi_resources - Query all quicki2c devices' ACPI parameters
+ * quicki2c_get_acpi_resources - Query all QuickI2C devices' ACPI parameters
+ * @qcdev: Point to quicki2c_device structure
*
- * @qcdev: point to quicki2c device
+ * This function gets all QuickI2C devices' ACPI resource.
*
- * This function gets all quicki2c devices' ACPI resource.
- *
- * Return: 0 if success or error code on failed.
+ * Return: 0 if success or error code on failure.
*/
static int quicki2c_get_acpi_resources(struct quicki2c_device *qcdev)
{
@@ -192,10 +204,9 @@ static int quicki2c_get_acpi_resources(struct quicki2c_device *qcdev)
}
/**
- * quicki2c_irq_quick_handler - The ISR of the quicki2c driver
- *
+ * quicki2c_irq_quick_handler - The ISR of the QuickI2C driver
* @irq: The irq number
- * @dev_id: pointer to the device structure
+ * @dev_id: Pointer to the quicki2c_device structure
*
* Return: IRQ_WAKE_THREAD if further process needed.
*/
@@ -214,13 +225,13 @@ static irqreturn_t quicki2c_irq_quick_handler(int irq, void *dev_id)
/**
* try_recover - Try to recovery THC and Device
- * @qcdev: pointer to quicki2c device
+ * @qcdev: Pointer to quicki2c_device structure
*
- * This function is a error handler, called when fatal error happens.
- * It try to reset Touch Device and re-configure THC to recovery
- * transferring between Device and THC.
+ * This function is an error handler, called when fatal error happens.
+ * It try to reset touch device and re-configure THC to recovery
+ * communication between touch device and THC.
*
- * Return: 0 if successful or error code on failed
+ * Return: 0 if successful or error code on failure
*/
static int try_recover(struct quicki2c_device *qcdev)
{
@@ -264,7 +275,7 @@ static int handle_input_report(struct quicki2c_device *qcdev)
continue;
}
- /* discard samples before driver probe complete */
+ /* Discard samples before driver probe complete */
if (qcdev->state != QUICKI2C_ENABLED)
continue;
@@ -276,10 +287,9 @@ static int handle_input_report(struct quicki2c_device *qcdev)
}
/**
- * quicki2c_irq_thread_handler - IRQ thread handler of quicki2c driver
- *
+ * quicki2c_irq_thread_handler - IRQ thread handler of QuickI2C driver
* @irq: The IRQ number
- * @dev_id: pointer to the quicki2c device structure
+ * @dev_id: Pointer to the quicki2c_device structure
*
* Return: IRQ_HANDLED to finish this handler.
*/
@@ -325,20 +335,21 @@ exit:
}
/**
- * quicki2c_dev_init - Initialize quicki2c device
- *
- * @pdev: pointer to the thc pci device
- * @mem_addr: The pointer of MMIO memory address
+ * quicki2c_dev_init - Initialize QuickI2C device
+ * @pdev: Pointer to the THC PCI device
+ * @mem_addr: The Pointer of MMIO memory address
+ * @ddata: Point to quicki2c_ddata structure
*
- * Alloc quicki2c device structure and initialized THC device,
+ * Alloc quicki2c_device structure and initialized THC device,
* then configure THC to HIDI2C mode.
*
* If success, enable THC hardware interrupt.
*
- * Return: pointer to the quicki2c device structure if success
- * or NULL on failed.
+ * Return: Pointer to the quicki2c_device structure if success
+ * or NULL on failure.
*/
-static struct quicki2c_device *quicki2c_dev_init(struct pci_dev *pdev, void __iomem *mem_addr)
+static struct quicki2c_device *quicki2c_dev_init(struct pci_dev *pdev, void __iomem *mem_addr,
+ const struct quicki2c_ddata *ddata)
{
struct device *dev = &pdev->dev;
struct quicki2c_device *qcdev;
@@ -352,10 +363,11 @@ static struct quicki2c_device *quicki2c_dev_init(struct pci_dev *pdev, void __io
qcdev->dev = dev;
qcdev->mem_addr = mem_addr;
qcdev->state = QUICKI2C_DISABLED;
+ qcdev->ddata = ddata;
init_waitqueue_head(&qcdev->reset_ack_wq);
- /* thc hw init */
+ /* THC hardware init */
qcdev->thc_hw = thc_dev_init(qcdev->dev, qcdev->mem_addr);
if (IS_ERR(qcdev->thc_hw)) {
ret = PTR_ERR(qcdev->thc_hw);
@@ -392,15 +404,16 @@ static struct quicki2c_device *quicki2c_dev_init(struct pci_dev *pdev, void __io
thc_interrupt_enable(qcdev->thc_hw, true);
+ thc_wot_config(qcdev->thc_hw, &quicki2c_gpios[0]);
+
qcdev->state = QUICKI2C_INITED;
return qcdev;
}
/**
- * quicki2c_dev_deinit - De-initialize quicki2c device
- *
- * @qcdev: pointer to the quicki2c device structure
+ * quicki2c_dev_deinit - De-initialize QuickI2C device
+ * @qcdev: Pointer to the quicki2c_device structure
*
* Disable THC interrupt and deinitilize THC.
*/
@@ -408,18 +421,63 @@ static void quicki2c_dev_deinit(struct quicki2c_device *qcdev)
{
thc_interrupt_enable(qcdev->thc_hw, false);
thc_ltr_unconfig(qcdev->thc_hw);
+ thc_wot_unconfig(qcdev->thc_hw);
qcdev->state = QUICKI2C_DISABLED;
}
/**
- * quicki2c_dma_init - Configure THC DMA for quicki2c device
- * @qcdev: pointer to the quicki2c device structure
+ * quicki2c_dma_adv_enable - Configure and enable DMA advanced features
+ * @qcdev: Pointer to the quicki2c_device structure
+ *
+ * If platform supports THC DMA advanced features, such as max input size
+ * control or interrupt delay, configures and enables them.
+ */
+static void quicki2c_dma_adv_enable(struct quicki2c_device *qcdev)
+{
+ /*
+ * If platform supports max input size control feature and touch device
+ * max input length <= THC detect capability, enable the feature with device
+ * max input length.
+ */
+ if (qcdev->ddata->max_detect_size >=
+ le16_to_cpu(qcdev->dev_desc.max_input_len)) {
+ thc_i2c_set_rx_max_size(qcdev->thc_hw,
+ le16_to_cpu(qcdev->dev_desc.max_input_len));
+ thc_i2c_rx_max_size_enable(qcdev->thc_hw, true);
+ }
+
+ /* If platform supports interrupt delay feature, enable it with given delay */
+ if (qcdev->ddata->interrupt_delay) {
+ thc_i2c_set_rx_int_delay(qcdev->thc_hw,
+ qcdev->ddata->interrupt_delay);
+ thc_i2c_rx_int_delay_enable(qcdev->thc_hw, true);
+ }
+}
+
+/**
+ * quicki2c_dma_adv_disable - Disable DMA advanced features
+ * @qcdev: Pointer to the quicki2c device structure
+ *
+ * Disable all DMA advanced features if platform supports.
+ */
+static void quicki2c_dma_adv_disable(struct quicki2c_device *qcdev)
+{
+ if (qcdev->ddata->max_detect_size)
+ thc_i2c_rx_max_size_enable(qcdev->thc_hw, false);
+
+ if (qcdev->ddata->interrupt_delay)
+ thc_i2c_rx_int_delay_enable(qcdev->thc_hw, false);
+}
+
+/**
+ * quicki2c_dma_init - Configure THC DMA for QuickI2C device
+ * @qcdev: Pointer to the quicki2c_device structure
*
* This function uses TIC's parameters(such as max input length, max output
* length) to allocate THC DMA buffers and configure THC DMA engines.
*
- * Return: 0 if success or error code on failed.
+ * Return: 0 if success or error code on failure.
*/
static int quicki2c_dma_init(struct quicki2c_device *qcdev)
{
@@ -451,12 +509,15 @@ static int quicki2c_dma_init(struct quicki2c_device *qcdev)
return ret;
}
- return ret;
+ if (qcdev->ddata)
+ quicki2c_dma_adv_enable(qcdev);
+
+ return 0;
}
/**
- * quicki2c_dma_deinit - Release THC DMA for quicki2c device
- * @qcdev: pointer to the quicki2c device structure
+ * quicki2c_dma_deinit - Release THC DMA for QuickI2C device
+ * @qcdev: Pointer to the quicki2c_device structure
*
* Stop THC DMA engines and release all DMA buffers.
*
@@ -465,11 +526,14 @@ static void quicki2c_dma_deinit(struct quicki2c_device *qcdev)
{
thc_dma_unconfigure(qcdev->thc_hw);
thc_dma_release(qcdev->thc_hw);
+
+ if (qcdev->ddata)
+ quicki2c_dma_adv_disable(qcdev);
}
/**
* quicki2c_alloc_report_buf - Alloc report buffers
- * @qcdev: pointer to the quicki2c device structure
+ * @qcdev: Pointer to the quicki2c_device structure
*
* Allocate report descriptor buffer, it will be used for restore TIC HID
* report descriptor.
@@ -480,7 +544,7 @@ static void quicki2c_dma_deinit(struct quicki2c_device *qcdev)
* Allocate output report buffer, it will be used for store HID output report,
* such as set feature.
*
- * Return: 0 if success or error code on failed.
+ * Return: 0 if success or error code on failure.
*/
static int quicki2c_alloc_report_buf(struct quicki2c_device *qcdev)
{
@@ -518,28 +582,27 @@ static int quicki2c_alloc_report_buf(struct quicki2c_device *qcdev)
}
/*
- * quicki2c_probe: Quicki2c driver probe function
- *
- * @pdev: point to pci device
- * @id: point to pci_device_id structure
+ * quicki2c_probe: QuickI2C driver probe function
+ * @pdev: Point to PCI device
+ * @id: Point to pci_device_id structure
*
* This function initializes THC and HIDI2C device, the flow is:
- * - do THC pci device initialization
- * - query HIDI2C ACPI parameters
- * - configure THC to HIDI2C mode
- * - go through HIDI2C enumeration flow
- * |- read device descriptor
- * |- reset HIDI2C device
- * - enable THC interrupt and DMA
- * - read report descriptor
- * - register HID device
- * - enable runtime power management
- *
- * Return 0 if success or error code on failed.
+ * - Do THC pci device initialization
+ * - Query HIDI2C ACPI parameters
+ * - Configure THC to HIDI2C mode
+ * - Go through HIDI2C enumeration flow
+ * |- Read device descriptor
+ * |- Reset HIDI2C device
+ * - Enable THC interrupt and DMA
+ * - Read report descriptor
+ * - Register HID device
+ * - Enable runtime power management
+ *
+ * Return 0 if success or error code on failure.
*/
-static int quicki2c_probe(struct pci_dev *pdev,
- const struct pci_device_id *id)
+static int quicki2c_probe(struct pci_dev *pdev, const struct pci_device_id *id)
{
+ const struct quicki2c_ddata *ddata = (const struct quicki2c_ddata *)id->driver_data;
struct quicki2c_device *qcdev;
void __iomem *mem_addr;
int ret;
@@ -577,7 +640,7 @@ static int quicki2c_probe(struct pci_dev *pdev,
pdev->irq = pci_irq_vector(pdev, 0);
- qcdev = quicki2c_dev_init(pdev, mem_addr);
+ qcdev = quicki2c_dev_init(pdev, mem_addr, ddata);
if (IS_ERR(qcdev)) {
dev_err_once(&pdev->dev, "QuickI2C device init failed\n");
ret = PTR_ERR(qcdev);
@@ -668,11 +731,10 @@ disable_pci_device:
/**
* quicki2c_remove - Device Removal Routine
+ * @pdev: Point to PCI device structure
*
- * @pdev: PCI device structure
- *
- * This is called by the PCI subsystem to alert the driver
- * that it should release a PCI device.
+ * This is called by the PCI subsystem to alert the driver that it should
+ * release a PCI device.
*/
static void quicki2c_remove(struct pci_dev *pdev)
{
@@ -694,12 +756,10 @@ static void quicki2c_remove(struct pci_dev *pdev)
/**
* quicki2c_shutdown - Device Shutdown Routine
+ * @pdev: Point to PCI device structure
*
- * @pdev: PCI device structure
- *
- * This is called from the reboot notifier
- * it's a simplified version of remove so we go down
- * faster.
+ * This is called from the reboot notifier, it's a simplified version of remove
+ * so we go down faster.
*/
static void quicki2c_shutdown(struct pci_dev *pdev)
{
@@ -930,13 +990,13 @@ static const struct dev_pm_ops quicki2c_pm_ops = {
};
static const struct pci_device_id quicki2c_pci_tbl[] = {
- {PCI_VDEVICE(INTEL, THC_LNL_DEVICE_ID_I2C_PORT1), },
- {PCI_VDEVICE(INTEL, THC_LNL_DEVICE_ID_I2C_PORT2), },
- {PCI_VDEVICE(INTEL, THC_PTL_H_DEVICE_ID_I2C_PORT1), },
- {PCI_VDEVICE(INTEL, THC_PTL_H_DEVICE_ID_I2C_PORT2), },
- {PCI_VDEVICE(INTEL, THC_PTL_U_DEVICE_ID_I2C_PORT1), },
- {PCI_VDEVICE(INTEL, THC_PTL_U_DEVICE_ID_I2C_PORT2), },
- {}
+ { PCI_DEVICE_DATA(INTEL, THC_LNL_DEVICE_ID_I2C_PORT1, NULL) },
+ { PCI_DEVICE_DATA(INTEL, THC_LNL_DEVICE_ID_I2C_PORT2, NULL) },
+ { PCI_DEVICE_DATA(INTEL, THC_PTL_H_DEVICE_ID_I2C_PORT1, &ptl_ddata) },
+ { PCI_DEVICE_DATA(INTEL, THC_PTL_H_DEVICE_ID_I2C_PORT2, &ptl_ddata) },
+ { PCI_DEVICE_DATA(INTEL, THC_PTL_U_DEVICE_ID_I2C_PORT1, &ptl_ddata) },
+ { PCI_DEVICE_DATA(INTEL, THC_PTL_U_DEVICE_ID_I2C_PORT2, &ptl_ddata) },
+ { }
};
MODULE_DEVICE_TABLE(pci, quicki2c_pci_tbl);
diff --git a/drivers/hid/intel-thc-hid/intel-quicki2c/quicki2c-dev.h b/drivers/hid/intel-thc-hid/intel-quicki2c/quicki2c-dev.h
index 6ddb584bd611..93d6fa982d60 100644
--- a/drivers/hid/intel-thc-hid/intel-quicki2c/quicki2c-dev.h
+++ b/drivers/hid/intel-thc-hid/intel-quicki2c/quicki2c-dev.h
@@ -7,12 +7,12 @@
#include <linux/hid-over-i2c.h>
#include <linux/workqueue.h>
-#define THC_LNL_DEVICE_ID_I2C_PORT1 0xA848
-#define THC_LNL_DEVICE_ID_I2C_PORT2 0xA84A
-#define THC_PTL_H_DEVICE_ID_I2C_PORT1 0xE348
-#define THC_PTL_H_DEVICE_ID_I2C_PORT2 0xE34A
-#define THC_PTL_U_DEVICE_ID_I2C_PORT1 0xE448
-#define THC_PTL_U_DEVICE_ID_I2C_PORT2 0xE44A
+#define PCI_DEVICE_ID_INTEL_THC_LNL_DEVICE_ID_I2C_PORT1 0xA848
+#define PCI_DEVICE_ID_INTEL_THC_LNL_DEVICE_ID_I2C_PORT2 0xA84A
+#define PCI_DEVICE_ID_INTEL_THC_PTL_H_DEVICE_ID_I2C_PORT1 0xE348
+#define PCI_DEVICE_ID_INTEL_THC_PTL_H_DEVICE_ID_I2C_PORT2 0xE34A
+#define PCI_DEVICE_ID_INTEL_THC_PTL_U_DEVICE_ID_I2C_PORT1 0xE448
+#define PCI_DEVICE_ID_INTEL_THC_PTL_U_DEVICE_ID_I2C_PORT2 0xE44A
/* Packet size value, the unit is 16 bytes */
#define MAX_PACKET_SIZE_VALUE_LNL 256
@@ -36,6 +36,12 @@
#define QUICKI2C_DEFAULT_LP_LTR_VALUE 500
#define QUICKI2C_RPM_TIMEOUT_MS 500
+/* PTL Max packet size detection capability is 255 Bytes */
+#define MAX_RX_DETECT_SIZE_PTL 255
+
+/* Default interrupt delay is 1ms, suitable for most devices */
+#define DEFAULT_INTERRUPT_DELAY_US (1 * USEC_PER_MSEC)
+
/*
* THC uses runtime auto suspend to dynamically switch between THC active LTR
* and low power LTR to save CPU power.
@@ -122,6 +128,16 @@ struct quicki2c_subip_acpi_config {
u64 HMSL;
};
+/**
+ * struct quicki2c_ddata - Driver specific data for quicki2c device
+ * @max_detect_size: Identify max packet size detect for rx
+ * @interrupt_delay: Identify interrupt detect delay for rx
+ */
+struct quicki2c_ddata {
+ u32 max_detect_size;
+ u32 interrupt_delay;
+};
+
struct device;
struct pci_dev;
struct thc_device;
@@ -130,15 +146,15 @@ struct acpi_device;
/**
* struct quicki2c_device - THC QuickI2C device struct
- * @dev: point to kernel device
- * @pdev: point to PCI device
- * @thc_hw: point to THC device
- * @hid_dev: point to hid device
- * @acpi_dev: point to ACPI device
- * @driver_data: point to quicki2c specific driver data
+ * @dev: Point to kernel device
+ * @pdev: Point to PCI device
+ * @thc_hw: Point to THC device
+ * @hid_dev: Point to HID device
+ * @acpi_dev: Point to ACPI device
+ * @ddata: Point to QuickI2C platform specific driver data
* @state: THC I2C device state
* @mem_addr: MMIO memory address
- * @dev_desc: device descriptor for HIDI2C protocol
+ * @dev_desc: Device descriptor for HIDI2C protocol
* @i2c_slave_addr: HIDI2C device slave address
* @hid_desc_addr: Register address for retrieve HID device descriptor
* @active_ltr_val: THC active LTR value
@@ -146,12 +162,12 @@ struct acpi_device;
* @i2c_speed_mode: 0 - standard mode, 1 - fast mode, 2 - fast mode plus
* @i2c_clock_hcnt: I2C CLK high period time (unit in cycle count)
* @i2c_clock_lcnt: I2C CLK low period time (unit in cycle count)
- * @report_descriptor: store a copy of device report descriptor
- * @input_buf: store a copy of latest input report data
- * @report_buf: store a copy of latest input/output report packet from set/get feature
- * @report_len: the length of input/output report packet
- * @reset_ack_wq: workqueue for waiting reset response from device
- * @reset_ack: indicate reset response received or not
+ * @report_descriptor: Store a copy of device report descriptor
+ * @input_buf: Store a copy of latest input report data
+ * @report_buf: Store a copy of latest input/output report packet from set/get feature
+ * @report_len: The length of input/output report packet
+ * @reset_ack_wq: Workqueue for waiting reset response from device
+ * @reset_ack: Indicate reset response received or not
*/
struct quicki2c_device {
struct device *dev;
@@ -159,6 +175,7 @@ struct quicki2c_device {
struct thc_device *thc_hw;
struct hid_device *hid_dev;
struct acpi_device *acpi_dev;
+ const struct quicki2c_ddata *ddata;
enum quicki2c_dev_state state;
void __iomem *mem_addr;
diff --git a/drivers/hid/intel-thc-hid/intel-quickspi/pci-quickspi.c b/drivers/hid/intel-thc-hid/intel-quickspi/pci-quickspi.c
index d4f89f44c3b4..5e5f179dd113 100644
--- a/drivers/hid/intel-thc-hid/intel-quickspi/pci-quickspi.c
+++ b/drivers/hid/intel-thc-hid/intel-quickspi/pci-quickspi.c
@@ -11,8 +11,11 @@
#include <linux/pci.h>
#include <linux/pm_runtime.h>
+#include <linux/gpio/consumer.h>
+
#include "intel-thc-dev.h"
#include "intel-thc-hw.h"
+#include "intel-thc-wot.h"
#include "quickspi-dev.h"
#include "quickspi-hid.h"
@@ -46,6 +49,15 @@ static guid_t thc_platform_guid =
GUID_INIT(0x84005682, 0x5b71, 0x41a4, 0x8d, 0x66, 0x81, 0x30,
0xf7, 0x87, 0xa1, 0x38);
+
+/* QuickSPI Wake-on-Touch GPIO resource */
+static const struct acpi_gpio_params wake_gpio = { 0, 0, true };
+
+static const struct acpi_gpio_mapping quickspi_gpios[] = {
+ { "wake-on-touch", &wake_gpio, 1 },
+ { }
+};
+
/**
* thc_acpi_get_property - Query device ACPI parameter
*
@@ -426,6 +438,8 @@ static struct quickspi_device *quickspi_dev_init(struct pci_dev *pdev, void __io
thc_interrupt_enable(qsdev->thc_hw, true);
+ thc_wot_config(qsdev->thc_hw, &quickspi_gpios[0]);
+
qsdev->state = QUICKSPI_INITIATED;
return qsdev;
@@ -442,6 +456,7 @@ static void quickspi_dev_deinit(struct quickspi_device *qsdev)
{
thc_interrupt_enable(qsdev->thc_hw, false);
thc_ltr_unconfig(qsdev->thc_hw);
+ thc_wot_unconfig(qsdev->thc_hw);
qsdev->state = QUICKSPI_DISABLED;
}
diff --git a/drivers/hid/intel-thc-hid/intel-thc/intel-thc-dev.c b/drivers/hid/intel-thc-hid/intel-thc/intel-thc-dev.c
index c105df7f6c87..6f2263869b20 100644
--- a/drivers/hid/intel-thc-hid/intel-thc/intel-thc-dev.c
+++ b/drivers/hid/intel-thc-hid/intel-thc/intel-thc-dev.c
@@ -2,6 +2,7 @@
/* Copyright (c) 2024 Intel Corporation */
#include <linux/bitfield.h>
+#include <linux/math.h>
#include <linux/regmap.h>
#include "intel-thc-dev.h"
@@ -1571,6 +1572,145 @@ int thc_i2c_subip_regs_restore(struct thc_device *dev)
}
EXPORT_SYMBOL_NS_GPL(thc_i2c_subip_regs_restore, "INTEL_THC");
+/**
+ * thc_i2c_set_rx_max_size - Set I2C Rx transfer max input size
+ * @dev: The pointer of THC private device context
+ * @max_rx_size: Max input report packet size for input report
+ *
+ * Set @max_rx_size for I2C RxDMA max input size control feature.
+ *
+ * Return: 0 on success, other error codes on failure.
+ */
+int thc_i2c_set_rx_max_size(struct thc_device *dev, u32 max_rx_size)
+{
+ u32 val;
+ int ret;
+
+ if (!dev)
+ return -EINVAL;
+
+ if (!max_rx_size)
+ return -EOPNOTSUPP;
+
+ ret = regmap_read(dev->thc_regmap, THC_M_PRT_SW_SEQ_STS_OFFSET, &val);
+ if (ret)
+ return ret;
+
+ val |= FIELD_PREP(THC_M_PRT_SPI_ICRRD_OPCODE_I2C_MAX_SIZE, max_rx_size);
+
+ ret = regmap_write(dev->thc_regmap, THC_M_PRT_SPI_ICRRD_OPCODE_OFFSET, val);
+ if (ret)
+ return ret;
+
+ dev->i2c_max_rx_size = max_rx_size;
+
+ return 0;
+}
+EXPORT_SYMBOL_NS_GPL(thc_i2c_set_rx_max_size, "INTEL_THC");
+
+/**
+ * thc_i2c_rx_max_size_enable - Enable I2C Rx max input size control
+ * @dev: The pointer of THC private device context
+ * @enable: Enable max input size control or not
+ *
+ * Enable or disable I2C RxDMA max input size control feature.
+ * Max input size control only can be enabled after max input size
+ * was set by thc_i2c_set_rx_max_size().
+ *
+ * Return: 0 on success, other error codes on failure.
+ */
+int thc_i2c_rx_max_size_enable(struct thc_device *dev, bool enable)
+{
+ u32 mask = THC_M_PRT_SPI_ICRRD_OPCODE_I2C_MAX_SIZE_EN;
+ u32 val = enable ? mask : 0;
+ int ret;
+
+ if (!dev)
+ return -EINVAL;
+
+ if (!dev->i2c_max_rx_size)
+ return -EOPNOTSUPP;
+
+ ret = regmap_write_bits(dev->thc_regmap, THC_M_PRT_SPI_ICRRD_OPCODE_OFFSET, mask, val);
+ if (ret)
+ return ret;
+
+ dev->i2c_max_rx_size_en = enable;
+
+ return 0;
+}
+EXPORT_SYMBOL_NS_GPL(thc_i2c_rx_max_size_enable, "INTEL_THC");
+
+/**
+ * thc_i2c_set_rx_int_delay - Set I2C Rx input interrupt delay value
+ * @dev: The pointer of THC private device context
+ * @delay_us: Interrupt delay value, unit is us
+ *
+ * Set @delay_us for I2C RxDMA input interrupt delay feature.
+ *
+ * Return: 0 on success, other error codes on failure.
+ */
+int thc_i2c_set_rx_int_delay(struct thc_device *dev, u32 delay_us)
+{
+ u32 val;
+ int ret;
+
+ if (!dev)
+ return -EINVAL;
+
+ if (!delay_us)
+ return -EOPNOTSUPP;
+
+ ret = regmap_read(dev->thc_regmap, THC_M_PRT_SW_SEQ_STS_OFFSET, &val);
+ if (ret)
+ return ret;
+
+ /* THC hardware counts at 10us unit */
+ val |= FIELD_PREP(THC_M_PRT_SPI_ICRRD_OPCODE_I2C_INTERVAL, DIV_ROUND_UP(delay_us, 10));
+
+ ret = regmap_write(dev->thc_regmap, THC_M_PRT_SPI_ICRRD_OPCODE_OFFSET, val);
+ if (ret)
+ return ret;
+
+ dev->i2c_int_delay_us = delay_us;
+
+ return 0;
+}
+EXPORT_SYMBOL_NS_GPL(thc_i2c_set_rx_int_delay, "INTEL_THC");
+
+/**
+ * thc_i2c_rx_int_delay_enable - Enable I2C Rx interrupt delay
+ * @dev: The pointer of THC private device context
+ * @enable: Enable interrupt delay or not
+ *
+ * Enable or disable I2C RxDMA input interrupt delay feature.
+ * Input interrupt delay can only be enabled after interrupt delay value
+ * was set by thc_i2c_set_rx_int_delay().
+ *
+ * Return: 0 on success, other error codes on failure.
+ */
+int thc_i2c_rx_int_delay_enable(struct thc_device *dev, bool enable)
+{
+ u32 mask = THC_M_PRT_SPI_ICRRD_OPCODE_I2C_INTERVAL_EN;
+ u32 val = enable ? mask : 0;
+ int ret;
+
+ if (!dev)
+ return -EINVAL;
+
+ if (!dev->i2c_int_delay_us)
+ return -EOPNOTSUPP;
+
+ ret = regmap_write_bits(dev->thc_regmap, THC_M_PRT_SPI_ICRRD_OPCODE_OFFSET, mask, val);
+ if (ret)
+ return ret;
+
+ dev->i2c_int_delay_en = enable;
+
+ return 0;
+}
+EXPORT_SYMBOL_NS_GPL(thc_i2c_rx_int_delay_enable, "INTEL_THC");
+
MODULE_AUTHOR("Xinpeng Sun <xinpeng.sun@intel.com>");
MODULE_AUTHOR("Even Xu <even.xu@intel.com>");
diff --git a/drivers/hid/intel-thc-hid/intel-thc/intel-thc-dev.h b/drivers/hid/intel-thc-hid/intel-thc/intel-thc-dev.h
index 0517fee2c668..0db435335e24 100644
--- a/drivers/hid/intel-thc-hid/intel-thc/intel-thc-dev.h
+++ b/drivers/hid/intel-thc-hid/intel-thc/intel-thc-dev.h
@@ -9,6 +9,7 @@
#include <linux/workqueue.h>
#include "intel-thc-dma.h"
+#include "intel-thc-wot.h"
#define THC_REGMAP_COMMON_OFFSET 0x10
#define THC_REGMAP_MMIO_OFFSET 0x1000
@@ -52,16 +53,21 @@ enum thc_int_type {
* struct thc_device - THC private device struct
* @thc_regmap: MMIO regmap structure for accessing THC registers
* @mmio_addr: MMIO registers address
- * @thc_bus_lock: mutex locker for THC config
- * @port_type: port type of THC port instance
+ * @thc_bus_lock: Mutex locker for THC config
+ * @port_type: Port type of THC port instance
* @pio_int_supported: PIO interrupt supported flag
* @dma_ctx: DMA specific data
- * @write_complete_wait: signal event for DMA write complete
- * @swdma_complete_wait: signal event for SWDMA sequence complete
- * @write_done: bool value that indicates if DMA write is done
- * @swdma_done: bool value that indicates if SWDMA swquence is done
- * @perf_limit: the delay between read operation and write operation
- * @i2c_subip_regs: the copy of THC I2C sub-system registers for resuming restore
+ * @wot: THC Wake-on-Touch data
+ * @write_complete_wait: Signal event for DMA write complete
+ * @swdma_complete_wait: Signal event for SWDMA sequence complete
+ * @write_done: Bool value that indicates if DMA write is done
+ * @swdma_done: Bool value that indicates if SWDMA sequence is done
+ * @perf_limit: The delay between read operation and write operation
+ * @i2c_subip_regs: The copy of THC I2C sub-system registers for resuming restore
+ * @i2c_max_rx_size: I2C Rx transfer max input size
+ * @i2c_int_delay_us: I2C input interrupt delay, unit is us
+ * @i2c_max_rx_size_en: Bool value that indicates I2C max input size control enabled or not
+ * @i2c_int_delay_en: Bool value that indicates I2C input interrupt delay enabled or not
*/
struct thc_device {
struct device *dev;
@@ -73,6 +79,8 @@ struct thc_device {
struct thc_dma_context *dma_ctx;
+ struct thc_wot wot;
+
wait_queue_head_t write_complete_wait;
wait_queue_head_t swdma_complete_wait;
bool write_done;
@@ -81,6 +89,11 @@ struct thc_device {
u32 perf_limit;
u32 *i2c_subip_regs;
+
+ u32 i2c_max_rx_size;
+ u32 i2c_int_delay_us;
+ bool i2c_max_rx_size_en;
+ bool i2c_int_delay_en;
};
struct thc_device *thc_dev_init(struct device *device, void __iomem *mem_addr);
@@ -112,5 +125,9 @@ int thc_i2c_subip_init(struct thc_device *dev, const u32 target_address,
const u32 speed, const u32 hcnt, const u32 lcnt);
int thc_i2c_subip_regs_save(struct thc_device *dev);
int thc_i2c_subip_regs_restore(struct thc_device *dev);
+int thc_i2c_set_rx_max_size(struct thc_device *dev, u32 max_rx_size);
+int thc_i2c_rx_max_size_enable(struct thc_device *dev, bool enable);
+int thc_i2c_set_rx_int_delay(struct thc_device *dev, u32 delay_us);
+int thc_i2c_rx_int_delay_enable(struct thc_device *dev, bool enable);
#endif /* _INTEL_THC_DEV_H_ */
diff --git a/drivers/hid/intel-thc-hid/intel-thc/intel-thc-dma.c b/drivers/hid/intel-thc-hid/intel-thc/intel-thc-dma.c
index 8f97e71df7f4..82b8854843e0 100644
--- a/drivers/hid/intel-thc-hid/intel-thc/intel-thc-dma.c
+++ b/drivers/hid/intel-thc-hid/intel-thc/intel-thc-dma.c
@@ -712,6 +712,28 @@ static int thc_swdma_read_start(struct thc_device *dev, void *write_buff,
thc_reset_dma_settings(dev);
+ /*
+ * Max input size control feature is only available for RxDMA, it must keep disabled
+ * during SWDMA operation, and restore to previous state after SWDMA is done.
+ * Max input size variables in THC device context track hardware state, and keep change
+ * when feature state was changed, so those variables cannot be used to record feature
+ * state after state was changed during SWDMA operation. Here have to use a temp variable
+ * in DMA context to record feature state before SWDMA operation.
+ */
+ if (dev->i2c_max_rx_size_en) {
+ thc_i2c_rx_max_size_enable(dev, false);
+ dev->dma_ctx->rx_max_size_en = true;
+ }
+
+ /*
+ * Interrupt delay feature is in the same situation with max input size control feature,
+ * needs record feature state before SWDMA.
+ */
+ if (dev->i2c_int_delay_en) {
+ thc_i2c_rx_int_delay_enable(dev, false);
+ dev->dma_ctx->rx_int_delay_en = true;
+ }
+
mask = THC_M_PRT_RPRD_CNTRL_SW_THC_SWDMA_I2C_WBC |
THC_M_PRT_RPRD_CNTRL_SW_THC_SWDMA_I2C_RX_DLEN_EN;
val = FIELD_PREP(THC_M_PRT_RPRD_CNTRL_SW_THC_SWDMA_I2C_WBC, write_len) |
@@ -754,6 +776,24 @@ static int thc_swdma_read_completion(struct thc_device *dev)
if (ret)
return ret;
+ /*
+ * Restore max input size control feature to previous state after SWDMA if it was
+ * enabled before SWDMA, and reset temp rx_max_size_en variable for next time.
+ */
+ if (dev->dma_ctx->rx_max_size_en) {
+ thc_i2c_rx_max_size_enable(dev, true);
+ dev->dma_ctx->rx_max_size_en = false;
+ }
+
+ /*
+ * Restore input interrupt delay feature to previous state after SWDMA if it was
+ * enabled before SWDMA, and reset temp rx_int_delay_en variable for next time.
+ */
+ if (dev->dma_ctx->rx_int_delay_en) {
+ thc_i2c_rx_int_delay_enable(dev, true);
+ dev->dma_ctx->rx_int_delay_en = false;
+ }
+
thc_reset_dma_settings(dev);
dma_set_start_bit(dev, &dev->dma_ctx->dma_config[THC_RXDMA2]);
diff --git a/drivers/hid/intel-thc-hid/intel-thc/intel-thc-dma.h b/drivers/hid/intel-thc-hid/intel-thc/intel-thc-dma.h
index ca923ff2bef9..78917400492c 100644
--- a/drivers/hid/intel-thc-hid/intel-thc/intel-thc-dma.h
+++ b/drivers/hid/intel-thc-hid/intel-thc/intel-thc-dma.h
@@ -27,7 +27,7 @@
/**
* THC DMA channels:
- * @THC_RXDMA1: legacy channel, reserved for raw data reading
+ * @THC_RXDMA1: Legacy channel, reserved for raw data reading
* @THC_RXDMA2: DMA to read HID data from touch device
* @THC_TXDMA: DMA to write to touch device
* @THC_SWDMA: SW triggered DMA to write and read from touch device
@@ -42,11 +42,11 @@ enum thc_dma_channel {
/**
* THC DMA Physical Memory Descriptor (PRD)
- * @dest_addr: bit[53:0], destination address in system memory
- * @int_on_completion: bit[63], if set, thc will trigger interrupt to driver
- * @len: bit[87:64], length of this entry
- * @end_of_prd: bit[88], if set, this entry is last one of current PRD table
- * @hw_status: bit[90:89], hw status bits
+ * @dest_addr: Bit[53:0], destination address in system memory
+ * @int_on_completion: Bit[63], if set, thc will trigger interrupt to driver
+ * @len: Bit[87:64], length of this entry
+ * @end_of_prd: Bit[88], if set, this entry is last one of current PRD table
+ * @hw_status: Bit[90:89], hardware status bits
*/
struct thc_prd_entry {
u64 dest_addr : 54;
@@ -88,14 +88,14 @@ struct thc_prd_table {
* struct thc_dma_configuration - THC DMA configure
* @dma_channel: DMA channel for current DMA configuration
* @prd_tbls_dma_handle: DMA buffer handle
- * @dir: direction of DMA for this config
+ * @dir: Direction of DMA for this config
* @prd_tbls: PRD tables for current DMA
- * @sgls: array of pointers to scatter-gather lists
- * @sgls_nent: actual number of entries per sg list
- * @prd_tbl_num: actual number of PRD tables
- * @max_packet_size: size of the buffer needed for 1 DMA message (1 PRD table)
+ * @sgls: Array of pointers to scatter-gather lists
+ * @sgls_nent: Actual number of entries per scatter-gather list
+ * @prd_tbl_num: Actual number of PRD tables
+ * @max_packet_size: Size of the buffer needed for 1 DMA message (1 PRD table)
* @prd_base_addr_high: High 32bits memory address where stores PRD table
- * @prd_base_addr_low: low 32bits memory address where stores PRD table
+ * @prd_base_addr_low: Low 32bits memory address where stores PRD table
* @prd_cntrl: PRD control register value
* @dma_cntrl: DMA control register value
*/
@@ -117,13 +117,21 @@ struct thc_dma_configuration {
u32 dma_cntrl;
};
-/*
- * THC DMA context
- * Store all THC Channel configures
+/**
+ * struct thc_dma_context - THC DMA context
+ * @thc_dma_configuration: Array of all THC Channel configures
+ * @use_write_interrupts: Indicate TxDMA using interrupt or polling
+ * @rx_max_size_en: Temp flag to indicate THC I2C Rx max input size control feature
+ * enabled or not, only be used during SWDMA operation.
+ * @rx_int_delay_en: Temp flag to indicate THC I2C Rx interrupt delay feature
+ * enabled or not, only be used during SWDMA operation.
*/
struct thc_dma_context {
struct thc_dma_configuration dma_config[MAX_THC_DMA_CHANNEL];
u8 use_write_interrupts;
+
+ bool rx_max_size_en;
+ bool rx_int_delay_en;
};
struct thc_device;
diff --git a/drivers/hid/intel-thc-hid/intel-thc/intel-thc-hw.h b/drivers/hid/intel-thc-hid/intel-thc/intel-thc-hw.h
index 6729c4c25dab..413730f8e3f7 100644
--- a/drivers/hid/intel-thc-hid/intel-thc/intel-thc-hw.h
+++ b/drivers/hid/intel-thc-hid/intel-thc/intel-thc-hw.h
@@ -399,6 +399,11 @@
#define THC_M_PRT_SPI_ICRRD_OPCODE_SPI_DIO GENMASK(23, 16)
#define THC_M_PRT_SPI_ICRRD_OPCODE_SPI_QIO GENMASK(15, 8)
+#define THC_M_PRT_SPI_ICRRD_OPCODE_I2C_MAX_SIZE GENMASK(15, 0)
+#define THC_M_PRT_SPI_ICRRD_OPCODE_I2C_INTERVAL GENMASK(23, 16)
+#define THC_M_PRT_SPI_ICRRD_OPCODE_I2C_INTERVAL_EN BIT(30)
+#define THC_M_PRT_SPI_ICRRD_OPCODE_I2C_MAX_SIZE_EN BIT(31)
+
#define THC_M_PRT_INT_EN_SIPE BIT(0)
#define THC_M_PRT_INT_EN_SBO BIT(1)
#define THC_M_PRT_INT_EN_SIDR BIT(2)
diff --git a/drivers/hid/intel-thc-hid/intel-thc/intel-thc-wot.c b/drivers/hid/intel-thc-hid/intel-thc/intel-thc-wot.c
new file mode 100644
index 000000000000..1291b4ea2cd8
--- /dev/null
+++ b/drivers/hid/intel-thc-hid/intel-thc/intel-thc-wot.c
@@ -0,0 +1,94 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (c) 2025 Intel Corporation */
+
+#include <linux/acpi.h>
+#include <linux/pm_wakeirq.h>
+
+#include "intel-thc-dev.h"
+#include "intel-thc-wot.h"
+
+/**
+ * thc_wot_config - Query and configure wake-on-touch feature
+ * @thc_dev: Point to thc_device structure
+ * @gpio_map: Point to ACPI GPIO resource mapping structure
+ *
+ * THC ACPI device only provides _CRS with GpioInt() resources, doesn't contain
+ * _DSD to map this GPIO resource, so this function first registers wake GPIO
+ * mapping manually, then queries wake-on-touch GPIO resource from ACPI,
+ * if it exists and is wake-able, configure driver to enable it, otherwise,
+ * return immediately.
+ * This function will not return error as it doesn't impact major function.
+ */
+void thc_wot_config(struct thc_device *thc_dev, const struct acpi_gpio_mapping *gpio_map)
+{
+ struct acpi_device *adev;
+ struct thc_wot *wot;
+ int ret;
+
+ if (!thc_dev)
+ return;
+
+ adev = ACPI_COMPANION(thc_dev->dev);
+ if (!adev)
+ return;
+
+ wot = &thc_dev->wot;
+
+ ret = acpi_dev_add_driver_gpios(adev, gpio_map);
+ if (ret) {
+ dev_warn(thc_dev->dev, "Can't add wake GPIO resource, ret = %d\n", ret);
+ return;
+ }
+
+ wot->gpio_irq = acpi_dev_gpio_irq_wake_get_by(adev, "wake-on-touch", 0,
+ &wot->gpio_irq_wakeable);
+ if (wot->gpio_irq <= 0) {
+ dev_warn(thc_dev->dev, "Can't find wake GPIO resource\n");
+ return;
+ }
+
+ if (!wot->gpio_irq_wakeable) {
+ dev_warn(thc_dev->dev, "GPIO resource isn't wakeable\n");
+ return;
+ }
+
+ ret = device_init_wakeup(thc_dev->dev, true);
+ if (ret) {
+ dev_warn(thc_dev->dev, "Failed to init wake up.\n");
+ return;
+ }
+
+ ret = dev_pm_set_dedicated_wake_irq(thc_dev->dev, wot->gpio_irq);
+ if (ret) {
+ dev_warn(thc_dev->dev, "Failed to set wake up IRQ.\n");
+ device_init_wakeup(thc_dev->dev, false);
+ }
+}
+EXPORT_SYMBOL_NS_GPL(thc_wot_config, "INTEL_THC");
+
+/**
+ * thc_wot_unconfig - Unconfig wake-on-touch feature
+ * @thc_dev: Point to thc_device structure
+ *
+ * Configure driver to disable wake-on-touch and release ACPI resource.
+ */
+void thc_wot_unconfig(struct thc_device *thc_dev)
+{
+ struct acpi_device *adev;
+
+ if (!thc_dev)
+ return;
+
+ adev = ACPI_COMPANION(thc_dev->dev);
+ if (!adev)
+ return;
+
+ if (thc_dev->wot.gpio_irq_wakeable)
+ device_init_wakeup(thc_dev->dev, false);
+
+ if (thc_dev->wot.gpio_irq > 0) {
+ dev_pm_clear_wake_irq(thc_dev->dev);
+ acpi_dev_remove_driver_gpios(adev);
+ }
+}
+EXPORT_SYMBOL_NS_GPL(thc_wot_unconfig, "INTEL_THC");
diff --git a/drivers/hid/intel-thc-hid/intel-thc/intel-thc-wot.h b/drivers/hid/intel-thc-hid/intel-thc/intel-thc-wot.h
new file mode 100644
index 000000000000..6c700621b242
--- /dev/null
+++ b/drivers/hid/intel-thc-hid/intel-thc/intel-thc-wot.h
@@ -0,0 +1,26 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (c) 2025 Intel Corporation */
+
+#ifndef _INTEL_THC_WOT_H_
+#define _INTEL_THC_WOT_H_
+
+#include <linux/types.h>
+
+#include <linux/gpio/consumer.h>
+
+/**
+ * struct thc_wot - THC Wake-on-Touch data structure
+ * @gpio_irq : GPIO interrupt IRQ number for wake-on-touch
+ * @gpio_irq_wakeable : Indicate GPIO IRQ workable or not
+ */
+struct thc_wot {
+ int gpio_irq;
+ bool gpio_irq_wakeable;
+};
+
+struct thc_device;
+
+void thc_wot_config(struct thc_device *thc_dev, const struct acpi_gpio_mapping *gpio_map);
+void thc_wot_unconfig(struct thc_device *thc_dev);
+
+#endif /* _INTEL_THC_WOT_H_ */
diff --git a/drivers/hid/usbhid/hid-pidff.c b/drivers/hid/usbhid/hid-pidff.c
index 8dfd2c554a27..614a20b62023 100644
--- a/drivers/hid/usbhid/hid-pidff.c
+++ b/drivers/hid/usbhid/hid-pidff.c
@@ -210,9 +210,7 @@ struct pidff_device {
*/
static s32 pidff_clamp(s32 i, struct hid_field *field)
{
- s32 clamped = clamp(i, field->logical_minimum, field->logical_maximum);
- pr_debug("clamped from %d to %d", i, clamped);
- return clamped;
+ return (s32)clamp(i, field->logical_minimum, field->logical_maximum);
}
/*
@@ -229,8 +227,10 @@ static int pidff_rescale(int i, int max, struct hid_field *field)
*/
static int pidff_rescale_signed(int i, struct hid_field *field)
{
- if (i > 0) return i * field->logical_maximum / S16_MAX;
- if (i < 0) return i * field->logical_minimum / S16_MIN;
+ if (i > 0)
+ return i * field->logical_maximum / S16_MAX;
+ if (i < 0)
+ return i * field->logical_minimum / S16_MIN;
return 0;
}
@@ -241,11 +241,11 @@ static u32 pidff_rescale_time(u16 time, struct hid_field *field)
{
u32 scaled_time = time;
int exponent = field->unit_exponent;
- pr_debug("time field exponent: %d\n", exponent);
- for (;exponent < FF_TIME_EXPONENT; exponent++)
+ pr_debug("time field exponent: %d\n", exponent);
+ for (; exponent < FF_TIME_EXPONENT; exponent++)
scaled_time *= 10;
- for (;exponent > FF_TIME_EXPONENT; exponent--)
+ for (; exponent > FF_TIME_EXPONENT; exponent--)
scaled_time /= 10;
pr_debug("time calculated from %d to %d\n", time, scaled_time);
@@ -275,8 +275,8 @@ static void pidff_set_signed(struct pidff_usage *usage, s16 value)
static void pidff_set_time(struct pidff_usage *usage, u16 time)
{
- u32 modified_time = pidff_rescale_time(time, usage->field);
- usage->value[0] = pidff_clamp(modified_time, usage->field);
+ usage->value[0] = pidff_clamp(
+ pidff_rescale_time(time, usage->field), usage->field);
}
static void pidff_set_duration(struct pidff_usage *usage, u16 duration)
@@ -332,6 +332,7 @@ static int pidff_needs_set_envelope(struct ff_envelope *envelope,
struct ff_envelope *old)
{
bool needs_new_envelope;
+
needs_new_envelope = envelope->attack_level != 0 ||
envelope->fade_level != 0 ||
envelope->attack_length != 0 ||
@@ -568,7 +569,7 @@ static void pidff_set_device_control(struct pidff_device *pidff, int field)
hid_dbg(pidff->hid, "DEVICE_CONTROL is a bitmask\n");
/* Clear current bitmask */
- for(i = 0; i < sizeof(pidff_device_control); i++) {
+ for (i = 0; i < sizeof(pidff_device_control); i++) {
index = pidff->control_id[i];
if (index < 1)
continue;
@@ -619,7 +620,7 @@ static void pidff_fetch_pool(struct pidff_device *pidff)
struct hid_device *hid = pidff->hid;
/* Repeat if PID_SIMULTANEOUS_MAX < 2 to make sure it's correct */
- for(i = 0; i < 20; i++) {
+ for (i = 0; i < 20; i++) {
hid_hw_request(hid, pidff->reports[PID_POOL], HID_REQ_GET_REPORT);
hid_hw_wait(hid);
@@ -715,6 +716,7 @@ static void pidff_playback_pid(struct pidff_device *pidff, int pid_id, int n)
static int pidff_playback(struct input_dev *dev, int effect_id, int value)
{
struct pidff_device *pidff = dev->ff->private;
+
pidff_playback_pid(pidff, pidff->pid_id[effect_id], value);
return 0;
}
@@ -849,7 +851,7 @@ static int pidff_upload_effect(struct input_dev *dev, struct ff_effect *effect,
case FF_INERTIA:
case FF_FRICTION:
if (!old) {
- switch(effect->type) {
+ switch (effect->type) {
case FF_SPRING:
type_id = PID_SPRING;
break;
@@ -940,7 +942,7 @@ static int pidff_find_fields(struct pidff_usage *usage, const u8 *table,
struct hid_report *report, int count, int strict)
{
if (!report) {
- pr_debug("pidff_find_fields, null report\n");
+ pr_debug("%s, null report\n", __func__);
return -1;
}
@@ -974,13 +976,11 @@ static int pidff_find_fields(struct pidff_usage *usage, const u8 *table,
pr_debug("Delay field not found, but that's OK\n");
pr_debug("Setting MISSING_DELAY quirk\n");
return_value |= HID_PIDFF_QUIRK_MISSING_DELAY;
- }
- else if (!found && table[k] == pidff_set_condition[PID_PARAM_BLOCK_OFFSET]) {
+ } else if (!found && table[k] == pidff_set_condition[PID_PARAM_BLOCK_OFFSET]) {
pr_debug("PBO field not found, but that's OK\n");
pr_debug("Setting MISSING_PBO quirk\n");
return_value |= HID_PIDFF_QUIRK_MISSING_PBO;
- }
- else if (!found && strict) {
+ } else if (!found && strict) {
pr_debug("failed to locate %d\n", k);
return -1;
}
@@ -1069,7 +1069,7 @@ static struct hid_field *pidff_find_special_field(struct hid_report *report,
int usage, int enforce_min)
{
if (!report) {
- pr_debug("pidff_find_special_field, null report\n");
+ pr_debug("%s, null report\n", __func__);
return NULL;
}
@@ -1081,10 +1081,9 @@ static struct hid_field *pidff_find_special_field(struct hid_report *report,
if (!enforce_min ||
report->field[i]->logical_minimum == 1)
return report->field[i];
- else {
- pr_err("logical_minimum is not 1 as it should be\n");
- return NULL;
- }
+
+ pr_err("logical_minimum is not 1 as it should be\n");
+ return NULL;
}
}
return NULL;
@@ -1207,6 +1206,7 @@ static int pidff_find_effects(struct pidff_device *pidff,
for (i = 0; i < sizeof(pidff_effect_types); i++) {
int pidff_type = pidff->type_id[i];
+
if (pidff->set_effect_type->usage[pidff_type].hid !=
pidff->create_new_effect_type->usage[pidff_type].hid) {
hid_err(pidff->hid,
diff --git a/drivers/hid/usbhid/hid-pidff.h b/drivers/hid/usbhid/hid-pidff.h
index dda571e0a5bd..a53a8b436baa 100644
--- a/drivers/hid/usbhid/hid-pidff.h
+++ b/drivers/hid/usbhid/hid-pidff.h
@@ -9,8 +9,7 @@
/* Delay field (0xA7) missing. Skip it during set effect report upload */
#define HID_PIDFF_QUIRK_MISSING_DELAY BIT(0)
-/* Missing Paramter block offset (0x23). Skip it during SET_CONDITION
- report upload */
+/* Missing Paramter block offset (0x23). Skip it during SET_CONDITION upload */
#define HID_PIDFF_QUIRK_MISSING_PBO BIT(1)
/* Initialise device control field even if logical_minimum != 1 */