Skip to content

Commit fb1a79a

Browse files
evilynuxJiri Kosina
authored andcommitted
HID: sony: fix freeze when inserting ghlive ps3/wii dongles
This commit fixes a freeze on insertion of a Guitar Hero Live PS3/WiiU USB dongle. Indeed, with the current implementation, inserting one of those USB dongles will lead to a hard freeze. I apologize for not catching this earlier, it didn't occur on my old laptop. While the issue was isolated to memory alloc/free, I could not figure out why it causes a freeze. So this patch fixes this issue by simplifying memory allocation and usage. We remind that for the dongle to work properly, a control URB needs to be sent periodically. We used to alloc/free the URB each time this URB needed to be sent. With this patch, the memory for the URB is allocated on the probe, reused for as long as the dongle is plugged in, and freed once the dongle is unplugged. Signed-off-by: Pascal Giard <[email protected]> Signed-off-by: Jiri Kosina <[email protected]>
1 parent a3af901 commit fb1a79a

File tree

1 file changed

+49
-49
lines changed

1 file changed

+49
-49
lines changed

drivers/hid/hid-sony.c

Lines changed: 49 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -597,9 +597,8 @@ struct sony_sc {
597597
/* DS4 calibration data */
598598
struct ds4_calibration_data ds4_calib_data[6];
599599
/* GH Live */
600+
struct urb *ghl_urb;
600601
struct timer_list ghl_poke_timer;
601-
struct usb_ctrlrequest *ghl_cr;
602-
u8 *ghl_databuf;
603602
};
604603

605604
static void sony_set_leds(struct sony_sc *sc);
@@ -625,66 +624,54 @@ static inline void sony_schedule_work(struct sony_sc *sc,
625624

626625
static void ghl_magic_poke_cb(struct urb *urb)
627626
{
628-
if (urb) {
629-
/* Free sc->ghl_cr and sc->ghl_databuf allocated in
630-
* ghl_magic_poke()
631-
*/
632-
kfree(urb->setup_packet);
633-
kfree(urb->transfer_buffer);
634-
}
627+
struct sony_sc *sc = urb->context;
628+
629+
if (urb->status < 0)
630+
hid_err(sc->hdev, "URB transfer failed : %d", urb->status);
631+
632+
mod_timer(&sc->ghl_poke_timer, jiffies + GHL_GUITAR_POKE_INTERVAL*HZ);
635633
}
636634

637635
static void ghl_magic_poke(struct timer_list *t)
638636
{
637+
int ret;
639638
struct sony_sc *sc = from_timer(sc, t, ghl_poke_timer);
640639

641-
int ret;
640+
ret = usb_submit_urb(sc->ghl_urb, GFP_ATOMIC);
641+
if (ret < 0)
642+
hid_err(sc->hdev, "usb_submit_urb failed: %d", ret);
643+
}
644+
645+
static int ghl_init_urb(struct sony_sc *sc, struct usb_device *usbdev)
646+
{
647+
struct usb_ctrlrequest *cr;
648+
u16 poke_size;
649+
u8 *databuf;
642650
unsigned int pipe;
643-
struct urb *urb;
644-
struct usb_device *usbdev = to_usb_device(sc->hdev->dev.parent->parent);
645-
const u16 poke_size =
646-
ARRAY_SIZE(ghl_ps3wiiu_magic_data);
647651

652+
poke_size = ARRAY_SIZE(ghl_ps3wiiu_magic_data);
648653
pipe = usb_sndctrlpipe(usbdev, 0);
649654

650-
if (!sc->ghl_cr) {
651-
sc->ghl_cr = kzalloc(sizeof(*sc->ghl_cr), GFP_ATOMIC);
652-
if (!sc->ghl_cr)
653-
goto resched;
654-
}
655-
656-
if (!sc->ghl_databuf) {
657-
sc->ghl_databuf = kzalloc(poke_size, GFP_ATOMIC);
658-
if (!sc->ghl_databuf)
659-
goto resched;
660-
}
655+
cr = devm_kzalloc(&sc->hdev->dev, sizeof(*cr), GFP_ATOMIC);
656+
if (cr == NULL)
657+
return -ENOMEM;
661658

662-
urb = usb_alloc_urb(0, GFP_ATOMIC);
663-
if (!urb)
664-
goto resched;
659+
databuf = devm_kzalloc(&sc->hdev->dev, poke_size, GFP_ATOMIC);
660+
if (databuf == NULL)
661+
return -ENOMEM;
665662

666-
sc->ghl_cr->bRequestType =
663+
cr->bRequestType =
667664
USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT;
668-
sc->ghl_cr->bRequest = USB_REQ_SET_CONFIGURATION;
669-
sc->ghl_cr->wValue = cpu_to_le16(ghl_ps3wiiu_magic_value);
670-
sc->ghl_cr->wIndex = 0;
671-
sc->ghl_cr->wLength = cpu_to_le16(poke_size);
672-
memcpy(sc->ghl_databuf, ghl_ps3wiiu_magic_data, poke_size);
673-
665+
cr->bRequest = USB_REQ_SET_CONFIGURATION;
666+
cr->wValue = cpu_to_le16(ghl_ps3wiiu_magic_value);
667+
cr->wIndex = 0;
668+
cr->wLength = cpu_to_le16(poke_size);
669+
memcpy(databuf, ghl_ps3wiiu_magic_data, poke_size);
674670
usb_fill_control_urb(
675-
urb, usbdev, pipe,
676-
(unsigned char *) sc->ghl_cr, sc->ghl_databuf,
677-
poke_size, ghl_magic_poke_cb, NULL);
678-
ret = usb_submit_urb(urb, GFP_ATOMIC);
679-
if (ret < 0) {
680-
kfree(sc->ghl_databuf);
681-
kfree(sc->ghl_cr);
682-
}
683-
usb_free_urb(urb);
684-
685-
resched:
686-
/* Reschedule for next time */
687-
mod_timer(&sc->ghl_poke_timer, jiffies + GHL_GUITAR_POKE_INTERVAL*HZ);
671+
sc->ghl_urb, usbdev, pipe,
672+
(unsigned char *) cr, databuf, poke_size,
673+
ghl_magic_poke_cb, sc);
674+
return 0;
688675
}
689676

