Skip to content

Commit d9c9987

Browse files
committed
ALSA: usb-audio: Create UMP blocks from USB MIDI GTBs
USB MIDI spec defines the Group Terminal Blocks (GTB) that associate multiple UMP Groups. Those correspond to snd_ump_block entities in ALSA UMP abstraction, and now we create those UMP Block objects for each UMP Endpoint from the parsed GTB information. Reviewed-by: Jaroslav Kysela <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Takashi Iwai <[email protected]>
1 parent 5170140 commit d9c9987

File tree

1 file changed

+94
-6
lines changed

1 file changed

+94
-6
lines changed

sound/usb/midi2.c

Lines changed: 94 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -599,14 +599,8 @@ find_group_terminal_block(struct snd_usb_midi2_interface *umidi, int id)
599599
static int parse_group_terminal_block(struct snd_usb_midi2_ump *rmidi,
600600
const struct usb_ms20_gr_trm_block_descriptor *desc)
601601
{
602-
struct snd_usb_audio *chip = rmidi->umidi->chip;
603602
struct snd_ump_endpoint *ump = rmidi->ump;
604603

605-
usb_audio_dbg(chip,
606-
"GTB id %d: groups = %d / %d, type = %d\n",
607-
desc->bGrpTrmBlkID, desc->nGroupTrm, desc->nNumGroupTrm,
608-
desc->bGrpTrmBlkType);
609-
610604
/* set default protocol */
611605
switch (desc->bMIDIProtocol) {
612606
case USB_MS_MIDI_PROTO_1_0_64:
@@ -798,6 +792,94 @@ static int find_matching_ep_partner(struct snd_usb_midi2_interface *umidi,
798792
return 0;
799793
}
800794

795+
/* create a UMP block from a GTB entry */
796+
static int create_gtb_block(struct snd_usb_midi2_ump *rmidi, int dir, int blk)
797+
{
798+
struct snd_usb_midi2_interface *umidi = rmidi->umidi;
799+
const struct usb_ms20_gr_trm_block_descriptor *desc;
800+
struct snd_ump_block *fb;
801+
int type, err;
802+
803+
desc = find_group_terminal_block(umidi, blk);
804+
if (!desc)
805+
return 0;
806+
807+
usb_audio_dbg(umidi->chip,
808+
"GTB %d: type=%d, group=%d/%d, protocol=%d, in bw=%d, out bw=%d\n",
809+
blk, desc->bGrpTrmBlkType, desc->nGroupTrm,
810+
desc->nNumGroupTrm, desc->bMIDIProtocol,
811+
__le16_to_cpu(desc->wMaxInputBandwidth),
812+
__le16_to_cpu(desc->wMaxOutputBandwidth));
813+
814+
/* assign the direction */
815+
switch (desc->bGrpTrmBlkType) {
816+
case USB_MS_GR_TRM_BLOCK_TYPE_BIDIRECTIONAL:
817+
type = SNDRV_UMP_DIR_BIDIRECTION;
818+
break;
819+
case USB_MS_GR_TRM_BLOCK_TYPE_INPUT_ONLY:
820+
type = SNDRV_UMP_DIR_INPUT;
821+
break;
822+
case USB_MS_GR_TRM_BLOCK_TYPE_OUTPUT_ONLY:
823+
type = SNDRV_UMP_DIR_OUTPUT;
824+
break;
825+
default:
826+
usb_audio_dbg(umidi->chip, "Unsupported GTB type %d\n",
827+
desc->bGrpTrmBlkType);
828+
return 0; /* unsupported */
829+
}
830+
831+
/* guess work: set blk-1 as the (0-based) block ID */
832+
err = snd_ump_block_new(rmidi->ump, blk - 1, type,
833+
desc->nGroupTrm, desc->nNumGroupTrm,
834+
&fb);
835+
if (err == -EBUSY)
836+
return 0; /* already present */
837+
else if (err)
838+
return err;
839+
840+
if (desc->iBlockItem)
841+
usb_string(rmidi->dev, desc->iBlockItem,
842+
fb->info.name, sizeof(fb->info.name));
843+
844+
if (__le16_to_cpu(desc->wMaxInputBandwidth) == 1 ||
845+
__le16_to_cpu(desc->wMaxOutputBandwidth) == 1)
846+
fb->info.flags |= SNDRV_UMP_BLOCK_IS_MIDI1 |
847+
SNDRV_UMP_BLOCK_IS_LOWSPEED;
848+
849+
usb_audio_dbg(umidi->chip,
850+
"Created a UMP block %d from GTB, name=%s\n",
851+
blk, fb->info.name);
852+
return 0;
853+
}
854+
855+
/* Create UMP blocks for each UMP EP */
856+
static int create_blocks_from_gtb(struct snd_usb_midi2_interface *umidi)
857+
{
858+
struct snd_usb_midi2_ump *rmidi;
859+
int i, blk, err, dir;
860+
861+
list_for_each_entry(rmidi, &umidi->rawmidi_list, list) {
862+
if (!rmidi->ump)
863+
continue;
864+
/* Blocks have been already created? */
865+
if (rmidi->ump->info.num_blocks)
866+
continue;
867+
/* loop over GTBs */
868+
for (dir = 0; dir < 2; dir++) {
869+
if (!rmidi->eps[dir])
870+
continue;
871+
for (i = 0; i < rmidi->eps[dir]->ms_ep->bNumGrpTrmBlock; i++) {
872+
blk = rmidi->eps[dir]->ms_ep->baAssoGrpTrmBlkID[i];
873+
err = create_gtb_block(rmidi, dir, blk);
874+
if (err < 0)
875+
return err;
876+
}
877+
}
878+
}
879+
880+
return 0;
881+
}
882+
801883
static void snd_usb_midi_v2_free(struct snd_usb_midi2_interface *umidi)
802884
{
803885
free_all_midi2_endpoints(umidi);
@@ -1009,6 +1091,12 @@ int snd_usb_midi_v2_create(struct snd_usb_audio *chip,
10091091
goto error;
10101092
}
10111093

1094+
err = create_blocks_from_gtb(umidi);
1095+
if (err < 0) {
1096+
usb_audio_err(chip, "Failed to create GTB blocks\n");
1097+
goto error;
1098+
}
1099+
10121100
set_fallback_rawmidi_names(umidi);
10131101
return 0;
10141102

0 commit comments

Comments
 (0)