Skip to content

Commit b04dcbb

Browse files
committed
ALSA: caiaq: Use snd_card_free_when_closed() at disconnection
The USB disconnect callback is supposed to be short and not too-long waiting. OTOH, the current code uses snd_card_free() at disconnection, but this waits for the close of all used fds, hence it can take long. It eventually blocks the upper layer USB ioctls, which may trigger a soft lockup. An easy workaround is to replace snd_card_free() with snd_card_free_when_closed(). This variant returns immediately while the release of resources is done asynchronously by the card device release at the last close. This patch also splits the code to the disconnect and the free phases; the former is called immediately at the USB disconnect callback while the latter is called from the card destructor. Fixes: 523f1dc ("[ALSA] Add Native Instrument usb audio device support") Signed-off-by: Takashi Iwai <tiwai@suse.de> Link: https://patch.msgid.link/20241113111042.15058-5-tiwai@suse.de
1 parent f86af06 commit b04dcbb

File tree

5 files changed

+34
-9
lines changed

5 files changed

+34
-9
lines changed

sound/usb/caiaq/audio.c

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -858,14 +858,20 @@ int snd_usb_caiaq_audio_init(struct snd_usb_caiaqdev *cdev)
858858
return 0;
859859
}
860860

861-
void snd_usb_caiaq_audio_free(struct snd_usb_caiaqdev *cdev)
861+
void snd_usb_caiaq_audio_disconnect(struct snd_usb_caiaqdev *cdev)
862862
{
863863
struct device *dev = caiaqdev_to_dev(cdev);
864864

865865
dev_dbg(dev, "%s(%p)\n", __func__, cdev);
866866
stream_stop(cdev);
867+
}
868+
869+
void snd_usb_caiaq_audio_free(struct snd_usb_caiaqdev *cdev)
870+
{
871+
struct device *dev = caiaqdev_to_dev(cdev);
872+
873+
dev_dbg(dev, "%s(%p)\n", __func__, cdev);
867874
free_urbs(cdev->data_urbs_in);
868875
free_urbs(cdev->data_urbs_out);
869876
kfree(cdev->data_cb_info);
870877
}
871-

sound/usb/caiaq/audio.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
#define CAIAQ_AUDIO_H
44

55
int snd_usb_caiaq_audio_init(struct snd_usb_caiaqdev *cdev);
6+
void snd_usb_caiaq_audio_disconnect(struct snd_usb_caiaqdev *cdev);
67
void snd_usb_caiaq_audio_free(struct snd_usb_caiaqdev *cdev);
78

89
#endif /* CAIAQ_AUDIO_H */

sound/usb/caiaq/device.c

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -376,6 +376,17 @@ static void setup_card(struct snd_usb_caiaqdev *cdev)
376376
dev_err(dev, "Unable to set up control system (ret=%d)\n", ret);
377377
}
378378

379+
static void card_free(struct snd_card *card)
380+
{
381+
struct snd_usb_caiaqdev *cdev = caiaqdev(card);
382+
383+
#ifdef CONFIG_SND_USB_CAIAQ_INPUT
384+
snd_usb_caiaq_input_free(cdev);
385+
#endif
386+
snd_usb_caiaq_audio_free(cdev);
387+
usb_reset_device(cdev->chip.dev);
388+
}
389+
379390
static int create_card(struct usb_device *usb_dev,
380391
struct usb_interface *intf,
381392
struct snd_card **cardp)
@@ -489,6 +500,7 @@ static int init_card(struct snd_usb_caiaqdev *cdev)
489500
cdev->vendor_name, cdev->product_name, usbpath);
490501

491502
setup_card(cdev);
503+
card->private_free = card_free;
492504
return 0;
493505

494506
err_kill_urb:
@@ -534,15 +546,14 @@ static void snd_disconnect(struct usb_interface *intf)
534546
snd_card_disconnect(card);
535547

536548
#ifdef CONFIG_SND_USB_CAIAQ_INPUT
537-
snd_usb_caiaq_input_free(cdev);
549+
snd_usb_caiaq_input_disconnect(cdev);
538550
#endif
539-
snd_usb_caiaq_audio_free(cdev);
551+
snd_usb_caiaq_audio_disconnect(cdev);
540552

541553
usb_kill_urb(&cdev->ep1_in_urb);
542554
usb_kill_urb(&cdev->midi_out_urb);
543555

544-
snd_card_free(card);
545-
usb_reset_device(interface_to_usbdev(intf));
556+
snd_card_free_when_closed(card);
546557
}
547558

548559

sound/usb/caiaq/input.c

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -829,15 +829,21 @@ int snd_usb_caiaq_input_init(struct snd_usb_caiaqdev *cdev)
829829
return ret;
830830
}
831831

832-
void snd_usb_caiaq_input_free(struct snd_usb_caiaqdev *cdev)
832+
void snd_usb_caiaq_input_disconnect(struct snd_usb_caiaqdev *cdev)
833833
{
834834
if (!cdev || !cdev->input_dev)
835835
return;
836836

837837
usb_kill_urb(cdev->ep4_in_urb);
838+
input_unregister_device(cdev->input_dev);
839+
}
840+
841+
void snd_usb_caiaq_input_free(struct snd_usb_caiaqdev *cdev)
842+
{
843+
if (!cdev || !cdev->input_dev)
844+
return;
845+
838846
usb_free_urb(cdev->ep4_in_urb);
839847
cdev->ep4_in_urb = NULL;
840-
841-
input_unregister_device(cdev->input_dev);
842848
cdev->input_dev = NULL;
843849
}

sound/usb/caiaq/input.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
void snd_usb_caiaq_input_dispatch(struct snd_usb_caiaqdev *cdev, char *buf, unsigned int len);
66
int snd_usb_caiaq_input_init(struct snd_usb_caiaqdev *cdev);
7+
void snd_usb_caiaq_input_disconnect(struct snd_usb_caiaqdev *cdev);
78
void snd_usb_caiaq_input_free(struct snd_usb_caiaqdev *cdev);
89

910
#endif

0 commit comments

Comments
 (0)