mirror of
https://github.com/linux-msm/laptops-kernel.git
synced 2026-08-13 14:19:53 -07:00
Merge tag 'hid-for-linus-2025073101' of git://git.kernel.org/pub/scm/linux/kernel/git/hid/hid
Pull HID updates from Jiri Kosina: - hardening of HID core parser against conversion to 0 bits in s32ton() by buggy/malicious devices (Alan Stern) - fix for potential NULL pointer dereference in hid-apple that could be caused by malicious device with APPLE_MAGIC_BACKLIGHT quirk present triggering overflow in data field (Qasim Ijaz) - support for Wake-on-touch in intel-thc (Even Xu) - support for "Input max input size control" and "Input interrupt delay" I2C features in order to improve compatibility of THC devices with legacy HIDI2C touch devices (Even Xu) - support for Touch Bars on x86 MacBook Pros (Kerem Karabay) - support for XP-PEN Artist 22R Pro (Joshua Goins) - third party trackpart support for MacBookPro15,1 (Aditya Garg) - Apple Magic Keyboard A311[89] USB-C support (Aditya Garg, Grigorii Sokoli) - support for operating modes in amd-sfh (Basavaraj Natikar) - avoid setting up battery timer for Apple and Magicmouse devices without battery (Aditya Garg) - fix for behavior of the hid-mcp2221 driver for !CONFIG_IIO cases (Heiko Schocher) - other assorted fixups and device ID additions * tag 'hid-for-linus-2025073101' of git://git.kernel.org/pub/scm/linux/kernel/git/hid/hid: (54 commits) HID: core: Harden s32ton() against conversion to 0 bits HID: apple: validate feature-report field count to prevent NULL pointer dereference HID: core: Improve the kerneldoc for hid_report_len() selftests/hid: sync python tests to hid-tools 0.10 selftests/hid: sync the python tests to hid-tools 0.8 selftests/hid: run ruff format on the python part HID: magicmouse: use secs_to_jiffies() for battery timeout HID: apple: use secs_to_jiffies() for battery timeout HID: magicmouse: avoid setting up battery timer when not needed HID: apple: avoid setting up battery timer for devices without battery HID: amd_sfh: Enable operating mode HID: uclogic: Add support for XP-PEN Artist 22R Pro HID: rate-limit hid_warn to prevent log flooding HID: replace scnprintf() with sysfs_emit() HID: uclogic: make read-only array reconnect_event static const HID: mcp-2221: Replace manual comparison with min() macro HID: intel-thc-hid: Separate max input size control conditional list HID: mcp2221: set gpio pin mode HID: multitouch: add device ID for Apple Touch Bar HID: multitouch: specify that Apple Touch Bar is direct ...
This commit is contained in:
@@ -188,6 +188,34 @@ Control register.
|
||||
Reset line is controlled by BIOS (or EFI) through ACPI _RST method, driver needs to call this
|
||||
device ACPI _RST method to reset touch IC during initialization.
|
||||
|
||||
2.3 Max input size control
|
||||
--------------------------
|
||||
|
||||
This is a new feature introduced in Panther Lake platform, THC hardware allows driver to set
|
||||
a max input size for RxDMA. After this max size gets set and enabled, for every input report
|
||||
packet reading, THC hardware sequencer will first read incoming input packet size, then compare
|
||||
input packet size with the given max size:
|
||||
|
||||
- if input packet size <= max size, THC continues using input packet size to finish the reading
|
||||
- if input packet size > max size, there is potential input data crash risk during
|
||||
transferring, THC will use max size instead of input packet size for reading
|
||||
|
||||
This feature is used to avoid data corruption which will cause RxDMA buffer overrun issue for
|
||||
I2C bus, and enhance whole system stability.
|
||||
|
||||
2.4 Interrupt delay
|
||||
-------------------
|
||||
|
||||
Because of MCU performance limitation, some touch devices cannot de-assert interrupt pin
|
||||
immediately after input data is transferred, which cause an interrupt toggle delay. But THC
|
||||
always detects next interrupt immediately after last input interrupt is handled. In this
|
||||
case, the delayed interrupt de-assertion will be recognized as a new interrupt signal by THC,
|
||||
and causes THC to start an input report reading spuriously.
|
||||
|
||||
In order to avoid this situation, THC introduced interrupt delay new feature in Panther Lake
|
||||
platform, where THC allows driver to set an interrupt delay. After this feature is enabled,
|
||||
THC will delay this given time for next interrupt detection.
|
||||
|
||||
3. High level concept
|
||||
=====================
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -79,6 +79,7 @@ enum sensor_idx {
|
||||
accel_idx = 0,
|
||||
gyro_idx = 1,
|
||||
mag_idx = 2,
|
||||
op_idx = 15,
|
||||
als_idx = 19
|
||||
};
|
||||
|
||||
|
||||
+145
-99
@@ -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,9 +542,17 @@ 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 },
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -2809,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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
+17
-13
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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 (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 (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) &&
|
||||
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");
|
||||
|
||||
+100
-8
@@ -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)
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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) },
|
||||
{ }
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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.
|
||||
@@ -1845,6 +1967,16 @@ int uclogic_params_init(struct uclogic_params *params,
|
||||
uclogic_params_init_invalid(&p);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 */
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user