Skip to content

Commit 385a488

Browse files
rodrigorcJiri Kosina
authored andcommitted
HID: steam: remove input device when a hid client is running.
Previously, when a HID client such as the Steam Client was running, this driver disabled its input device to avoid doubling the input events. While it worked mostly fine, some games got confused by the idle gamepad, and switched to two player mode, or asked the user to choose which gamepad to use. Other games just crashed, probably a bug in Unity [1]. With this commit, when a HID client starts, the input device is removed; when the HID client ends the input device is recreated. [1]: ValveSoftware/steam-for-linux#5645 Signed-off-by: Rodrigo Rivas Costa <rodrigorivascosta@gmail.com> Signed-off-by: Jiri Kosina <jkosina@suse.cz>
1 parent 4d26d1d commit 385a488

File tree

1 file changed

+90
-64
lines changed

1 file changed

+90
-64
lines changed

drivers/hid/hid-steam.c

Lines changed: 90 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,9 @@
2323
* In order to avoid breaking them this driver creates a layered hidraw device,
2424
* so it can detect when the client is running and then:
2525
* - it will not send any command to the controller.
26-
* - this input device will be disabled, to avoid double input of the same
26+
* - this input device will be removed, to avoid double input of the same
2727
* user action.
28+
* When the client is closed, this input device will be created again.
2829
*
2930
* For additional functions, such as changing the right-pad margin or switching
3031
* the led, you can use the user-space tool at:
@@ -113,7 +114,7 @@ struct steam_device {
113114
spinlock_t lock;
114115
struct hid_device *hdev, *client_hdev;
115116
struct mutex mutex;
116-
bool client_opened, input_opened;
117+
bool client_opened;
117118
struct input_dev __rcu *input;
118119
unsigned long quirks;
119120
struct work_struct work_connect;
@@ -279,18 +280,6 @@ static void steam_set_lizard_mode(struct steam_device *steam, bool enable)
279280
}
280281
}
281282

282-
static void steam_update_lizard_mode(struct steam_device *steam)
283-
{
284-
mutex_lock(&steam->mutex);
285-
if (!steam->client_opened) {
286-
if (steam->input_opened)
287-
steam_set_lizard_mode(steam, false);
288-
else
289-
steam_set_lizard_mode(steam, lizard_mode);
290-
}
291-
mutex_unlock(&steam->mutex);
292-
}
293-
294283
static int steam_input_open(struct input_dev *dev)
295284
{
296285
struct steam_device *steam = input_get_drvdata(dev);
@@ -301,7 +290,6 @@ static int steam_input_open(struct input_dev *dev)
301290
return ret;
302291

303292
mutex_lock(&steam->mutex);
304-
steam->input_opened = true;
305293
if (!steam->client_opened && lizard_mode)
306294
steam_set_lizard_mode(steam, false);
307295
mutex_unlock(&steam->mutex);
@@ -313,7 +301,6 @@ static void steam_input_close(struct input_dev *dev)
313301
struct steam_device *steam = input_get_drvdata(dev);
314302

315303
mutex_lock(&steam->mutex);
316-
steam->input_opened = false;
317304
if (!steam->client_opened && lizard_mode)
318305
steam_set_lizard_mode(steam, true);
319306
mutex_unlock(&steam->mutex);
@@ -400,7 +387,7 @@ static int steam_battery_register(struct steam_device *steam)
400387
return 0;
401388
}
402389

403-
static int steam_register(struct steam_device *steam)
390+
static int steam_input_register(struct steam_device *steam)
404391
{
405392
struct hid_device *hdev = steam->hdev;
406393
struct input_dev *input;
@@ -414,17 +401,6 @@ static int steam_register(struct steam_device *steam)
414401
return 0;
415402
}
416403

