mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-09-04 20:19:47 +08:00
hid-for-linus-2025073101
-----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEL65usyKPHcrRDEicpmLzj2vtYEkFAmiL2DAACgkQpmLzj2vt YEk9aRAApXAYs/LNZ6hS2FvqxSKJhThLEm4sib6CvdQ82Er92aqrZEutkpb8Rq0/ KMPLYTv9QsZgFKilZJnxIRwZRpy37C7SGO8Y3PSARpakxpCPe76RyqcY+DghrB9+ kBRUzfDq9JR8RM8lcxw5dgEjgI3cz/5gS8OFh/LOVqe2nqub3U3Dr2kQkDE3DSiG BqIPhIG//TW0al6IxJQVL59egzVqzzqcgK/efBwT7WjToaCjXuZTClDiKASVLcmW p/xvsPjIBeVuEdOTfboiHowOs3RyXa3zWlHS76/x9JXVDPOrPcleJyoxEedU4BBG selhkdVEYcCOYMlzz7/p1BrIkkpczWfye5rSGQ05qmOeApMAxicKRp0DfTLm0EGa bdmDLIncSBRBb5iATrRS+rQcV6PSzLCaB9+rGiWS/EQPFCKh54SZSNvl5rw0WCHY +b9zmxmr2KG7B8eQQXx0/x6RNCC3gANqkVO4+TXamcGhJaoW2M0+xT9tzid0sL+S Y7t5C8T4KoI4dc2be76KNs/LlR6F5LK1E0HTkapdG+ZoiLc/PsqK0pnGc0aXd+/z Ee246MZEMsURgOEA68dEm4XBdh2xp9xVZIsZtaWcfSSQZJnfpx89v9Tl4MUlfqzj 8BPLeYxxg9gxfxpGcP+oGMjXbeKDjSbmRJroOP4jw/WdPZ2rs0s= =kYcB -----END PGP SIGNATURE----- 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:
commit
b80a75cf69
@ -188,6 +188,34 @@ Control register.
|
|||||||
Reset line is controlled by BIOS (or EFI) through ACPI _RST method, driver needs to call this
|
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.
|
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
|
3. High level concept
|
||||||
=====================
|
=====================
|
||||||
|
|
||||||
|
@ -771,6 +771,7 @@ config HID_MULTITOUCH
|
|||||||
Say Y here if you have one of the following devices:
|
Say Y here if you have one of the following devices:
|
||||||
- 3M PCT touch screens
|
- 3M PCT touch screens
|
||||||
- ActionStar dual touch panels
|
- ActionStar dual touch panels
|
||||||
|
- Apple Touch Bar on x86 MacBook Pros
|
||||||
- Atmel panels
|
- Atmel panels
|
||||||
- Cando dual touch panels
|
- Cando dual touch panels
|
||||||
- Chunghwa panels
|
- Chunghwa panels
|
||||||
|
@ -146,6 +146,8 @@ static const char *get_sensor_name(int idx)
|
|||||||
return "gyroscope";
|
return "gyroscope";
|
||||||
case mag_idx:
|
case mag_idx:
|
||||||
return "magnetometer";
|
return "magnetometer";
|
||||||
|
case op_idx:
|
||||||
|
return "operating-mode";
|
||||||
case als_idx:
|
case als_idx:
|
||||||
case ACS_IDX: /* ambient color sensor */
|
case ACS_IDX: /* ambient color sensor */
|
||||||
return "ALS";
|
return "ALS";
|
||||||
@ -243,6 +245,20 @@ int amd_sfh_hid_client_init(struct amd_mp2_dev *privdata)
|
|||||||
rc = -ENOMEM;
|
rc = -ENOMEM;
|
||||||
goto cleanup;
|
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_sts[i] = SENSOR_DISABLED;
|
||||||
cl_data->sensor_requested_cnt[i] = 0;
|
cl_data->sensor_requested_cnt[i] = 0;
|
||||||
cl_data->cur_hid_dev = i;
|
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++) {
|
for (i = 0; i < cl_data->num_hid_devices; i++) {
|
||||||
cl_data->cur_hid_dev = 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) {
|
if (cl_data->sensor_sts[i] == SENSOR_ENABLED) {
|
||||||
rc = amdtp_hid_probe(i, cl_data);
|
rc = amdtp_hid_probe(i, cl_data);
|
||||||
if (rc)
|
if (rc)
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
#ifndef AMDSFH_HID_H
|
#ifndef AMDSFH_HID_H
|
||||||
#define 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_VENDOR 0x1022
|
||||||
#define AMD_SFH_HID_PRODUCT 0x0001
|
#define AMD_SFH_HID_PRODUCT 0x0001
|
||||||
|
|
||||||
|
@ -29,6 +29,7 @@
|
|||||||
#define ACEL_EN BIT(0)
|
#define ACEL_EN BIT(0)
|
||||||
#define GYRO_EN BIT(1)
|
#define GYRO_EN BIT(1)
|
||||||
#define MAGNO_EN BIT(2)
|
#define MAGNO_EN BIT(2)
|
||||||
|
#define OP_EN BIT(15)
|
||||||
#define HPD_EN BIT(16)
|
#define HPD_EN BIT(16)
|
||||||
#define ALS_EN BIT(19)
|
#define ALS_EN BIT(19)
|
||||||
#define ACS_EN BIT(22)
|
#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)
|
if (MAGNO_EN & activestatus)
|
||||||
sensor_id[num_of_sensors++] = mag_idx;
|
sensor_id[num_of_sensors++] = mag_idx;
|
||||||
|
|
||||||
|
if (OP_EN & activestatus)
|
||||||
|
sensor_id[num_of_sensors++] = op_idx;
|
||||||
|
|
||||||
if (ALS_EN & activestatus)
|
if (ALS_EN & activestatus)
|
||||||
sensor_id[num_of_sensors++] = als_idx;
|
sensor_id[num_of_sensors++] = als_idx;
|
||||||
|
|
||||||
|
@ -79,6 +79,7 @@ enum sensor_idx {
|
|||||||
accel_idx = 0,
|
accel_idx = 0,
|
||||||
gyro_idx = 1,
|
gyro_idx = 1,
|
||||||
mag_idx = 2,
|
mag_idx = 2,
|
||||||
|
op_idx = 15,
|
||||||
als_idx = 19
|
als_idx = 19
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -30,7 +30,7 @@
|
|||||||
#include "hid-ids.h"
|
#include "hid-ids.h"
|
||||||
|
|
||||||
#define APPLE_RDESC_JIS BIT(0)
|
#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)
|
#define APPLE_HAS_FN BIT(2)
|
||||||
/* BIT(3) reserved, was: APPLE_HIDDEV */
|
/* BIT(3) reserved, was: APPLE_HIDDEV */
|
||||||
#define APPLE_ISO_TILDE_QUIRK BIT(4)
|
#define APPLE_ISO_TILDE_QUIRK BIT(4)
|
||||||
@ -42,11 +42,13 @@
|
|||||||
#define APPLE_BACKLIGHT_CTL BIT(10)
|
#define APPLE_BACKLIGHT_CTL BIT(10)
|
||||||
#define APPLE_IS_NON_APPLE BIT(11)
|
#define APPLE_IS_NON_APPLE BIT(11)
|
||||||
#define APPLE_MAGIC_BACKLIGHT BIT(12)
|
#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 HID_COUNTRY_INTERNATIONAL_ISO 13
|
||||||
#define APPLE_BATTERY_TIMEOUT_MS 60000
|
#define APPLE_BATTERY_TIMEOUT_SEC 60
|
||||||
|
|
||||||
#define HID_USAGE_MAGIC_BL 0xff00000f
|
#define HID_USAGE_MAGIC_BL 0xff00000f
|
||||||
#define APPLE_MAGIC_REPORT_ID_POWER 3
|
#define APPLE_MAGIC_REPORT_ID_POWER 3
|
||||||
@ -55,7 +57,7 @@
|
|||||||
static unsigned int fnmode = 3;
|
static unsigned int fnmode = 3;
|
||||||
module_param(fnmode, uint, 0644);
|
module_param(fnmode, uint, 0644);
|
||||||
MODULE_PARM_DESC(fnmode, "Mode of fn key on Apple keyboards (0 = disabled, "
|
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;
|
static int iso_layout = -1;
|
||||||
module_param(iso_layout, int, 0644);
|
module_param(iso_layout, int, 0644);
|
||||||
@ -89,6 +91,19 @@ struct apple_sc_backlight {
|
|||||||
struct hid_device *hdev;
|
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 apple_magic_backlight {
|
||||||
struct led_classdev cdev;
|
struct led_classdev cdev;
|
||||||
struct hid_report *brightness;
|
struct hid_report *brightness;
|
||||||
@ -108,7 +123,7 @@ struct apple_sc {
|
|||||||
struct apple_key_translation {
|
struct apple_key_translation {
|
||||||
u16 from;
|
u16 from;
|
||||||
u16 to;
|
u16 to;
|
||||||
u8 flags;
|
unsigned long flags;
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct apple_key_translation magic_keyboard_alu_fn_keys[] = {
|
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 {
|
static const struct apple_key_translation magic_keyboard_2021_and_2024_fn_keys[] = {
|
||||||
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[] = {
|
|
||||||
{ KEY_BACKSPACE, KEY_DELETE },
|
{ KEY_BACKSPACE, KEY_DELETE },
|
||||||
{ KEY_ENTER, KEY_INSERT },
|
{ KEY_ENTER, KEY_INSERT },
|
||||||
{ KEY_F1, KEY_BRIGHTNESSDOWN, APPLE_FLAG_FKEY },
|
{ 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[] = {
|
static const struct apple_key_translation macbookpro_no_esc_fn_keys[] = {
|
||||||
{ KEY_BACKSPACE, KEY_DELETE },
|
{ KEY_BACKSPACE, KEY_DELETE },
|
||||||
{ KEY_ENTER, KEY_INSERT },
|
{ KEY_ENTER, KEY_INSERT },
|
||||||
{ KEY_GRAVE, KEY_ESC },
|
{ KEY_GRAVE, KEY_ESC, APPLE_FLAG_TB_FKEY },
|
||||||
{ KEY_1, KEY_F1 },
|
{ KEY_1, KEY_F1, APPLE_FLAG_TB_FKEY },
|
||||||
{ KEY_2, KEY_F2 },
|
{ KEY_2, KEY_F2, APPLE_FLAG_TB_FKEY },
|
||||||
{ KEY_3, KEY_F3 },
|
{ KEY_3, KEY_F3, APPLE_FLAG_TB_FKEY },
|
||||||
{ KEY_4, KEY_F4 },
|
{ KEY_4, KEY_F4, APPLE_FLAG_TB_FKEY },
|
||||||
{ KEY_5, KEY_F5 },
|
{ KEY_5, KEY_F5, APPLE_FLAG_TB_FKEY },
|
||||||
{ KEY_6, KEY_F6 },
|
{ KEY_6, KEY_F6, APPLE_FLAG_TB_FKEY },
|
||||||
{ KEY_7, KEY_F7 },
|
{ KEY_7, KEY_F7, APPLE_FLAG_TB_FKEY },
|
||||||
{ KEY_8, KEY_F8 },
|
{ KEY_8, KEY_F8, APPLE_FLAG_TB_FKEY },
|
||||||
{ KEY_9, KEY_F9 },
|
{ KEY_9, KEY_F9, APPLE_FLAG_TB_FKEY },
|
||||||
{ KEY_0, KEY_F10 },
|
{ KEY_0, KEY_F10, APPLE_FLAG_TB_FKEY },
|
||||||
{ KEY_MINUS, KEY_F11 },
|
{ KEY_MINUS, KEY_F11, APPLE_FLAG_TB_FKEY },
|
||||||
{ KEY_EQUAL, KEY_F12 },
|
{ KEY_EQUAL, KEY_F12, APPLE_FLAG_TB_FKEY },
|
||||||
{ KEY_UP, KEY_PAGEUP },
|
{ KEY_UP, KEY_PAGEUP },
|
||||||
{ KEY_DOWN, KEY_PAGEDOWN },
|
{ KEY_DOWN, KEY_PAGEDOWN },
|
||||||
{ KEY_LEFT, KEY_HOME },
|
{ 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[] = {
|
static const struct apple_key_translation macbookpro_dedicated_esc_fn_keys[] = {
|
||||||
{ KEY_BACKSPACE, KEY_DELETE },
|
{ KEY_BACKSPACE, KEY_DELETE },
|
||||||
{ KEY_ENTER, KEY_INSERT },
|
{ KEY_ENTER, KEY_INSERT },
|
||||||
{ KEY_1, KEY_F1 },
|
{ KEY_1, KEY_F1, APPLE_FLAG_TB_FKEY },
|
||||||
{ KEY_2, KEY_F2 },
|
{ KEY_2, KEY_F2, APPLE_FLAG_TB_FKEY },
|
||||||
{ KEY_3, KEY_F3 },
|
{ KEY_3, KEY_F3, APPLE_FLAG_TB_FKEY },
|
||||||
{ KEY_4, KEY_F4 },
|
{ KEY_4, KEY_F4, APPLE_FLAG_TB_FKEY },
|
||||||
{ KEY_5, KEY_F5 },
|
{ KEY_5, KEY_F5, APPLE_FLAG_TB_FKEY },
|
||||||
{ KEY_6, KEY_F6 },
|
{ KEY_6, KEY_F6, APPLE_FLAG_TB_FKEY },
|
||||||
{ KEY_7, KEY_F7 },
|
{ KEY_7, KEY_F7, APPLE_FLAG_TB_FKEY },
|
||||||
{ KEY_8, KEY_F8 },
|
{ KEY_8, KEY_F8, APPLE_FLAG_TB_FKEY },
|
||||||
{ KEY_9, KEY_F9 },
|
{ KEY_9, KEY_F9, APPLE_FLAG_TB_FKEY },
|
||||||
{ KEY_0, KEY_F10 },
|
{ KEY_0, KEY_F10, APPLE_FLAG_TB_FKEY },
|
||||||
{ KEY_MINUS, KEY_F11 },
|
{ KEY_MINUS, KEY_F11, APPLE_FLAG_TB_FKEY },
|
||||||
{ KEY_EQUAL, KEY_F12 },
|
{ KEY_EQUAL, KEY_F12, APPLE_FLAG_TB_FKEY },
|
||||||
{ KEY_UP, KEY_PAGEUP },
|
{ KEY_UP, KEY_PAGEUP },
|
||||||
{ KEY_DOWN, KEY_PAGEDOWN },
|
{ KEY_DOWN, KEY_PAGEDOWN },
|
||||||
{ KEY_LEFT, KEY_HOME },
|
{ 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;
|
unsigned int real_fnmode;
|
||||||
|
|
||||||
if (fnmode == 3) {
|
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 {
|
} else {
|
||||||
real_fnmode = fnmode;
|
real_fnmode = fnmode;
|
||||||
}
|
}
|
||||||
@ -466,42 +472,54 @@ static int hidinput_apple_event(struct hid_device *hid, struct input_dev *input,
|
|||||||
asc->fn_on = !!value;
|
asc->fn_on = !!value;
|
||||||
|
|
||||||
if (real_fnmode) {
|
if (real_fnmode) {
|
||||||
if (hid->product == USB_DEVICE_ID_APPLE_ALU_WIRELESS_ANSI ||
|
switch (hid->product) {
|
||||||
hid->product == USB_DEVICE_ID_APPLE_ALU_WIRELESS_ISO ||
|
case USB_DEVICE_ID_APPLE_ALU_WIRELESS_ANSI:
|
||||||
hid->product == USB_DEVICE_ID_APPLE_ALU_WIRELESS_JIS ||
|
case USB_DEVICE_ID_APPLE_ALU_WIRELESS_ISO:
|
||||||
hid->product == USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ANSI ||
|
case USB_DEVICE_ID_APPLE_ALU_WIRELESS_JIS:
|
||||||
hid->product == USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ISO ||
|
case USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ANSI:
|
||||||
hid->product == USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_JIS ||
|
case USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ISO:
|
||||||
hid->product == USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ANSI ||
|
case USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_JIS:
|
||||||
hid->product == USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ISO ||
|
case USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ANSI:
|
||||||
hid->product == USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_JIS)
|
case USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ISO:
|
||||||
|
case USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_JIS:
|
||||||
table = magic_keyboard_alu_fn_keys;
|
table = magic_keyboard_alu_fn_keys;
|
||||||
else if (hid->product == USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_2015 ||
|
break;
|
||||||
hid->product == USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_NUMPAD_2015)
|
case USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_2015:
|
||||||
|
case USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_NUMPAD_2015:
|
||||||
table = magic_keyboard_2015_fn_keys;
|
table = magic_keyboard_2015_fn_keys;
|
||||||
else if (hid->product == USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_2021 ||
|
break;
|
||||||
hid->product == USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_2024 ||
|
case USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_2021:
|
||||||
hid->product == USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_FINGERPRINT_2021 ||
|
case USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_FINGERPRINT_2021:
|
||||||
hid->product == USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_NUMPAD_2021)
|
case USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_NUMPAD_2021:
|
||||||
table = apple2021_fn_keys;
|
case USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_2024:
|
||||||
else if (hid->product == USB_DEVICE_ID_APPLE_WELLSPRINGT2_J132 ||
|
case USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_FINGERPRINT_2024:
|
||||||
hid->product == USB_DEVICE_ID_APPLE_WELLSPRINGT2_J680 ||
|
case USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_NUMPAD_2024:
|
||||||
hid->product == USB_DEVICE_ID_APPLE_WELLSPRINGT2_J213)
|
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;
|
table = macbookpro_no_esc_fn_keys;
|
||||||
else if (hid->product == USB_DEVICE_ID_APPLE_WELLSPRINGT2_J214K ||
|
break;
|
||||||
hid->product == USB_DEVICE_ID_APPLE_WELLSPRINGT2_J223 ||
|
case USB_DEVICE_ID_APPLE_WELLSPRINGT2_J152F:
|
||||||
hid->product == 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;
|
table = macbookpro_dedicated_esc_fn_keys;
|
||||||
else if (hid->product == USB_DEVICE_ID_APPLE_WELLSPRINGT2_J140K ||
|
break;
|
||||||
hid->product == USB_DEVICE_ID_APPLE_WELLSPRINGT2_J230K)
|
case USB_DEVICE_ID_APPLE_WELLSPRINGT2_J140K:
|
||||||
|
case USB_DEVICE_ID_APPLE_WELLSPRINGT2_J230K:
|
||||||
table = apple_fn_keys;
|
table = apple_fn_keys;
|
||||||
else if (hid->product >= USB_DEVICE_ID_APPLE_WELLSPRING4_ANSI &&
|
break;
|
||||||
|
default:
|
||||||
|
if (hid->product >= USB_DEVICE_ID_APPLE_WELLSPRING4_ANSI &&
|
||||||
hid->product <= USB_DEVICE_ID_APPLE_WELLSPRING4A_JIS)
|
hid->product <= USB_DEVICE_ID_APPLE_WELLSPRING4A_JIS)
|
||||||
table = macbookair_fn_keys;
|
table = macbookair_fn_keys;
|
||||||
else if (hid->product < 0x21d || hid->product >= 0x300)
|
else if (hid->product < 0x21d || hid->product >= 0x300)
|
||||||
table = powerbook_fn_keys;
|
table = powerbook_fn_keys;
|
||||||
else
|
else
|
||||||
table = apple_fn_keys;
|
table = apple_fn_keys;
|
||||||
|
}
|
||||||
|
|
||||||
trans = apple_find_translation(table, code);
|
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;
|
do_translate = asc->fn_on;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
/* should never happen */
|
/* case 4 */
|
||||||
do_translate = false;
|
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 {
|
} else {
|
||||||
do_translate = asc->fn_on;
|
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) {
|
if (apple_fetch_battery(hdev) == 0) {
|
||||||
mod_timer(&asc->battery_timer,
|
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, apple_iso_keyboard);
|
||||||
apple_setup_key_translation(input, magic_keyboard_alu_fn_keys);
|
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, 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_no_esc_fn_keys);
|
||||||
apple_setup_key_translation(input, macbookpro_dedicated_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->brightness = report_enum->report_id_hash[APPLE_MAGIC_REPORT_ID_BRIGHTNESS];
|
||||||
backlight->power = report_enum->report_id_hash[APPLE_MAGIC_REPORT_ID_POWER];
|
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;
|
return -ENODEV;
|
||||||
|
|
||||||
backlight->cdev.name = ":white:" LED_FUNCTION_KBD_BACKLIGHT;
|
backlight->cdev.name = ":white:" LED_FUNCTION_KBD_BACKLIGHT;
|
||||||
@ -933,10 +960,12 @@ static int apple_probe(struct hid_device *hdev,
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (quirks & APPLE_RDESC_BATTERY) {
|
||||||
timer_setup(&asc->battery_timer, apple_battery_timer_tick, 0);
|
timer_setup(&asc->battery_timer, apple_battery_timer_tick, 0);
|
||||||
mod_timer(&asc->battery_timer,
|
mod_timer(&asc->battery_timer,
|
||||||
jiffies + msecs_to_jiffies(APPLE_BATTERY_TIMEOUT_MS));
|
jiffies + secs_to_jiffies(APPLE_BATTERY_TIMEOUT_SEC));
|
||||||
apple_fetch_battery(hdev);
|
apple_fetch_battery(hdev);
|
||||||
|
}
|
||||||
|
|
||||||
if (quirks & APPLE_BACKLIGHT_CTL)
|
if (quirks & APPLE_BACKLIGHT_CTL)
|
||||||
apple_backlight_init(hdev);
|
apple_backlight_init(hdev);
|
||||||
@ -950,7 +979,9 @@ static int apple_probe(struct hid_device *hdev,
|
|||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
out_err:
|
out_err:
|
||||||
|
if (quirks & APPLE_RDESC_BATTERY)
|
||||||
timer_delete_sync(&asc->battery_timer);
|
timer_delete_sync(&asc->battery_timer);
|
||||||
|
|
||||||
hid_hw_stop(hdev);
|
hid_hw_stop(hdev);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@ -959,6 +990,7 @@ static void apple_remove(struct hid_device *hdev)
|
|||||||
{
|
{
|
||||||
struct apple_sc *asc = hid_get_drvdata(hdev);
|
struct apple_sc *asc = hid_get_drvdata(hdev);
|
||||||
|
|
||||||
|
if (asc->quirks & APPLE_RDESC_BATTERY)
|
||||||
timer_delete_sync(&asc->battery_timer);
|
timer_delete_sync(&asc->battery_timer);
|
||||||
|
|
||||||
hid_hw_stop(hdev);
|
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),
|
{ 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 },
|
.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),
|
{ 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),
|
{ 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),
|
{ 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),
|
{ 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),
|
{ 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),
|
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRINGT2_J230K),
|
||||||
.driver_data = APPLE_HAS_FN | APPLE_ISO_TILDE_QUIRK },
|
.driver_data = APPLE_HAS_FN | APPLE_ISO_TILDE_QUIRK },
|
||||||
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRINGT2_J152F),
|
{ 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),
|
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ANSI),
|
||||||
.driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN },
|
.driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN },
|
||||||
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ISO),
|
{ 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 },
|
.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),
|
{ HID_BLUETOOTH_DEVICE(BT_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_2021),
|
||||||
.driver_data = APPLE_HAS_FN | APPLE_ISO_TILDE_QUIRK },
|
.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),
|
{ 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 },
|
.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),
|
{ 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 },
|
.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),
|
{ HID_BLUETOOTH_DEVICE(BT_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_NUMPAD_2021),
|
||||||
.driver_data = APPLE_HAS_FN | APPLE_ISO_TILDE_QUIRK },
|
.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),
|
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_TOUCHBAR_BACKLIGHT),
|
||||||
.driver_data = APPLE_MAGIC_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)
|
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)
|
if (a && a != -1)
|
||||||
return value < 0 ? 1 << (n - 1) : (1 << (n - 1)) - 1;
|
return value < 0 ? 1 << (n - 1) : (1 << (n - 1)) - 1;
|
||||||
return value & ((1 << n) - 1);
|
return value & ((1 << n) - 1);
|
||||||
@ -659,9 +663,9 @@ static int hid_parser_main(struct hid_parser *parser, struct hid_item *item)
|
|||||||
default:
|
default:
|
||||||
if (item->tag >= HID_MAIN_ITEM_TAG_RESERVED_MIN &&
|
if (item->tag >= HID_MAIN_ITEM_TAG_RESERVED_MIN &&
|
||||||
item->tag <= HID_MAIN_ITEM_TAG_RESERVED_MAX)
|
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
|
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;
|
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);
|
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);
|
hdev->bus, hdev->group, hdev->vendor, hdev->product);
|
||||||
}
|
}
|
||||||
static DEVICE_ATTR_RO(modalias);
|
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) {
|
if (!list->hdev || !list->hdev->debug) {
|
||||||
ret = -EIO;
|
ret = -EIO;
|
||||||
set_current_state(TASK_RUNNING);
|
__set_current_state(TASK_RUNNING);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -167,6 +167,12 @@
|
|||||||
#define USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_JIS 0x0257
|
#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_2015 0x0267
|
||||||
#define USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_NUMPAD_2015 0x026c
|
#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_ANSI 0x0290
|
||||||
#define USB_DEVICE_ID_APPLE_WELLSPRING8_ISO 0x0291
|
#define USB_DEVICE_ID_APPLE_WELLSPRING8_ISO 0x0291
|
||||||
#define USB_DEVICE_ID_APPLE_WELLSPRING8_JIS 0x0292
|
#define USB_DEVICE_ID_APPLE_WELLSPRING8_JIS 0x0292
|
||||||
@ -176,6 +182,7 @@
|
|||||||
#define USB_DEVICE_ID_APPLE_WELLSPRINGT2_J140K 0x027a
|
#define USB_DEVICE_ID_APPLE_WELLSPRINGT2_J140K 0x027a
|
||||||
#define USB_DEVICE_ID_APPLE_WELLSPRINGT2_J132 0x027b
|
#define USB_DEVICE_ID_APPLE_WELLSPRINGT2_J132 0x027b
|
||||||
#define USB_DEVICE_ID_APPLE_WELLSPRINGT2_J680 0x027c
|
#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_J213 0x027d
|
||||||
#define USB_DEVICE_ID_APPLE_WELLSPRINGT2_J214K 0x027e
|
#define USB_DEVICE_ID_APPLE_WELLSPRINGT2_J214K 0x027e
|
||||||
#define USB_DEVICE_ID_APPLE_WELLSPRINGT2_J223 0x027f
|
#define USB_DEVICE_ID_APPLE_WELLSPRINGT2_J223 0x027f
|
||||||
@ -188,10 +195,6 @@
|
|||||||
#define USB_DEVICE_ID_APPLE_IRCONTROL3 0x8241
|
#define USB_DEVICE_ID_APPLE_IRCONTROL3 0x8241
|
||||||
#define USB_DEVICE_ID_APPLE_IRCONTROL4 0x8242
|
#define USB_DEVICE_ID_APPLE_IRCONTROL4 0x8242
|
||||||
#define USB_DEVICE_ID_APPLE_IRCONTROL5 0x8243
|
#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_BACKLIGHT 0x8102
|
||||||
#define USB_DEVICE_ID_APPLE_TOUCHBAR_DISPLAY 0x8302
|
#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 0x1212
|
||||||
#define USB_DEVICE_ID_PXN_V12_LITE 0x1112
|
#define USB_DEVICE_ID_PXN_V12_LITE 0x1112
|
||||||
#define USB_DEVICE_ID_PXN_V12_LITE_2 0x1211
|
#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_VENDOR_ID_LOGITECH 0x046d
|
||||||
#define USB_DEVICE_ID_LOGITECH_Z_10_SPK 0x0a07
|
#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_S 0x0909
|
||||||
#define USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO_PRO_SW 0x0933
|
#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_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_G5 0x0074
|
||||||
#define USB_DEVICE_ID_UGEE_TABLET_EX07S 0x0071
|
#define USB_DEVICE_ID_UGEE_TABLET_EX07S 0x0071
|
||||||
#define USB_DEVICE_ID_UGEE_TABLET_RAINBOW_CV720 0x0055
|
#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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
count = scnprintf(buf, PAGE_SIZE, "%u\n", entry->wdata.combine);
|
count = sysfs_emit(buf, "%u\n", entry->wdata.combine);
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1009,7 +1009,7 @@ static ssize_t lg4ff_range_show(struct device *dev, struct device_attribute *att
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
count = scnprintf(buf, PAGE_SIZE, "%u\n", entry->wdata.range);
|
count = sysfs_emit(buf, "%u\n", entry->wdata.range);
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1073,7 +1073,7 @@ static ssize_t lg4ff_real_id_show(struct device *dev, struct device_attribute *a
|
|||||||
return 0;
|
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;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -60,7 +60,7 @@ MODULE_PARM_DESC(report_undeciphered, "Report undeciphered multi-touch state fie
|
|||||||
#define MOUSE_REPORT_ID 0x29
|
#define MOUSE_REPORT_ID 0x29
|
||||||
#define MOUSE2_REPORT_ID 0x12
|
#define MOUSE2_REPORT_ID 0x12
|
||||||
#define DOUBLE_REPORT_ID 0xf7
|
#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
|
/* These definitions are not precise, but they're close enough. (Bits
|
||||||
* 0x03 seem to indicate the aspect ratio of the touch, bits 0x70 seem
|
* 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);
|
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)
|
static int magicmouse_fetch_battery(struct hid_device *hdev)
|
||||||
{
|
{
|
||||||
#ifdef CONFIG_HID_BATTERY_STRENGTH
|
#ifdef CONFIG_HID_BATTERY_STRENGTH
|
||||||
struct hid_report_enum *report_enum;
|
struct hid_report_enum *report_enum;
|
||||||
struct hid_report *report;
|
struct hid_report *report;
|
||||||
|
|
||||||
if (!hdev->battery || hdev->vendor != USB_VENDOR_ID_APPLE ||
|
if (!hdev->battery ||
|
||||||
(hdev->product != USB_DEVICE_ID_APPLE_MAGICMOUSE2 &&
|
(!is_usb_magicmouse2(hdev->vendor, hdev->product) &&
|
||||||
hdev->product != USB_DEVICE_ID_APPLE_MAGICMOUSE2_USBC &&
|
!is_usb_magictrackpad2(hdev->vendor, hdev->product)))
|
||||||
hdev->product != USB_DEVICE_ID_APPLE_MAGICTRACKPAD2 &&
|
|
||||||
hdev->product != USB_DEVICE_ID_APPLE_MAGICTRACKPAD2_USBC))
|
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
report_enum = &hdev->report_enum[hdev->battery_report_type];
|
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) {
|
if (magicmouse_fetch_battery(hdev) == 0) {
|
||||||
mod_timer(&msc->battery_timer,
|
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;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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);
|
timer_setup(&msc->battery_timer, magicmouse_battery_timer_tick, 0);
|
||||||
mod_timer(&msc->battery_timer,
|
mod_timer(&msc->battery_timer,
|
||||||
jiffies + msecs_to_jiffies(USB_BATTERY_TIMEOUT_MS));
|
jiffies + secs_to_jiffies(USB_BATTERY_TIMEOUT_SEC));
|
||||||
magicmouse_fetch_battery(hdev);
|
magicmouse_fetch_battery(hdev);
|
||||||
|
}
|
||||||
|
|
||||||
if (id->vendor == USB_VENDOR_ID_APPLE &&
|
if (is_usb_magicmouse2(id->vendor, id->product) ||
|
||||||
(id->product == USB_DEVICE_ID_APPLE_MAGICMOUSE2 ||
|
(is_usb_magictrackpad2(id->vendor, id->product) &&
|
||||||
id->product == USB_DEVICE_ID_APPLE_MAGICMOUSE2_USBC ||
|
hdev->type != HID_TYPE_USBMOUSE))
|
||||||
((id->product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2 ||
|
|
||||||
id->product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2_USBC) &&
|
|
||||||
hdev->type != HID_TYPE_USBMOUSE)))
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (!msc->input) {
|
if (!msc->input) {
|
||||||
@ -936,7 +950,10 @@ static int magicmouse_probe(struct hid_device *hdev,
|
|||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
err_stop_hw:
|
err_stop_hw:
|
||||||
|
if (is_usb_magicmouse2(id->vendor, id->product) ||
|
||||||
|
is_usb_magictrackpad2(id->vendor, id->product))
|
||||||
timer_delete_sync(&msc->battery_timer);
|
timer_delete_sync(&msc->battery_timer);
|
||||||
|
|
||||||
hid_hw_stop(hdev);
|
hid_hw_stop(hdev);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@ -947,6 +964,8 @@ static void magicmouse_remove(struct hid_device *hdev)
|
|||||||
|
|
||||||
if (msc) {
|
if (msc) {
|
||||||
cancel_delayed_work_sync(&msc->work);
|
cancel_delayed_work_sync(&msc->work);
|
||||||
|
if (is_usb_magicmouse2(hdev->vendor, hdev->product) ||
|
||||||
|
is_usb_magictrackpad2(hdev->vendor, hdev->product))
|
||||||
timer_delete_sync(&msc->battery_timer);
|
timer_delete_sync(&msc->battery_timer);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -964,11 +983,8 @@ static const __u8 *magicmouse_report_fixup(struct hid_device *hdev, __u8 *rdesc,
|
|||||||
* 0x05, 0x01, // Usage Page (Generic Desktop) 0
|
* 0x05, 0x01, // Usage Page (Generic Desktop) 0
|
||||||
* 0x09, 0x02, // Usage (Mouse) 2
|
* 0x09, 0x02, // Usage (Mouse) 2
|
||||||
*/
|
*/
|
||||||
if (hdev->vendor == USB_VENDOR_ID_APPLE &&
|
if ((is_usb_magicmouse2(hdev->vendor, hdev->product) ||
|
||||||
(hdev->product == USB_DEVICE_ID_APPLE_MAGICMOUSE2 ||
|
is_usb_magictrackpad2(hdev->vendor, hdev->product)) &&
|
||||||
hdev->product == USB_DEVICE_ID_APPLE_MAGICMOUSE2_USBC ||
|
|
||||||
hdev->product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2 ||
|
|
||||||
hdev->product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2_USBC) &&
|
|
||||||
*rsize == 83 && rdesc[46] == 0x84 && rdesc[58] == 0x85) {
|
*rsize == 83 && rdesc[46] == 0x84 && rdesc[58] == 0x85) {
|
||||||
hid_info(hdev,
|
hid_info(hdev,
|
||||||
"fixing up magicmouse battery report descriptor\n");
|
"fixing up magicmouse battery report descriptor\n");
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
#include <linux/i2c.h>
|
#include <linux/i2c.h>
|
||||||
#include <linux/gpio/driver.h>
|
#include <linux/gpio/driver.h>
|
||||||
#include <linux/iio/iio.h>
|
#include <linux/iio/iio.h>
|
||||||
|
#include <linux/minmax.h>
|
||||||
#include "hid-ids.h"
|
#include "hid-ids.h"
|
||||||
|
|
||||||
/* Commands codes in a raw output report */
|
/* Commands codes in a raw output report */
|
||||||
@ -55,6 +56,27 @@ enum {
|
|||||||
MCP2221_ALT_F_NOT_GPIOD = 0xEF,
|
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 */
|
/* MCP GPIO direction encoding */
|
||||||
enum {
|
enum {
|
||||||
MCP2221_DIR_OUT = 0x00,
|
MCP2221_DIR_OUT = 0x00,
|
||||||
@ -241,10 +263,7 @@ static int mcp_i2c_write(struct mcp2221 *mcp,
|
|||||||
|
|
||||||
idx = 0;
|
idx = 0;
|
||||||
sent = 0;
|
sent = 0;
|
||||||
if (msg->len < 60)
|
len = min(msg->len, 60);
|
||||||
len = msg->len;
|
|
||||||
else
|
|
||||||
len = 60;
|
|
||||||
|
|
||||||
do {
|
do {
|
||||||
mcp->txbuf[0] = type;
|
mcp->txbuf[0] = type;
|
||||||
@ -271,10 +290,7 @@ static int mcp_i2c_write(struct mcp2221 *mcp,
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
idx = idx + len;
|
idx = idx + len;
|
||||||
if ((msg->len - sent) < 60)
|
len = min(msg->len - sent, 60);
|
||||||
len = msg->len - sent;
|
|
||||||
else
|
|
||||||
len = 60;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Testing shows delay is needed between successive writes
|
* 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)
|
#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,
|
static int mcp_gpio_get(struct gpio_chip *gc,
|
||||||
unsigned int offset)
|
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);
|
ret = devm_gpiochip_add_data(&hdev->dev, mcp->gc, mcp);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
mcp2221_check_gpio_pinfunc(mcp);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if IS_REACHABLE(CONFIG_IIO)
|
#if IS_REACHABLE(CONFIG_IIO)
|
||||||
|
@ -73,6 +73,7 @@ MODULE_LICENSE("GPL");
|
|||||||
#define MT_QUIRK_FORCE_MULTI_INPUT BIT(20)
|
#define MT_QUIRK_FORCE_MULTI_INPUT BIT(20)
|
||||||
#define MT_QUIRK_DISABLE_WAKEUP BIT(21)
|
#define MT_QUIRK_DISABLE_WAKEUP BIT(21)
|
||||||
#define MT_QUIRK_ORIENTATION_INVERT BIT(22)
|
#define MT_QUIRK_ORIENTATION_INVERT BIT(22)
|
||||||
|
#define MT_QUIRK_APPLE_TOUCHBAR BIT(23)
|
||||||
|
|
||||||
#define MT_INPUTMODE_TOUCHSCREEN 0x02
|
#define MT_INPUTMODE_TOUCHSCREEN 0x02
|
||||||
#define MT_INPUTMODE_TOUCHPAD 0x03
|
#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_GOOGLE 0x0111
|
||||||
#define MT_CLS_RAZER_BLADE_STEALTH 0x0112
|
#define MT_CLS_RAZER_BLADE_STEALTH 0x0112
|
||||||
#define MT_CLS_SMART_TECH 0x0113
|
#define MT_CLS_SMART_TECH 0x0113
|
||||||
|
#define MT_CLS_APPLE_TOUCHBAR 0x0114
|
||||||
#define MT_CLS_SIS 0x0457
|
#define MT_CLS_SIS 0x0457
|
||||||
|
|
||||||
#define MT_DEFAULT_MAXCONTACT 10
|
#define MT_DEFAULT_MAXCONTACT 10
|
||||||
@ -405,6 +407,12 @@ static const struct mt_class mt_classes[] = {
|
|||||||
MT_QUIRK_CONTACT_CNT_ACCURATE |
|
MT_QUIRK_CONTACT_CNT_ACCURATE |
|
||||||
MT_QUIRK_SEPARATE_APP_REPORT,
|
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,
|
{ .name = MT_CLS_SIS,
|
||||||
.quirks = MT_QUIRK_NOT_SEEN_MEANS_UP |
|
.quirks = MT_QUIRK_NOT_SEEN_MEANS_UP |
|
||||||
MT_QUIRK_ALWAYS_VALID |
|
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,
|
static struct mt_report_data *mt_allocate_report_data(struct mt_device *td,
|
||||||
struct hid_report *report)
|
struct hid_report *report)
|
||||||
{
|
{
|
||||||
|
struct mt_class *cls = &td->mtclass;
|
||||||
struct mt_report_data *rdata;
|
struct mt_report_data *rdata;
|
||||||
struct hid_field *field;
|
struct hid_field *field;
|
||||||
int r, n;
|
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) {
|
if (field->logical == HID_DG_FINGER || td->hdev->group != HID_GROUP_MULTITOUCH_WIN_8) {
|
||||||
for (n = 0; n < field->report_count; n++) {
|
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;
|
rdata->is_mt_collection = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -821,12 +834,31 @@ static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi,
|
|||||||
|
|
||||||
MT_STORE_FIELD(confidence_state);
|
MT_STORE_FIELD(confidence_state);
|
||||||
return 1;
|
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:
|
case HID_DG_TIPSWITCH:
|
||||||
if (field->application != HID_GD_SYSTEM_MULTIAXIS)
|
if (field->application != HID_GD_SYSTEM_MULTIAXIS)
|
||||||
input_set_capability(hi->input,
|
input_set_capability(hi->input,
|
||||||
EV_KEY, BTN_TOUCH);
|
EV_KEY, BTN_TOUCH);
|
||||||
MT_STORE_FIELD(tip_state);
|
MT_STORE_FIELD(tip_state);
|
||||||
return 1;
|
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:
|
case HID_DG_CONTACTID:
|
||||||
MT_STORE_FIELD(contactid);
|
MT_STORE_FIELD(contactid);
|
||||||
app->touches_by_report++;
|
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:
|
case HID_DG_CONTACTMAX:
|
||||||
/* contact max are global to the report */
|
/* contact max are global to the report */
|
||||||
return -1;
|
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 */
|
/* let hid-input decide for the others */
|
||||||
return 0;
|
return 0;
|
||||||
@ -1314,6 +1342,13 @@ static int mt_touch_input_configured(struct hid_device *hdev,
|
|||||||
struct input_dev *input = hi->input;
|
struct input_dev *input = hi->input;
|
||||||
int ret;
|
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)
|
if (!td->maxcontacts)
|
||||||
td->maxcontacts = MT_DEFAULT_MAXCONTACT;
|
td->maxcontacts = MT_DEFAULT_MAXCONTACT;
|
||||||
|
|
||||||
@ -1321,6 +1356,13 @@ static int mt_touch_input_configured(struct hid_device *hdev,
|
|||||||
if (td->serial_maybe)
|
if (td->serial_maybe)
|
||||||
mt_post_parse_default_settings(td, app);
|
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)
|
if (cls->is_indirect)
|
||||||
app->mt_flags |= INPUT_MT_POINTER;
|
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)
|
if (ret != 0)
|
||||||
return ret;
|
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)
|
if (mtclass->quirks & MT_QUIRK_FIX_CONST_CONTACT_ID)
|
||||||
mt_fix_const_fields(hdev, HID_DG_CONTACTID);
|
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,
|
MT_USB_DEVICE(USB_VENDOR_ID_XIROKU,
|
||||||
USB_DEVICE_ID_XIROKU_CSR2) },
|
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 */
|
/* Google MT devices */
|
||||||
{ .driver_data = MT_CLS_GOOGLE,
|
{ .driver_data = MT_CLS_GOOGLE,
|
||||||
HID_DEVICE(HID_BUS_ANY, HID_GROUP_ANY, USB_VENDOR_ID_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_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_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) },
|
||||||
|
{ 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_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_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_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_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_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_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_FOUNTAIN_TP_ONLY) },
|
||||||
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY) },
|
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY) },
|
||||||
{ }
|
{ }
|
||||||
|
@ -62,6 +62,30 @@ static const __u8 *uclogic_report_fixup(struct hid_device *hdev, __u8 *rdesc,
|
|||||||
return 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,
|
static int uclogic_input_mapping(struct hid_device *hdev,
|
||||||
struct hid_input *hi,
|
struct hid_input *hi,
|
||||||
struct hid_field *field,
|
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_drvdata *drvdata = hid_get_drvdata(hdev);
|
||||||
struct uclogic_params *params = &drvdata->params;
|
struct uclogic_params *params = &drvdata->params;
|
||||||
|
|
||||||
|
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 */
|
/* Discard invalid pen usages */
|
||||||
if (params->pen.usage_invalid && (field->application == HID_DG_PEN))
|
if (params->pen.usage_invalid)
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
/* Let hid-core decide what to do */
|
/* Let hid-core decide what to do */
|
||||||
return 0;
|
return 0;
|
||||||
@ -407,8 +449,22 @@ static int uclogic_raw_event_frame(
|
|||||||
|
|
||||||
/* If need to, and can, transform the bitmap dial reports */
|
/* If need to, and can, transform the bitmap dial reports */
|
||||||
if (frame->bitmap_dial_byte > 0 && frame->bitmap_dial_byte < size) {
|
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;
|
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;
|
return 0;
|
||||||
@ -546,6 +602,8 @@ static const struct hid_device_id uclogic_devices[] = {
|
|||||||
.driver_data = UCLOGIC_MOUSE_FRAME_QUIRK | UCLOGIC_BATTERY_QUIRK },
|
.driver_data = UCLOGIC_MOUSE_FRAME_QUIRK | UCLOGIC_BATTERY_QUIRK },
|
||||||
{ HID_USB_DEVICE(USB_VENDOR_ID_UGEE,
|
{ HID_USB_DEVICE(USB_VENDOR_ID_UGEE,
|
||||||
USB_DEVICE_ID_UGEE_XPPEN_TABLET_STAR06) },
|
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);
|
MODULE_DEVICE_TABLE(hid, uclogic_devices);
|
||||||
|
@ -103,6 +103,8 @@ static void uclogic_params_frame_hid_dbg(
|
|||||||
frame->touch_flip_at);
|
frame->touch_flip_at);
|
||||||
hid_dbg(hdev, "\t\t.bitmap_dial_byte = %u\n",
|
hid_dbg(hdev, "\t\t.bitmap_dial_byte = %u\n",
|
||||||
frame->bitmap_dial_byte);
|
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_params *p)
|
||||||
{
|
{
|
||||||
struct uclogic_raw_event_hook *event_hook;
|
struct uclogic_raw_event_hook *event_hook;
|
||||||
__u8 reconnect_event[] = {
|
static const __u8 reconnect_event[] = {
|
||||||
/* Event received on wireless tablet reconnection */
|
/* Event received on wireless tablet reconnection */
|
||||||
0x02, 0xF8, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
0x02, 0xF8, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||||
};
|
};
|
||||||
@ -1529,6 +1531,126 @@ cleanup:
|
|||||||
return rc;
|
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
|
* uclogic_params_init() - initialize a tablet interface and discover its
|
||||||
* parameters.
|
* parameters.
|
||||||
@ -1845,6 +1967,16 @@ int uclogic_params_init(struct uclogic_params *params,
|
|||||||
uclogic_params_init_invalid(&p);
|
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;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -175,6 +175,11 @@ struct uclogic_params_frame {
|
|||||||
* counterclockwise, as opposed to the normal 1 and -1.
|
* counterclockwise, as opposed to the normal 1 and -1.
|
||||||
*/
|
*/
|
||||||
unsigned int bitmap_dial_byte;
|
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 =
|
const size_t uclogic_rdesc_xppen_deco01_frame_size =
|
||||||
sizeof(uclogic_rdesc_xppen_deco01_frame_arr);
|
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
|
* uclogic_rdesc_template_apply() - apply report descriptor parameters to a
|
||||||
* report descriptor template, creating a report descriptor. Copies the
|
* 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 */
|
/* Least-significant bit of Ugee G5 frame rotary encoder state */
|
||||||
#define UCLOGIC_RDESC_UGEE_G5_FRAME_RE_LSB 38
|
#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 */
|
#endif /* _HID_UCLOGIC_RDESC_H */
|
||||||
|
@ -57,6 +57,7 @@ static int universal_pidff_probe(struct hid_device *hdev,
|
|||||||
const struct hid_device_id *id)
|
const struct hid_device_id *id)
|
||||||
{
|
{
|
||||||
int i, error;
|
int i, error;
|
||||||
|
|
||||||
error = hid_parse(hdev);
|
error = hid_parse(hdev);
|
||||||
if (error) {
|
if (error) {
|
||||||
hid_err(hdev, "HID parse failed\n");
|
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 */
|
/* Check if HID_PID support is enabled */
|
||||||
int (*init_function)(struct hid_device *, u32);
|
int (*init_function)(struct hid_device *, u32);
|
||||||
init_function = hid_pidff_init_with_quirks;
|
|
||||||
|
|
||||||
|
init_function = hid_pidff_init_with_quirks;
|
||||||
if (!init_function) {
|
if (!init_function) {
|
||||||
hid_warn(hdev, "HID_PID support not enabled!\n");
|
hid_warn(hdev, "HID_PID support not enabled!\n");
|
||||||
return 0;
|
return 0;
|
||||||
@ -177,7 +178,7 @@ static const struct hid_device_id universal_pidff_devices[] = {
|
|||||||
.driver_data = HID_PIDFF_QUIRK_PERIODIC_SINE_ONLY },
|
.driver_data = HID_PIDFF_QUIRK_PERIODIC_SINE_ONLY },
|
||||||
{ HID_USB_DEVICE(USB_VENDOR_ID_LITE_STAR, USB_DEVICE_ID_PXN_V12_LITE_2),
|
{ HID_USB_DEVICE(USB_VENDOR_ID_LITE_STAR, USB_DEVICE_ID_PXN_V12_LITE_2),
|
||||||
.driver_data = HID_PIDFF_QUIRK_PERIODIC_SINE_ONLY },
|
.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 },
|
.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_INVICTA) },
|
||||||
{ HID_USB_DEVICE(USB_VENDOR_ID_ASETEK, USB_DEVICE_ID_ASETEK_FORTE) },
|
{ HID_USB_DEVICE(USB_VENDOR_ID_ASETEK, USB_DEVICE_ID_ASETEK_FORTE) },
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
obj-$(CONFIG_INTEL_THC_HID) += intel-thc.o
|
obj-$(CONFIG_INTEL_THC_HID) += intel-thc.o
|
||||||
intel-thc-objs += intel-thc/intel-thc-dev.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-dma.o
|
||||||
|
intel-thc-objs += intel-thc/intel-thc-wot.o
|
||||||
|
|
||||||
obj-$(CONFIG_INTEL_QUICKSPI) += intel-quickspi.o
|
obj-$(CONFIG_INTEL_QUICKSPI) += intel-quickspi.o
|
||||||
intel-quickspi-objs += intel-quickspi/pci-quickspi.o
|
intel-quickspi-objs += intel-quickspi/pci-quickspi.o
|
||||||
|
@ -11,13 +11,20 @@
|
|||||||
#include <linux/sizes.h>
|
#include <linux/sizes.h>
|
||||||
#include <linux/pm_runtime.h>
|
#include <linux/pm_runtime.h>
|
||||||
|
|
||||||
|
#include <linux/gpio/consumer.h>
|
||||||
|
|
||||||
#include "intel-thc-dev.h"
|
#include "intel-thc-dev.h"
|
||||||
#include "intel-thc-hw.h"
|
#include "intel-thc-hw.h"
|
||||||
|
#include "intel-thc-wot.h"
|
||||||
|
|
||||||
#include "quicki2c-dev.h"
|
#include "quicki2c-dev.h"
|
||||||
#include "quicki2c-hid.h"
|
#include "quicki2c-hid.h"
|
||||||
#include "quicki2c-protocol.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 */
|
/* THC QuickI2C ACPI method to get device properties */
|
||||||
/* HIDI2C device method */
|
/* HIDI2C device method */
|
||||||
static guid_t i2c_hid_guid =
|
static guid_t i2c_hid_guid =
|
||||||
@ -27,19 +34,26 @@ static guid_t i2c_hid_guid =
|
|||||||
static guid_t thc_platform_guid =
|
static guid_t thc_platform_guid =
|
||||||
GUID_INIT(0x84005682, 0x5b71, 0x41a4, 0x8d, 0x66, 0x81, 0x30, 0xf7, 0x87, 0xa1, 0x38);
|
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
|
* 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
|
* @guid: ACPI method's guid
|
||||||
* @rev: ACPI method's revision
|
* @rev: ACPI method's revision
|
||||||
* @func: ACPI method's function number
|
* @func: ACPI method's function number
|
||||||
* @type: ACPI parameter's data type
|
* @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.
|
* 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,
|
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)
|
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
|
* 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
|
* @dsd_method_name: ACPI method's property name
|
||||||
* @type: ACPI parameter's data type
|
* @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.
|
* 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 failure.
|
||||||
*
|
|
||||||
* Return: 0 if success or error code on failed.
|
|
||||||
*/
|
*/
|
||||||
static int quicki2c_get_acpi_resources(struct quicki2c_device *qcdev)
|
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
|
* @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.
|
* 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
|
* 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.
|
* This function is an error handler, called when fatal error happens.
|
||||||
* It try to reset Touch Device and re-configure THC to recovery
|
* It try to reset touch device and re-configure THC to recovery
|
||||||
* transferring between Device and THC.
|
* 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)
|
static int try_recover(struct quicki2c_device *qcdev)
|
||||||
{
|
{
|
||||||
@ -264,7 +275,7 @@ static int handle_input_report(struct quicki2c_device *qcdev)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* discard samples before driver probe complete */
|
/* Discard samples before driver probe complete */
|
||||||
if (qcdev->state != QUICKI2C_ENABLED)
|
if (qcdev->state != QUICKI2C_ENABLED)
|
||||||
continue;
|
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
|
* @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.
|
* Return: IRQ_HANDLED to finish this handler.
|
||||||
*/
|
*/
|
||||||
@ -325,20 +335,21 @@ exit:
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* quicki2c_dev_init - Initialize quicki2c device
|
* 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
|
||||||
*
|
*
|
||||||
* @pdev: pointer to the thc pci device
|
* Alloc quicki2c_device structure and initialized THC device,
|
||||||
* @mem_addr: The pointer of MMIO memory address
|
|
||||||
*
|
|
||||||
* Alloc quicki2c device structure and initialized THC device,
|
|
||||||
* then configure THC to HIDI2C mode.
|
* then configure THC to HIDI2C mode.
|
||||||
*
|
*
|
||||||
* If success, enable THC hardware interrupt.
|
* If success, enable THC hardware interrupt.
|
||||||
*
|
*
|
||||||
* Return: pointer to the quicki2c device structure if success
|
* Return: Pointer to the quicki2c_device structure if success
|
||||||
* or NULL on failed.
|
* 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 device *dev = &pdev->dev;
|
||||||
struct quicki2c_device *qcdev;
|
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->dev = dev;
|
||||||
qcdev->mem_addr = mem_addr;
|
qcdev->mem_addr = mem_addr;
|
||||||
qcdev->state = QUICKI2C_DISABLED;
|
qcdev->state = QUICKI2C_DISABLED;
|
||||||
|
qcdev->ddata = ddata;
|
||||||
|
|
||||||
init_waitqueue_head(&qcdev->reset_ack_wq);
|
init_waitqueue_head(&qcdev->reset_ack_wq);
|
||||||
|
|
||||||
/* thc hw init */
|
/* THC hardware init */
|
||||||
qcdev->thc_hw = thc_dev_init(qcdev->dev, qcdev->mem_addr);
|
qcdev->thc_hw = thc_dev_init(qcdev->dev, qcdev->mem_addr);
|
||||||
if (IS_ERR(qcdev->thc_hw)) {
|
if (IS_ERR(qcdev->thc_hw)) {
|
||||||
ret = PTR_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_interrupt_enable(qcdev->thc_hw, true);
|
||||||
|
|
||||||
|
thc_wot_config(qcdev->thc_hw, &quicki2c_gpios[0]);
|
||||||
|
|
||||||
qcdev->state = QUICKI2C_INITED;
|
qcdev->state = QUICKI2C_INITED;
|
||||||
|
|
||||||
return qcdev;
|
return qcdev;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* quicki2c_dev_deinit - De-initialize quicki2c device
|
* quicki2c_dev_deinit - De-initialize QuickI2C device
|
||||||
*
|
* @qcdev: Pointer to the quicki2c_device structure
|
||||||
* @qcdev: pointer to the quicki2c device structure
|
|
||||||
*
|
*
|
||||||
* Disable THC interrupt and deinitilize THC.
|
* 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_interrupt_enable(qcdev->thc_hw, false);
|
||||||
thc_ltr_unconfig(qcdev->thc_hw);
|
thc_ltr_unconfig(qcdev->thc_hw);
|
||||||
|
thc_wot_unconfig(qcdev->thc_hw);
|
||||||
|
|
||||||
qcdev->state = QUICKI2C_DISABLED;
|
qcdev->state = QUICKI2C_DISABLED;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* quicki2c_dma_init - Configure THC DMA for quicki2c device
|
* quicki2c_dma_adv_enable - Configure and enable DMA advanced features
|
||||||
* @qcdev: pointer to the quicki2c device structure
|
* @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
|
* This function uses TIC's parameters(such as max input length, max output
|
||||||
* length) to allocate THC DMA buffers and configure THC DMA engines.
|
* 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)
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
if (qcdev->ddata)
|
||||||
|
quicki2c_dma_adv_enable(qcdev);
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* quicki2c_dma_deinit - Release THC DMA for quicki2c device
|
* quicki2c_dma_deinit - Release THC DMA for QuickI2C device
|
||||||
* @qcdev: pointer to the quicki2c device structure
|
* @qcdev: Pointer to the quicki2c_device structure
|
||||||
*
|
*
|
||||||
* Stop THC DMA engines and release all DMA buffers.
|
* 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_unconfigure(qcdev->thc_hw);
|
||||||
thc_dma_release(qcdev->thc_hw);
|
thc_dma_release(qcdev->thc_hw);
|
||||||
|
|
||||||
|
if (qcdev->ddata)
|
||||||
|
quicki2c_dma_adv_disable(qcdev);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* quicki2c_alloc_report_buf - Alloc report buffers
|
* 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
|
* Allocate report descriptor buffer, it will be used for restore TIC HID
|
||||||
* report descriptor.
|
* 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,
|
* Allocate output report buffer, it will be used for store HID output report,
|
||||||
* such as set feature.
|
* 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)
|
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
|
* quicki2c_probe: QuickI2C driver probe function
|
||||||
*
|
* @pdev: Point to PCI device
|
||||||
* @pdev: point to pci device
|
* @id: Point to pci_device_id structure
|
||||||
* @id: point to pci_device_id structure
|
|
||||||
*
|
*
|
||||||
* This function initializes THC and HIDI2C device, the flow is:
|
* This function initializes THC and HIDI2C device, the flow is:
|
||||||
* - do THC pci device initialization
|
* - Do THC pci device initialization
|
||||||
* - query HIDI2C ACPI parameters
|
* - Query HIDI2C ACPI parameters
|
||||||
* - configure THC to HIDI2C mode
|
* - Configure THC to HIDI2C mode
|
||||||
* - go through HIDI2C enumeration flow
|
* - Go through HIDI2C enumeration flow
|
||||||
* |- read device descriptor
|
* |- Read device descriptor
|
||||||
* |- reset HIDI2C device
|
* |- Reset HIDI2C device
|
||||||
* - enable THC interrupt and DMA
|
* - Enable THC interrupt and DMA
|
||||||
* - read report descriptor
|
* - Read report descriptor
|
||||||
* - register HID device
|
* - Register HID device
|
||||||
* - enable runtime power management
|
* - Enable runtime power management
|
||||||
*
|
*
|
||||||
* Return 0 if success or error code on failed.
|
* Return 0 if success or error code on failure.
|
||||||
*/
|
*/
|
||||||
static int quicki2c_probe(struct pci_dev *pdev,
|
static int quicki2c_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
||||||
const struct pci_device_id *id)
|
|
||||||
{
|
{
|
||||||
|
const struct quicki2c_ddata *ddata = (const struct quicki2c_ddata *)id->driver_data;
|
||||||
struct quicki2c_device *qcdev;
|
struct quicki2c_device *qcdev;
|
||||||
void __iomem *mem_addr;
|
void __iomem *mem_addr;
|
||||||
int ret;
|
int ret;
|
||||||
@ -577,7 +640,7 @@ static int quicki2c_probe(struct pci_dev *pdev,
|
|||||||
|
|
||||||
pdev->irq = pci_irq_vector(pdev, 0);
|
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)) {
|
if (IS_ERR(qcdev)) {
|
||||||
dev_err_once(&pdev->dev, "QuickI2C device init failed\n");
|
dev_err_once(&pdev->dev, "QuickI2C device init failed\n");
|
||||||
ret = PTR_ERR(qcdev);
|
ret = PTR_ERR(qcdev);
|
||||||
@ -668,11 +731,10 @@ disable_pci_device:
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* quicki2c_remove - Device Removal Routine
|
* 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)
|
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
|
* 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)
|
static void quicki2c_shutdown(struct pci_dev *pdev)
|
||||||
{
|
{
|
||||||
@ -930,12 +990,12 @@ static const struct dev_pm_ops quicki2c_pm_ops = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
static const struct pci_device_id quicki2c_pci_tbl[] = {
|
static const struct pci_device_id quicki2c_pci_tbl[] = {
|
||||||
{PCI_VDEVICE(INTEL, THC_LNL_DEVICE_ID_I2C_PORT1), },
|
{ PCI_DEVICE_DATA(INTEL, THC_LNL_DEVICE_ID_I2C_PORT1, NULL) },
|
||||||
{PCI_VDEVICE(INTEL, THC_LNL_DEVICE_ID_I2C_PORT2), },
|
{ PCI_DEVICE_DATA(INTEL, THC_LNL_DEVICE_ID_I2C_PORT2, NULL) },
|
||||||
{PCI_VDEVICE(INTEL, THC_PTL_H_DEVICE_ID_I2C_PORT1), },
|
{ PCI_DEVICE_DATA(INTEL, THC_PTL_H_DEVICE_ID_I2C_PORT1, &ptl_ddata) },
|
||||||
{PCI_VDEVICE(INTEL, THC_PTL_H_DEVICE_ID_I2C_PORT2), },
|
{ PCI_DEVICE_DATA(INTEL, THC_PTL_H_DEVICE_ID_I2C_PORT2, &ptl_ddata) },
|
||||||
{PCI_VDEVICE(INTEL, THC_PTL_U_DEVICE_ID_I2C_PORT1), },
|
{ PCI_DEVICE_DATA(INTEL, THC_PTL_U_DEVICE_ID_I2C_PORT1, &ptl_ddata) },
|
||||||
{PCI_VDEVICE(INTEL, THC_PTL_U_DEVICE_ID_I2C_PORT2), },
|
{ PCI_DEVICE_DATA(INTEL, THC_PTL_U_DEVICE_ID_I2C_PORT2, &ptl_ddata) },
|
||||||
{ }
|
{ }
|
||||||
};
|
};
|
||||||
MODULE_DEVICE_TABLE(pci, quicki2c_pci_tbl);
|
MODULE_DEVICE_TABLE(pci, quicki2c_pci_tbl);
|
||||||
|
@ -7,12 +7,12 @@
|
|||||||
#include <linux/hid-over-i2c.h>
|
#include <linux/hid-over-i2c.h>
|
||||||
#include <linux/workqueue.h>
|
#include <linux/workqueue.h>
|
||||||
|
|
||||||
#define THC_LNL_DEVICE_ID_I2C_PORT1 0xA848
|
#define PCI_DEVICE_ID_INTEL_THC_LNL_DEVICE_ID_I2C_PORT1 0xA848
|
||||||
#define THC_LNL_DEVICE_ID_I2C_PORT2 0xA84A
|
#define PCI_DEVICE_ID_INTEL_THC_LNL_DEVICE_ID_I2C_PORT2 0xA84A
|
||||||
#define THC_PTL_H_DEVICE_ID_I2C_PORT1 0xE348
|
#define PCI_DEVICE_ID_INTEL_THC_PTL_H_DEVICE_ID_I2C_PORT1 0xE348
|
||||||
#define THC_PTL_H_DEVICE_ID_I2C_PORT2 0xE34A
|
#define PCI_DEVICE_ID_INTEL_THC_PTL_H_DEVICE_ID_I2C_PORT2 0xE34A
|
||||||
#define THC_PTL_U_DEVICE_ID_I2C_PORT1 0xE448
|
#define PCI_DEVICE_ID_INTEL_THC_PTL_U_DEVICE_ID_I2C_PORT1 0xE448
|
||||||
#define THC_PTL_U_DEVICE_ID_I2C_PORT2 0xE44A
|
#define PCI_DEVICE_ID_INTEL_THC_PTL_U_DEVICE_ID_I2C_PORT2 0xE44A
|
||||||
|
|
||||||
/* Packet size value, the unit is 16 bytes */
|
/* Packet size value, the unit is 16 bytes */
|
||||||
#define MAX_PACKET_SIZE_VALUE_LNL 256
|
#define MAX_PACKET_SIZE_VALUE_LNL 256
|
||||||
@ -36,6 +36,12 @@
|
|||||||
#define QUICKI2C_DEFAULT_LP_LTR_VALUE 500
|
#define QUICKI2C_DEFAULT_LP_LTR_VALUE 500
|
||||||
#define QUICKI2C_RPM_TIMEOUT_MS 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
|
* THC uses runtime auto suspend to dynamically switch between THC active LTR
|
||||||
* and low power LTR to save CPU power.
|
* and low power LTR to save CPU power.
|
||||||
@ -122,6 +128,16 @@ struct quicki2c_subip_acpi_config {
|
|||||||
u64 HMSL;
|
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 device;
|
||||||
struct pci_dev;
|
struct pci_dev;
|
||||||
struct thc_device;
|
struct thc_device;
|
||||||
@ -130,15 +146,15 @@ struct acpi_device;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* struct quicki2c_device - THC QuickI2C device struct
|
* struct quicki2c_device - THC QuickI2C device struct
|
||||||
* @dev: point to kernel device
|
* @dev: Point to kernel device
|
||||||
* @pdev: point to PCI device
|
* @pdev: Point to PCI device
|
||||||
* @thc_hw: point to THC device
|
* @thc_hw: Point to THC device
|
||||||
* @hid_dev: point to hid device
|
* @hid_dev: Point to HID device
|
||||||
* @acpi_dev: point to ACPI device
|
* @acpi_dev: Point to ACPI device
|
||||||
* @driver_data: point to quicki2c specific driver data
|
* @ddata: Point to QuickI2C platform specific driver data
|
||||||
* @state: THC I2C device state
|
* @state: THC I2C device state
|
||||||
* @mem_addr: MMIO memory address
|
* @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
|
* @i2c_slave_addr: HIDI2C device slave address
|
||||||
* @hid_desc_addr: Register address for retrieve HID device descriptor
|
* @hid_desc_addr: Register address for retrieve HID device descriptor
|
||||||
* @active_ltr_val: THC active LTR value
|
* @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_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_hcnt: I2C CLK high period time (unit in cycle count)
|
||||||
* @i2c_clock_lcnt: I2C CLK low 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
|
* @report_descriptor: Store a copy of device report descriptor
|
||||||
* @input_buf: store a copy of latest input report data
|
* @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_buf: Store a copy of latest input/output report packet from set/get feature
|
||||||
* @report_len: the length of input/output report packet
|
* @report_len: The length of input/output report packet
|
||||||
* @reset_ack_wq: workqueue for waiting reset response from device
|
* @reset_ack_wq: Workqueue for waiting reset response from device
|
||||||
* @reset_ack: indicate reset response received or not
|
* @reset_ack: Indicate reset response received or not
|
||||||
*/
|
*/
|
||||||
struct quicki2c_device {
|
struct quicki2c_device {
|
||||||
struct device *dev;
|
struct device *dev;
|
||||||
@ -159,6 +175,7 @@ struct quicki2c_device {
|
|||||||
struct thc_device *thc_hw;
|
struct thc_device *thc_hw;
|
||||||
struct hid_device *hid_dev;
|
struct hid_device *hid_dev;
|
||||||
struct acpi_device *acpi_dev;
|
struct acpi_device *acpi_dev;
|
||||||
|
const struct quicki2c_ddata *ddata;
|
||||||
enum quicki2c_dev_state state;
|
enum quicki2c_dev_state state;
|
||||||
|
|
||||||
void __iomem *mem_addr;
|
void __iomem *mem_addr;
|
||||||
|
@ -11,8 +11,11 @@
|
|||||||
#include <linux/pci.h>
|
#include <linux/pci.h>
|
||||||
#include <linux/pm_runtime.h>
|
#include <linux/pm_runtime.h>
|
||||||
|
|
||||||
|
#include <linux/gpio/consumer.h>
|
||||||
|
|
||||||
#include "intel-thc-dev.h"
|
#include "intel-thc-dev.h"
|
||||||
#include "intel-thc-hw.h"
|
#include "intel-thc-hw.h"
|
||||||
|
#include "intel-thc-wot.h"
|
||||||
|
|
||||||
#include "quickspi-dev.h"
|
#include "quickspi-dev.h"
|
||||||
#include "quickspi-hid.h"
|
#include "quickspi-hid.h"
|
||||||
@ -46,6 +49,15 @@ static guid_t thc_platform_guid =
|
|||||||
GUID_INIT(0x84005682, 0x5b71, 0x41a4, 0x8d, 0x66, 0x81, 0x30,
|
GUID_INIT(0x84005682, 0x5b71, 0x41a4, 0x8d, 0x66, 0x81, 0x30,
|
||||||
0xf7, 0x87, 0xa1, 0x38);
|
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
|
* 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_interrupt_enable(qsdev->thc_hw, true);
|
||||||
|
|
||||||
|
thc_wot_config(qsdev->thc_hw, &quickspi_gpios[0]);
|
||||||
|
|
||||||
qsdev->state = QUICKSPI_INITIATED;
|
qsdev->state = QUICKSPI_INITIATED;
|
||||||
|
|
||||||
return qsdev;
|
return qsdev;
|
||||||
@ -442,6 +456,7 @@ static void quickspi_dev_deinit(struct quickspi_device *qsdev)
|
|||||||
{
|
{
|
||||||
thc_interrupt_enable(qsdev->thc_hw, false);
|
thc_interrupt_enable(qsdev->thc_hw, false);
|
||||||
thc_ltr_unconfig(qsdev->thc_hw);
|
thc_ltr_unconfig(qsdev->thc_hw);
|
||||||
|
thc_wot_unconfig(qsdev->thc_hw);
|
||||||
|
|
||||||
qsdev->state = QUICKSPI_DISABLED;
|
qsdev->state = QUICKSPI_DISABLED;
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
/* Copyright (c) 2024 Intel Corporation */
|
/* Copyright (c) 2024 Intel Corporation */
|
||||||
|
|
||||||
#include <linux/bitfield.h>
|
#include <linux/bitfield.h>
|
||||||
|
#include <linux/math.h>
|
||||||
#include <linux/regmap.h>
|
#include <linux/regmap.h>
|
||||||
|
|
||||||
#include "intel-thc-dev.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");
|
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("Xinpeng Sun <xinpeng.sun@intel.com>");
|
||||||
MODULE_AUTHOR("Even Xu <even.xu@intel.com>");
|
MODULE_AUTHOR("Even Xu <even.xu@intel.com>");
|
||||||
|
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
#include <linux/workqueue.h>
|
#include <linux/workqueue.h>
|
||||||
|
|
||||||
#include "intel-thc-dma.h"
|
#include "intel-thc-dma.h"
|
||||||
|
#include "intel-thc-wot.h"
|
||||||
|
|
||||||
#define THC_REGMAP_COMMON_OFFSET 0x10
|
#define THC_REGMAP_COMMON_OFFSET 0x10
|
||||||
#define THC_REGMAP_MMIO_OFFSET 0x1000
|
#define THC_REGMAP_MMIO_OFFSET 0x1000
|
||||||
@ -52,16 +53,21 @@ enum thc_int_type {
|
|||||||
* struct thc_device - THC private device struct
|
* struct thc_device - THC private device struct
|
||||||
* @thc_regmap: MMIO regmap structure for accessing THC registers
|
* @thc_regmap: MMIO regmap structure for accessing THC registers
|
||||||
* @mmio_addr: MMIO registers address
|
* @mmio_addr: MMIO registers address
|
||||||
* @thc_bus_lock: mutex locker for THC config
|
* @thc_bus_lock: Mutex locker for THC config
|
||||||
* @port_type: port type of THC port instance
|
* @port_type: Port type of THC port instance
|
||||||
* @pio_int_supported: PIO interrupt supported flag
|
* @pio_int_supported: PIO interrupt supported flag
|
||||||
* @dma_ctx: DMA specific data
|
* @dma_ctx: DMA specific data
|
||||||
* @write_complete_wait: signal event for DMA write complete
|
* @wot: THC Wake-on-Touch data
|
||||||
* @swdma_complete_wait: signal event for SWDMA sequence complete
|
* @write_complete_wait: Signal event for DMA write complete
|
||||||
* @write_done: bool value that indicates if DMA write is done
|
* @swdma_complete_wait: Signal event for SWDMA sequence complete
|
||||||
* @swdma_done: bool value that indicates if SWDMA swquence is done
|
* @write_done: Bool value that indicates if DMA write is done
|
||||||
* @perf_limit: the delay between read operation and write operation
|
* @swdma_done: Bool value that indicates if SWDMA sequence is done
|
||||||
* @i2c_subip_regs: the copy of THC I2C sub-system registers for resuming restore
|
* @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 thc_device {
|
||||||
struct device *dev;
|
struct device *dev;
|
||||||
@ -73,6 +79,8 @@ struct thc_device {
|
|||||||
|
|
||||||
struct thc_dma_context *dma_ctx;
|
struct thc_dma_context *dma_ctx;
|
||||||
|
|
||||||
|
struct thc_wot wot;
|
||||||
|
|
||||||
wait_queue_head_t write_complete_wait;
|
wait_queue_head_t write_complete_wait;
|
||||||
wait_queue_head_t swdma_complete_wait;
|
wait_queue_head_t swdma_complete_wait;
|
||||||
bool write_done;
|
bool write_done;
|
||||||
@ -81,6 +89,11 @@ struct thc_device {
|
|||||||
u32 perf_limit;
|
u32 perf_limit;
|
||||||
|
|
||||||
u32 *i2c_subip_regs;
|
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);
|
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);
|
const u32 speed, const u32 hcnt, const u32 lcnt);
|
||||||
int thc_i2c_subip_regs_save(struct thc_device *dev);
|
int thc_i2c_subip_regs_save(struct thc_device *dev);
|
||||||
int thc_i2c_subip_regs_restore(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_ */
|
#endif /* _INTEL_THC_DEV_H_ */
|
||||||
|
@ -712,6 +712,28 @@ static int thc_swdma_read_start(struct thc_device *dev, void *write_buff,
|
|||||||
|
|
||||||
thc_reset_dma_settings(dev);
|
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 |
|
mask = THC_M_PRT_RPRD_CNTRL_SW_THC_SWDMA_I2C_WBC |
|
||||||
THC_M_PRT_RPRD_CNTRL_SW_THC_SWDMA_I2C_RX_DLEN_EN;
|
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) |
|
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)
|
if (ret)
|
||||||
return 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);
|
thc_reset_dma_settings(dev);
|
||||||
|
|
||||||
dma_set_start_bit(dev, &dev->dma_ctx->dma_config[THC_RXDMA2]);
|
dma_set_start_bit(dev, &dev->dma_ctx->dma_config[THC_RXDMA2]);
|
||||||
|
@ -27,7 +27,7 @@
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* THC DMA channels:
|
* 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_RXDMA2: DMA to read HID data from touch device
|
||||||
* @THC_TXDMA: DMA to write to touch device
|
* @THC_TXDMA: DMA to write to touch device
|
||||||
* @THC_SWDMA: SW triggered DMA to write and read from 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)
|
* THC DMA Physical Memory Descriptor (PRD)
|
||||||
* @dest_addr: bit[53:0], destination address in system memory
|
* @dest_addr: Bit[53:0], destination address in system memory
|
||||||
* @int_on_completion: bit[63], if set, thc will trigger interrupt to driver
|
* @int_on_completion: Bit[63], if set, thc will trigger interrupt to driver
|
||||||
* @len: bit[87:64], length of this entry
|
* @len: Bit[87:64], length of this entry
|
||||||
* @end_of_prd: bit[88], if set, this entry is last one of current PRD table
|
* @end_of_prd: Bit[88], if set, this entry is last one of current PRD table
|
||||||
* @hw_status: bit[90:89], hw status bits
|
* @hw_status: Bit[90:89], hardware status bits
|
||||||
*/
|
*/
|
||||||
struct thc_prd_entry {
|
struct thc_prd_entry {
|
||||||
u64 dest_addr : 54;
|
u64 dest_addr : 54;
|
||||||
@ -88,14 +88,14 @@ struct thc_prd_table {
|
|||||||
* struct thc_dma_configuration - THC DMA configure
|
* struct thc_dma_configuration - THC DMA configure
|
||||||
* @dma_channel: DMA channel for current DMA configuration
|
* @dma_channel: DMA channel for current DMA configuration
|
||||||
* @prd_tbls_dma_handle: DMA buffer handle
|
* @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
|
* @prd_tbls: PRD tables for current DMA
|
||||||
* @sgls: array of pointers to scatter-gather lists
|
* @sgls: Array of pointers to scatter-gather lists
|
||||||
* @sgls_nent: actual number of entries per sg list
|
* @sgls_nent: Actual number of entries per scatter-gather list
|
||||||
* @prd_tbl_num: actual number of PRD tables
|
* @prd_tbl_num: Actual number of PRD tables
|
||||||
* @max_packet_size: size of the buffer needed for 1 DMA message (1 PRD table)
|
* @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_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
|
* @prd_cntrl: PRD control register value
|
||||||
* @dma_cntrl: DMA control register value
|
* @dma_cntrl: DMA control register value
|
||||||
*/
|
*/
|
||||||
@ -117,13 +117,21 @@ struct thc_dma_configuration {
|
|||||||
u32 dma_cntrl;
|
u32 dma_cntrl;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* THC DMA context
|
* struct thc_dma_context - THC DMA context
|
||||||
* Store all THC Channel configures
|
* @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_context {
|
||||||
struct thc_dma_configuration dma_config[MAX_THC_DMA_CHANNEL];
|
struct thc_dma_configuration dma_config[MAX_THC_DMA_CHANNEL];
|
||||||
u8 use_write_interrupts;
|
u8 use_write_interrupts;
|
||||||
|
|
||||||
|
bool rx_max_size_en;
|
||||||
|
bool rx_int_delay_en;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct thc_device;
|
struct thc_device;
|
||||||
|
@ -399,6 +399,11 @@
|
|||||||
#define THC_M_PRT_SPI_ICRRD_OPCODE_SPI_DIO GENMASK(23, 16)
|
#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_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_SIPE BIT(0)
|
||||||
#define THC_M_PRT_INT_EN_SBO BIT(1)
|
#define THC_M_PRT_INT_EN_SBO BIT(1)
|
||||||
#define THC_M_PRT_INT_EN_SIDR BIT(2)
|
#define THC_M_PRT_INT_EN_SIDR BIT(2)
|
||||||
|
94
drivers/hid/intel-thc-hid/intel-thc/intel-thc-wot.c
Normal file
94
drivers/hid/intel-thc-hid/intel-thc/intel-thc-wot.c
Normal file
@ -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");
|
26
drivers/hid/intel-thc-hid/intel-thc/intel-thc-wot.h
Normal file
26
drivers/hid/intel-thc-hid/intel-thc/intel-thc-wot.h
Normal file
@ -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_ */
|
@ -210,9 +210,7 @@ struct pidff_device {
|
|||||||
*/
|
*/
|
||||||
static s32 pidff_clamp(s32 i, struct hid_field *field)
|
static s32 pidff_clamp(s32 i, struct hid_field *field)
|
||||||
{
|
{
|
||||||
s32 clamped = clamp(i, field->logical_minimum, field->logical_maximum);
|
return (s32)clamp(i, field->logical_minimum, field->logical_maximum);
|
||||||
pr_debug("clamped from %d to %d", i, clamped);
|
|
||||||
return clamped;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -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)
|
static int pidff_rescale_signed(int i, struct hid_field *field)
|
||||||
{
|
{
|
||||||
if (i > 0) return i * field->logical_maximum / S16_MAX;
|
if (i > 0)
|
||||||
if (i < 0) return i * field->logical_minimum / S16_MIN;
|
return i * field->logical_maximum / S16_MAX;
|
||||||
|
if (i < 0)
|
||||||
|
return i * field->logical_minimum / S16_MIN;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -241,8 +241,8 @@ static u32 pidff_rescale_time(u16 time, struct hid_field *field)
|
|||||||
{
|
{
|
||||||
u32 scaled_time = time;
|
u32 scaled_time = time;
|
||||||
int exponent = field->unit_exponent;
|
int exponent = field->unit_exponent;
|
||||||
pr_debug("time field exponent: %d\n", exponent);
|
|
||||||
|
|
||||||
|
pr_debug("time field exponent: %d\n", exponent);
|
||||||
for (; exponent < FF_TIME_EXPONENT; exponent++)
|
for (; exponent < FF_TIME_EXPONENT; exponent++)
|
||||||
scaled_time *= 10;
|
scaled_time *= 10;
|
||||||
for (; exponent > FF_TIME_EXPONENT; exponent--)
|
for (; exponent > FF_TIME_EXPONENT; exponent--)
|
||||||
@ -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)
|
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(
|
||||||
usage->value[0] = pidff_clamp(modified_time, usage->field);
|
pidff_rescale_time(time, usage->field), usage->field);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void pidff_set_duration(struct pidff_usage *usage, u16 duration)
|
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)
|
struct ff_envelope *old)
|
||||||
{
|
{
|
||||||
bool needs_new_envelope;
|
bool needs_new_envelope;
|
||||||
|
|
||||||
needs_new_envelope = envelope->attack_level != 0 ||
|
needs_new_envelope = envelope->attack_level != 0 ||
|
||||||
envelope->fade_level != 0 ||
|
envelope->fade_level != 0 ||
|
||||||
envelope->attack_length != 0 ||
|
envelope->attack_length != 0 ||
|
||||||
@ -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)
|
static int pidff_playback(struct input_dev *dev, int effect_id, int value)
|
||||||
{
|
{
|
||||||
struct pidff_device *pidff = dev->ff->private;
|
struct pidff_device *pidff = dev->ff->private;
|
||||||
|
|
||||||
pidff_playback_pid(pidff, pidff->pid_id[effect_id], value);
|
pidff_playback_pid(pidff, pidff->pid_id[effect_id], value);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -940,7 +942,7 @@ static int pidff_find_fields(struct pidff_usage *usage, const u8 *table,
|
|||||||
struct hid_report *report, int count, int strict)
|
struct hid_report *report, int count, int strict)
|
||||||
{
|
{
|
||||||
if (!report) {
|
if (!report) {
|
||||||
pr_debug("pidff_find_fields, null report\n");
|
pr_debug("%s, null report\n", __func__);
|
||||||
return -1;
|
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("Delay field not found, but that's OK\n");
|
||||||
pr_debug("Setting MISSING_DELAY quirk\n");
|
pr_debug("Setting MISSING_DELAY quirk\n");
|
||||||
return_value |= HID_PIDFF_QUIRK_MISSING_DELAY;
|
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("PBO field not found, but that's OK\n");
|
||||||
pr_debug("Setting MISSING_PBO quirk\n");
|
pr_debug("Setting MISSING_PBO quirk\n");
|
||||||
return_value |= HID_PIDFF_QUIRK_MISSING_PBO;
|
return_value |= HID_PIDFF_QUIRK_MISSING_PBO;
|
||||||
}
|
} else if (!found && strict) {
|
||||||
else if (!found && strict) {
|
|
||||||
pr_debug("failed to locate %d\n", k);
|
pr_debug("failed to locate %d\n", k);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -1069,7 +1069,7 @@ static struct hid_field *pidff_find_special_field(struct hid_report *report,
|
|||||||
int usage, int enforce_min)
|
int usage, int enforce_min)
|
||||||
{
|
{
|
||||||
if (!report) {
|
if (!report) {
|
||||||
pr_debug("pidff_find_special_field, null report\n");
|
pr_debug("%s, null report\n", __func__);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1081,12 +1081,11 @@ static struct hid_field *pidff_find_special_field(struct hid_report *report,
|
|||||||
if (!enforce_min ||
|
if (!enforce_min ||
|
||||||
report->field[i]->logical_minimum == 1)
|
report->field[i]->logical_minimum == 1)
|
||||||
return report->field[i];
|
return report->field[i];
|
||||||
else {
|
|
||||||
pr_err("logical_minimum is not 1 as it should be\n");
|
pr_err("logical_minimum is not 1 as it should be\n");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
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++) {
|
for (i = 0; i < sizeof(pidff_effect_types); i++) {
|
||||||
int pidff_type = pidff->type_id[i];
|
int pidff_type = pidff->type_id[i];
|
||||||
|
|
||||||
if (pidff->set_effect_type->usage[pidff_type].hid !=
|
if (pidff->set_effect_type->usage[pidff_type].hid !=
|
||||||
pidff->create_new_effect_type->usage[pidff_type].hid) {
|
pidff->create_new_effect_type->usage[pidff_type].hid) {
|
||||||
hid_err(pidff->hid,
|
hid_err(pidff->hid,
|
||||||
|
@ -9,8 +9,7 @@
|
|||||||
/* Delay field (0xA7) missing. Skip it during set effect report upload */
|
/* Delay field (0xA7) missing. Skip it during set effect report upload */
|
||||||
#define HID_PIDFF_QUIRK_MISSING_DELAY BIT(0)
|
#define HID_PIDFF_QUIRK_MISSING_DELAY BIT(0)
|
||||||
|
|
||||||
/* Missing Paramter block offset (0x23). Skip it during SET_CONDITION
|
/* Missing Paramter block offset (0x23). Skip it during SET_CONDITION upload */
|
||||||
report upload */
|
|
||||||
#define HID_PIDFF_QUIRK_MISSING_PBO BIT(1)
|
#define HID_PIDFF_QUIRK_MISSING_PBO BIT(1)
|
||||||
|
|
||||||
/* Initialise device control field even if logical_minimum != 1 */
|
/* Initialise device control field even if logical_minimum != 1 */
|
||||||
|
@ -1216,7 +1216,11 @@ static inline void hid_hw_wait(struct hid_device *hdev)
|
|||||||
/**
|
/**
|
||||||
* hid_report_len - calculate the report length
|
* hid_report_len - calculate the report length
|
||||||
*
|
*
|
||||||
* @report: the report we want to know the length
|
* @report: the report whose length we want to know
|
||||||
|
*
|
||||||
|
* The length counts the report ID byte, but only if the ID is nonzero
|
||||||
|
* and therefore is included in the report. Reports whose ID is zero
|
||||||
|
* never include an ID byte.
|
||||||
*/
|
*/
|
||||||
static inline u32 hid_report_len(struct hid_report *report)
|
static inline u32 hid_report_len(struct hid_report *report)
|
||||||
{
|
{
|
||||||
@ -1239,6 +1243,8 @@ void hid_quirks_exit(__u16 bus);
|
|||||||
dev_notice(&(hid)->dev, fmt, ##__VA_ARGS__)
|
dev_notice(&(hid)->dev, fmt, ##__VA_ARGS__)
|
||||||
#define hid_warn(hid, fmt, ...) \
|
#define hid_warn(hid, fmt, ...) \
|
||||||
dev_warn(&(hid)->dev, fmt, ##__VA_ARGS__)
|
dev_warn(&(hid)->dev, fmt, ##__VA_ARGS__)
|
||||||
|
#define hid_warn_ratelimited(hid, fmt, ...) \
|
||||||
|
dev_warn_ratelimited(&(hid)->dev, fmt, ##__VA_ARGS__)
|
||||||
#define hid_info(hid, fmt, ...) \
|
#define hid_info(hid, fmt, ...) \
|
||||||
dev_info(&(hid)->dev, fmt, ##__VA_ARGS__)
|
dev_info(&(hid)->dev, fmt, ##__VA_ARGS__)
|
||||||
#define hid_dbg(hid, fmt, ...) \
|
#define hid_dbg(hid, fmt, ...) \
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
# Copyright (c) 2017 Benjamin Tissoires <benjamin.tissoires@gmail.com>
|
# Copyright (c) 2017 Benjamin Tissoires <benjamin.tissoires@gmail.com>
|
||||||
# Copyright (c) 2017 Red Hat, Inc.
|
# Copyright (c) 2017 Red Hat, Inc.
|
||||||
|
|
||||||
|
import dataclasses
|
||||||
import libevdev
|
import libevdev
|
||||||
import os
|
import os
|
||||||
import pytest
|
import pytest
|
||||||
@ -145,6 +146,18 @@ class UHIDTestDevice(BaseDevice):
|
|||||||
self.name = name
|
self.name = name
|
||||||
|
|
||||||
|
|
||||||
|
@dataclasses.dataclass
|
||||||
|
class HidBpf:
|
||||||
|
object_name: str
|
||||||
|
has_rdesc_fixup: bool
|
||||||
|
|
||||||
|
|
||||||
|
@dataclasses.dataclass
|
||||||
|
class KernelModule:
|
||||||
|
driver_name: str
|
||||||
|
module_name: str
|
||||||
|
|
||||||
|
|
||||||
class BaseTestCase:
|
class BaseTestCase:
|
||||||
class TestUhid(object):
|
class TestUhid(object):
|
||||||
syn_event = libevdev.InputEvent(libevdev.EV_SYN.SYN_REPORT) # type: ignore
|
syn_event = libevdev.InputEvent(libevdev.EV_SYN.SYN_REPORT) # type: ignore
|
||||||
@ -155,20 +168,20 @@ class BaseTestCase:
|
|||||||
|
|
||||||
# List of kernel modules to load before starting the test
|
# List of kernel modules to load before starting the test
|
||||||
# if any module is not available (not compiled), the test will skip.
|
# if any module is not available (not compiled), the test will skip.
|
||||||
# Each element is a tuple '(kernel driver name, kernel module)',
|
# Each element is a KernelModule object, for example
|
||||||
# for example ("playstation", "hid-playstation")
|
# KernelModule("playstation", "hid-playstation")
|
||||||
kernel_modules: List[Tuple[str, str]] = []
|
kernel_modules: List[KernelModule] = []
|
||||||
|
|
||||||
# List of in kernel HID-BPF object files to load
|
# List of in kernel HID-BPF object files to load
|
||||||
# before starting the test
|
# before starting the test
|
||||||
# Any existing pre-loaded HID-BPF module will be removed
|
# Any existing pre-loaded HID-BPF module will be removed
|
||||||
# before the ones in this list will be manually loaded.
|
# before the ones in this list will be manually loaded.
|
||||||
# Each Element is a tuple '(hid_bpf_object, rdesc_fixup_present)',
|
# Each Element is a HidBpf object, for example
|
||||||
# for example '("xppen-ArtistPro16Gen2.bpf.o", True)'
|
# 'HidBpf("xppen-ArtistPro16Gen2.bpf.o", True)'
|
||||||
# If 'rdesc_fixup_present' is True, the test needs to wait
|
# If 'has_rdesc_fixup' is True, the test needs to wait
|
||||||
# for one unbind and rebind before it can be sure the kernel is
|
# for one unbind and rebind before it can be sure the kernel is
|
||||||
# ready
|
# ready
|
||||||
hid_bpfs: List[Tuple[str, bool]] = []
|
hid_bpfs: List[HidBpf] = []
|
||||||
|
|
||||||
def assertInputEventsIn(self, expected_events, effective_events):
|
def assertInputEventsIn(self, expected_events, effective_events):
|
||||||
effective_events = effective_events.copy()
|
effective_events = effective_events.copy()
|
||||||
@ -232,25 +245,26 @@ class BaseTestCase:
|
|||||||
|
|
||||||
@pytest.fixture()
|
@pytest.fixture()
|
||||||
def load_kernel_module(self):
|
def load_kernel_module(self):
|
||||||
for kernel_driver, kernel_module in self.kernel_modules:
|
for k in self.kernel_modules:
|
||||||
self._load_kernel_module(kernel_driver, kernel_module)
|
self._load_kernel_module(k.driver_name, k.module_name)
|
||||||
yield
|
yield
|
||||||
|
|
||||||
def load_hid_bpfs(self):
|
def load_hid_bpfs(self):
|
||||||
|
# this function will only work when run in the kernel tree
|
||||||
script_dir = Path(os.path.dirname(os.path.realpath(__file__)))
|
script_dir = Path(os.path.dirname(os.path.realpath(__file__)))
|
||||||
root_dir = (script_dir / "../../../../..").resolve()
|
root_dir = (script_dir / "../../../../..").resolve()
|
||||||
bpf_dir = root_dir / "drivers/hid/bpf/progs"
|
bpf_dir = root_dir / "drivers/hid/bpf/progs"
|
||||||
|
|
||||||
|
if not bpf_dir.exists():
|
||||||
|
pytest.skip("looks like we are not in the kernel tree, skipping")
|
||||||
|
|
||||||
udev_hid_bpf = shutil.which("udev-hid-bpf")
|
udev_hid_bpf = shutil.which("udev-hid-bpf")
|
||||||
if not udev_hid_bpf:
|
if not udev_hid_bpf:
|
||||||
pytest.skip("udev-hid-bpf not found in $PATH, skipping")
|
pytest.skip("udev-hid-bpf not found in $PATH, skipping")
|
||||||
|
|
||||||
wait = False
|
wait = any(b.has_rdesc_fixup for b in self.hid_bpfs)
|
||||||
for _, rdesc_fixup in self.hid_bpfs:
|
|
||||||
if rdesc_fixup:
|
|
||||||
wait = True
|
|
||||||
|
|
||||||
for hid_bpf, _ in self.hid_bpfs:
|
for hid_bpf in self.hid_bpfs:
|
||||||
# We need to start `udev-hid-bpf` in the background
|
# We need to start `udev-hid-bpf` in the background
|
||||||
# and dispatch uhid events in case the kernel needs
|
# and dispatch uhid events in case the kernel needs
|
||||||
# to fetch features on the device
|
# to fetch features on the device
|
||||||
@ -260,13 +274,13 @@ class BaseTestCase:
|
|||||||
"--verbose",
|
"--verbose",
|
||||||
"add",
|
"add",
|
||||||
str(self.uhdev.sys_path),
|
str(self.uhdev.sys_path),
|
||||||
str(bpf_dir / hid_bpf),
|
str(bpf_dir / hid_bpf.object_name),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
while process.poll() is None:
|
while process.poll() is None:
|
||||||
self.uhdev.dispatch(1)
|
self.uhdev.dispatch(1)
|
||||||
|
|
||||||
if process.poll() != 0:
|
if process.returncode != 0:
|
||||||
pytest.fail(
|
pytest.fail(
|
||||||
f"Couldn't insert hid-bpf program '{hid_bpf}', marking the test as failed"
|
f"Couldn't insert hid-bpf program '{hid_bpf}', marking the test as failed"
|
||||||
)
|
)
|
||||||
|
@ -18,10 +18,12 @@
|
|||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import dataclasses
|
||||||
import fcntl
|
import fcntl
|
||||||
import functools
|
import functools
|
||||||
import libevdev
|
import libevdev
|
||||||
import os
|
import os
|
||||||
|
import threading
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import pyudev
|
import pyudev
|
||||||
@ -104,6 +106,12 @@ class PowerSupply(object):
|
|||||||
return self._type.str_value
|
return self._type.str_value
|
||||||
|
|
||||||
|
|
||||||
|
@dataclasses.dataclass
|
||||||
|
class HidReadiness:
|
||||||
|
is_ready: bool = False
|
||||||
|
count: int = 0
|
||||||
|
|
||||||
|
|
||||||
class HIDIsReady(object):
|
class HIDIsReady(object):
|
||||||
"""
|
"""
|
||||||
Companion class that binds to a kernel mechanism
|
Companion class that binds to a kernel mechanism
|
||||||
@ -115,18 +123,18 @@ class HIDIsReady(object):
|
|||||||
def __init__(self: "HIDIsReady", uhid: UHIDDevice) -> None:
|
def __init__(self: "HIDIsReady", uhid: UHIDDevice) -> None:
|
||||||
self.uhid = uhid
|
self.uhid = uhid
|
||||||
|
|
||||||
def is_ready(self: "HIDIsReady") -> bool:
|
def is_ready(self: "HIDIsReady") -> HidReadiness:
|
||||||
"""
|
"""
|
||||||
Overwrite in subclasses: should return True or False whether
|
Overwrite in subclasses: should return True or False whether
|
||||||
the attached uhid device is ready or not.
|
the attached uhid device is ready or not.
|
||||||
"""
|
"""
|
||||||
return False
|
return HidReadiness()
|
||||||
|
|
||||||
|
|
||||||
class UdevHIDIsReady(HIDIsReady):
|
class UdevHIDIsReady(HIDIsReady):
|
||||||
_pyudev_context: ClassVar[Optional[pyudev.Context]] = None
|
_pyudev_context: ClassVar[Optional[pyudev.Context]] = None
|
||||||
_pyudev_monitor: ClassVar[Optional[pyudev.Monitor]] = None
|
_pyudev_monitor: ClassVar[Optional[pyudev.Monitor]] = None
|
||||||
_uhid_devices: ClassVar[Dict[int, Tuple[bool, int]]] = {}
|
_uhid_devices: ClassVar[Dict[int, HidReadiness]] = {}
|
||||||
|
|
||||||
def __init__(self: "UdevHIDIsReady", uhid: UHIDDevice) -> None:
|
def __init__(self: "UdevHIDIsReady", uhid: UHIDDevice) -> None:
|
||||||
super().__init__(uhid)
|
super().__init__(uhid)
|
||||||
@ -157,18 +165,19 @@ class UdevHIDIsReady(HIDIsReady):
|
|||||||
|
|
||||||
id = int(event.sys_path.strip().split(".")[-1], 16)
|
id = int(event.sys_path.strip().split(".")[-1], 16)
|
||||||
|
|
||||||
device_ready, count = cls._uhid_devices.get(id, (False, 0))
|
readiness = cls._uhid_devices.setdefault(id, HidReadiness())
|
||||||
|
|
||||||
ready = event.action == "bind"
|
ready = event.action == "bind"
|
||||||
if not device_ready and ready:
|
if not readiness.is_ready and ready:
|
||||||
count += 1
|
readiness.count += 1
|
||||||
cls._uhid_devices[id] = (ready, count)
|
|
||||||
|
|
||||||
def is_ready(self: "UdevHIDIsReady") -> Tuple[bool, int]:
|
readiness.is_ready = ready
|
||||||
|
|
||||||
|
def is_ready(self: "UdevHIDIsReady") -> HidReadiness:
|
||||||
try:
|
try:
|
||||||
return self._uhid_devices[self.uhid.hid_id]
|
return self._uhid_devices[self.uhid.hid_id]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
return (False, 0)
|
return HidReadiness()
|
||||||
|
|
||||||
|
|
||||||
class EvdevMatch(object):
|
class EvdevMatch(object):
|
||||||
@ -322,11 +331,11 @@ class BaseDevice(UHIDDevice):
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def kernel_is_ready(self: "BaseDevice") -> bool:
|
def kernel_is_ready(self: "BaseDevice") -> bool:
|
||||||
return self._kernel_is_ready.is_ready()[0] and self.started
|
return self._kernel_is_ready.is_ready().is_ready and self.started
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def kernel_ready_count(self: "BaseDevice") -> int:
|
def kernel_ready_count(self: "BaseDevice") -> int:
|
||||||
return self._kernel_is_ready.is_ready()[1]
|
return self._kernel_is_ready.is_ready().count
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def input_nodes(self: "BaseDevice") -> List[EvdevDevice]:
|
def input_nodes(self: "BaseDevice") -> List[EvdevDevice]:
|
||||||
@ -336,10 +345,28 @@ class BaseDevice(UHIDDevice):
|
|||||||
if not self.kernel_is_ready or not self.started:
|
if not self.kernel_is_ready or not self.started:
|
||||||
return []
|
return []
|
||||||
|
|
||||||
|
# Starting with kernel v6.16, an event is emitted when
|
||||||
|
# userspace opens a kernel device, and for some devices
|
||||||
|
# this translates into a SET_REPORT.
|
||||||
|
# Because EvdevDevice(path) opens every single evdev node
|
||||||
|
# we need to have a separate thread to process the incoming
|
||||||
|
# SET_REPORT or we end up having to wait for the kernel
|
||||||
|
# timeout of 5 seconds.
|
||||||
|
done = False
|
||||||
|
|
||||||
|
def dispatch():
|
||||||
|
while not done:
|
||||||
|
self.dispatch(1)
|
||||||
|
|
||||||
|
t = threading.Thread(target=dispatch)
|
||||||
|
t.start()
|
||||||
|
|
||||||
self._input_nodes = [
|
self._input_nodes = [
|
||||||
EvdevDevice(path)
|
EvdevDevice(path)
|
||||||
for path in self.walk_sysfs("input", "input/input*/event*")
|
for path in self.walk_sysfs("input", "input/input*/event*")
|
||||||
]
|
]
|
||||||
|
done = True
|
||||||
|
t.join()
|
||||||
return self._input_nodes
|
return self._input_nodes
|
||||||
|
|
||||||
def match_evdev_rule(self, application, evdev):
|
def match_evdev_rule(self, application, evdev):
|
||||||
|
@ -8,13 +8,14 @@
|
|||||||
|
|
||||||
from .test_keyboard import ArrayKeyboard, TestArrayKeyboard
|
from .test_keyboard import ArrayKeyboard, TestArrayKeyboard
|
||||||
from hidtools.util import BusType
|
from hidtools.util import BusType
|
||||||
|
from . import base
|
||||||
|
|
||||||
import libevdev
|
import libevdev
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
logger = logging.getLogger("hidtools.test.apple-keyboard")
|
logger = logging.getLogger("hidtools.test.apple-keyboard")
|
||||||
|
|
||||||
KERNEL_MODULE = ("apple", "hid-apple")
|
KERNEL_MODULE = base.KernelModule("apple", "hid-apple")
|
||||||
|
|
||||||
|
|
||||||
class KbdData(object):
|
class KbdData(object):
|
||||||
|
@ -12,6 +12,7 @@ import pytest
|
|||||||
|
|
||||||
from .base_gamepad import BaseGamepad, JoystickGamepad, AxisMapping
|
from .base_gamepad import BaseGamepad, JoystickGamepad, AxisMapping
|
||||||
from hidtools.util import BusType
|
from hidtools.util import BusType
|
||||||
|
from .base import HidBpf
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
@ -654,7 +655,7 @@ class TestAsusGamepad(BaseTest.TestGamepad):
|
|||||||
|
|
||||||
|
|
||||||
class TestRaptorMach2Joystick(BaseTest.TestGamepad):
|
class TestRaptorMach2Joystick(BaseTest.TestGamepad):
|
||||||
hid_bpfs = [("FR-TEC__Raptor-Mach-2.bpf.o", True)]
|
hid_bpfs = [HidBpf("FR-TEC__Raptor-Mach-2.bpf.o", True)]
|
||||||
|
|
||||||
def create_device(self):
|
def create_device(self):
|
||||||
return RaptorMach2Joystick(
|
return RaptorMach2Joystick(
|
||||||
|
@ -11,10 +11,11 @@ from hidtools.util import BusType
|
|||||||
|
|
||||||
import libevdev
|
import libevdev
|
||||||
import logging
|
import logging
|
||||||
|
from . import base
|
||||||
|
|
||||||
logger = logging.getLogger("hidtools.test.ite-keyboard")
|
logger = logging.getLogger("hidtools.test.ite-keyboard")
|
||||||
|
|
||||||
KERNEL_MODULE = ("itetech", "hid_ite")
|
KERNEL_MODULE = base.KernelModule("itetech", "hid_ite")
|
||||||
|
|
||||||
|
|
||||||
class KbdData(object):
|
class KbdData(object):
|
||||||
|
@ -17,7 +17,7 @@ import time
|
|||||||
|
|
||||||
logger = logging.getLogger("hidtools.test.multitouch")
|
logger = logging.getLogger("hidtools.test.multitouch")
|
||||||
|
|
||||||
KERNEL_MODULE = ("hid-multitouch", "hid_multitouch")
|
KERNEL_MODULE = base.KernelModule("hid-multitouch", "hid_multitouch")
|
||||||
|
|
||||||
|
|
||||||
def BIT(x):
|
def BIT(x):
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
#
|
#
|
||||||
|
|
||||||
from .base import application_matches
|
from .base import application_matches
|
||||||
|
from .base import KernelModule
|
||||||
from .test_gamepad import BaseTest
|
from .test_gamepad import BaseTest
|
||||||
from hidtools.device.sony_gamepad import (
|
from hidtools.device.sony_gamepad import (
|
||||||
PS3Controller,
|
PS3Controller,
|
||||||
@ -24,9 +25,9 @@ import pytest
|
|||||||
|
|
||||||
logger = logging.getLogger("hidtools.test.sony")
|
logger = logging.getLogger("hidtools.test.sony")
|
||||||
|
|
||||||
PS3_MODULE = ("sony", "hid_sony")
|
PS3_MODULE = KernelModule("sony", "hid_sony")
|
||||||
PS4_MODULE = ("playstation", "hid_playstation")
|
PS4_MODULE = KernelModule("playstation", "hid_playstation")
|
||||||
PS5_MODULE = ("playstation", "hid_playstation")
|
PS5_MODULE = KernelModule("playstation", "hid_playstation")
|
||||||
|
|
||||||
|
|
||||||
class SonyBaseTest:
|
class SonyBaseTest:
|
||||||
|
@ -10,6 +10,7 @@ from . import base
|
|||||||
import copy
|
import copy
|
||||||
from enum import Enum
|
from enum import Enum
|
||||||
from hidtools.util import BusType
|
from hidtools.util import BusType
|
||||||
|
from .base import HidBpf
|
||||||
import libevdev
|
import libevdev
|
||||||
import logging
|
import logging
|
||||||
import pytest
|
import pytest
|
||||||
@ -1228,9 +1229,9 @@ class Huion_Kamvas_Pro_19_256c_006b(PenDigitizer):
|
|||||||
pen.current_state = state
|
pen.current_state = state
|
||||||
|
|
||||||
def call_input_event(self, report):
|
def call_input_event(self, report):
|
||||||
if report[0] == 0x0a:
|
if report[0] == 0x0A:
|
||||||
# ensures the original second Eraser usage is null
|
# ensures the original second Eraser usage is null
|
||||||
report[1] &= 0xdf
|
report[1] &= 0xDF
|
||||||
|
|
||||||
# ensures the original last bit is equal to bit 6 (In Range)
|
# ensures the original last bit is equal to bit 6 (In Range)
|
||||||
if report[1] & 0x40:
|
if report[1] & 0x40:
|
||||||
@ -1472,7 +1473,7 @@ class TestGoodix_27c6_0e00(BaseTest.TestTablet):
|
|||||||
|
|
||||||
|
|
||||||
class TestXPPen_ArtistPro16Gen2_28bd_095b(BaseTest.TestTablet):
|
class TestXPPen_ArtistPro16Gen2_28bd_095b(BaseTest.TestTablet):
|
||||||
hid_bpfs = [("XPPen__ArtistPro16Gen2.bpf.o", True)]
|
hid_bpfs = [HidBpf("XPPen__ArtistPro16Gen2.bpf.o", True)]
|
||||||
|
|
||||||
def create_device(self):
|
def create_device(self):
|
||||||
dev = XPPen_ArtistPro16Gen2_28bd_095b(
|
dev = XPPen_ArtistPro16Gen2_28bd_095b(
|
||||||
@ -1484,7 +1485,7 @@ class TestXPPen_ArtistPro16Gen2_28bd_095b(BaseTest.TestTablet):
|
|||||||
|
|
||||||
|
|
||||||
class TestXPPen_Artist24_28bd_093a(BaseTest.TestTablet):
|
class TestXPPen_Artist24_28bd_093a(BaseTest.TestTablet):
|
||||||
hid_bpfs = [("XPPen__Artist24.bpf.o", True)]
|
hid_bpfs = [HidBpf("XPPen__Artist24.bpf.o", True)]
|
||||||
|
|
||||||
def create_device(self):
|
def create_device(self):
|
||||||
return XPPen_Artist24_28bd_093a(
|
return XPPen_Artist24_28bd_093a(
|
||||||
@ -1495,7 +1496,7 @@ class TestXPPen_Artist24_28bd_093a(BaseTest.TestTablet):
|
|||||||
|
|
||||||
|
|
||||||
class TestHuion_Kamvas_Pro_19_256c_006b(BaseTest.TestTablet):
|
class TestHuion_Kamvas_Pro_19_256c_006b(BaseTest.TestTablet):
|
||||||
hid_bpfs = [("Huion__Kamvas-Pro-19.bpf.o", True)]
|
hid_bpfs = [HidBpf("Huion__Kamvas-Pro-19.bpf.o", True)]
|
||||||
|
|
||||||
def create_device(self):
|
def create_device(self):
|
||||||
return Huion_Kamvas_Pro_19_256c_006b(
|
return Huion_Kamvas_Pro_19_256c_006b(
|
||||||
|
@ -40,7 +40,7 @@ import logging
|
|||||||
|
|
||||||
logger = logging.getLogger("hidtools.test.wacom")
|
logger = logging.getLogger("hidtools.test.wacom")
|
||||||
|
|
||||||
KERNEL_MODULE = ("wacom", "wacom")
|
KERNEL_MODULE = base.KernelModule("wacom", "wacom")
|
||||||
|
|
||||||
|
|
||||||
class ProximityState(Enum):
|
class ProximityState(Enum):
|
||||||
@ -894,7 +894,7 @@ class TestDTH2452Tablet(test_multitouch.BaseTest.TestMultitouch, TouchTabletTest
|
|||||||
"""
|
"""
|
||||||
return [self.make_contact(id, t) for id in range(0, n)]
|
return [self.make_contact(id, t) for id in range(0, n)]
|
||||||
|
|
||||||
def assert_contact(self, uhdev, evdev, contact_ids, t=0):
|
def assert_contact(self, evdev, contact_ids, t=0):
|
||||||
"""
|
"""
|
||||||
Assert properties of a contact generated by make_contact.
|
Assert properties of a contact generated by make_contact.
|
||||||
"""
|
"""
|
||||||
@ -916,12 +916,12 @@ class TestDTH2452Tablet(test_multitouch.BaseTest.TestMultitouch, TouchTabletTest
|
|||||||
assert evdev.slots[slot_num][libevdev.EV_ABS.ABS_MT_POSITION_X] == x
|
assert evdev.slots[slot_num][libevdev.EV_ABS.ABS_MT_POSITION_X] == x
|
||||||
assert evdev.slots[slot_num][libevdev.EV_ABS.ABS_MT_POSITION_Y] == y
|
assert evdev.slots[slot_num][libevdev.EV_ABS.ABS_MT_POSITION_Y] == y
|
||||||
|
|
||||||
def assert_contacts(self, uhdev, evdev, data, t=0):
|
def assert_contacts(self, evdev, data, t=0):
|
||||||
"""
|
"""
|
||||||
Assert properties of a list of contacts generated by make_contacts.
|
Assert properties of a list of contacts generated by make_contacts.
|
||||||
"""
|
"""
|
||||||
for contact_ids in data:
|
for contact_ids in data:
|
||||||
self.assert_contact(uhdev, evdev, contact_ids, t)
|
self.assert_contact(evdev, contact_ids, t)
|
||||||
|
|
||||||
def test_contact_id_0(self):
|
def test_contact_id_0(self):
|
||||||
"""
|
"""
|
||||||
@ -997,12 +997,16 @@ class TestDTH2452Tablet(test_multitouch.BaseTest.TestMultitouch, TouchTabletTest
|
|||||||
|
|
||||||
assert libevdev.InputEvent(libevdev.EV_KEY.BTN_TOUCH, 1) in events
|
assert libevdev.InputEvent(libevdev.EV_KEY.BTN_TOUCH, 1) in events
|
||||||
|
|
||||||
self.assert_contacts(uhdev, evdev,
|
self.assert_contacts(
|
||||||
[ self.ContactIds(contact_id = 0, tracking_id = -1, slot_num = None),
|
evdev,
|
||||||
|
[
|
||||||
|
self.ContactIds(contact_id=0, tracking_id=-1, slot_num=None),
|
||||||
self.ContactIds(contact_id=1, tracking_id=0, slot_num=0),
|
self.ContactIds(contact_id=1, tracking_id=0, slot_num=0),
|
||||||
self.ContactIds(contact_id=2, tracking_id=-1, slot_num=None),
|
self.ContactIds(contact_id=2, tracking_id=-1, slot_num=None),
|
||||||
self.ContactIds(contact_id=3, tracking_id=1, slot_num=1),
|
self.ContactIds(contact_id=3, tracking_id=1, slot_num=1),
|
||||||
self.ContactIds(contact_id = 4, tracking_id = -1, slot_num = None) ])
|
self.ContactIds(contact_id=4, tracking_id=-1, slot_num=None),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
def confidence_change_assert_playback(self, uhdev, evdev, timeline):
|
def confidence_change_assert_playback(self, uhdev, evdev, timeline):
|
||||||
"""
|
"""
|
||||||
@ -1027,7 +1031,7 @@ class TestDTH2452Tablet(test_multitouch.BaseTest.TestMultitouch, TouchTabletTest
|
|||||||
self.debug_reports(r, uhdev, events)
|
self.debug_reports(r, uhdev, events)
|
||||||
|
|
||||||
ids = [x[0] for x in state]
|
ids = [x[0] for x in state]
|
||||||
self.assert_contacts(uhdev, evdev, ids, t)
|
self.assert_contacts(evdev, ids, t)
|
||||||
|
|
||||||
t += 1
|
t += 1
|
||||||
|
|
||||||
@ -1044,27 +1048,68 @@ class TestDTH2452Tablet(test_multitouch.BaseTest.TestMultitouch, TouchTabletTest
|
|||||||
uhdev = self.uhdev
|
uhdev = self.uhdev
|
||||||
evdev = uhdev.get_evdev()
|
evdev = uhdev.get_evdev()
|
||||||
|
|
||||||
self.confidence_change_assert_playback(uhdev, evdev, [
|
self.confidence_change_assert_playback(
|
||||||
|
uhdev,
|
||||||
|
evdev,
|
||||||
|
[
|
||||||
# t=0: Contact 0 == Down + confident; Contact 1 == Down + confident
|
# t=0: Contact 0 == Down + confident; Contact 1 == Down + confident
|
||||||
# Both fingers confidently in contact
|
# Both fingers confidently in contact
|
||||||
[(self.ContactIds(contact_id = 0, tracking_id = 0, slot_num = 0), True, True),
|
[
|
||||||
(self.ContactIds(contact_id = 1, tracking_id = 1, slot_num = 1), True, True)],
|
(
|
||||||
|
self.ContactIds(contact_id=0, tracking_id=0, slot_num=0),
|
||||||
|
True,
|
||||||
|
True,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
self.ContactIds(contact_id=1, tracking_id=1, slot_num=1),
|
||||||
|
True,
|
||||||
|
True,
|
||||||
|
),
|
||||||
|
],
|
||||||
# t=1: Contact 0 == !Down + confident; Contact 1 == Down + confident
|
# t=1: Contact 0 == !Down + confident; Contact 1 == Down + confident
|
||||||
# First finger looses confidence and clears only the tipswitch flag
|
# First finger looses confidence and clears only the tipswitch flag
|
||||||
[(self.ContactIds(contact_id = 0, tracking_id = -1, slot_num = 0), False, True),
|
[
|
||||||
(self.ContactIds(contact_id = 1, tracking_id = 1, slot_num = 1), True, True)],
|
(
|
||||||
|
self.ContactIds(contact_id=0, tracking_id=-1, slot_num=0),
|
||||||
|
False,
|
||||||
|
True,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
self.ContactIds(contact_id=1, tracking_id=1, slot_num=1),
|
||||||
|
True,
|
||||||
|
True,
|
||||||
|
),
|
||||||
|
],
|
||||||
# t=2: Contact 0 == !Down + !confident; Contact 1 == Down + confident
|
# t=2: Contact 0 == !Down + !confident; Contact 1 == Down + confident
|
||||||
# First finger has lost confidence and has both flags cleared
|
# First finger has lost confidence and has both flags cleared
|
||||||
[(self.ContactIds(contact_id = 0, tracking_id = -1, slot_num = 0), False, False),
|
[
|
||||||
(self.ContactIds(contact_id = 1, tracking_id = 1, slot_num = 1), True, True)],
|
(
|
||||||
|
self.ContactIds(contact_id=0, tracking_id=-1, slot_num=0),
|
||||||
|
False,
|
||||||
|
False,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
self.ContactIds(contact_id=1, tracking_id=1, slot_num=1),
|
||||||
|
True,
|
||||||
|
True,
|
||||||
|
),
|
||||||
|
],
|
||||||
# t=3: Contact 0 == !Down + !confident; Contact 1 == Down + confident
|
# t=3: Contact 0 == !Down + !confident; Contact 1 == Down + confident
|
||||||
# First finger has lost confidence and has both flags cleared
|
# First finger has lost confidence and has both flags cleared
|
||||||
[(self.ContactIds(contact_id = 0, tracking_id = -1, slot_num = 0), False, False),
|
[
|
||||||
(self.ContactIds(contact_id = 1, tracking_id = 1, slot_num = 1), True, True)]
|
(
|
||||||
])
|
self.ContactIds(contact_id=0, tracking_id=-1, slot_num=0),
|
||||||
|
False,
|
||||||
|
False,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
self.ContactIds(contact_id=1, tracking_id=1, slot_num=1),
|
||||||
|
True,
|
||||||
|
True,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
def test_confidence_loss_b(self):
|
def test_confidence_loss_b(self):
|
||||||
"""
|
"""
|
||||||
@ -1079,27 +1124,68 @@ class TestDTH2452Tablet(test_multitouch.BaseTest.TestMultitouch, TouchTabletTest
|
|||||||
uhdev = self.uhdev
|
uhdev = self.uhdev
|
||||||
evdev = uhdev.get_evdev()
|
evdev = uhdev.get_evdev()
|
||||||
|
|
||||||
self.confidence_change_assert_playback(uhdev, evdev, [
|
self.confidence_change_assert_playback(
|
||||||
|
uhdev,
|
||||||
|
evdev,
|
||||||
|
[
|
||||||
# t=0: Contact 0 == Down + confident; Contact 1 == Down + confident
|
# t=0: Contact 0 == Down + confident; Contact 1 == Down + confident
|
||||||
# Both fingers confidently in contact
|
# Both fingers confidently in contact
|
||||||
[(self.ContactIds(contact_id = 0, tracking_id = 0, slot_num = 0), True, True),
|
[
|
||||||
(self.ContactIds(contact_id = 1, tracking_id = 1, slot_num = 1), True, True)],
|
(
|
||||||
|
self.ContactIds(contact_id=0, tracking_id=0, slot_num=0),
|
||||||
|
True,
|
||||||
|
True,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
self.ContactIds(contact_id=1, tracking_id=1, slot_num=1),
|
||||||
|
True,
|
||||||
|
True,
|
||||||
|
),
|
||||||
|
],
|
||||||
# t=1: Contact 0 == !Down + !confident; Contact 1 == Down + confident
|
# t=1: Contact 0 == !Down + !confident; Contact 1 == Down + confident
|
||||||
# First finger looses confidence and has both flags cleared simultaneously
|
# First finger looses confidence and has both flags cleared simultaneously
|
||||||
[(self.ContactIds(contact_id = 0, tracking_id = -1, slot_num = 0), False, False),
|
[
|
||||||
(self.ContactIds(contact_id = 1, tracking_id = 1, slot_num = 1), True, True)],
|
(
|
||||||
|
self.ContactIds(contact_id=0, tracking_id=-1, slot_num=0),
|
||||||
|
False,
|
||||||
|
False,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
self.ContactIds(contact_id=1, tracking_id=1, slot_num=1),
|
||||||
|
True,
|
||||||
|
True,
|
||||||
|
),
|
||||||
|
],
|
||||||
# t=2: Contact 0 == !Down + !confident; Contact 1 == Down + confident
|
# t=2: Contact 0 == !Down + !confident; Contact 1 == Down + confident
|
||||||
# First finger has lost confidence and has both flags cleared
|
# First finger has lost confidence and has both flags cleared
|
||||||
[(self.ContactIds(contact_id = 0, tracking_id = -1, slot_num = 0), False, False),
|
[
|
||||||
(self.ContactIds(contact_id = 1, tracking_id = 1, slot_num = 1), True, True)],
|
(
|
||||||
|
self.ContactIds(contact_id=0, tracking_id=-1, slot_num=0),
|
||||||
|
False,
|
||||||
|
False,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
self.ContactIds(contact_id=1, tracking_id=1, slot_num=1),
|
||||||
|
True,
|
||||||
|
True,
|
||||||
|
),
|
||||||
|
],
|
||||||
# t=3: Contact 0 == !Down + !confident; Contact 1 == Down + confident
|
# t=3: Contact 0 == !Down + !confident; Contact 1 == Down + confident
|
||||||
# First finger has lost confidence and has both flags cleared
|
# First finger has lost confidence and has both flags cleared
|
||||||
[(self.ContactIds(contact_id = 0, tracking_id = -1, slot_num = 0), False, False),
|
[
|
||||||
(self.ContactIds(contact_id = 1, tracking_id = 1, slot_num = 1), True, True)]
|
(
|
||||||
])
|
self.ContactIds(contact_id=0, tracking_id=-1, slot_num=0),
|
||||||
|
False,
|
||||||
|
False,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
self.ContactIds(contact_id=1, tracking_id=1, slot_num=1),
|
||||||
|
True,
|
||||||
|
True,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
def test_confidence_loss_c(self):
|
def test_confidence_loss_c(self):
|
||||||
"""
|
"""
|
||||||
@ -1113,27 +1199,68 @@ class TestDTH2452Tablet(test_multitouch.BaseTest.TestMultitouch, TouchTabletTest
|
|||||||
uhdev = self.uhdev
|
uhdev = self.uhdev
|
||||||
evdev = uhdev.get_evdev()
|
evdev = uhdev.get_evdev()
|
||||||
|
|
||||||
self.confidence_change_assert_playback(uhdev, evdev, [
|
self.confidence_change_assert_playback(
|
||||||
|
uhdev,
|
||||||
|
evdev,
|
||||||
|
[
|
||||||
# t=0: Contact 0 == Down + confident; Contact 1 == Down + confident
|
# t=0: Contact 0 == Down + confident; Contact 1 == Down + confident
|
||||||
# Both fingers confidently in contact
|
# Both fingers confidently in contact
|
||||||
[(self.ContactIds(contact_id = 0, tracking_id = 0, slot_num = 0), True, True),
|
[
|
||||||
(self.ContactIds(contact_id = 1, tracking_id = 1, slot_num = 1), True, True)],
|
(
|
||||||
|
self.ContactIds(contact_id=0, tracking_id=0, slot_num=0),
|
||||||
|
True,
|
||||||
|
True,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
self.ContactIds(contact_id=1, tracking_id=1, slot_num=1),
|
||||||
|
True,
|
||||||
|
True,
|
||||||
|
),
|
||||||
|
],
|
||||||
# t=1: Contact 0 == Down + !confident; Contact 1 == Down + confident
|
# t=1: Contact 0 == Down + !confident; Contact 1 == Down + confident
|
||||||
# First finger looses confidence and clears only the confidence flag
|
# First finger looses confidence and clears only the confidence flag
|
||||||
[(self.ContactIds(contact_id = 0, tracking_id = -1, slot_num = 0), True, False),
|
[
|
||||||
(self.ContactIds(contact_id = 1, tracking_id = 1, slot_num = 1), True, True)],
|
(
|
||||||
|
self.ContactIds(contact_id=0, tracking_id=-1, slot_num=0),
|
||||||
|
True,
|
||||||
|
False,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
self.ContactIds(contact_id=1, tracking_id=1, slot_num=1),
|
||||||
|
True,
|
||||||
|
True,
|
||||||
|
),
|
||||||
|
],
|
||||||
# t=2: Contact 0 == !Down + !confident; Contact 1 == Down + confident
|
# t=2: Contact 0 == !Down + !confident; Contact 1 == Down + confident
|
||||||
# First finger has lost confidence and has both flags cleared
|
# First finger has lost confidence and has both flags cleared
|
||||||
[(self.ContactIds(contact_id = 0, tracking_id = -1, slot_num = 0), False, False),
|
[
|
||||||
(self.ContactIds(contact_id = 1, tracking_id = 1, slot_num = 1), True, True)],
|
(
|
||||||
|
self.ContactIds(contact_id=0, tracking_id=-1, slot_num=0),
|
||||||
|
False,
|
||||||
|
False,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
self.ContactIds(contact_id=1, tracking_id=1, slot_num=1),
|
||||||
|
True,
|
||||||
|
True,
|
||||||
|
),
|
||||||
|
],
|
||||||
# t=3: Contact 0 == !Down + !confident; Contact 1 == Down + confident
|
# t=3: Contact 0 == !Down + !confident; Contact 1 == Down + confident
|
||||||
# First finger has lost confidence and has both flags cleared
|
# First finger has lost confidence and has both flags cleared
|
||||||
[(self.ContactIds(contact_id = 0, tracking_id = -1, slot_num = 0), False, False),
|
[
|
||||||
(self.ContactIds(contact_id = 1, tracking_id = 1, slot_num = 1), True, True)]
|
(
|
||||||
])
|
self.ContactIds(contact_id=0, tracking_id=-1, slot_num=0),
|
||||||
|
False,
|
||||||
|
False,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
self.ContactIds(contact_id=1, tracking_id=1, slot_num=1),
|
||||||
|
True,
|
||||||
|
True,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
def test_confidence_gain_a(self):
|
def test_confidence_gain_a(self):
|
||||||
"""
|
"""
|
||||||
@ -1144,27 +1271,68 @@ class TestDTH2452Tablet(test_multitouch.BaseTest.TestMultitouch, TouchTabletTest
|
|||||||
uhdev = self.uhdev
|
uhdev = self.uhdev
|
||||||
evdev = uhdev.get_evdev()
|
evdev = uhdev.get_evdev()
|
||||||
|
|
||||||
self.confidence_change_assert_playback(uhdev, evdev, [
|
self.confidence_change_assert_playback(
|
||||||
|
uhdev,
|
||||||
|
evdev,
|
||||||
|
[
|
||||||
# t=0: Contact 0 == Down + !confident; Contact 1 == Down + confident
|
# t=0: Contact 0 == Down + !confident; Contact 1 == Down + confident
|
||||||
# Only second finger is confidently in contact
|
# Only second finger is confidently in contact
|
||||||
[(self.ContactIds(contact_id = 0, tracking_id = -1, slot_num = None), True, False),
|
[
|
||||||
(self.ContactIds(contact_id = 1, tracking_id = 0, slot_num = 0), True, True)],
|
(
|
||||||
|
self.ContactIds(contact_id=0, tracking_id=-1, slot_num=None),
|
||||||
|
True,
|
||||||
|
False,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
self.ContactIds(contact_id=1, tracking_id=0, slot_num=0),
|
||||||
|
True,
|
||||||
|
True,
|
||||||
|
),
|
||||||
|
],
|
||||||
# t=1: Contact 0 == Down + !confident; Contact 1 == Down + confident
|
# t=1: Contact 0 == Down + !confident; Contact 1 == Down + confident
|
||||||
# First finger gains confidence
|
# First finger gains confidence
|
||||||
[(self.ContactIds(contact_id = 0, tracking_id = -1, slot_num = None), True, False),
|
[
|
||||||
(self.ContactIds(contact_id = 1, tracking_id = 0, slot_num = 0), True, True)],
|
(
|
||||||
|
self.ContactIds(contact_id=0, tracking_id=-1, slot_num=None),
|
||||||
|
True,
|
||||||
|
False,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
self.ContactIds(contact_id=1, tracking_id=0, slot_num=0),
|
||||||
|
True,
|
||||||
|
True,
|
||||||
|
),
|
||||||
|
],
|
||||||
# t=2: Contact 0 == Down + confident; Contact 1 == Down + confident
|
# t=2: Contact 0 == Down + confident; Contact 1 == Down + confident
|
||||||
# First finger remains confident
|
# First finger remains confident
|
||||||
[(self.ContactIds(contact_id = 0, tracking_id = 1, slot_num = 1), True, True),
|
[
|
||||||
(self.ContactIds(contact_id = 1, tracking_id = 0, slot_num = 0), True, True)],
|
(
|
||||||
|
self.ContactIds(contact_id=0, tracking_id=1, slot_num=1),
|
||||||
|
True,
|
||||||
|
True,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
self.ContactIds(contact_id=1, tracking_id=0, slot_num=0),
|
||||||
|
True,
|
||||||
|
True,
|
||||||
|
),
|
||||||
|
],
|
||||||
# t=3: Contact 0 == Down + confident; Contact 1 == Down + confident
|
# t=3: Contact 0 == Down + confident; Contact 1 == Down + confident
|
||||||
# First finger remains confident
|
# First finger remains confident
|
||||||
[(self.ContactIds(contact_id = 0, tracking_id = 1, slot_num = 1), True, True),
|
[
|
||||||
(self.ContactIds(contact_id = 1, tracking_id = 0, slot_num = 0), True, True)]
|
(
|
||||||
])
|
self.ContactIds(contact_id=0, tracking_id=1, slot_num=1),
|
||||||
|
True,
|
||||||
|
True,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
self.ContactIds(contact_id=1, tracking_id=0, slot_num=0),
|
||||||
|
True,
|
||||||
|
True,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
def test_confidence_gain_b(self):
|
def test_confidence_gain_b(self):
|
||||||
"""
|
"""
|
||||||
@ -1175,24 +1343,65 @@ class TestDTH2452Tablet(test_multitouch.BaseTest.TestMultitouch, TouchTabletTest
|
|||||||
uhdev = self.uhdev
|
uhdev = self.uhdev
|
||||||
evdev = uhdev.get_evdev()
|
evdev = uhdev.get_evdev()
|
||||||
|
|
||||||
self.confidence_change_assert_playback(uhdev, evdev, [
|
self.confidence_change_assert_playback(
|
||||||
|
uhdev,
|
||||||
|
evdev,
|
||||||
|
[
|
||||||
# t=0: Contact 0 == Down + confident; Contact 1 == Down + confident
|
# t=0: Contact 0 == Down + confident; Contact 1 == Down + confident
|
||||||
# First and second finger confidently in contact
|
# First and second finger confidently in contact
|
||||||
[(self.ContactIds(contact_id = 0, tracking_id = 0, slot_num = 0), True, True),
|
[
|
||||||
(self.ContactIds(contact_id = 1, tracking_id = 1, slot_num = 1), True, True)],
|
(
|
||||||
|
self.ContactIds(contact_id=0, tracking_id=0, slot_num=0),
|
||||||
|
True,
|
||||||
|
True,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
self.ContactIds(contact_id=1, tracking_id=1, slot_num=1),
|
||||||
|
True,
|
||||||
|
True,
|
||||||
|
),
|
||||||
|
],
|
||||||
# t=1: Contact 0 == Down + !confident; Contact 1 == Down + confident
|
# t=1: Contact 0 == Down + !confident; Contact 1 == Down + confident
|
||||||
# Firtst finger looses confidence
|
# Firtst finger looses confidence
|
||||||
[(self.ContactIds(contact_id = 0, tracking_id = -1, slot_num = 0), True, False),
|
[
|
||||||
(self.ContactIds(contact_id = 1, tracking_id = 1, slot_num = 1), True, True)],
|
(
|
||||||
|
self.ContactIds(contact_id=0, tracking_id=-1, slot_num=0),
|
||||||
|
True,
|
||||||
|
False,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
self.ContactIds(contact_id=1, tracking_id=1, slot_num=1),
|
||||||
|
True,
|
||||||
|
True,
|
||||||
|
),
|
||||||
|
],
|
||||||
# t=2: Contact 0 == Down + confident; Contact 1 == Down + confident
|
# t=2: Contact 0 == Down + confident; Contact 1 == Down + confident
|
||||||
# First finger gains confidence
|
# First finger gains confidence
|
||||||
[(self.ContactIds(contact_id = 0, tracking_id = 2, slot_num = 0), True, True),
|
[
|
||||||
(self.ContactIds(contact_id = 1, tracking_id = 1, slot_num = 1), True, True)],
|
(
|
||||||
|
self.ContactIds(contact_id=0, tracking_id=2, slot_num=0),
|
||||||
|
True,
|
||||||
|
True,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
self.ContactIds(contact_id=1, tracking_id=1, slot_num=1),
|
||||||
|
True,
|
||||||
|
True,
|
||||||
|
),
|
||||||
|
],
|
||||||
# t=3: Contact 0 == !Down + confident; Contact 1 == Down + confident
|
# t=3: Contact 0 == !Down + confident; Contact 1 == Down + confident
|
||||||
# First finger goes up
|
# First finger goes up
|
||||||
[(self.ContactIds(contact_id = 0, tracking_id = -1, slot_num = 0), False, True),
|
[
|
||||||
(self.ContactIds(contact_id = 1, tracking_id = 1, slot_num = 1), True, True)]
|
(
|
||||||
])
|
self.ContactIds(contact_id=0, tracking_id=-1, slot_num=0),
|
||||||
|
False,
|
||||||
|
True,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
self.ContactIds(contact_id=1, tracking_id=1, slot_num=1),
|
||||||
|
True,
|
||||||
|
True,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
],
|
||||||
|
)
|
||||||
|
Loading…
Reference in New Issue
Block a user