690677
static int guitar_mapping(struct hid_device *hdev, struct hid_input *hi,
@@ -2981,6 +2968,7 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
29812968
int ret;
29822969
unsigned long quirks = id->driver_data;
29832970
struct sony_sc *sc;
2971+
struct usb_device *usbdev;
29842972
unsigned int connect_mask = HID_CONNECT_DEFAULT;
29852973

29862974
if (!strcmp(hdev->name, "FutureMax Dance Mat"))
@@ -3000,6 +2988,7 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
30002988
sc->quirks = quirks;
30012989
hid_set_drvdata(hdev, sc);
30022990
sc->hdev = hdev;
2991+
usbdev = to_usb_device(sc->hdev->dev.parent->parent);
30032992

30042993
ret = hid_parse(hdev);
30052994
if (ret) {
@@ -3042,6 +3031,15 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
30423031
}
30433032

30443033
if (sc->quirks & GHL_GUITAR_PS3WIIU) {
3034+
sc->ghl_urb = usb_alloc_urb(0, GFP_ATOMIC);
3035+
if (!sc->ghl_urb)
3036+
return -ENOMEM;
3037+
ret = ghl_init_urb(sc, usbdev);
3038+
if (ret) {
3039+
hid_err(hdev, "error preparing URB\n");
3040+
return ret;
3041+
}
3042+
30453043
timer_setup(&sc->ghl_poke_timer, ghl_magic_poke, 0);
30463044
mod_timer(&sc->ghl_poke_timer,
30473045
jiffies + GHL_GUITAR_POKE_INTERVAL*HZ);
@@ -3054,8 +3052,10 @@ static void sony_remove(struct hid_device *hdev)
30543052
{
30553053
struct sony_sc *sc = hid_get_drvdata(hdev);
30563054

3057-
if (sc->quirks & GHL_GUITAR_PS3WIIU)
3055+
if (sc->quirks & GHL_GUITAR_PS3WIIU) {
30583056
del_timer_sync(&sc->ghl_poke_timer);
3057+
usb_free_urb(sc->ghl_urb);
3058+
}
30593059

30603060
hid_hw_close(hdev);
30613061

0 commit comments

Comments
 (0)