417-
/*
418-
* Unlikely, but getting the serial could fail, and it is not so
419-
* important, so make up a serial number and go on.
420-
*/
421-
if (steam_get_serial(steam) < 0)
422-
strlcpy(steam->serial_no, "XXXXXXXXXX",
423-
sizeof(steam->serial_no));
424-
425-
hid_info(hdev, "Steam Controller '%s' connected",
426-
steam->serial_no);
427-
428404
input = input_allocate_device();
429405
if (!input)
430406
return -ENOMEM;
@@ -492,39 +468,95 @@ static int steam_register(struct steam_device *steam)
492468
goto input_register_fail;
493469

494470
rcu_assign_pointer(steam->input, input);
495-
496-
/* ignore battery errors, we can live without it */
497-
if (steam->quirks & STEAM_QUIRK_WIRELESS)
498-
steam_battery_register(steam);
499-
500471
return 0;
501472

502473
input_register_fail:
503474
input_free_device(input);
504475
return ret;
505476
}
506477

507-
static void steam_unregister(struct steam_device *steam)
478+
static void steam_input_unregister(struct steam_device *steam)
508479
{
509480
struct input_dev *input;
481+
rcu_read_lock();
482+
input = rcu_dereference(steam->input);
483+
rcu_read_unlock();
484+
if (!input)
485+
return;
486+
RCU_INIT_POINTER(steam->input, NULL);
487+
synchronize_rcu();
488+
input_unregister_device(input);
489+
}
490+
491+
static void steam_battery_unregister(struct steam_device *steam)
492+
{
510493
struct power_supply *battery;
511494

512495
rcu_read_lock();
513-
input = rcu_dereference(steam->input);
514496
battery = rcu_dereference(steam->battery);
515497
rcu_read_unlock();
516498

517-
if (battery) {
518-
RCU_INIT_POINTER(steam->battery, NULL);
519-
synchronize_rcu();
520-
power_supply_unregister(battery);
499+
if (!battery)
500+
return;
501+
RCU_INIT_POINTER(steam->battery, NULL);
502+
synchronize_rcu();
503+
power_supply_unregister(battery);
504+
}
505+
506+
static int steam_register(struct steam_device *steam)
507+
{
508+
int ret;
509+
510+
/*
511+
* This function can be called several times in a row with the
512+
* wireless adaptor, without steam_unregister() between them, because
513+
* another client send a get_connection_status command, for example.
514+
* The battery and serial number are set just once per device.
515+
*/
516+
if (!steam->serial_no[0]) {
517+
/*
518+
* Unlikely, but getting the serial could fail, and it is not so
519+
* important, so make up a serial number and go on.
520+
*/
521+
if (steam_get_serial(steam) < 0)
522+
strlcpy(steam->serial_no, "XXXXXXXXXX",
523+
sizeof(steam->serial_no));
524+
525+
hid_info(steam->hdev, "Steam Controller '%s' connected",
526+
steam->serial_no);
527+
528+
/* ignore battery errors, we can live without it */
529+
if (steam->quirks & STEAM_QUIRK_WIRELESS)
530+
steam_battery_register(steam);
531+
532+
mutex_lock(&steam_devices_lock);
533+
list_add(&steam->list, &steam_devices);
534+
mutex_unlock(&steam_devices_lock);
521535
}
522-
if (input) {
523-
RCU_INIT_POINTER(steam->input, NULL);
524-
synchronize_rcu();
536+
537+
mutex_lock(&steam->mutex);
538+
if (!steam->client_opened) {
539+
steam_set_lizard_mode(steam, lizard_mode);
540+
ret = steam_input_register(steam);
541+
} else {
542+
ret = 0;
543+
}
544+
mutex_unlock(&steam->mutex);
545+
546+
return ret;
547+
}
548+
549+
static void steam_unregister(struct steam_device *steam)
550+
{
551+
steam_battery_unregister(steam);
552+
steam_input_unregister(steam);
553+
if (steam->serial_no[0]) {
525554
hid_info(steam->hdev, "Steam Controller '%s' disconnected",
526555
steam->serial_no);
527-
input_unregister_device(input);
556+
mutex_lock(&steam_devices_lock);
557+
list_del(&steam->list);
558+
mutex_unlock(&steam_devices_lock);
559+
steam->serial_no[0] = 0;
528560
}
529561
}
530562

@@ -600,6 +632,9 @@ static int steam_client_ll_open(struct hid_device *hdev)
600632
mutex_lock(&steam->mutex);
601633
steam->client_opened = true;
602634
mutex_unlock(&steam->mutex);
635+
636+
steam_input_unregister(steam);
637+
603638
return ret;
604639
}
605640

@@ -609,13 +644,13 @@ static void steam_client_ll_close(struct hid_device *hdev)
609644

610645
mutex_lock(&steam->mutex);
611646
steam->client_opened = false;
612-
if (steam->input_opened)
613-
steam_set_lizard_mode(steam, false);
614-
else
615-
steam_set_lizard_mode(steam, lizard_mode);
616647
mutex_unlock(&steam->mutex);
617648

618649
hid_hw_close(steam->hdev);
650+
if (steam->connected) {
651+
steam_set_lizard_mode(steam, lizard_mode);
652+
steam_input_register(steam);
653+
}
619654
}
620655

