summaryrefslogtreecommitdiff
path: root/sound/usb/line6/driver.c
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2019-05-28 09:39:44 +0300
committerTakashi Iwai <tiwai@suse.de>2019-05-28 09:42:45 +0300
commit0b074ab7fc0d575247b9cc9f93bb7e007ca38840 (patch)
treeaa64c8c81a16725f8f7e88199f095539e9f17365 /sound/usb/line6/driver.c
parentfa763f1b2858752e6150ffff46886a1b7faffc82 (diff)
downloadlinux-0b074ab7fc0d575247b9cc9f93bb7e007ca38840.tar.xz
ALSA: line6: Assure canceling delayed work at disconnection
The current code performs the cancel of a delayed work at the late stage of disconnection procedure, which may lead to the access to the already cleared state. This patch assures to call cancel_delayed_work_sync() at the beginning of the disconnection procedure for avoiding that race. The delayed work object is now assigned in the common line6 object instead of its derivative, so that we can call cancel_delayed_work_sync(). Along with the change, the startup function is called via the new callback instead. This will make it easier to port other LINE6 drivers to use the delayed work for startup in later patches. Reported-by: syzbot+5255458d5e0a2b10bbb9@syzkaller.appspotmail.com Fixes: 7f84ff68be05 ("ALSA: line6: toneport: Fix broken usage of timer for delayed execution") Cc: <stable@vger.kernel.org> Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/usb/line6/driver.c')
-rw-r--r--sound/usb/line6/driver.c12
1 files changed, 12 insertions, 0 deletions
diff --git a/sound/usb/line6/driver.c b/sound/usb/line6/driver.c
index b61f65bed4e4..2b57854335b3 100644
--- a/sound/usb/line6/driver.c
+++ b/sound/usb/line6/driver.c
@@ -720,6 +720,15 @@ static int line6_init_cap_control(struct usb_line6 *line6)
return 0;
}
+static void line6_startup_work(struct work_struct *work)
+{
+ struct usb_line6 *line6 =
+ container_of(work, struct usb_line6, startup_work.work);
+
+ if (line6->startup)
+ line6->startup(line6);
+}
+
/*
Probe USB device.
*/
@@ -755,6 +764,7 @@ int line6_probe(struct usb_interface *interface,
line6->properties = properties;
line6->usbdev = usbdev;
line6->ifcdev = &interface->dev;
+ INIT_DELAYED_WORK(&line6->startup_work, line6_startup_work);
strcpy(card->id, properties->id);
strcpy(card->driver, driver_name);
@@ -825,6 +835,8 @@ void line6_disconnect(struct usb_interface *interface)
if (WARN_ON(usbdev != line6->usbdev))
return;
+ cancel_delayed_work(&line6->startup_work);
+
if (line6->urb_listen != NULL)
line6_stop_listen(line6);