From 8b30fb40f8f2c5e56b7af553a398340f92d17aae Mon Sep 17 00:00:00 2001 From: Icenowy Zheng Date: Fri, 15 Apr 2022 18:04:32 +0800 Subject: HID: nintendo: deregister home LED when it fails Some Pro Controller compatible controllers do not support home LED, and will fail when setting it. Currently this leads to probe failure. Change the code that fails probing to deregistering home LED. Signed-off-by: Icenowy Zheng Reviewed-by: Daniel J. Ogorchock Reviewed-by: Silvan Jegen [bentiss: changed "dflt" to "default"] Signed-off-by: Benjamin Tissoires Link: https://lore.kernel.org/r/20220415100432.23453-1-icenowy@aosc.io --- drivers/hid/hid-nintendo.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/hid/hid-nintendo.c b/drivers/hid/hid-nintendo.c index 6028af3c3aae..5cb5a1d53b71 100644 --- a/drivers/hid/hid-nintendo.c +++ b/drivers/hid/hid-nintendo.c @@ -1904,9 +1904,8 @@ static int joycon_leds_create(struct joycon_ctlr *ctlr) /* Set the home LED to 0 as default state */ ret = joycon_home_led_brightness_set(led, 0); if (ret) { - hid_err(hdev, "Failed to set home LED dflt; ret=%d\n", - ret); - return ret; + hid_warn(hdev, "Failed to set home LED default, unregistering home LED"); + devm_led_classdev_unregister(&hdev->dev, led); } } -- cgit From 50503e360eeb968a3d00234c9cc4057d774c3e9a Mon Sep 17 00:00:00 2001 From: Johnothan King Date: Wed, 21 Sep 2022 10:55:57 +0000 Subject: HID: nintendo: check analog user calibration for plausibility Arne Wendt writes: Cheap clone controllers may (falsely) report as having a user calibration for the analog sticks in place, but return wrong/impossible values for the actual calibration data. In the present case at mine, the controller reports having a user calibration in place and successfully executes the read commands. The reported user calibration however is min = center = max = 0. This pull request addresses problems of this kind by checking the provided user calibration-data for plausibility (min < center < max) and falling back to the default values if implausible. I'll note that I was experiencing a crash because of this bug when using the GuliKit KingKong 2 controller. The crash manifests as a divide by zero error in the kernel logs: kernel: divide error: 0000 [#1] PREEMPT SMP NOPTI Link: https://github.com/nicman23/dkms-hid-nintendo/pull/25 Link: https://github.com/DanielOgorchock/linux/issues/36 Co-authored-by: Arne Wendt Signed-off-by: Johnothan King Signed-off-by: Benjamin Tissoires Link: https://lore.kernel.org/r/gvpL2G6VwXGJPvxX5KRiu9pVjvTivgayug_jdKDY6zfuAaAqncP9BkKLosjwUXNlgVVTMfJSKfwPF1K79cKAkwGComyC21vCV3q9B3EXNkE=@protonmail.com --- drivers/hid/hid-nintendo.c | 55 +++++++++++++++++++++++++--------------------- 1 file changed, 30 insertions(+), 25 deletions(-) diff --git a/drivers/hid/hid-nintendo.c b/drivers/hid/hid-nintendo.c index 5cb5a1d53b71..5bfc0c450460 100644 --- a/drivers/hid/hid-nintendo.c +++ b/drivers/hid/hid-nintendo.c @@ -760,12 +760,31 @@ static int joycon_read_stick_calibration(struct joycon_ctlr *ctlr, u16 cal_addr, cal_y->max = cal_y->center + y_max_above; cal_y->min = cal_y->center - y_min_below; - return 0; + /* check if calibration values are plausible */ + if (cal_x->min >= cal_x->center || cal_x->center >= cal_x->max || + cal_y->min >= cal_y->center || cal_y->center >= cal_y->max) + ret = -EINVAL; + + return ret; } static const u16 DFLT_STICK_CAL_CEN = 2000; static const u16 DFLT_STICK_CAL_MAX = 3500; static const u16 DFLT_STICK_CAL_MIN = 500; +static void joycon_use_default_calibration(struct hid_device *hdev, + struct joycon_stick_cal *cal_x, + struct joycon_stick_cal *cal_y, + const char *stick, int ret) +{ + hid_warn(hdev, + "Failed to read %s stick cal, using defaults; e=%d\n", + stick, ret); + + cal_x->center = cal_y->center = DFLT_STICK_CAL_CEN; + cal_x->max = cal_y->max = DFLT_STICK_CAL_MAX; + cal_x->min = cal_y->min = DFLT_STICK_CAL_MIN; +} + static int joycon_request_calibration(struct joycon_ctlr *ctlr) { u16 left_stick_addr = JC_CAL_FCT_DATA_LEFT_ADDR; @@ -793,38 +812,24 @@ static int joycon_request_calibration(struct joycon_ctlr *ctlr) &ctlr->left_stick_cal_x, &ctlr->left_stick_cal_y, true); - if (ret) { - hid_warn(ctlr->hdev, - "Failed to read left stick cal, using dflts; e=%d\n", - ret); - - ctlr->left_stick_cal_x.center = DFLT_STICK_CAL_CEN; - ctlr->left_stick_cal_x.max = DFLT_STICK_CAL_MAX; - ctlr->left_stick_cal_x.min = DFLT_STICK_CAL_MIN; - ctlr->left_stick_cal_y.center = DFLT_STICK_CAL_CEN; - ctlr->left_stick_cal_y.max = DFLT_STICK_CAL_MAX; - ctlr->left_stick_cal_y.min = DFLT_STICK_CAL_MIN; - } + if (ret) + joycon_use_default_calibration(ctlr->hdev, + &ctlr->left_stick_cal_x, + &ctlr->left_stick_cal_y, + "left", ret); /* read the right stick calibration data */ ret = joycon_read_stick_calibration(ctlr, right_stick_addr, &ctlr->right_stick_cal_x, &ctlr->right_stick_cal_y, false); - if (ret) { - hid_warn(ctlr->hdev, - "Failed to read right stick cal, using dflts; e=%d\n", - ret); - - ctlr->right_stick_cal_x.center = DFLT_STICK_CAL_CEN; - ctlr->right_stick_cal_x.max = DFLT_STICK_CAL_MAX; - ctlr->right_stick_cal_x.min = DFLT_STICK_CAL_MIN; - ctlr->right_stick_cal_y.center = DFLT_STICK_CAL_CEN; - ctlr->right_stick_cal_y.max = DFLT_STICK_CAL_MAX; - ctlr->right_stick_cal_y.min = DFLT_STICK_CAL_MIN; - } + if (ret) + joycon_use_default_calibration(ctlr->hdev, + &ctlr->right_stick_cal_x, + &ctlr->right_stick_cal_y, + "right", ret); hid_dbg(ctlr->hdev, "calibration:\n" "l_x_c=%d l_x_max=%d l_x_min=%d\n" -- cgit