diff options
author | Nadia Holmquist Pedersen | 2021-01-07 18:08:28 +0100 |
---|---|---|
committer | Nadia Holmquist Pedersen | 2021-01-07 18:08:28 +0100 |
commit | ffce16e529f8c3cacf1e9084486664509fb32cc9 (patch) | |
tree | da5749cb9c5a256df5cca96a04f2de50f0179564 | |
parent | 2f0de9deadcf1a81447c1f91ddf6b244441ba16e (diff) | |
download | aur-ffce16e529f8c3cacf1e9084486664509fb32cc9.tar.gz |
Update for latest hid-nintendo source
-rw-r--r-- | .SRCINFO | 6 | ||||
-rw-r--r-- | PKGBUILD | 6 | ||||
-rw-r--r-- | hid-nintendo.c | 775 |
3 files changed, 585 insertions, 202 deletions
@@ -1,7 +1,7 @@ pkgbase = hid-nintendo-nso-dkms pkgdesc = HID driver for Nintendo Switch controllers patched with Switch Online NES and SNES controller support. - pkgver = 1.1 - pkgrel = 2 + pkgver = 1.2 + pkgrel = 1 url = https://github.com/nadiaholmquist/linux/tree/hid-nintendo arch = x86_64 arch = aarch64 @@ -12,7 +12,7 @@ pkgbase = hid-nintendo-nso-dkms source = dkms.conf source = hid-ids.h source = Makefile - md5sums = dbc0bd6f144503547cb6e140c1ea2729 + md5sums = f6592f96d94c215e3de807bd8a80c612 md5sums = 6d97239c33773b3f2fc5d497e98a1017 md5sums = 6d1c428af9d73b4fd493ee1d4465700b md5sums = 3a628988ca479023b45d2bd6b9b1cfb8 @@ -1,8 +1,8 @@ _pkgbase=hid-nintendo pkgname=hid-nintendo-nso-dkms -pkgver=1.1 -pkgrel=2 +pkgver=1.2 +pkgrel=1 pkgdesc="HID driver for Nintendo Switch controllers patched with Switch Online NES and SNES controller support." arch=('x86_64' 'aarch64') url="https://github.com/nadiaholmquist/linux/tree/hid-nintendo" @@ -11,7 +11,7 @@ depends=('dkms') source=('hid-nintendo.c' 'dkms.conf' 'hid-ids.h' 'Makefile') conflicts=(hid-nintendo-dkms) -md5sums=('dbc0bd6f144503547cb6e140c1ea2729' +md5sums=('f6592f96d94c215e3de807bd8a80c612' '6d97239c33773b3f2fc5d497e98a1017' '6d1c428af9d73b4fd493ee1d4465700b' '3a628988ca479023b45d2bd6b9b1cfb8') diff --git a/hid-nintendo.c b/hid-nintendo.c index 71d564e74b7e..56e9b8fbd9d4 100644 --- a/hid-nintendo.c +++ b/hid-nintendo.c @@ -2,7 +2,7 @@ /* * HID driver for Nintendo Switch Joy-Cons and Pro Controllers * - * Copyright (c) 2019 Daniel J. Ogorchock <djogorchock@gmail.com> + * Copyright (c) 2019-2020 Daniel J. Ogorchock <djogorchock@gmail.com> * * The following resources/projects were referenced for this driver: * https://github.com/dekuNukem/Nintendo_Switch_Reverse_Engineering @@ -23,8 +23,10 @@ */ #include "hid-ids.h" +#include <asm/unaligned.h> #include <linux/delay.h> #include <linux/device.h> +#include <linux/kernel.h> #include <linux/hid.h> #include <linux/input.h> #include <linux/jiffies.h> @@ -96,33 +98,83 @@ static const u8 JC_USB_RESET = 0x06; static const u8 JC_USB_PRE_HANDSHAKE = 0x91; static const u8 JC_USB_SEND_UART = 0x92; +/* Magic value denoting presence of user calibration */ +static const u16 JC_CAL_USR_MAGIC_0 = 0xB2; +static const u16 JC_CAL_USR_MAGIC_1 = 0xA1; +static const u8 JC_CAL_USR_MAGIC_SIZE = 2; + +/* SPI storage addresses of user calibration data */ +static const u16 JC_CAL_USR_LEFT_MAGIC_ADDR = 0x8010; +static const u16 JC_CAL_USR_LEFT_DATA_ADDR = 0x8012; +static const u16 JC_CAL_USR_LEFT_DATA_END = 0x801A; +static const u16 JC_CAL_USR_RIGHT_MAGIC_ADDR = 0x801B; +static const u16 JC_CAL_USR_RIGHT_DATA_ADDR = 0x801D; +#define JC_CAL_STICK_DATA_SIZE \ + (JC_CAL_USR_LEFT_DATA_END - JC_CAL_USR_LEFT_DATA_ADDR + 1) + /* SPI storage addresses of factory calibration data */ -static const u16 JC_CAL_DATA_START = 0x603d; -static const u16 JC_CAL_DATA_END = 0x604e; -#define JC_CAL_DATA_SIZE (JC_CAL_DATA_END - JC_CAL_DATA_START + 1) +static const u16 JC_CAL_FCT_DATA_LEFT_ADDR = 0x603d; +static const u16 JC_CAL_FCT_DATA_RIGHT_ADDR = 0x6046; /* SPI storage addresses of IMU factory calibration data */ -static const u16 JC_IMU_CAL_DATA_START = 0x6020; -static const u16 JC_IMU_CAL_DATA_END = 0x6037; +static const u16 JC_IMU_CAL_FCT_DATA_ADDR = 0x6020; +static const u16 JC_IMU_CAL_FCT_DATA_END = 0x6037; #define JC_IMU_CAL_DATA_SIZE \ - (JC_IMU_CAL_DATA_END - JC_IMU_CAL_DATA_START + 1) + (JC_IMU_CAL_FCT_DATA_END - JC_IMU_CAL_FCT_DATA_ADDR + 1) +/* SPI storage addresses of IMU user calibration data */ +static const u16 JC_IMU_CAL_USR_MAGIC_ADDR = 0x8026; +static const u16 JC_IMU_CAL_USR_DATA_ADDR = 0x8028; /* The raw analog joystick values will be mapped in terms of this magnitude */ static const u16 JC_MAX_STICK_MAG = 32767; static const u16 JC_STICK_FUZZ = 250; static const u16 JC_STICK_FLAT = 500; -/* The accel axes will be mapped in terms of this magnitude */ -static const u16 JC_MAX_ACCEL_MAG = 32767; -static const u16 JC_ACCEL_RES = 4096; -static const u16 JC_ACCEL_FUZZ = 10; -static const u16 JC_ACCEL_FLAT /*= 0*/; +/* Hat values for pro controller's d-pad */ +static const u16 JC_MAX_DPAD_MAG = 1; +static const u16 JC_DPAD_FUZZ /*= 0*/; +static const u16 JC_DPAD_FLAT /*= 0*/; + +/* Under most circumstances IMU reports are pushed every 15ms; use as default */ +static const u16 JC_IMU_DFLT_AVG_DELTA_MS = 15; +/* How many samples to sum before calculating average IMU report delta */ +static const u16 JC_IMU_SAMPLES_PER_DELTA_AVG = 300; +/* Controls how many dropped IMU packets at once trigger a warning message */ +static const u16 JC_IMU_DROPPED_PKT_WARNING = 3; + +/* + * The controller's accelerometer has a sensor resolution of 16bits and is + * configured with a range of +-8000 milliGs. Therefore, the resolution can be + * calculated thus: (2^16-1)/(8000 * 2) = 4.096 digits per milliG + * Resolution per G (rather than per millliG): 4.096 * 1000 = 4096 digits per G + * Alternatively: 1/4096 = .0002441 Gs per digit + */ +static const s32 JC_IMU_MAX_ACCEL_MAG = 32767; +static const u16 JC_IMU_ACCEL_RES_PER_G = 4096; +static const u16 JC_IMU_ACCEL_FUZZ = 10; +static const u16 JC_IMU_ACCEL_FLAT /*= 0*/; -/* The gyro axes will be mapped in terms of this magnitude */ -static const u16 JC_MAX_GYRO_MAG = 32767; -static const u16 JC_GYRO_RES = 13371 / 936; /* 14 (14.285) */ -static const u16 JC_GYRO_FUZZ = 10; -static const u16 JC_GYRO_FLAT /*= 0*/; +/* + * The controller's gyroscope has a sensor resolution of 16bits and is + * configured with a range of +-2000 degrees/second. + * Digits per dps: (2^16 -1)/(2000*2) = 16.38375 + * dps per digit: 16.38375E-1 = .0610 + * + * STMicro recommends in the datasheet to add 15% to the dps/digit. This allows + * the full sensitivity range to be saturated without clipping. This yields more + * accurate results, so it's the technique this driver uses. + * dps per digit (corrected): .0610 * 1.15 = .0702 + * digits per dps (corrected): .0702E-1 = 14.247 + * + * Now, 14.247 truncating to 14 loses a lot of precision, so we rescale the + * min/max range by 1000. + */ +static const s32 JC_IMU_PREC_RANGE_SCALE = 1000; +/* Note: change mag and res_per_dps if prec_range_scale is ever altered */ +static const s32 JC_IMU_MAX_GYRO_MAG = 32767000; /* (2^16-1)*1000 */ +static const u16 JC_IMU_GYRO_RES_PER_DPS = 14247; /* (14.247*1000) */ +static const u16 JC_IMU_GYRO_FUZZ = 10; +static const u16 JC_IMU_GYRO_FLAT /*= 0*/; /* frequency/amplitude tables for rumble */ struct joycon_rumble_freq_data { @@ -322,10 +374,6 @@ struct joycon_imu_data { s16 gyro_z; } __packed; -struct joycon_imu_report { - struct joycon_imu_data data[3]; -} __packed; - struct joycon_input_report { u8 id; u8 timer; @@ -337,7 +385,8 @@ struct joycon_input_report { union { struct joycon_subcmd_reply subcmd_reply; - struct joycon_imu_report imu_report; + /* IMU input reports contain 3 samples */ + u8 imu_raw_bytes[sizeof(struct joycon_imu_data) * 3]; }; } __packed; @@ -382,6 +431,10 @@ struct joycon_ctlr { struct joycon_imu_cal accel_cal; struct joycon_imu_cal gyro_cal; + /* prevents needlessly recalculating these divisors every sample */ + s32 imu_cal_accel_divisor[3]; + s32 imu_cal_gyro_divisor[3]; + /* power supply data */ struct power_supply *battery; struct power_supply_desc battery_desc; @@ -400,10 +453,17 @@ struct joycon_ctlr { u16 rumble_lh_freq; u16 rumble_rl_freq; u16 rumble_rh_freq; + bool rumble_zero_amp; /* imu */ struct input_dev *imu_input; - int timestamp; + bool imu_first_packet_received; /* helps in initiating timestamp */ + unsigned int imu_timestamp_us; /* timestamp we report to userspace */ + unsigned int imu_last_pkt_ms; /* used to calc imu report delta */ + /* the following are used to track the average imu report time delta */ + unsigned int imu_delta_samples_count; + unsigned int imu_delta_samples_sum; + unsigned int imu_avg_delta_ms; }; /* Helper macros for checking controller type */ @@ -441,7 +501,11 @@ struct joycon_ctlr { /* Does this controller have motion sensors */ #define jc_has_imu(ctlr) \ - (jc_type_is_joycon(ctlr) || jc_type_is_procon(ctlr)) + (!jc_type_is_nescon(ctlr) && !jc_type_is_snescon(ctlr)) + +/* Does this controller have rumble */ +#define jc_has_rumble(ctlr) \ + (!jc_type_is_nescon(ctlr) && !jc_type_is_snescon(ctlr)) static int __joycon_hid_send(struct hid_device *hdev, u8 *data, size_t len) { @@ -483,12 +547,10 @@ static int joycon_hid_send_sync(struct joycon_ctlr *ctlr, u8 *data, size_t len, ret = wait_event_timeout(ctlr->wait, ctlr->received_input_report, HZ / 4); - spin_lock_irqsave(&ctlr->lock, flags); /* We will still proceed, even with a timeout here */ if (!ret) hid_warn(ctlr->hdev, "timeout waiting for input report\n"); - spin_unlock_irqrestore(&ctlr->lock, flags); } ret = __joycon_hid_send(ctlr->hdev, data, len); @@ -582,38 +644,140 @@ static int joycon_set_player_leds(struct joycon_ctlr *ctlr, u8 flash, u8 on) return joycon_send_subcmd(ctlr, req, 1, HZ/4); } -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 int joycon_request_calibration(struct joycon_ctlr *ctlr) +static int joycon_request_spi_flash_read(struct joycon_ctlr *ctlr, + u32 start_addr, u8 size, u8 **reply) { struct joycon_subcmd_request *req; - u8 buffer[sizeof(*req) + 5] = { 0 }; struct joycon_input_report *report; - struct joycon_stick_cal *cal_x; - struct joycon_stick_cal *cal_y; + u8 buffer[sizeof(*req) + 5] = { 0 }; + u8 *data; + int ret; + + if (!reply) + return -EINVAL; + + req = (struct joycon_subcmd_request *)buffer; + req->subcmd_id = JC_SUBCMD_SPI_FLASH_READ; + data = req->data; + put_unaligned_le32(start_addr, data); + data[4] = size; + + hid_dbg(ctlr->hdev, "requesting SPI flash data\n"); + ret = joycon_send_subcmd(ctlr, req, 5, HZ); + if (ret) { + hid_err(ctlr->hdev, "failed reading SPI flash; ret=%d\n", ret); + } else { + report = (struct joycon_input_report *)ctlr->input_buf; + /* The read data starts at the 6th byte */ + *reply = &report->subcmd_reply.data[5]; + } + return ret; +} + +/* + * User calibration's presence is denoted with a magic byte preceding it. + * returns 0 if magic val is present, 1 if not present, < 0 on error + */ +static int joycon_check_for_cal_magic(struct joycon_ctlr *ctlr, u32 flash_addr) +{ + int ret; + u8 *reply; + + ret = joycon_request_spi_flash_read(ctlr, flash_addr, + JC_CAL_USR_MAGIC_SIZE, &reply); + if (ret) + return ret; + + return reply[0] != JC_CAL_USR_MAGIC_0 || reply[1] != JC_CAL_USR_MAGIC_1; +} + +static int joycon_read_stick_calibration(struct joycon_ctlr *ctlr, u16 cal_addr, + struct joycon_stick_cal *cal_x, + struct joycon_stick_cal *cal_y, + bool left_stick) +{ s32 x_max_above; s32 x_min_below; s32 y_max_above; s32 y_min_below; - u8 *data; u8 *raw_cal; int ret; - req = (struct joycon_subcmd_request *)buffer; - req->subcmd_id = JC_SUBCMD_SPI_FLASH_READ; - data = req->data; - data[0] = 0xFF & JC_CAL_DATA_START; - data[1] = 0xFF & (JC_CAL_DATA_START >> 8); - data[2] = 0xFF & (JC_CAL_DATA_START >> 16); - data[3] = 0xFF & (JC_CAL_DATA_START >> 24); - data[4] = JC_CAL_DATA_SIZE; + ret = joycon_request_spi_flash_read(ctlr, cal_addr, + JC_CAL_STICK_DATA_SIZE, &raw_cal); + if (ret) + return ret; + + /* stick calibration parsing: note the order differs based on stick */ + if (left_stick) { + x_max_above = hid_field_extract(ctlr->hdev, (raw_cal + 0), 0, + 12); + y_max_above = hid_field_extract(ctlr->hdev, (raw_cal + 1), 4, + 12); + cal_x->center = hid_field_extract(ctlr->hdev, (raw_cal + 3), 0, + 12); + cal_y->center = hid_field_extract(ctlr->hdev, (raw_cal + 4), 4, + 12); + x_min_below = hid_field_extract(ctlr->hdev, (raw_cal + 6), 0, + 12); + y_min_below = hid_field_extract(ctlr->hdev, (raw_cal + 7), 4, + 12); + } else { + cal_x->center = hid_field_extract(ctlr->hdev, (raw_cal + 0), 0, + 12); + cal_y->center = hid_field_extract(ctlr->hdev, (raw_cal + 1), 4, + 12); + x_min_below = hid_field_extract(ctlr->hdev, (raw_cal + 3), 0, + 12); + y_min_below = hid_field_extract(ctlr->hdev, (raw_cal + 4), 4, + 12); + x_max_above = hid_field_extract(ctlr->hdev, (raw_cal + 6), 0, + 12); + y_max_above = hid_field_extract(ctlr->hdev, (raw_cal + 7), 4, + 12); + } + + cal_x->max = cal_x->center + x_max_above; + cal_x->min = cal_x->center - x_min_below; + cal_y->max = cal_y->center + y_max_above; + cal_y->min = cal_y->center - y_min_below; + + return 0; +} + +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 int joycon_request_calibration(struct joycon_ctlr *ctlr) +{ + u16 left_stick_addr = JC_CAL_FCT_DATA_LEFT_ADDR; + u16 right_stick_addr = JC_CAL_FCT_DATA_RIGHT_ADDR; + int ret; hid_dbg(ctlr->hdev, "requesting cal data\n"); - ret = joycon_send_subcmd(ctlr, req, 5, HZ); + + /* check if user stick calibrations are present */ + if (!joycon_check_for_cal_magic(ctlr, JC_CAL_USR_LEFT_MAGIC_ADDR)) { + left_stick_addr = JC_CAL_USR_LEFT_DATA_ADDR; + hid_info(ctlr->hdev, "using user cal for left stick\n"); + } else { + hid_info(ctlr->hdev, "using factory cal for left stick\n"); + } + if (!joycon_check_for_cal_magic(ctlr, JC_CAL_USR_RIGHT_MAGIC_ADDR)) { + right_stick_addr = JC_CAL_USR_RIGHT_DATA_ADDR; + hid_info(ctlr->hdev, "using user cal for right stick\n"); + } else { + hid_info(ctlr->hdev, "using factory cal for right stick\n"); + } + + /* read the left stick calibration data */ + ret = joycon_read_stick_calibration(ctlr, left_stick_addr, + &ctlr->left_stick_cal_x, + &ctlr->left_stick_cal_y, + true); if (ret) { hid_warn(ctlr->hdev, - "Failed to read stick cal, using defaults; ret=%d\n", + "Failed to read left stick cal, using dflts; e=%d\n", ret); ctlr->left_stick_cal_x.center = DFLT_STICK_CAL_CEN; @@ -623,6 +787,17 @@ static int joycon_request_calibration(struct joycon_ctlr *ctlr) 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; + } + + /* 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; @@ -631,44 +806,8 @@ static int joycon_request_calibration(struct joycon_ctlr *ctlr) 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; - - return ret; } - report = (struct joycon_input_report *)ctlr->input_buf; - raw_cal = &report->subcmd_reply.data[5]; - - /* left stick calibration parsing */ - cal_x = &ctlr->left_stick_cal_x; - cal_y = &ctlr->left_stick_cal_y; - - x_max_above = hid_field_extract(ctlr->hdev, (raw_cal + 0), 0, 12); - y_max_above = hid_field_extract(ctlr->hdev, (raw_cal + 1), 4, 12); - cal_x->center = hid_field_extract(ctlr->hdev, (raw_cal + 3), 0, 12); - cal_y->center = hid_field_extract(ctlr->hdev, (raw_cal + 4), 4, 12); - x_min_below = hid_field_extract(ctlr->hdev, (raw_cal + 6), 0, 12); - y_min_below = hid_field_extract(ctlr->hdev, (raw_cal + 7), 4, 12); - cal_x->max = cal_x->center + x_max_above; - cal_x->min = cal_x->center - x_min_below; - cal_y->max = cal_y->center + y_max_above; - cal_y->min = cal_y->center - y_min_below; - - /* right stick calibration parsing */ - raw_cal += 9; - cal_x = &ctlr->right_stick_cal_x; - cal_y = &ctlr->right_stick_cal_y; - - cal_x->center = hid_field_extract(ctlr->hdev, (raw_cal + 0), 0, 12); - cal_y->center = hid_field_extract(ctlr->hdev, (raw_cal + 1), 4, 12); - x_min_below = hid_field_extract(ctlr->hdev, (raw_cal + 3), 0, 12); - y_min_below = hid_field_extract(ctlr->hdev, (raw_cal + 4), 4, 12); - x_max_above = hid_field_extract(ctlr->hdev, (raw_cal + 6), 0, 12); - y_max_above = hid_field_extract(ctlr->hdev, (raw_cal + 7), 4, 12); - cal_x->max = cal_x->center + x_max_above; - cal_x->min = cal_x->center - x_min_below; - cal_y->max = cal_y->center + y_max_above; - cal_y->min = cal_y->center - y_min_below; - hid_dbg(ctlr->hdev, "calibration:\n" "l_x_c=%d l_x_max=%d l_x_min=%d\n" "l_y_c=%d l_y_max=%d l_y_min=%d\n" @@ -690,33 +829,46 @@ static int joycon_request_calibration(struct joycon_ctlr *ctlr) return 0; } +/* + * These divisors are calculated once rather than for each sample. They are only + * dependent on the IMU calibration values. They are used when processing the + * IMU input reports. + */ +static void joycon_calc_imu_cal_divisors(struct joycon_ctlr *ctlr) +{ + int i; + + for (i = 0; i < 3; i++) { + ctlr->imu_cal_accel_divisor[i] = ctlr->accel_cal.scale[i] - + ctlr->accel_cal.offset[i]; + ctlr->imu_cal_gyro_divisor[i] = ctlr->gyro_cal.scale[i] - + ctlr->gyro_cal.offset[i]; + } +} + static const s16 DFLT_ACCEL_OFFSET /*= 0*/; static const s16 DFLT_ACCEL_SCALE = 16384; static const s16 DFLT_GYRO_OFFSET /*= 0*/; static const s16 DFLT_GYRO_SCALE = 13371; static int joycon_request_imu_calibration(struct joycon_ctlr *ctlr) { - struct joycon_subcmd_request *req; - u8 buffer[sizeof(*req) + 5] = { 0 }; - struct joycon_input_report *report; - u8 *data; + u16 imu_cal_addr = JC_IMU_CAL_FCT_DATA_ADDR; u8 *raw_cal; int ret; int i; - /* request IMU calibration data */ - req = (struct joycon_subcmd_request *)buffer; - req->subcmd_id = JC_SUBCMD_SPI_FLASH_READ; - data = req->data; - data[0] = 0xFF & JC_IMU_CAL_DATA_START; - data[1] = 0xFF & (JC_IMU_CAL_DATA_START >> 8); - data[2] = 0xFF & (JC_IMU_CAL_DATA_START >> 16); - data[3] = 0xFF & (JC_IMU_CAL_DATA_START >> 24); - data[4] = JC_IMU_CAL_DATA_SIZE; + /* check if user calibration exists */ + if (!joycon_check_for_cal_magic(ctlr, JC_IMU_CAL_USR_MAGIC_ADDR)) { + imu_cal_addr = JC_IMU_CAL_USR_DATA_ADDR; + hid_info(ctlr->hdev, "using user cal for IMU\n"); + } else { + hid_info(ctlr->hdev, "using factory cal for IMU\n"); + } + /* request IMU calibration data */ hid_dbg(ctlr->hdev, "requesting IMU cal data\n"); - ret = joycon_send_subcmd(ctlr, req, 5, HZ); - + ret = joycon_request_spi_flash_read(ctlr, imu_cal_addr, + JC_IMU_CAL_DATA_SIZE, &raw_cal); if (ret) { hid_warn(ctlr->hdev, "Failed to read IMU cal, using defaults; ret=%d\n", @@ -728,26 +880,22 @@ static int joycon_request_imu_calibration(struct joycon_ctlr *ctlr) ctlr->gyro_cal.offset[i] = DFLT_GYRO_OFFSET; ctlr->gyro_cal.scale[i] = DFLT_GYRO_SCALE; } + joycon_calc_imu_cal_divisors(ctlr); return ret; } - report = (struct joycon_input_report *)ctlr->input_buf; - raw_cal = &report->subcmd_reply.data[5]; - /* IMU calibration parsing */ for (i = 0; i < 3; i++) { int j = i * 2; - ctlr->accel_cal.offset[i] = raw_cal[j + 0] | - ((s16)raw_cal[j + 1] << 8); - ctlr->accel_cal.scale[i] = raw_cal[j + 6] | - ((s16)raw_cal[j + 7] << 8); - ctlr->gyro_cal.offset[i] = raw_cal[j + 12] | - ((s16)raw_cal[j + 13] << 8); - ctlr->gyro_cal.scale[i] = raw_cal[j + 18] | - ((s16)raw_cal[j + 19] << 8); + ctlr->accel_cal.offset[i] = get_unaligned_le16(raw_cal + j); + ctlr->accel_cal.scale[i] = get_unaligned_le16(raw_cal + j + 6); + ctlr->gyro_cal.offset[i] = get_unaligned_le16(raw_cal + j + 12); + ctlr->gyro_cal.scale[i] = get_unaligned_le16(raw_cal + j + 18); } + joycon_calc_imu_cal_divisors(ctlr); + hid_dbg(ctlr->hdev, "IMU calibration:\n" "a_o[0]=%d a_o[1]=%d a_o[2]=%d\n" "a_s[0]=%d a_s[1]=%d a_s[2]=%d\n" @@ -826,6 +974,224 @@ static s32 joycon_map_stick_val(struct joycon_stick_cal *cal, s32 val) return new_val; } +static void joycon_input_report_parse_imu_data(struct joycon_ctlr *ctlr, + struct joycon_input_report *rep, + struct joycon_imu_data *imu_data) +{ + u8 *raw = rep->imu_raw_bytes; + int i; + + for (i = 0; i < 3; i++) { + struct joycon_imu_data *data = &imu_data[i]; + + data->accel_x = get_unaligned_le16(raw + 0); + data->accel_y = get_unaligned_le16(raw + 2); + data->accel_z = get_unaligned_le16(raw + 4); + data->gyro_x = get_unaligned_le16(raw + 6); + data->gyro_y = get_unaligned_le16(raw + 8); + data->gyro_z = get_unaligned_le16(raw + 10); + /* point to next imu sample */ + raw += sizeof(struct joycon_imu_data); + } +} + +static void joycon_parse_imu_report(struct joycon_ctlr *ctlr, + struct joycon_input_report *rep) +{ + struct joycon_imu_data imu_data[3] = {0}; /* 3 reports per packet */ + struct input_dev *idev = ctlr->imu_input; + unsigned int msecs = jiffies_to_msecs(jiffies); + unsigned int last_msecs = ctlr->imu_last_pkt_ms; + int i; + int value[6]; + + joycon_input_report_parse_imu_data(ctlr, rep, imu_data); + + /* + * There are complexities surrounding how we determine the timestamps we + * associate with the samples we pass to userspace. The IMU input + * reports do not provide us with a good timestamp. There's a quickly + * incrementing 8-bit counter per input report, but it is not very + * useful for this purpose (it is not entirely clear what rate it + * increments at or if it varies based on packet push rate - more on + * the push rate below...). + * + * The reverse engineering work done on the joy-cons and pro controllers + * by the community seems to indicate the following: + * - The controller samples the IMU every 1.35ms. It then does some of + * its own processing, probably averaging the samples out. + * - Each imu input report contains 3 IMU samples, (usually 5ms apart). + * - In the standard reporting mode (which this driver uses exclusively) + * input reports are pushed from the controller as follows: + * * joy-con (bluetooth): every 15 ms + * * joy-cons (in charging grip via USB): every 15 ms + * * pro controller (USB): every 15 ms + * * pro controller (bluetooth): every 8 ms (this is the wildcard) + * + * Further complicating matters is that some bluetooth stacks are known + * to alter the controller's packet rate by hardcoding the bluetooth + * SSR for the switch controllers (android's stack currently sets the + * SSR to 11ms for both the joy-cons and pro controllers). + * + * In my own testing, I've discovered that my pro controller either + * reports IMU sample batches every 11ms or every 15ms. This rate is + * stable after connecting. It isn't 100% clear what determines this + * rate. Importantly, even when sending every 11ms, none of the samples + * are duplicates. This seems to indicate that the time deltas between + * reported samples can vary based on the input report rate. + * + * The solution employed in this driver is to keep track of the average + * time delta between IMU input reports. In testing, this value has + * proven to be stable, staying at 15ms or 11ms, though other hardware + * configurations and bluetooth stacks could potentially see other rates + * (hopefully this will become more clear as more people use the + * driver). + * + * Keeping track of the average report delta allows us to submit our + * timestamps to userspace based on that. Each report contains 3 + * samples, so the IMU sampling rate should be avg_time_delta/3. We can + * also use this average to detect events where we have dropped a + * packet. The userspace timestamp for the samples will be adjusted + * accordingly to prevent unwanted behvaior. + */ + if (!ctlr->imu_first_packet_received) { + ctlr->imu_timestamp_us = 0; + ctlr->imu_delta_samples_count = 0; + ctlr->imu_delta_samples_sum = 0; + ctlr->imu_avg_delta_ms = JC_IMU_DFLT_AVG_DELTA_MS; + ctlr->imu_first_packet_received = true; + } else { + unsigned int delta = msecs - last_msecs; + unsigned int dropped_pkts; + unsigned int dropped_threshold; + + /* avg imu report delta housekeeping */ + ctlr->imu_delta_samples_sum += delta; + ctlr->imu_delta_samples_count++; + if (ctlr->imu_delta_samples_count >= + JC_IMU_SAMPLES_PER_DELTA_AVG) { + ctlr->imu_avg_delta_ms = ctlr->imu_delta_samples_sum / + ctlr->imu_delta_samples_count; + /* don't ever want divide by zero shenanigans */ + if (ctlr->imu_avg_delta_ms == 0) { + ctlr->imu_avg_delta_ms = 1; + hid_warn(ctlr->hdev, + "calculated avg imu delta of 0\n"); + } + ctlr->imu_delta_samples_count = 0; + ctlr->imu_delta_samples_sum = 0; + } + + /* useful for debugging IMU sample rate */ + hid_dbg(ctlr->hdev, + "imu_report: ms=%u last_ms=%u delta=%u avg_delta=%u\n", + msecs, last_msecs, delta, ctlr->imu_avg_delta_ms); + + /* check if any packets have been dropped */ + dropped_threshold = ctlr->imu_avg_delta_ms * 3 / 2; + dropped_pkts = (delta - min(delta, dropped_threshold)) / + ctlr->imu_avg_delta_ms; + ctlr->imu_timestamp_us += 1000 * ctlr->imu_avg_delta_ms; + if (dropped_pkts > JC_IMU_DROPPED_PKT_WARNING) { + hid_warn(ctlr->hdev, + "compensating for %u dropped IMU reports\n", + dropped_pkts); + hid_warn(ctlr->hdev, + "delta=%u avg_delta=%u\n", + delta, ctlr->imu_avg_delta_ms); + } + } + ctlr->imu_last_pkt_ms = msecs; + + /* Each IMU input report contains three samples */ + for (i = 0; i < 3; i++) { + input_event(idev, EV_MSC, MSC_TIMESTAMP, + ctlr->imu_timestamp_us); + + /* + * These calculations (which use the controller's calibration + * settings to improve the final values) are based on those + * found in the community's reverse-engineering repo (linked at + * top of driver). For hid-nintendo, we make sure that the final + * value given to userspace is always in terms of the axis + * resolution we provided. + * + * Currently only the gyro calculations subtract the calibration + * offsets from the raw value itself. In testing, doing the same + * for the accelerometer raw values decreased accuracy. + * + * Note that the gyro values are multiplied by the + * precision-saving scaling factor to prevent large inaccuracies + * due to truncation of the resolution value which would + * otherwise occur. To prevent overflow (without resorting to 64 + * bit integer math), the mult_frac macro is used. + */ + value[0] = mult_frac((JC_IMU_PREC_RANGE_SCALE * + (imu_data[i].gyro_x - + ctlr->gyro_cal.offset[0])), + ctlr->gyro_cal.scale[0], + ctlr->imu_cal_gyro_divisor[0]); + value[1] = mult_frac((JC_IMU_PREC_RANGE_SCALE * + (imu_data[i].gyro_y - + ctlr->gyro_cal.offset[1])), + ctlr->gyro_cal.scale[1], + ctlr->imu_cal_gyro_divisor[1]); + value[2] = mult_frac((JC_IMU_PREC_RANGE_SCALE * + (imu_data[i].gyro_z - + ctlr->gyro_cal.offset[2])), + ctlr->gyro_cal.scale[2], + ctlr->imu_cal_gyro_divisor[2]); + + value[3] = ((s32)imu_data[i].accel_x * + ctlr->accel_cal.scale[0]) / + ctlr->imu_cal_accel_divisor[0]; + value[4] = ((s32)imu_data[i].accel_y * + ctlr->accel_cal.scale[1]) / + ctlr->imu_cal_accel_divisor[1]; + value[5] = ((s32)imu_data[i].accel_z * + ctlr->accel_cal.scale[2]) / + ctlr->imu_cal_accel_divisor[2]; + + hid_dbg(ctlr->hdev, "raw_gyro: g_x=%hd g_y=%hd g_z=%hd\n", + imu_data[i].gyro_x, imu_data[i].gyro_y, + imu_data[i].gyro_z); + hid_dbg(ctlr->hdev, "raw_accel: a_x=%hd a_y=%hd a_z=%hd\n", + imu_data[i].accel_x, imu_data[i].accel_y, + imu_data[i].accel_z); + + /* + * The right joy-con has 2 axes negated, Y and Z. This is due to + * the orientation of the IMU in the controller. We negate those + * axes' values in order to be consistent with the left joy-con + * and the pro controller: + * X: positive is pointing toward the triggers + * Y: positive is pointing to the left + * Z: positive is pointing up (out of the buttons/sticks) + * The axes follow the right-hand rule. + */ + if (jc_type_is_joycon(ctlr) && jc_type_has_right(ctlr)) { + int j; + + /* negate all but x axis */ + for (j = 1; j < 6; ++j) { + if (j == 3) + continue; + value[j] *= -1; + } + } + + input_report_abs(idev, ABS_RX, value[0]); + input_report_abs(idev, ABS_RY, value[1]); + input_report_abs(idev, ABS_RZ, value[2]); + input_report_abs(idev, ABS_X, value[3]); + input_report_abs(idev, ABS_Y, value[4]); + input_report_abs(idev, ABS_Z, value[5]); + input_sync(idev); + /* convert to micros and divide by 3 (3 samples per report). */ + ctlr->imu_timestamp_us += ctlr->imu_avg_delta_ms * 1000 / 3; + } +} + static void joycon_parse_report(struct joycon_ctlr *ctlr, struct joycon_input_report *rep) { @@ -836,8 +1202,11 @@ static void joycon_parse_report(struct joycon_ctlr *ctlr, unsigned long msecs = jiffies_to_msecs(jiffies); spin_lock_irqsave(&ctlr->lock, flags); - if (/*IS_ENABLED(CONFIG_NINTENDO_FF) &&*/ rep->vibrator_report && - (msecs - ctlr->rumble_msecs) >= JC_RUMBLE_PERIOD_MS) + if (/*IS_ENABLED(CONFIG_NINTENDO_FF) && */ jc_has_rumble(ctlr) && \ + rep->vibrator_report && + (msecs - ctlr->rumble_msecs) >= JC_RUMBLE_PERIOD_MS && + (ctlr->rumble_queue_head != ctlr->rumble_queue_tail || + !ctlr->rumble_zero_amp)) queue_work(ctlr->rumble_queue, &ctlr->rumble_worker); /* Parse the battery status */ @@ -891,18 +1260,41 @@ static void joycon_parse_report(struct joycon_ctlr *ctlr, /* report buttons */ input_report_key(dev, BTN_TL, btns & JC_BTN_L); input_report_key(dev, BTN_TL2, btns & JC_BTN_ZL); + input_report_key(dev, BTN_SELECT, btns & JC_BTN_MINUS); + input_report_key(dev, BTN_THUMBL, btns & JC_BTN_LSTICK); + input_report_key(dev, BTN_Z, btns & JC_BTN_CAP); + if (jc_type_is_joycon(ctlr)) { /* Report the S buttons as the non-existent triggers */ input_report_key(dev, BTN_TR, btns & JC_BTN_SL_L); input_report_key(dev, BTN_TR2, btns & JC_BTN_SR_L); + + /* Report d-pad as digital buttons for the joy-cons */ + input_report_key(dev, BTN_DPAD_DOWN, + btns & JC_BTN_DOWN); + input_report_key(dev, BTN_DPAD_UP, btns & JC_BTN_UP); + input_report_key(dev, BTN_DPAD_RIGHT, + btns & JC_BTN_RIGHT); + input_report_key(dev, BTN_DPAD_LEFT, + btns & JC_BTN_LEFT); + } else { + int hatx = 0; + int haty = 0; + + /* d-pad x */ + if (btns & JC_BTN_LEFT) + hatx = -1; + else if (btns & JC_BTN_RIGHT) + hatx = 1; + input_report_abs(dev, ABS_HAT0X, hatx); + + /* d-pad y */ + if (btns & JC_BTN_UP) + haty = -1; + else if (btns & JC_BTN_DOWN) + haty = 1; + input_report_abs(dev, ABS_HAT0Y, haty); } - input_report_key(dev, BTN_SELECT, btns & JC_BTN_MINUS); - input_report_key(dev, BTN_THUMBL, btns & JC_BTN_LSTICK); - input_report_key(dev, BTN_Z, btns & JC_BTN_CAP); - input_report_key(dev, BTN_DPAD_DOWN, btns & JC_BTN_DOWN); - input_report_key(dev, BTN_DPAD_UP, btns & JC_BTN_UP); - input_report_key(dev, BTN_DPAD_RIGHT, btns & JC_BTN_RIGHT); - input_report_key(dev, BTN_DPAD_LEFT, btns & JC_BTN_LEFT); } if (jc_type_has_right(ctlr)) { u16 raw_x; @@ -986,52 +1378,8 @@ static void joycon_parse_report(struct joycon_ctlr *ctlr, } /* parse IMU data if present */ - if (rep->id == JC_INPUT_IMU_DATA && jc_has_imu(ctlr)) { - struct joycon_imu_data *imu_data = rep->imu_report.data; - struct input_dev *idev = ctlr->imu_input; - int i; - int value[6]; - - for (i = 0; i < 3; i++) { /* there are 3 reports */ - ctlr->timestamp += 5000; /* each is 5 ms apart */ - input_event(idev, EV_MSC, MSC_TIMESTAMP, - ctlr->timestamp); - - /* - * Rather than convert to floats, we adjust by - * calibration factors and then multiply by the default - * scaling values. This way, the consumer only needs to - * divide by the default scale values. - */ - value[0] = (imu_data[i].gyro_x - - ctlr->gyro_cal.offset[0]) * - DFLT_GYRO_SCALE / ctlr->gyro_cal.scale[0]; - value[1] = (imu_data[i].gyro_y - - ctlr->gyro_cal.offset[1]) * - DFLT_GYRO_SCALE / ctlr->gyro_cal.scale[1]; - value[2] = (imu_data[i].gyro_z - - ctlr->gyro_cal.offset[2]) * - DFLT_GYRO_SCALE / ctlr->gyro_cal.scale[2]; - - value[3] = (imu_data[i].accel_x - - ctlr->accel_cal.offset[0]) * - DFLT_ACCEL_SCALE / ctlr->accel_cal.scale[0]; - value[4] = (imu_data[i].accel_y - - ctlr->accel_cal.offset[1]) * - DFLT_ACCEL_SCALE / ctlr->accel_cal.scale[1]; - value[5] = (imu_data[i].accel_z - - ctlr->accel_cal.offset[2]) * - DFLT_ACCEL_SCALE / ctlr->accel_cal.scale[2]; - - input_report_abs(idev, ABS_RX, value[0]); - input_report_abs(idev, ABS_RY, value[1]); - input_report_abs(idev, ABS_RZ, value[2]); - input_report_abs(idev, ABS_X, value[3]); - input_report_abs(idev, ABS_Y, value[4]); - input_report_abs(idev, ABS_Z, value[5]); - input_sync(idev); - } - } + if (jc_has_imu(ctlr) && rep->id == JC_INPUT_IMU_DATA) + joycon_parse_imu_report(ctlr, rep); } static void joycon_rumble_worker(struct work_struct *work) @@ -1042,6 +1390,10 @@ static void joycon_rumble_worker(struct work_struct *work) bool again = true; int ret; + if (!jc_has_rumble(ctlr)) { + return; + } + while (again) { mutex_lock(&ctlr->output_mutex); ret = joycon_enable_rumble(ctlr, true); @@ -1154,6 +1506,8 @@ static int joycon_set_rumble(struct joycon_ctlr *ctlr, u16 amp_r, u16 amp_l, freq_r_high = ctlr->rumble_rh_freq; freq_l_low = ctlr->rumble_ll_freq; freq_l_high = ctlr->rumble_lh_freq; + /* this flag is used to reduce subcommand traffic */ + ctlr->rumble_zero_amp = (amp_l == 0) && (amp_r == 0); spin_unlock_irqrestore(&ctlr->lock, flags); /* right joy-con */ @@ -1195,7 +1549,6 @@ static int joycon_play_effect(struct input_dev *dev, void *data, static const unsigned int joycon_button_inputs_l[] = { BTN_SELECT, BTN_Z, BTN_THUMBL, - BTN_DPAD_UP, BTN_DPAD_DOWN, BTN_DPAD_LEFT, BTN_DPAD_RIGHT, BTN_TL, BTN_TL2, 0 /* 0 signals end of array */ }; @@ -1207,6 +1560,11 @@ static const unsigned int joycon_button_inputs_r[] = { 0 /* 0 signals end of array */ }; +/* We report joy-con d-pad inputs as buttons and pro controller as a hat. */ +static const unsigned int joycon_dpad_inputs_jc[] = { + BTN_DPAD_UP, BTN_DPAD_DOWN, BTN_DPAD_LEFT, BTN_DPAD_RIGHT, +}; + static const unsigned int nescon_button_inputs[] = { BTN_SELECT, BTN_START, BTN_SOUTH, BTN_EAST, BTN_TL, BTN_TR, 0 /* 0 signals end of array */ @@ -1247,15 +1605,15 @@ static int joycon_input_create(struct joycon_ctlr *ctlr) imu_name = "Nintendo Switch Left Joy-Con IMU"; break; case USB_DEVICE_ID_NINTENDO_JOYCONR: - if (ctlr->ctlr_type == JOYCON_CTLR_TYPE_NESL) { + if (ctlr->ctlr_type == JOYCON_CTLR_TYPE_JCR) { + name = "Nintendo Switch Right Joy-Con"; + imu_name = "Nintendo Switch Right Joy-Con IMU"; + } else if (ctlr->ctlr_type == JOYCON_CTLR_TYPE_NESL) { name = "Nintendo Switch NES Controller (L)"; imu_name = NULL; } else if (ctlr->ctlr_type == JOYCON_CTLR_TYPE_NESR) { name = "Nintendo Switch NES Controller (R)"; imu_name = NULL; - } else { - name = "Nintendo Switch Right Joy-Con"; - imu_name = "Nintendo Switch Right Joy-Con IMU"; } break; case USB_DEVICE_ID_NINTENDO_SNESCON: @@ -1278,28 +1636,41 @@ static int joycon_input_create(struct joycon_ctlr *ctlr) ctlr->input->name = name; input_set_drvdata(ctlr->input, ctlr); + /* set up sticks and buttons */ if (jc_type_has_left(ctlr)) { - /* set up sticks */ input_set_abs_params(ctlr->input, ABS_X, -JC_MAX_STICK_MAG, JC_MAX_STICK_MAG, JC_STICK_FUZZ, JC_STICK_FLAT); input_set_abs_params(ctlr->input, ABS_Y, -JC_MAX_STICK_MAG, JC_MAX_STICK_MAG, JC_STICK_FUZZ, JC_STICK_FLAT); - /* set up buttons */ + for (i = 0; joycon_button_inputs_l[i] > 0; i++) input_set_capability(ctlr->input, EV_KEY, joycon_button_inputs_l[i]); + + /* configure d-pad differently for joy-con vs pro controller */ + if (hdev->product != USB_DEVICE_ID_NINTENDO_PROCON) { + for (i = 0; joycon_dpad_inputs_jc[i] > 0; i++) + input_set_capability(ctlr->input, EV_KEY, + joycon_dpad_inputs_jc[i]); + } else { + input_set_abs_params(ctlr->input, ABS_HAT0X, + -JC_MAX_DPAD_MAG, JC_MAX_DPAD_MAG, + JC_DPAD_FUZZ, JC_DPAD_FLAT); + input_set_abs_params(ctlr->input, ABS_HAT0Y, + -JC_MAX_DPAD_MAG, JC_MAX_DPAD_MAG, + JC_DPAD_FUZZ, JC_DPAD_FLAT); + } } if (jc_type_has_right(ctlr)) { - /* set up sticks */ input_set_abs_params(ctlr->input, ABS_RX, -JC_MAX_STICK_MAG, JC_MAX_STICK_MAG, JC_STICK_FUZZ, JC_STICK_FLAT); input_set_abs_params(ctlr->input, ABS_RY, -JC_MAX_STICK_MAG, JC_MAX_STICK_MAG, JC_STICK_FUZZ, JC_STICK_FLAT); - /* set up buttons */ + for (i = 0; joycon_button_inputs_r[i] > 0; i++) input_set_capability(ctlr->input, EV_KEY, joycon_button_inputs_r[i]); @@ -1309,8 +1680,12 @@ static int joycon_input_create(struct joycon_ctlr *ctlr) nescon_button_inputs : snescon_button_inputs; /* set up d-pad hat */ - input_set_abs_params(ctlr->input, ABS_HAT0X, -1, 1, 0, 0); - input_set_abs_params(ctlr->input, ABS_HAT0Y, -1, 1, 0, 0); + input_set_abs_params(ctlr->input, ABS_HAT0X, + -JC_MAX_DPAD_MAG, JC_MAX_DPAD_MAG, + JC_DPAD_FUZZ, JC_DPAD_FLAT); + input_set_abs_params(ctlr->input, ABS_HAT0Y, + -JC_MAX_DPAD_MAG, JC_MAX_DPAD_MAG, + JC_DPAD_FUZZ, JC_DPAD_FLAT); /* set up buttons */ for (i = 0; inputs[i] > 0; i++) @@ -1324,6 +1699,15 @@ static int joycon_input_create(struct joycon_ctlr *ctlr) return 0; } + /* Let's report joy-con S triggers separately */ + if (hdev->product == USB_DEVICE_ID_NINTENDO_JOYCONL) { + input_set_capability(ctlr->input, EV_KEY, BTN_TR); + input_set_capability(ctlr->input, EV_KEY, BTN_TR2); + } else if (hdev->product == USB_DEVICE_ID_NINTENDO_JOYCONR) { + input_set_capability(ctlr->input, EV_KEY, BTN_TL); + input_set_capability(ctlr->input, EV_KEY, BTN_TL2); + } + //#if IS_ENABLED(CONFIG_NINTENDO_FF) /* set up rumble */ input_set_capability(ctlr->input, EV_FF, FF_RUMBLE); @@ -1356,31 +1740,31 @@ static int joycon_input_create(struct joycon_ctlr *ctlr) /* configure imu axes */ input_set_abs_params(ctlr->imu_input, ABS_X, - -JC_MAX_ACCEL_MAG, JC_MAX_ACCEL_MAG, - JC_ACCEL_FUZZ, JC_ACCEL_FLAT); + -JC_IMU_MAX_ACCEL_MAG, JC_IMU_MAX_ACCEL_MAG, + JC_IMU_ACCEL_FUZZ, JC_IMU_ACCEL_FLAT); input_set_abs_params(ctlr->imu_input, ABS_Y, - -JC_MAX_ACCEL_MAG, JC_MAX_ACCEL_MAG, - JC_ACCEL_FUZZ, JC_ACCEL_FLAT); + -JC_IMU_MAX_ACCEL_MAG, JC_IMU_MAX_ACCEL_MAG, + JC_IMU_ACCEL_FUZZ, JC_IMU_ACCEL_FLAT); input_set_abs_params(ctlr->imu_input, ABS_Z, - -JC_MAX_ACCEL_MAG, JC_MAX_ACCEL_MAG, - JC_ACCEL_FUZZ, JC_ACCEL_FLAT); - input_abs_set_res(ctlr->imu_input, ABS_X, JC_ACCEL_RES); - input_abs_set_res(ctlr->imu_input, ABS_Y, JC_ACCEL_RES); - input_abs_set_res(ctlr->imu_input, ABS_Z, JC_ACCEL_RES); + -JC_IMU_MAX_ACCEL_MAG, JC_IMU_MAX_ACCEL_MAG, + JC_IMU_ACCEL_FUZZ, JC_IMU_ACCEL_FLAT); + input_abs_set_res(ctlr->imu_input, ABS_X, JC_IMU_ACCEL_RES_PER_G); + input_abs_set_res(ctlr->imu_input, ABS_Y, JC_IMU_ACCEL_RES_PER_G); + input_abs_set_res(ctlr->imu_input, ABS_Z, JC_IMU_ACCEL_RES_PER_G); input_set_abs_params(ctlr->imu_input, ABS_RX, - -JC_MAX_GYRO_MAG, JC_MAX_GYRO_MAG, - JC_GYRO_FUZZ, JC_GYRO_FLAT); + -JC_IMU_MAX_GYRO_MAG, JC_IMU_MAX_GYRO_MAG, + JC_IMU_GYRO_FUZZ, JC_IMU_GYRO_FLAT); input_set_abs_params(ctlr->imu_input, ABS_RY, - -JC_MAX_GYRO_MAG, JC_MAX_GYRO_MAG, - JC_GYRO_FUZZ, JC_GYRO_FLAT); + -JC_IMU_MAX_GYRO_MAG, JC_IMU_MAX_GYRO_MAG, + JC_IMU_GYRO_FUZZ, JC_IMU_GYRO_FLAT); input_set_abs_params(ctlr->imu_input, ABS_RZ, - -JC_MAX_GYRO_MAG, JC_MAX_GYRO_MAG, - JC_GYRO_FUZZ, JC_GYRO_FLAT); + -JC_IMU_MAX_GYRO_MAG, JC_IMU_MAX_GYRO_MAG, + JC_IMU_GYRO_FUZZ, JC_IMU_GYRO_FLAT); - input_abs_set_res(ctlr->imu_input, ABS_RX, JC_GYRO_RES); - input_abs_set_res(ctlr->imu_input, ABS_RY, JC_GYRO_RES); - input_abs_set_res(ctlr->imu_input, ABS_RZ, JC_GYRO_RES); + input_abs_set_res(ctlr->imu_input, ABS_RX, JC_IMU_GYRO_RES_PER_DPS); + input_abs_set_res(ctlr->imu_input, ABS_RY, JC_IMU_GYRO_RES_PER_DPS); + input_abs_set_res(ctlr->imu_input, ABS_RZ, JC_IMU_GYRO_RES_PER_DPS); __set_bit(EV_MSC, ctlr->imu_input->evbit); __set_bit(MSC_TIMESTAMP, ctlr->imu_input->mscbit); @@ -1612,6 +1996,7 @@ static int joycon_power_supply_create(struct joycon_ctlr *ctlr) ctlr->battery_desc.num_properties = ARRAY_SIZE(joycon_battery_props); ctlr->battery_desc.get_property = joycon_battery_get_property; + ctlr->battery_desc.type = POWER_SUPPLY_TYPE_BATTERY; ctlr->battery_desc.use_for_apm = 0; ctlr->battery_desc.name = devm_kasprintf(&hdev->dev, GFP_KERNEL, name_fmt, @@ -1854,21 +2239,18 @@ static int nintendo_hid_probe(struct hid_device *hdev, goto err_mutex; } - - if (!jc_type_is_snescon(ctlr)) { + if (!jc_type_is_nescon(ctlr) && !jc_type_is_snescon(ctlr)) { /* Enable rumble */ ret = joycon_enable_rumble(ctlr, true); if (ret) { - hid_err(hdev, - "Failed to enable rumble; ret=%d\n", ret); + hid_err(hdev, "Failed to enable rumble; ret=%d\n", ret); goto err_mutex; } /* Enable the IMU */ ret = joycon_enable_imu(ctlr, true); if (ret) { - hid_err(hdev, - "Failed to enable the IMU; ret=%d\n", ret); + hid_err(hdev, "Failed to enable the IMU; ret=%d\n", ret); goto err_mutex; } } @@ -1969,3 +2351,4 @@ module_hid_driver(nintendo_hid_driver); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Daniel J. Ogorchock <djogorchock@gmail.com>"); MODULE_DESCRIPTION("Driver for Nintendo Switch Controllers"); + |