mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-12-18 08:35:08 +08:00
Merge branch 'for-6.3/logitech' into for-linus
- HID++ fixes for scroll wheel, protocol and debug (Bastien Nocera) - add support of Logitech G923 Xbox Edition steering wheel (Walt Holman)
This commit is contained in:
commit
a74749efb4
@ -9217,6 +9217,13 @@ L: linux-input@vger.kernel.org
|
||||
S: Maintained
|
||||
F: drivers/hid/hid-logitech-*
|
||||
|
||||
HID++ LOGITECH DRIVERS
|
||||
R: Filipe Laíns <lains@riseup.net>
|
||||
R: Bastien Nocera <hadess@hadess.net>
|
||||
L: linux-input@vger.kernel.org
|
||||
S: Maintained
|
||||
F: drivers/hid/hid-logitech-hidpp.c
|
||||
|
||||
HID PLAYSTATION DRIVER
|
||||
M: Roderick Colenbrander <roderick.colenbrander@sony.com>
|
||||
L: linux-input@vger.kernel.org
|
||||
|
@ -825,6 +825,7 @@
|
||||
#define USB_DEVICE_ID_LOGITECH_G510_USB_AUDIO 0xc22e
|
||||
#define USB_DEVICE_ID_LOGITECH_G29_WHEEL 0xc24f
|
||||
#define USB_DEVICE_ID_LOGITECH_G920_WHEEL 0xc262
|
||||
#define USB_DEVICE_ID_LOGITECH_G923_XBOX_WHEEL 0xc26e
|
||||
#define USB_DEVICE_ID_LOGITECH_WINGMAN_F3D 0xc283
|
||||
#define USB_DEVICE_ID_LOGITECH_FORCE3D_PRO 0xc286
|
||||
#define USB_DEVICE_ID_LOGITECH_FLIGHT_SYSTEM_G940 0xc287
|
||||
|
@ -30,11 +30,7 @@
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Benjamin Tissoires <benjamin.tissoires@gmail.com>");
|
||||
MODULE_AUTHOR("Nestor Lopez Casado <nlopezcasad@logitech.com>");
|
||||
|
||||
static bool disable_raw_mode;
|
||||
module_param(disable_raw_mode, bool, 0644);
|
||||
MODULE_PARM_DESC(disable_raw_mode,
|
||||
"Disable Raw mode reporting for touchpads and keep firmware gestures.");
|
||||
MODULE_AUTHOR("Bastien Nocera <hadess@hadess.net>");
|
||||
|
||||
static bool disable_tap_to_click;
|
||||
module_param(disable_tap_to_click, bool, 0644);
|
||||
@ -71,12 +67,13 @@ MODULE_PARM_DESC(disable_tap_to_click,
|
||||
/* bits 2..20 are reserved for classes */
|
||||
/* #define HIDPP_QUIRK_CONNECT_EVENTS BIT(21) disabled */
|
||||
#define HIDPP_QUIRK_WTP_PHYSICAL_BUTTONS BIT(22)
|
||||
#define HIDPP_QUIRK_NO_HIDINPUT BIT(23)
|
||||
#define HIDPP_QUIRK_DELAYED_INIT BIT(23)
|
||||
#define HIDPP_QUIRK_FORCE_OUTPUT_REPORTS BIT(24)
|
||||
#define HIDPP_QUIRK_UNIFYING BIT(25)
|
||||
#define HIDPP_QUIRK_HIDPP_WHEELS BIT(26)
|
||||
#define HIDPP_QUIRK_HIDPP_EXTRA_MOUSE_BTNS BIT(27)
|
||||
#define HIDPP_QUIRK_HIDPP_CONSUMER_VENDOR_KEYS BIT(28)
|
||||
#define HIDPP_QUIRK_HI_RES_SCROLL_1P0 BIT(29)
|
||||
|
||||
/* These are just aliases for now */
|
||||
#define HIDPP_QUIRK_KBD_SCROLL_WHEEL HIDPP_QUIRK_HIDPP_WHEELS
|
||||
@ -87,8 +84,6 @@ MODULE_PARM_DESC(disable_tap_to_click,
|
||||
HIDPP_CAPABILITY_HIDPP20_HI_RES_SCROLL | \
|
||||
HIDPP_CAPABILITY_HIDPP20_HI_RES_WHEEL)
|
||||
|
||||
#define HIDPP_QUIRK_DELAYED_INIT HIDPP_QUIRK_NO_HIDINPUT
|
||||
|
||||
#define HIDPP_CAPABILITY_HIDPP10_BATTERY BIT(0)
|
||||
#define HIDPP_CAPABILITY_HIDPP20_BATTERY BIT(1)
|
||||
#define HIDPP_CAPABILITY_BATTERY_MILEAGE BIT(2)
|
||||
@ -225,6 +220,16 @@ struct hidpp_device {
|
||||
#define HIDPP_ERROR_INVALID_PARAM_VALUE 0x0b
|
||||
#define HIDPP_ERROR_WRONG_PIN_CODE 0x0c
|
||||
/* HID++ 2.0 error codes */
|
||||
#define HIDPP20_ERROR_NO_ERROR 0x00
|
||||
#define HIDPP20_ERROR_UNKNOWN 0x01
|
||||
#define HIDPP20_ERROR_INVALID_ARGS 0x02
|
||||
#define HIDPP20_ERROR_OUT_OF_RANGE 0x03
|
||||
#define HIDPP20_ERROR_HW_ERROR 0x04
|
||||
#define HIDPP20_ERROR_LOGITECH_INTERNAL 0x05
|
||||
#define HIDPP20_ERROR_INVALID_FEATURE_INDEX 0x06
|
||||
#define HIDPP20_ERROR_INVALID_FUNCTION_ID 0x07
|
||||
#define HIDPP20_ERROR_BUSY 0x08
|
||||
#define HIDPP20_ERROR_UNSUPPORTED 0x09
|
||||
#define HIDPP20_ERROR 0xff
|
||||
|
||||
static void hidpp_connect_event(struct hidpp_device *hidpp_dev);
|
||||
@ -279,6 +284,7 @@ static int hidpp_send_message_sync(struct hidpp_device *hidpp,
|
||||
struct hidpp_report *response)
|
||||
{
|
||||
int ret;
|
||||
int max_retries = 3;
|
||||
|
||||
mutex_lock(&hidpp->send_mutex);
|
||||
|
||||
@ -291,34 +297,39 @@ static int hidpp_send_message_sync(struct hidpp_device *hidpp,
|
||||
*/
|
||||
*response = *message;
|
||||
|
||||
ret = __hidpp_send_report(hidpp->hid_dev, message);
|
||||
for (; max_retries != 0; max_retries--) {
|
||||
ret = __hidpp_send_report(hidpp->hid_dev, message);
|
||||
|
||||
if (ret) {
|
||||
dbg_hid("__hidpp_send_report returned err: %d\n", ret);
|
||||
memset(response, 0, sizeof(struct hidpp_report));
|
||||
goto exit;
|
||||
}
|
||||
if (ret) {
|
||||
dbg_hid("__hidpp_send_report returned err: %d\n", ret);
|
||||
memset(response, 0, sizeof(struct hidpp_report));
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (!wait_event_timeout(hidpp->wait, hidpp->answer_available,
|
||||
5*HZ)) {
|
||||
dbg_hid("%s:timeout waiting for response\n", __func__);
|
||||
memset(response, 0, sizeof(struct hidpp_report));
|
||||
ret = -ETIMEDOUT;
|
||||
}
|
||||
if (!wait_event_timeout(hidpp->wait, hidpp->answer_available,
|
||||
5*HZ)) {
|
||||
dbg_hid("%s:timeout waiting for response\n", __func__);
|
||||
memset(response, 0, sizeof(struct hidpp_report));
|
||||
ret = -ETIMEDOUT;
|
||||
}
|
||||
|
||||
if (response->report_id == REPORT_ID_HIDPP_SHORT &&
|
||||
response->rap.sub_id == HIDPP_ERROR) {
|
||||
ret = response->rap.params[1];
|
||||
dbg_hid("%s:got hidpp error %02X\n", __func__, ret);
|
||||
goto exit;
|
||||
}
|
||||
if (response->report_id == REPORT_ID_HIDPP_SHORT &&
|
||||
response->rap.sub_id == HIDPP_ERROR) {
|
||||
ret = response->rap.params[1];
|
||||
dbg_hid("%s:got hidpp error %02X\n", __func__, ret);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if ((response->report_id == REPORT_ID_HIDPP_LONG ||
|
||||
response->report_id == REPORT_ID_HIDPP_VERY_LONG) &&
|
||||
response->fap.feature_index == HIDPP20_ERROR) {
|
||||
ret = response->fap.params[1];
|
||||
dbg_hid("%s:got hidpp 2.0 error %02X\n", __func__, ret);
|
||||
goto exit;
|
||||
if ((response->report_id == REPORT_ID_HIDPP_LONG ||
|
||||
response->report_id == REPORT_ID_HIDPP_VERY_LONG) &&
|
||||
response->fap.feature_index == HIDPP20_ERROR) {
|
||||
ret = response->fap.params[1];
|
||||
if (ret != HIDPP20_ERROR_BUSY) {
|
||||
dbg_hid("%s:got hidpp 2.0 error %02X\n", __func__, ret);
|
||||
goto exit;
|
||||
}
|
||||
dbg_hid("%s:got busy hidpp 2.0 error %02X, retrying\n", __func__, ret);
|
||||
}
|
||||
}
|
||||
|
||||
exit:
|
||||
@ -334,8 +345,13 @@ static int hidpp_send_fap_command_sync(struct hidpp_device *hidpp,
|
||||
struct hidpp_report *message;
|
||||
int ret;
|
||||
|
||||
if (param_count > sizeof(message->fap.params))
|
||||
if (param_count > sizeof(message->fap.params)) {
|
||||
hid_dbg(hidpp->hid_dev,
|
||||
"Invalid number of parameters passed to command (%d != %llu)\n",
|
||||
param_count,
|
||||
(unsigned long long) sizeof(message->fap.params));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
message = kzalloc(sizeof(struct hidpp_report), GFP_KERNEL);
|
||||
if (!message)
|
||||
@ -3436,11 +3452,17 @@ static int hi_res_scroll_enable(struct hidpp_device *hidpp)
|
||||
ret = hidpp10_enable_scrolling_acceleration(hidpp);
|
||||
multiplier = 8;
|
||||
}
|
||||
if (ret)
|
||||
if (ret) {
|
||||
hid_dbg(hidpp->hid_dev,
|
||||
"Could not enable hi-res scrolling: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (multiplier == 0)
|
||||
if (multiplier == 0) {
|
||||
hid_dbg(hidpp->hid_dev,
|
||||
"Invalid multiplier 0 from device, setting it to 1\n");
|
||||
multiplier = 1;
|
||||
}
|
||||
|
||||
hidpp->vertical_wheel_counter.wheel_multiplier = multiplier;
|
||||
hid_dbg(hidpp->hid_dev, "wheel multiplier = %d\n", multiplier);
|
||||
@ -3472,14 +3494,8 @@ static int hidpp_initialize_hires_scroll(struct hidpp_device *hidpp)
|
||||
hid_dbg(hidpp->hid_dev, "Detected HID++ 2.0 hi-res scrolling\n");
|
||||
}
|
||||
} else {
|
||||
struct hidpp_report response;
|
||||
|
||||
ret = hidpp_send_rap_command_sync(hidpp,
|
||||
REPORT_ID_HIDPP_SHORT,
|
||||
HIDPP_GET_REGISTER,
|
||||
HIDPP_ENABLE_FAST_SCROLL,
|
||||
NULL, 0, &response);
|
||||
if (!ret) {
|
||||
/* We cannot detect fast scrolling support on HID++ 1.0 devices */
|
||||
if (hidpp->quirks & HIDPP_QUIRK_HI_RES_SCROLL_1P0) {
|
||||
hidpp->capabilities |= HIDPP_CAPABILITY_HIDPP10_FAST_SCROLL;
|
||||
hid_dbg(hidpp->hid_dev, "Detected HID++ 1.0 fast scroll\n");
|
||||
}
|
||||
@ -4002,7 +4018,7 @@ static void hidpp_connect_event(struct hidpp_device *hidpp)
|
||||
if (hidpp->capabilities & HIDPP_CAPABILITY_HI_RES_SCROLL)
|
||||
hi_res_scroll_enable(hidpp);
|
||||
|
||||
if (!(hidpp->quirks & HIDPP_QUIRK_NO_HIDINPUT) || hidpp->delayed_input)
|
||||
if (!(hidpp->quirks & HIDPP_QUIRK_DELAYED_INIT) || hidpp->delayed_input)
|
||||
/* if the input nodes are already created, we can stop now */
|
||||
return;
|
||||
|
||||
@ -4107,6 +4123,7 @@ static int hidpp_probe(struct hid_device *hdev, const struct hid_device_id *id)
|
||||
bool connected;
|
||||
unsigned int connect_mask = HID_CONNECT_DEFAULT;
|
||||
struct hidpp_ff_private_data data;
|
||||
bool will_restart = false;
|
||||
|
||||
/* report_fixup needs drvdata to be set before we call hid_parse */
|
||||
hidpp = devm_kzalloc(&hdev->dev, sizeof(*hidpp), GFP_KERNEL);
|
||||
@ -4147,11 +4164,6 @@ static int hidpp_probe(struct hid_device *hdev, const struct hid_device_id *id)
|
||||
hidpp_application_equals(hdev, HID_GD_KEYBOARD))
|
||||
hidpp->quirks |= HIDPP_QUIRK_HIDPP_CONSUMER_VENDOR_KEYS;
|
||||
|
||||
if (disable_raw_mode) {
|
||||
hidpp->quirks &= ~HIDPP_QUIRK_CLASS_WTP;
|
||||
hidpp->quirks &= ~HIDPP_QUIRK_NO_HIDINPUT;
|
||||
}
|
||||
|
||||
if (hidpp->quirks & HIDPP_QUIRK_CLASS_WTP) {
|
||||
ret = wtp_allocate(hdev, id);
|
||||
if (ret)
|
||||
@ -4162,6 +4174,10 @@ static int hidpp_probe(struct hid_device *hdev, const struct hid_device_id *id)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (hidpp->quirks & HIDPP_QUIRK_DELAYED_INIT ||
|
||||
hidpp->quirks & HIDPP_QUIRK_UNIFYING)
|
||||
will_restart = true;
|
||||
|
||||
INIT_WORK(&hidpp->work, delayed_work_cb);
|
||||
mutex_init(&hidpp->send_mutex);
|
||||
init_waitqueue_head(&hidpp->wait);
|
||||
@ -4176,7 +4192,7 @@ static int hidpp_probe(struct hid_device *hdev, const struct hid_device_id *id)
|
||||
* Plain USB connections need to actually call start and open
|
||||
* on the transport driver to allow incoming data.
|
||||
*/
|
||||
ret = hid_hw_start(hdev, 0);
|
||||
ret = hid_hw_start(hdev, will_restart ? 0 : connect_mask);
|
||||
if (ret) {
|
||||
hid_err(hdev, "hw start failed\n");
|
||||
goto hid_hw_start_fail;
|
||||
@ -4213,6 +4229,7 @@ static int hidpp_probe(struct hid_device *hdev, const struct hid_device_id *id)
|
||||
hidpp->wireless_feature_index = 0;
|
||||
else if (ret)
|
||||
goto hid_hw_init_fail;
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
if (connected && (hidpp->quirks & HIDPP_QUIRK_CLASS_WTP)) {
|
||||
@ -4227,19 +4244,21 @@ static int hidpp_probe(struct hid_device *hdev, const struct hid_device_id *id)
|
||||
|
||||
hidpp_connect_event(hidpp);
|
||||
|
||||
/* Reset the HID node state */
|
||||
hid_device_io_stop(hdev);
|
||||
hid_hw_close(hdev);
|
||||
hid_hw_stop(hdev);
|
||||
if (will_restart) {
|
||||
/* Reset the HID node state */
|
||||
hid_device_io_stop(hdev);
|
||||
hid_hw_close(hdev);
|
||||
hid_hw_stop(hdev);
|
||||
|
||||
if (hidpp->quirks & HIDPP_QUIRK_NO_HIDINPUT)
|
||||
connect_mask &= ~HID_CONNECT_HIDINPUT;
|
||||
if (hidpp->quirks & HIDPP_QUIRK_DELAYED_INIT)
|
||||
connect_mask &= ~HID_CONNECT_HIDINPUT;
|
||||
|
||||
/* Now export the actual inputs and hidraw nodes to the world */
|
||||
ret = hid_hw_start(hdev, connect_mask);
|
||||
if (ret) {
|
||||
hid_err(hdev, "%s:hid_hw_start returned error\n", __func__);
|
||||
goto hid_hw_start_fail;
|
||||
/* Now export the actual inputs and hidraw nodes to the world */
|
||||
ret = hid_hw_start(hdev, connect_mask);
|
||||
if (ret) {
|
||||
hid_err(hdev, "%s:hid_hw_start returned error\n", __func__);
|
||||
goto hid_hw_start_fail;
|
||||
}
|
||||
}
|
||||
|
||||
if (hidpp->quirks & HIDPP_QUIRK_CLASS_G920) {
|
||||
@ -4297,9 +4316,15 @@ static const struct hid_device_id hidpp_devices[] = {
|
||||
HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH,
|
||||
USB_DEVICE_ID_LOGITECH_T651),
|
||||
.driver_data = HIDPP_QUIRK_CLASS_WTP },
|
||||
{ /* Mouse Logitech Anywhere MX */
|
||||
LDJ_DEVICE(0x1017), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_1P0 },
|
||||
{ /* Mouse logitech M560 */
|
||||
LDJ_DEVICE(0x402d),
|
||||
.driver_data = HIDPP_QUIRK_DELAYED_INIT | HIDPP_QUIRK_CLASS_M560 },
|
||||
{ /* Mouse Logitech M705 (firmware RQM17) */
|
||||
LDJ_DEVICE(0x101b), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_1P0 },
|
||||
{ /* Mouse Logitech Performance MX */
|
||||
LDJ_DEVICE(0x101a), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_1P0 },
|
||||
{ /* Keyboard logitech K400 */
|
||||
LDJ_DEVICE(0x4024),
|
||||
.driver_data = HIDPP_QUIRK_CLASS_K400 },
|
||||
@ -4348,6 +4373,9 @@ static const struct hid_device_id hidpp_devices[] = {
|
||||
{ /* Logitech G920 Wheel over USB */
|
||||
HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G920_WHEEL),
|
||||
.driver_data = HIDPP_QUIRK_CLASS_G920 | HIDPP_QUIRK_FORCE_OUTPUT_REPORTS},
|
||||
{ /* Logitech G923 Wheel (Xbox version) over USB */
|
||||
HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G923_XBOX_WHEEL),
|
||||
.driver_data = HIDPP_QUIRK_CLASS_G920 | HIDPP_QUIRK_FORCE_OUTPUT_REPORTS },
|
||||
{ /* Logitech G Pro Gaming Mouse over USB */
|
||||
HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, 0xC088) },
|
||||
|
||||
@ -4367,6 +4395,8 @@ static const struct hid_device_id hidpp_devices[] = {
|
||||
{ /* MX Ergo trackball over Bluetooth */
|
||||
HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb01d) },
|
||||
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb01e) },
|
||||
{ /* Signature M650 over Bluetooth */
|
||||
HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb02a) },
|
||||
{ /* MX Master 3 mouse over Bluetooth */
|
||||
HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb023) },
|
||||
{}
|
||||
|
Loading…
Reference in New Issue
Block a user