summaryrefslogtreecommitdiff
path: root/sound/usb/card.c
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2023-05-23 10:53:30 +0300
committerTakashi Iwai <tiwai@suse.de>2023-05-23 13:11:02 +0300
commitff49d1df79aef7580fe3ac99d17c3f886655d080 (patch)
tree041644baee19272edcb6398a5196428655113cf6 /sound/usb/card.c
parentf8ddb0fb3289dfb6f064b1f0573fd4f032189e9e (diff)
downloadlinux-ff49d1df79aef7580fe3ac99d17c3f886655d080.tar.xz
ALSA: usb-audio: USB MIDI 2.0 UMP support
This patch provides a basic support for USB MIDI 2.0. As of this patch, the driver creates a UMP device per MIDI I/O endpoints, which serves as a dumb terminal to read/write UMP streams. A new Kconfig CONFIG_SND_USB_AUDIO_MIDI_V2 manages whether to enable or disable the MIDI 2.0 support. Also, the driver provides a new module option, midi2_enable, to allow disabling the MIDI 2.0 at runtime, too. When MIDI 2.0 support is disabled, the driver tries to fall back to the already existing MIDI 1.0 device (each MIDI 2.0 device is supposed to provide the MIDI 1.0 interface at the altset 0). For now, the driver doesn't manage any MIDI-CI or other protocol setups by itself, but relies on the default protocol given via the group terminal block descriptors. The MIDI 1.0 messages on MIDI 2.0 device will be automatically converted in ALSA sequencer in a later patch. As of this commit, the driver accepts merely the rawmidi UMP accesses. The driver builds up the topology in the following way: - Create an object for each MIDI endpoint belonging to the USB interface - Find MIDI EP "pairs" that share the same GTB; note that MIDI EP is unidirectional, while UMP is (normally) bidirectional, so two MIDI EPs can form a single UMP EP - A UMP endpoint object is created for each I/O pair - For remaining "solo" MIDI EPs, create unidirectional UMP EPs - Finally, parse GTBs and fill the protocol bits on each UMP So the driver may support multiple UMP Endpoints in theory, although most devices are supposed to have a single UMP EP that can contain up to 16 groups -- which should be large enough. Reviewed-by: Jaroslav Kysela <perex@perex.cz> Link: https://lore.kernel.org/r/20230523075358.9672-10-tiwai@suse.de Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/usb/card.c')
-rw-r--r--sound/usb/card.c13
1 files changed, 9 insertions, 4 deletions
diff --git a/sound/usb/card.c b/sound/usb/card.c
index bd051e634516..1b2edc0fd2e9 100644
--- a/sound/usb/card.c
+++ b/sound/usb/card.c
@@ -44,6 +44,7 @@
#include "usbaudio.h"
#include "card.h"
#include "midi.h"
+#include "midi2.h"
#include "mixer.h"
#include "proc.h"
#include "quirks.h"
@@ -178,10 +179,8 @@ static int snd_usb_create_stream(struct snd_usb_audio *chip, int ctrlif, int int
if ((altsd->bInterfaceClass == USB_CLASS_AUDIO ||
altsd->bInterfaceClass == USB_CLASS_VENDOR_SPEC) &&
altsd->bInterfaceSubClass == USB_SUBCLASS_MIDISTREAMING) {
- int err = __snd_usbmidi_create(chip->card, iface,
- &chip->midi_list, NULL,
- chip->usb_id,
- &chip->num_rawmidis);
+ int err = snd_usb_midi_v2_create(chip, iface, NULL,
+ chip->usb_id);
if (err < 0) {
dev_err(&dev->dev,
"%u:%d: cannot create sequencer device\n",
@@ -486,6 +485,7 @@ static void snd_usb_audio_free(struct snd_card *card)
struct snd_usb_audio *chip = card->private_data;
snd_usb_endpoint_free_all(chip);
+ snd_usb_midi_v2_free_all(chip);
mutex_destroy(&chip->mutex);
if (!atomic_read(&chip->shutdown))
@@ -645,6 +645,7 @@ static int snd_usb_audio_create(struct usb_interface *intf,
INIT_LIST_HEAD(&chip->iface_ref_list);
INIT_LIST_HEAD(&chip->clock_ref_list);
INIT_LIST_HEAD(&chip->midi_list);
+ INIT_LIST_HEAD(&chip->midi_v2_list);
INIT_LIST_HEAD(&chip->mixer_list);
if (quirk_flags[idx])
@@ -969,6 +970,7 @@ static void usb_audio_disconnect(struct usb_interface *intf)
list_for_each(p, &chip->midi_list) {
snd_usbmidi_disconnect(p);
}
+ snd_usb_midi_v2_disconnect_all(chip);
/*
* Nice to check quirk && quirk->shares_media_device and
* then call the snd_media_device_delete(). Don't have
@@ -1080,6 +1082,7 @@ static int usb_audio_suspend(struct usb_interface *intf, pm_message_t message)
snd_usbmidi_suspend(p);
list_for_each_entry(mixer, &chip->mixer_list, list)
snd_usb_mixer_suspend(mixer);
+ snd_usb_midi_v2_suspend_all(chip);
}
if (!PMSG_IS_AUTO(message) && !chip->system_suspend) {
@@ -1125,6 +1128,8 @@ static int usb_audio_resume(struct usb_interface *intf)
snd_usbmidi_resume(p);
}
+ snd_usb_midi_v2_resume_all(chip);
+
out:
if (chip->num_suspended_intf == chip->system_suspend) {
snd_power_change_state(chip->card, SNDRV_CTL_POWER_D0);