Skip to content

Commit a84eeac

Browse files
name2965Jiri Kosina
authored andcommitted
HID: steelseries: refactor probe() and remove()
steelseries_srws1_probe() still does not use devm_kzalloc() and devm_led_classdev_register(), so there is a lot of code to safely manage heap, which reduces readability and may cause memory leaks due to minor patch mistakes in the future. Therefore, it should be changed to use devm_kzalloc() and devm_led_classdev_register() to easily and safely manage heap. Also, the current steelseries driver mainly checks sd->quriks to determine which product a specific HID device is, which is not the correct way. remove(), unlike probe(), does not receive struct hid_device_id as an argument, so it must check hdev unconditionally to know which product it is. However, since struct steelseries_device and struct steelseries_srws1_data have different structures, if SRWS1 is removed in remove(), converts hdev->dev, which is initialized to struct steelseries_srws1_data, to struct steelseries_device and uses it. This causes various memory-related bugs as completely unexpected values exist in member variables of the structure. Therefore, in order to modify probe() and remove() to work properly, Arctis 1, 9 should be added to HID_USB_DEVICE and some functions should be modified to check hdev->product when determining HID device product. Fixes: a0c7689 ("HID: steelseries: Add support for Arctis 1 XBox") Signed-off-by: Jeongjun Park <aha310510@gmail.com> Signed-off-by: Jiri Kosina <jkosina@suse.com>
1 parent b80a75c commit a84eeac

3 files changed

Lines changed: 43 additions & 70 deletions

File tree

drivers/hid/hid-ids.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1292,6 +1292,8 @@
12921292

12931293
#define USB_VENDOR_ID_STEELSERIES 0x1038
12941294
#define USB_DEVICE_ID_STEELSERIES_SRWS1 0x1410
1295+
#define USB_DEVICE_ID_STEELSERIES_ARCTIS_1 0x12b6
1296+
#define USB_DEVICE_ID_STEELSERIES_ARCTIS_9 0x12c2
12951297

12961298
#define USB_VENDOR_ID_SUN 0x0430
12971299
#define USB_DEVICE_ID_RARITAN_KVM_DONGLE 0xcdab