621656
static int steam_client_ll_raw_request(struct hid_device *hdev,
@@ -744,11 +779,6 @@ static int steam_probe(struct hid_device *hdev,
744779
}
745780
}
746781

747-
mutex_lock(&steam_devices_lock);
748-
steam_update_lizard_mode(steam);
749-
list_add(&steam->list, &steam_devices);
750-
mutex_unlock(&steam_devices_lock);
751-
752782
return 0;
753783

754784
hid_hw_open_fail:
@@ -774,10 +804,6 @@ static void steam_remove(struct hid_device *hdev)
774804
return;
775805
}
776806

777-
mutex_lock(&steam_devices_lock);
778-
list_del(&steam->list);
779-
mutex_unlock(&steam_devices_lock);
780-
781807
hid_destroy_device(steam->client_hdev);
782808
steam->client_opened = false;
783809
cancel_work_sync(&steam->work_connect);
@@ -792,12 +818,14 @@ static void steam_remove(struct hid_device *hdev)
792818
static void steam_do_connect_event(struct steam_device *steam, bool connected)
793819
{
794820
unsigned long flags;
821+
bool changed;
795822

796823
spin_lock_irqsave(&steam->lock, flags);
824+
changed = steam->connected != connected;
797825
steam->connected = connected;
798826
spin_unlock_irqrestore(&steam->lock, flags);
799827

800-
if (schedule_work(&steam->work_connect) == 0)
828+
if (changed && schedule_work(&steam->work_connect) == 0)
801829
dbg_hid("%s: connected=%d event already queued\n",
802830
__func__, connected);
803831
}
@@ -1019,13 +1047,8 @@ static int steam_raw_event(struct hid_device *hdev,
10191047
return 0;
10201048
rcu_read_lock();
10211049
input = rcu_dereference(steam->input);
1022-
if (likely(input)) {
1050+
if (likely(input))
10231051
steam_do_input_event(steam, input, data);
1024-
} else {
1025-
dbg_hid("%s: input data without connect event\n",
1026-
__func__);
1027-
steam_do_connect_event(steam, true);
1028-
}
10291052
rcu_read_unlock();
10301053
break;
10311054
case STEAM_EV_CONNECT:
@@ -1074,7 +1097,10 @@ static int steam_param_set_lizard_mode(const char *val,
10741097

10751098
mutex_lock(&steam_devices_lock);
10761099
list_for_each_entry(steam, &steam_devices, list) {
1077-
steam_update_lizard_mode(steam);
1100+
mutex_lock(&steam->mutex);
1101+
if (!steam->client_opened)
1102+
steam_set_lizard_mode(steam, lizard_mode);
1103+
mutex_unlock(&steam->mutex);
10781104
}
10791105
mutex_unlock(&steam_devices_lock);
10801106
return 0;

0 commit comments

Comments
 (0)