Skip to content

Commit 4c048f6

Browse files
DanielOgorchockJiri Kosina
authored andcommitted
HID: nintendo: improve rumble performance and stability
This patch alters the method that the rumble data is sent to the controller. Rather than using the enable rumble subcommand for this purpose, the driver now employs the RUMBLE_ONLY output report. This has the advantage of not needing to receive a subcommand reply (to the major benefit of reducing IMU latency) and also seems to make the rumble vibrations more continuous. Perhaps most importantly it reduces disconnects during times of heavy rumble. Signed-off-by: Daniel J. Ogorchock <djogorchock@gmail.com> Signed-off-by: Jiri Kosina <jkosina@suse.cz>
1 parent 4ff5b10 commit 4c048f6

1 file changed

Lines changed: 37 additions & 1 deletion

File tree

drivers/hid/hid-nintendo.c

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -348,6 +348,12 @@ enum joycon_msg_type {
348348
JOYCON_MSG_TYPE_SUBCMD,
349349
};
350350

351+
struct joycon_rumble_output {
352+
u8 output_id;
353+
u8 packet_num;
354+
u8 rumble_data[8];
355+
} __packed;
356+
351357
struct joycon_subcmd_request {
352358
u8 output_id; /* must be 0x01 for subcommand, 0x10 for rumble only */
353359
u8 packet_num; /* incremented every send */
@@ -1328,6 +1334,36 @@ static void joycon_parse_report(struct joycon_ctlr *ctlr,
13281334
joycon_parse_imu_report(ctlr, rep);
13291335
}
13301336

1337+
static int joycon_send_rumble_data(struct joycon_ctlr *ctlr)
1338+
{
1339+
int ret;
1340+
unsigned long flags;
1341+
struct joycon_rumble_output rumble_output = { 0 };
1342+
1343+
spin_lock_irqsave(&ctlr->lock, flags);
1344+
/*
1345+
* If the controller has been removed, just return ENODEV so the LED
1346+
* subsystem doesn't print invalid errors on removal.
1347+
*/
1348+
if (ctlr->ctlr_state == JOYCON_CTLR_STATE_REMOVED) {
1349+
spin_unlock_irqrestore(&ctlr->lock, flags);
1350+
return -ENODEV;
1351+
}
1352+
memcpy(rumble_output.rumble_data,
1353+
ctlr->rumble_data[ctlr->rumble_queue_tail],
1354+
JC_RUMBLE_DATA_SIZE);
1355+
spin_unlock_irqrestore(&ctlr->lock, flags);
1356+
1357+
rumble_output.output_id = JC_OUTPUT_RUMBLE_ONLY;
1358+
rumble_output.packet_num = ctlr->subcmd_num;
1359+
if (++ctlr->subcmd_num > 0xF)
1360+
ctlr->subcmd_num = 0;
1361+
1362+
ret = __joycon_hid_send(ctlr->hdev, (u8 *)&rumble_output,
1363+
sizeof(rumble_output));
1364+
return ret;
1365+
}
1366+
13311367
static void joycon_rumble_worker(struct work_struct *work)
13321368
{
13331369
struct joycon_ctlr *ctlr = container_of(work, struct joycon_ctlr,
@@ -1338,7 +1374,7 @@ static void joycon_rumble_worker(struct work_struct *work)
13381374

13391375
while (again) {
13401376
mutex_lock(&ctlr->output_mutex);
1341-
ret = joycon_enable_rumble(ctlr);
1377+
ret = joycon_send_rumble_data(ctlr);
13421378
mutex_unlock(&ctlr->output_mutex);
13431379

13441380
/* -ENODEV means the controller was just unplugged */

0 commit comments

Comments
 (0)