drivers/hid/hid-quirks.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -692,6 +692,8 @@ static const struct hid_device_id hid_have_special_driver[] = {
692692
#endif
693693
#if IS_ENABLED(CONFIG_HID_STEELSERIES)
694694
{ HID_USB_DEVICE(USB_VENDOR_ID_STEELSERIES, USB_DEVICE_ID_STEELSERIES_SRWS1) },
695+
{ HID_USB_DEVICE(USB_VENDOR_ID_STEELSERIES, USB_DEVICE_ID_STEELSERIES_ARCTIS_1) },
696+
{ HID_USB_DEVICE(USB_VENDOR_ID_STEELSERIES, USB_DEVICE_ID_STEELSERIES_ARCTIS_9) },
695697
#endif
696698
#if IS_ENABLED(CONFIG_HID_SUNPLUS)
697699
{ HID_USB_DEVICE(USB_VENDOR_ID_SUNPLUS, USB_DEVICE_ID_SUNPLUS_WDESKTOP) },

drivers/hid/hid-steelseries.c

Lines changed: 39 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -249,11 +249,11 @@ static int steelseries_srws1_probe(struct hid_device *hdev,
249249
{
250250
int ret, i;
251251
struct led_classdev *led;
252+
struct steelseries_srws1_data *drv_data;
252253
size_t name_sz;
253254
char *name;
254255

255-
struct steelseries_srws1_data *drv_data = kzalloc(sizeof(*drv_data), GFP_KERNEL);
256-
256+
drv_data = devm_kzalloc(&hdev->dev, sizeof(*drv_data), GFP_KERNEL);
257257
if (drv_data == NULL) {
258258
hid_err(hdev, "can't alloc SRW-S1 memory\n");
259259
return -ENOMEM;
@@ -264,18 +264,18 @@ static int steelseries_srws1_probe(struct hid_device *hdev,
264264
ret = hid_parse(hdev);
265265
if (ret) {
266266
hid_err(hdev, "parse failed\n");
267-
goto err_free;
267+
goto err;
268268
}
269269

270270
if (!hid_validate_values(hdev, HID_OUTPUT_REPORT, 0, 0, 16)) {
271271
ret = -ENODEV;
272-
goto err_free;
272+
goto err;
273273
}
274274

275275
ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
276276
if (ret) {
277277
hid_err(hdev, "hw start failed\n");
278-
goto err_free;
278+
goto err;
279279
}
280280

281281
/* register led subsystem */
@@ -288,10 +288,10 @@ static int steelseries_srws1_probe(struct hid_device *hdev,
288288
name_sz = strlen(hdev->uniq) + 16;
289289

290290
/* 'ALL', for setting all LEDs simultaneously */
291-
led = kzalloc(sizeof(struct led_classdev)+name_sz, GFP_KERNEL);
291+
led = devm_kzalloc(&hdev->dev, sizeof(struct led_classdev)+name_sz, GFP_KERNEL);
292292
if (!led) {
293293
hid_err(hdev, "can't allocate memory for LED ALL\n");
294-
goto err_led;
294+
goto out;
295295
}
296296

297297
name = (void *)(&led[1]);
@@ -303,16 +303,18 @@ static int steelseries_srws1_probe(struct hid_device *hdev,
303303
led->brightness_set = steelseries_srws1_led_all_set_brightness;
304304

305305
drv_data->led[SRWS1_NUMBER_LEDS] = led;
306-
ret = led_classdev_register(&hdev->dev, led);
307-
if (ret)
308-
goto err_led;
306+
ret = devm_led_classdev_register(&hdev->dev, led);
307+
if (ret) {
308+
hid_err(hdev, "failed to register LED %d. Aborting.\n", SRWS1_NUMBER_LEDS);
309+
goto out; /* let the driver continue without LEDs */
310+
}
309311

310312
/* Each individual LED */
311313
for (i = 0; i < SRWS1_NUMBER_LEDS; i++) {
312-
led = kzalloc(sizeof(struct led_classdev)+name_sz, GFP_KERNEL);
314+
led = devm_kzalloc(&hdev->dev, sizeof(struct led_classdev)+name_sz, GFP_KERNEL);
313315
if (!led) {
314316
hid_err(hdev, "can't allocate memory for LED %d\n", i);
315-
goto err_led;
317+
break;
316318
}
317319

318320
name = (void *)(&led[1]);
@@ -324,53 +326,18 @@ static int steelseries_srws1_probe(struct hid_device *hdev,
324326
led->brightness_set = steelseries_srws1_led_set_brightness;
325327

326328
drv_data->led[i] = led;
327-
ret = led_classdev_register(&hdev->dev, led);
329+
ret = devm_led_classdev_register(&hdev->dev, led);
328330

329331
if (ret) {
330332
hid_err(hdev, "failed to register LED %d. Aborting.\n", i);
331-
err_led:
332-
/* Deregister all LEDs (if any) */
333-
for (i = 0; i < SRWS1_NUMBER_LEDS + 1; i++) {
334-
led = drv_data->led[i];
335-
drv_data->led[i] = NULL;
336-
if (!led)
337-
continue;
338-
led_classdev_unregister(led);
339-
kfree(led);
340-
}
341-
goto out; /* but let the driver continue without LEDs */
333+
break; /* but let the driver continue without LEDs */
342334
}
343335
}
344336
out:
345337
return 0;
346-
err_free:
347-
kfree(drv_data);
338+
err:
348339
return ret;
349340
}
350-
351-
static void steelseries_srws1_remove(struct hid_device *hdev)
352-
{
353-
int i;
354-
struct led_classdev *led;
355-
356-
struct steelseries_srws1_data *drv_data = hid_get_drvdata(hdev);
357-
358-
if (drv_data) {
359-
/* Deregister LEDs (if any) */
360-
for (i = 0; i < SRWS1_NUMBER_LEDS + 1; i++) {
361-
led = drv_data->led[i];
362-
drv_data->led[i] = NULL;
363-
if (!led)
364-
continue;
365-
led_classdev_unregister(led);
366-
kfree(led);
367-
}
368-
369-
}
370-
371-
hid_hw_stop(hdev);
372-
kfree(drv_data);
373-
}
374341
#endif
375342

376343
#define STEELSERIES_HEADSET_BATTERY_TIMEOUT_MS 3000
@@ -405,13 +372,12 @@ static int steelseries_headset_request_battery(struct hid_device *hdev,
405372

406373
static void steelseries_headset_fetch_battery(struct hid_device *hdev)
407374
{
408-
struct steelseries_device *sd = hid_get_drvdata(hdev);
409375
int ret = 0;
410376

411-
if (sd->quirks & STEELSERIES_ARCTIS_1)
377+
if (hdev->product == USB_DEVICE_ID_STEELSERIES_ARCTIS_1)
412378
ret = steelseries_headset_request_battery(hdev,
413379
arctis_1_battery_request, sizeof(arctis_1_battery_request));
414-
else if (sd->quirks & STEELSERIES_ARCTIS_9)
380+
else if (hdev->product == USB_DEVICE_ID_STEELSERIES_ARCTIS_9)
415381
ret = steelseries_headset_request_battery(hdev,
416382
arctis_9_battery_request, sizeof(arctis_9_battery_request));
417383

@@ -567,14 +533,7 @@ static int steelseries_probe(struct hid_device *hdev, const struct hid_device_id
567533
struct steelseries_device *sd;
568534
int ret;
569535

570-
sd = devm_kzalloc(&hdev->dev, sizeof(*sd), GFP_KERNEL);
571-
if (!sd)
572-
return -ENOMEM;
573-
hid_set_drvdata(hdev, sd);
574-
sd->hdev = hdev;
575-
sd->quirks = id->driver_data;
576-
577-
if (sd->quirks & STEELSERIES_SRWS1) {
536+
if (hdev->product == USB_DEVICE_ID_STEELSERIES_SRWS1) {
578537
#if IS_BUILTIN(CONFIG_LEDS_CLASS) || \
579538
(IS_MODULE(CONFIG_LEDS_CLASS) && IS_MODULE(CONFIG_HID_STEELSERIES))
580539
return steelseries_srws1_probe(hdev, id);
@@ -583,6 +542,13 @@ static int steelseries_probe(struct hid_device *hdev, const struct hid_device_id
583542
#endif
584543
}
585544

545+
sd = devm_kzalloc(&hdev->dev, sizeof(*sd), GFP_KERNEL);
546+
if (!sd)
547+
return -ENOMEM;
548+
hid_set_drvdata(hdev, sd);
549+
sd->hdev = hdev;
550+
sd->quirks = id->driver_data;
551+
586552
ret = hid_parse(hdev);
587553
if (ret)
588554
return ret;
@@ -610,24 +576,27 @@ static int steelseries_probe(struct hid_device *hdev, const struct hid_device_id
610576

611577
static void steelseries_remove(struct hid_device *hdev)
612578
{
613-
struct steelseries_device *sd = hid_get_drvdata(hdev);
579+
struct steelseries_device *sd;
614580
unsigned long flags;
615581

616-
if (sd->quirks & STEELSERIES_SRWS1) {
582+
if (hdev->product == USB_DEVICE_ID_STEELSERIES_SRWS1) {
617583
#if IS_BUILTIN(CONFIG_LEDS_CLASS) || \
618584
(IS_MODULE(CONFIG_LEDS_CLASS) && IS_MODULE(CONFIG_HID_STEELSERIES))
619-
steelseries_srws1_remove(hdev);
585+
goto srws1_remove;
620586
#endif
621587
return;
622588
}
623589

590+
sd = hid_get_drvdata(hdev);
591+
624592
spin_lock_irqsave(&sd->lock, flags);
625593
sd->removed = true;
626594
spin_unlock_irqrestore(&sd->lock, flags);
627595

628596
cancel_delayed_work_sync(&sd->battery_work);
629597

630598
hid_hw_close(hdev);
599+
srws1_remove:
631600
hid_hw_stop(hdev);
632601
}
633602

@@ -667,10 +636,10 @@ static int steelseries_headset_raw_event(struct hid_device *hdev,
667636
unsigned long flags;
668637

669638
/* Not a headset */
670-
if (sd->quirks & STEELSERIES_SRWS1)
639+
if (hdev->product == USB_DEVICE_ID_STEELSERIES_SRWS1)
671640
return 0;
672641

673-
if (sd->quirks & STEELSERIES_ARCTIS_1) {
642+
if (hdev->product == USB_DEVICE_ID_STEELSERIES_ARCTIS_1) {
674643
hid_dbg(sd->hdev,
675644
"Parsing raw event for Arctis 1 headset (%*ph)\n", size, read_buf);
676645
if (size < ARCTIS_1_BATTERY_RESPONSE_LEN ||
@@ -688,7 +657,7 @@ static int steelseries_headset_raw_event(struct hid_device *hdev,
688657
}
689658
}
690659

691-
if (sd->quirks & STEELSERIES_ARCTIS_9) {
660+
if (hdev->product == USB_DEVICE_ID_STEELSERIES_ARCTIS_9) {
692661
hid_dbg(sd->hdev,
693662
"Parsing raw event for Arctis 9 headset (%*ph)\n", size, read_buf);
694663
if (size < ARCTIS_9_BATTERY_RESPONSE_LEN) {
@@ -757,11 +726,11 @@ static const struct hid_device_id steelseries_devices[] = {
757726
.driver_data = STEELSERIES_SRWS1 },
758727

759728
{ /* SteelSeries Arctis 1 Wireless for XBox */
760-
HID_USB_DEVICE(USB_VENDOR_ID_STEELSERIES, 0x12b6),
761-
.driver_data = STEELSERIES_ARCTIS_1 },
729+
HID_USB_DEVICE(USB_VENDOR_ID_STEELSERIES, USB_DEVICE_ID_STEELSERIES_ARCTIS_1),
730+
.driver_data = STEELSERIES_ARCTIS_1 },
762731

763732
{ /* SteelSeries Arctis 9 Wireless for XBox */
764-
HID_USB_DEVICE(USB_VENDOR_ID_STEELSERIES, 0x12c2),
733+
HID_USB_DEVICE(USB_VENDOR_ID_STEELSERIES, USB_DEVICE_ID_STEELSERIES_ARCTIS_9),
765734
.driver_data = STEELSERIES_ARCTIS_9 },
766735

767736
{ }

0 commit comments

Comments
 (0)