@@ -46,6 +46,7 @@ struct ps_device {
4646 uint32_t fw_version ;
4747
4848 int (* parse_report )(struct ps_device * dev , struct hid_report * report , u8 * data , int size );
49+ void (* remove )(struct ps_device * dev );
4950};
5051
5152/* Calibration data for playstation motion sensors. */
@@ -174,6 +175,7 @@ struct dualsense {
174175 struct led_classdev player_leds [5 ];
175176
176177 struct work_struct output_worker ;
178+ bool output_worker_initialized ;
177179 void * output_report_dmabuf ;
178180 uint8_t output_seq ; /* Sequence number for output report. */
179181};
@@ -299,6 +301,7 @@ static const struct {int x; int y; } ps_gamepad_hat_mapping[] = {
299301 {0 , 0 },
300302};
301303
304+ static inline void dualsense_schedule_work (struct dualsense * ds );
302305static void dualsense_set_lightbar (struct dualsense * ds , uint8_t red , uint8_t green , uint8_t blue );
303306
304307/*
@@ -789,6 +792,7 @@ static int dualsense_get_calibration_data(struct dualsense *ds)
789792 return ret ;
790793}
791794
795+
792796static int dualsense_get_firmware_info (struct dualsense * ds )
793797{
794798 uint8_t * buf ;
@@ -878,7 +882,7 @@ static int dualsense_player_led_set_brightness(struct led_classdev *led, enum le
878882 ds -> update_player_leds = true;
879883 spin_unlock_irqrestore (& ds -> base .lock , flags );
880884
881- schedule_work ( & ds -> output_worker );
885+ dualsense_schedule_work ( ds );
882886
883887 return 0 ;
884888}
@@ -922,6 +926,16 @@ static void dualsense_init_output_report(struct dualsense *ds, struct dualsense_
922926 }
923927}
924928
929+ static inline void dualsense_schedule_work (struct dualsense * ds )
930+ {
931+ unsigned long flags ;
932+
933+ spin_lock_irqsave (& ds -> base .lock , flags );
934+ if (ds -> output_worker_initialized )
935+ schedule_work (& ds -> output_worker );
936+ spin_unlock_irqrestore (& ds -> base .lock , flags );
937+ }
938+
925939/*
926940 * Helper function to send DualSense output reports. Applies a CRC at the end of a report
927941 * for Bluetooth reports.
@@ -1082,7 +1096,7 @@ static int dualsense_parse_report(struct ps_device *ps_dev, struct hid_report *r
10821096 spin_unlock_irqrestore (& ps_dev -> lock , flags );
10831097
10841098 /* Schedule updating of microphone state at hardware level. */
1085- schedule_work ( & ds -> output_worker );
1099+ dualsense_schedule_work ( ds );
10861100 }
10871101 ds -> last_btn_mic_state = btn_mic_state ;
10881102
@@ -1197,10 +1211,22 @@ static int dualsense_play_effect(struct input_dev *dev, void *data, struct ff_ef
11971211 ds -> motor_right = effect -> u .rumble .weak_magnitude / 256 ;
11981212 spin_unlock_irqrestore (& ds -> base .lock , flags );
11991213
1200- schedule_work ( & ds -> output_worker );
1214+ dualsense_schedule_work ( ds );
12011215 return 0 ;
12021216}
12031217
1218+ static void dualsense_remove (struct ps_device * ps_dev )
1219+ {
1220+ struct dualsense * ds = container_of (ps_dev , struct dualsense , base );
1221+ unsigned long flags ;
1222+
1223+ spin_lock_irqsave (& ds -> base .lock , flags );
1224+ ds -> output_worker_initialized = false;
1225+ spin_unlock_irqrestore (& ds -> base .lock , flags );
1226+
1227+ cancel_work_sync (& ds -> output_worker );
1228+ }
1229+
12041230static int dualsense_reset_leds (struct dualsense * ds )
12051231{
12061232 struct dualsense_output_report report ;
@@ -1237,7 +1263,7 @@ static void dualsense_set_lightbar(struct dualsense *ds, uint8_t red, uint8_t gr
12371263 ds -> lightbar_blue = blue ;
12381264 spin_unlock_irqrestore (& ds -> base .lock , flags );
12391265
1240- schedule_work ( & ds -> output_worker );
1266+ dualsense_schedule_work ( ds );
12411267}
12421268
12431269static void dualsense_set_player_leds (struct dualsense * ds )
@@ -1260,7 +1286,7 @@ static void dualsense_set_player_leds(struct dualsense *ds)
12601286
12611287 ds -> update_player_leds = true;
12621288 ds -> player_leds_state = player_ids [player_id ];
1263- schedule_work ( & ds -> output_worker );
1289+ dualsense_schedule_work ( ds );
12641290}
12651291
12661292static struct ps_device * dualsense_create (struct hid_device * hdev )
@@ -1299,7 +1325,9 @@ static struct ps_device *dualsense_create(struct hid_device *hdev)
12991325 ps_dev -> battery_capacity = 100 ; /* initial value until parse_report. */
13001326 ps_dev -> battery_status = POWER_SUPPLY_STATUS_UNKNOWN ;
13011327 ps_dev -> parse_report = dualsense_parse_report ;
1328+ ps_dev -> remove = dualsense_remove ;
13021329 INIT_WORK (& ds -> output_worker , dualsense_output_worker );
1330+ ds -> output_worker_initialized = true;
13031331 hid_set_drvdata (hdev , ds );
13041332
13051333 max_output_report_size = sizeof (struct dualsense_output_report_bt );
@@ -1461,6 +1489,9 @@ static void ps_remove(struct hid_device *hdev)
14611489 ps_devices_list_remove (dev );
14621490 ps_device_release_player_id (dev );
14631491
1492+ if (dev -> remove )
1493+ dev -> remove (dev );
1494+
14641495 hid_hw_close (hdev );
14651496 hid_hw_stop (hdev );
14661497}
0 commit comments