diff options
Diffstat (limited to 'drivers/hid/hid-nintendo.c')
| -rw-r--r-- | drivers/hid/hid-nintendo.c | 90 |
1 files changed, 50 insertions, 40 deletions
diff --git a/drivers/hid/hid-nintendo.c b/drivers/hid/hid-nintendo.c index 3062daf68d31..7ac9217d9096 100644 --- a/drivers/hid/hid-nintendo.c +++ b/drivers/hid/hid-nintendo.c @@ -29,7 +29,7 @@ */ #include "hid-ids.h" -#include <asm/unaligned.h> +#include <linux/unaligned.h> #include <linux/delay.h> #include <linux/device.h> #include <linux/kernel.h> @@ -308,6 +308,7 @@ enum joycon_ctlr_state { JOYCON_CTLR_STATE_INIT, JOYCON_CTLR_STATE_READ, JOYCON_CTLR_STATE_REMOVED, + JOYCON_CTLR_STATE_SUSPENDED, }; /* Controller type received as part of device info */ @@ -456,24 +457,20 @@ static const struct joycon_ctlr_button_mapping snescon_button_mappings[] = { { /* sentinel */ }, }; -/* - * "A", "B", and "C" are mapped positionally, rather than by label (e.g., "A" - * gets assigned to BTN_EAST instead of BTN_A). - */ static const struct joycon_ctlr_button_mapping gencon_button_mappings[] = { - { BTN_SOUTH, JC_BTN_A, }, - { BTN_EAST, JC_BTN_B, }, - { BTN_WEST, JC_BTN_R, }, - { BTN_SELECT, JC_BTN_ZR, }, + { BTN_WEST, JC_BTN_A, }, /* A */ + { BTN_SOUTH, JC_BTN_B, }, /* B */ + { BTN_EAST, JC_BTN_R, }, /* C */ + { BTN_TL, JC_BTN_X, }, /* X MD/GEN 6B Only */ + { BTN_NORTH, JC_BTN_Y, }, /* Y MD/GEN 6B Only */ + { BTN_TR, JC_BTN_L, }, /* Z MD/GEN 6B Only */ + { BTN_SELECT, JC_BTN_ZR, }, /* Mode */ { BTN_START, JC_BTN_PLUS, }, { BTN_MODE, JC_BTN_HOME, }, { BTN_Z, JC_BTN_CAP, }, { /* sentinel */ }, }; -/* - * N64's C buttons get assigned to d-pad directions and registered as buttons. - */ static const struct joycon_ctlr_button_mapping n64con_button_mappings[] = { { BTN_A, JC_BTN_A, }, { BTN_B, JC_BTN_B, }, @@ -658,7 +655,6 @@ struct joycon_ctlr { (ctlr->ctlr_type == JOYCON_CTLR_TYPE_JCR || \ ctlr->ctlr_type == JOYCON_CTLR_TYPE_PRO) - /* * Controller device helpers * @@ -669,31 +665,11 @@ struct joycon_ctlr { * These helpers are most useful early during the HID probe or in conjunction * with the capability helpers below. */ -static inline bool joycon_device_is_procon(struct joycon_ctlr *ctlr) -{ - return ctlr->hdev->product == USB_DEVICE_ID_NINTENDO_PROCON; -} - static inline bool joycon_device_is_chrggrip(struct joycon_ctlr *ctlr) { return ctlr->hdev->product == USB_DEVICE_ID_NINTENDO_CHRGGRIP; } -static inline bool joycon_device_is_snescon(struct joycon_ctlr *ctlr) -{ - return ctlr->hdev->product == USB_DEVICE_ID_NINTENDO_SNESCON; -} - -static inline bool joycon_device_is_gencon(struct joycon_ctlr *ctlr) -{ - return ctlr->hdev->product == USB_DEVICE_ID_NINTENDO_GENCON; -} - -static inline bool joycon_device_is_n64con(struct joycon_ctlr *ctlr) -{ - return ctlr->hdev->product == USB_DEVICE_ID_NINTENDO_N64CON; -} - /* * Controller type helpers * @@ -843,7 +819,7 @@ static void joycon_wait_for_input_report(struct joycon_ctlr *ctlr) #define JC_INPUT_REPORT_MAX_DELTA 17 #define JC_SUBCMD_TX_OFFSET_MS 4 #define JC_SUBCMD_VALID_DELTA_REQ 3 -#define JC_SUBCMD_RATE_MAX_ATTEMPTS 500 +#define JC_SUBCMD_RATE_MAX_ATTEMPTS 25 #define JC_SUBCMD_RATE_LIMITER_USB_MS 20 #define JC_SUBCMD_RATE_LIMITER_BT_MS 60 #define JC_SUBCMD_RATE_LIMITER_MS(ctlr) ((ctlr)->hdev->bus == BUS_USB ? JC_SUBCMD_RATE_LIMITER_USB_MS : JC_SUBCMD_RATE_LIMITER_BT_MS) @@ -1479,10 +1455,10 @@ static void joycon_parse_imu_report(struct joycon_ctlr *ctlr, 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, + hid_warn_ratelimited(ctlr->hdev, "compensating for %u dropped IMU reports\n", dropped_pkts); - hid_warn(ctlr->hdev, + hid_warn_ratelimited(ctlr->hdev, "delta=%u avg_delta=%u\n", delta, ctlr->imu_avg_delta_ms); } @@ -2444,7 +2420,7 @@ static int joycon_read_info(struct joycon_ctlr *ctlr) struct joycon_input_report *report; req.subcmd_id = JC_SUBCMD_REQ_DEV_INFO; - ret = joycon_send_subcmd(ctlr, &req, 0, HZ); + ret = joycon_send_subcmd(ctlr, &req, 0, 2 * HZ); if (ret) { hid_err(ctlr->hdev, "Failed to get joycon info; ret=%d\n", ret); return ret; @@ -2672,7 +2648,8 @@ static int nintendo_hid_probe(struct hid_device *hdev, init_waitqueue_head(&ctlr->wait); spin_lock_init(&ctlr->lock); ctlr->rumble_queue = alloc_workqueue("hid-nintendo-rumble_wq", - WQ_FREEZABLE | WQ_MEM_RECLAIM, 0); + WQ_FREEZABLE | WQ_MEM_RECLAIM | WQ_PERCPU, + 0); if (!ctlr->rumble_queue) { ret = -ENOMEM; goto err; @@ -2775,14 +2752,46 @@ static void nintendo_hid_remove(struct hid_device *hdev) static int nintendo_hid_resume(struct hid_device *hdev) { - int ret = joycon_init(hdev); + struct joycon_ctlr *ctlr = hid_get_drvdata(hdev); + int ret; + + hid_dbg(hdev, "resume\n"); + if (!joycon_using_usb(ctlr)) { + hid_dbg(hdev, "no-op resume for bt ctlr\n"); + ctlr->ctlr_state = JOYCON_CTLR_STATE_READ; + return 0; + } + ret = joycon_init(hdev); if (ret) - hid_err(hdev, "Failed to restore controller after resume"); + hid_err(hdev, + "Failed to restore controller after resume: %d\n", + ret); + else + ctlr->ctlr_state = JOYCON_CTLR_STATE_READ; return ret; } +static int nintendo_hid_suspend(struct hid_device *hdev, pm_message_t message) +{ + struct joycon_ctlr *ctlr = hid_get_drvdata(hdev); + + hid_dbg(hdev, "suspend: %d\n", message.event); + /* + * Avoid any blocking loops in suspend/resume transitions. + * + * joycon_enforce_subcmd_rate() can result in repeated retries if for + * whatever reason the controller stops providing input reports. + * + * This has been observed with bluetooth controllers which lose + * connectivity prior to suspend (but not long enough to result in + * complete disconnection). + */ + ctlr->ctlr_state = JOYCON_CTLR_STATE_SUSPENDED; + return 0; +} + #endif static const struct hid_device_id nintendo_hid_devices[] = { @@ -2821,6 +2830,7 @@ static struct hid_driver nintendo_hid_driver = { #ifdef CONFIG_PM .resume = nintendo_hid_resume, + .suspend = nintendo_hid_suspend, #endif }; static int __init nintendo_init(void) |
