Skip to content

Commit 7950424

Browse files
endriftJiri Kosina
authored and
Jiri Kosina
committed
HID: hid-steam: Move hidraw input (un)registering to work
Due to an interplay between locking in the input and hid transport subsystems, attempting to register or deregister the relevant input devices during the hidraw open/close events can lead to a lock ordering issue. Though this shouldn't cause a deadlock, this commit moves the input device manipulation to deferred work to sidestep the issue. Fixes: 385a488 ("HID: steam: remove input device when a hid client is running.") Signed-off-by: Vicki Pfau <[email protected]> Signed-off-by: Jiri Kosina <[email protected]>
1 parent 0b43d98 commit 7950424

File tree

1 file changed

+31
-7
lines changed

1 file changed

+31
-7
lines changed

drivers/hid/hid-steam.c

+31-7
Original file line numberDiff line numberDiff line change
@@ -313,6 +313,7 @@ struct steam_device {
313313
u16 rumble_left;
314314
u16 rumble_right;
315315
unsigned int sensor_timestamp_us;
316+
struct work_struct unregister_work;
316317
};
317318

318319
static int steam_recv_report(struct steam_device *steam,
@@ -1072,6 +1073,31 @@ static void steam_mode_switch_cb(struct work_struct *work)
10721073
}
10731074
}
10741075

1076+
static void steam_work_unregister_cb(struct work_struct *work)
1077+
{
1078+
struct steam_device *steam = container_of(work, struct steam_device,
1079+
unregister_work);
1080+
unsigned long flags;
1081+
bool connected;
1082+
bool opened;
1083+
1084+
spin_lock_irqsave(&steam->lock, flags);
1085+
opened = steam->client_opened;
1086+
connected = steam->connected;
1087+
spin_unlock_irqrestore(&steam->lock, flags);
1088+
1089+
if (connected) {
1090+
if (opened) {
1091+
steam_sensors_unregister(steam);
1092+
steam_input_unregister(steam);
1093+
} else {
1094+
steam_set_lizard_mode(steam, lizard_mode);
1095+
steam_input_register(steam);
1096+
steam_sensors_register(steam);
1097+
}
1098+
}
1099+
}
1100+
10751101
static bool steam_is_valve_interface(struct hid_device *hdev)
10761102
{
10771103
struct hid_report_enum *rep_enum;
@@ -1117,8 +1143,7 @@ static int steam_client_ll_open(struct hid_device *hdev)
11171143
steam->client_opened++;
11181144
spin_unlock_irqrestore(&steam->lock, flags);
11191145

1120-
steam_sensors_unregister(steam);
1121-
steam_input_unregister(steam);
1146+
schedule_work(&steam->unregister_work);
11221147

11231148
return 0;
11241149
}
@@ -1135,11 +1160,7 @@ static void steam_client_ll_close(struct hid_device *hdev)
11351160
connected = steam->connected && !steam->client_opened;
11361161
spin_unlock_irqrestore(&steam->lock, flags);
11371162

1138-
if (connected) {
1139-
steam_set_lizard_mode(steam, lizard_mode);
1140-
steam_input_register(steam);
1141-
steam_sensors_register(steam);
1142-
}
1163+
schedule_work(&steam->unregister_work);
11431164
}
11441165

11451166
static int steam_client_ll_raw_request(struct hid_device *hdev,
@@ -1231,6 +1252,7 @@ static int steam_probe(struct hid_device *hdev,
12311252
INIT_LIST_HEAD(&steam->list);
12321253
INIT_WORK(&steam->rumble_work, steam_haptic_rumble_cb);
12331254
steam->sensor_timestamp_us = 0;
1255+
INIT_WORK(&steam->unregister_work, steam_work_unregister_cb);
12341256

12351257
/*
12361258
* With the real steam controller interface, do not connect hidraw.
@@ -1291,6 +1313,7 @@ static int steam_probe(struct hid_device *hdev,
12911313
cancel_work_sync(&steam->work_connect);
12921314
cancel_delayed_work_sync(&steam->mode_switch);
12931315
cancel_work_sync(&steam->rumble_work);
1316+
cancel_work_sync(&steam->unregister_work);
12941317

12951318
return ret;
12961319
}
@@ -1307,6 +1330,7 @@ static void steam_remove(struct hid_device *hdev)
13071330
cancel_delayed_work_sync(&steam->mode_switch);
13081331
cancel_work_sync(&steam->work_connect);
13091332
cancel_work_sync(&steam->rumble_work);
1333+
cancel_work_sync(&steam->unregister_work);
13101334
hid_destroy_device(steam->client_hdev);
13111335
steam->client_hdev = NULL;
13121336
steam->client_opened = 0;

0 commit comments

Comments
 (0)