Message ID | 20240619152855.6809-3-tiwai@suse.de |
---|---|
State | New |
Headers | show |
Series | Add API helper functions for creating UMP Endpoint and Blocks | expand |
On 6/19/2024 5:28 PM, Takashi Iwai wrote: > For making it easer for applications to create a virtual UMP Endpoint > and UMP blocks, add two API helper functions. > > snd_seq_create_ump_endpoint() creates (unsurprisingly) a UMP Endpoint, > based on the given snd_ump_endpoint_info_t information. The number of > (max) UMP groups belonging to this Endpoint has to be specified. > This function sets up the Endpoint info on the sequencer client, and > creates a MIDI 2.0 UMP port as well as UMP Group ports automatically. > The name of the sequencer client is updated from the Endpoint name, > too. > > After creating a UMP Endpoint, create each UMP Block via > snd_seq_create_ump_block() function with a snd_ump_block_info_t info. > The associated groups for each block have to be specified there. > The port names and capability bits are updated accordingly after > setting each block information. > > Signed-off-by: Takashi Iwai <tiwai@suse.de> > --- ... > + if (*blknames) { > + strlcat(blknames, ", ", sizeof(blknames)); > + strlcat(blknames, (const char *)bp->name, > + sizeof(blknames)); FYI, this seems to introduce build problems on systems that do not have strlcpy: During build: seqmid.c: In function ‘update_group_ports’: seqmid.c:672:33: warning: implicit declaration of function ‘strlcat’; did you mean ‘strncat’? [-Wimplicit-function-declaration] 672 | strlcat(blknames, ", ", sizeof(blknames)); | ^~~~~~~ | strncat And then during linking: /usr/bin/ld: seq/.libs/libseq.a(seqmid.o): in function `update_group_ports': /home/amade/workdir/avs/alsa-lib/src/seq/seqmid.c:672: undefined reference to `strlcat' /usr/bin/ld: /home/amade/workdir/avs/alsa-lib/src/seq/seqmid.c:673: undefined reference to `strlcat' collect2: error: ld returned 1 exit status
On Wed, 31 Jul 2024 10:46:08 +0200, Amadeusz Sławiński wrote: > > On 6/19/2024 5:28 PM, Takashi Iwai wrote: > > For making it easer for applications to create a virtual UMP Endpoint > > and UMP blocks, add two API helper functions. > > > > snd_seq_create_ump_endpoint() creates (unsurprisingly) a UMP Endpoint, > > based on the given snd_ump_endpoint_info_t information. The number of > > (max) UMP groups belonging to this Endpoint has to be specified. > > This function sets up the Endpoint info on the sequencer client, and > > creates a MIDI 2.0 UMP port as well as UMP Group ports automatically. > > The name of the sequencer client is updated from the Endpoint name, > > too. > > > > After creating a UMP Endpoint, create each UMP Block via > > snd_seq_create_ump_block() function with a snd_ump_block_info_t info. > > The associated groups for each block have to be specified there. > > The port names and capability bits are updated accordingly after > > setting each block information. > > > > Signed-off-by: Takashi Iwai <tiwai@suse.de> > > --- > > ... > > > + if (*blknames) { > > + strlcat(blknames, ", ", sizeof(blknames)); > > + strlcat(blknames, (const char *)bp->name, > > + sizeof(blknames)); > > FYI, this seems to introduce build problems on systems that do not > have strlcpy: > > During build: > seqmid.c: In function ‘update_group_ports’: > seqmid.c:672:33: warning: implicit declaration of function > ‘strlcat’; did you mean ‘strncat’? > [-Wimplicit-function-declaration] > 672 | strlcat(blknames, ", ", > sizeof(blknames)); > | ^~~~~~~ > | strncat > > And then during linking: > /usr/bin/ld: seq/.libs/libseq.a(seqmid.o): in function `update_group_ports': > /home/amade/workdir/avs/alsa-lib/src/seq/seqmid.c:672: undefined > reference to `strlcat' > /usr/bin/ld: /home/amade/workdir/avs/alsa-lib/src/seq/seqmid.c:673: > undefined reference to `strlcat' > collect2: error: ld returned 1 exit status Thanks, I'll modify it to avoid strlcat() like below. Takashi -- 8< -- Subject: [PATCH] seq: Avoid strlcat() strlcat() isn't available in every system, so better to avoid it. Rewrite the code without strlcat(). Fixes: 6167b8ce3e80 ("seq: Add API helper functions for creating UMP Endpoint and Blocks") Link: https://lore.kernel.org/0796c157-1ac3-47a3-9d54-ba86f59d64d5@linux.intel.com Signed-off-by: Takashi Iwai <tiwai@suse.de> --- src/seq/seqmid.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/seq/seqmid.c b/src/seq/seqmid.c index 08c62d5c24b8..b30db4075254 100644 --- a/src/seq/seqmid.c +++ b/src/seq/seqmid.c @@ -635,6 +635,7 @@ static void update_group_ports(snd_seq_t *seq, snd_ump_endpoint_info_t *ep) char blknames[64]; char name[64]; unsigned int caps = 0; + int len; blknames[0] = 0; for (b = 0; b < ep->num_blocks; b++) { @@ -668,14 +669,13 @@ static void update_group_ports(snd_seq_t *seq, snd_ump_endpoint_info_t *ep) if (!*bp->name) continue; - if (*blknames) { - strlcat(blknames, ", ", sizeof(blknames)); - strlcat(blknames, (const char *)bp->name, - sizeof(blknames)); - } else { + len = strlen(blknames); + if (len) + snprintf(blknames + len, sizeof(blknames) - len, + ", %s", bp->name); + else snd_strlcpy(blknames, (const char *)bp->name, sizeof(blknames)); - } } if (!*blknames)
On 7/31/2024 11:21 AM, Takashi Iwai wrote: > On Wed, 31 Jul 2024 10:46:08 +0200, > Amadeusz Sławiński wrote: >> >> On 6/19/2024 5:28 PM, Takashi Iwai wrote: >>> For making it easer for applications to create a virtual UMP Endpoint >>> and UMP blocks, add two API helper functions. >>> >>> snd_seq_create_ump_endpoint() creates (unsurprisingly) a UMP Endpoint, >>> based on the given snd_ump_endpoint_info_t information. The number of >>> (max) UMP groups belonging to this Endpoint has to be specified. >>> This function sets up the Endpoint info on the sequencer client, and >>> creates a MIDI 2.0 UMP port as well as UMP Group ports automatically. >>> The name of the sequencer client is updated from the Endpoint name, >>> too. >>> >>> After creating a UMP Endpoint, create each UMP Block via >>> snd_seq_create_ump_block() function with a snd_ump_block_info_t info. >>> The associated groups for each block have to be specified there. >>> The port names and capability bits are updated accordingly after >>> setting each block information. >>> >>> Signed-off-by: Takashi Iwai <tiwai@suse.de> >>> --- >> >> ... >> >>> + if (*blknames) { >>> + strlcat(blknames, ", ", sizeof(blknames)); >>> + strlcat(blknames, (const char *)bp->name, >>> + sizeof(blknames)); >> >> FYI, this seems to introduce build problems on systems that do not >> have strlcpy: >> >> During build: >> seqmid.c: In function ‘update_group_ports’: >> seqmid.c:672:33: warning: implicit declaration of function >> ‘strlcat’; did you mean ‘strncat’? >> [-Wimplicit-function-declaration] >> 672 | strlcat(blknames, ", ", >> sizeof(blknames)); >> | ^~~~~~~ >> | strncat >> >> And then during linking: >> /usr/bin/ld: seq/.libs/libseq.a(seqmid.o): in function `update_group_ports': >> /home/amade/workdir/avs/alsa-lib/src/seq/seqmid.c:672: undefined >> reference to `strlcat' >> /usr/bin/ld: /home/amade/workdir/avs/alsa-lib/src/seq/seqmid.c:673: >> undefined reference to `strlcat' >> collect2: error: ld returned 1 exit status > > Thanks, I'll modify it to avoid strlcat() like below. > > > Takashi > > -- 8< -- > Subject: [PATCH] seq: Avoid strlcat() > > strlcat() isn't available in every system, so better to avoid it. > Rewrite the code without strlcat(). > > Fixes: 6167b8ce3e80 ("seq: Add API helper functions for creating UMP Endpoint and Blocks") > Link: https://lore.kernel.org/0796c157-1ac3-47a3-9d54-ba86f59d64d5@linux.intel.com > Signed-off-by: Takashi Iwai <tiwai@suse.de> > --- > src/seq/seqmid.c | 12 ++++++------ > 1 file changed, 6 insertions(+), 6 deletions(-) > > diff --git a/src/seq/seqmid.c b/src/seq/seqmid.c > index 08c62d5c24b8..b30db4075254 100644 > --- a/src/seq/seqmid.c > +++ b/src/seq/seqmid.c > @@ -635,6 +635,7 @@ static void update_group_ports(snd_seq_t *seq, snd_ump_endpoint_info_t *ep) > char blknames[64]; > char name[64]; > unsigned int caps = 0; > + int len; > > blknames[0] = 0; > for (b = 0; b < ep->num_blocks; b++) { > @@ -668,14 +669,13 @@ static void update_group_ports(snd_seq_t *seq, snd_ump_endpoint_info_t *ep) > > if (!*bp->name) > continue; > - if (*blknames) { > - strlcat(blknames, ", ", sizeof(blknames)); > - strlcat(blknames, (const char *)bp->name, > - sizeof(blknames)); > - } else { > + len = strlen(blknames); > + if (len) > + snprintf(blknames + len, sizeof(blknames) - len, > + ", %s", bp->name); > + else > snd_strlcpy(blknames, (const char *)bp->name, > sizeof(blknames)); > - } > } > > if (!*blknames) Builds now, but still gives warning: seqmid.c: In function ‘update_group_ports’: seqmid.c:675:45: warning: ‘%s’ directive output may be truncated writing up to 127 bytes into a region of size 61 [-Wformat-truncation=] 675 | ", %s", bp->name); | ^~ In file included from /usr/include/stdio.h:894, from ../../include/local.h:28, from seq_local.h:26, from seqmid.c:23: In function ‘snprintf’, inlined from ‘update_group_ports’ at seqmid.c:674:5: /usr/include/x86_64-linux-gnu/bits/stdio2.h:71:10: note: ‘__builtin___snprintf_chk’ output between 3 and 130 bytes into a destination of size 63 71 | return __builtin___snprintf_chk (__s, __n, __USE_FORTIFY_LEVEL - 1, | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 72 | __glibc_objsize (__s), __fmt, | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 73 | __va_arg_pack ()); | ~~~~~~~~~~~~~~~~~
On Wed, 31 Jul 2024 11:29:41 +0200, Amadeusz Sławiński wrote: > > On 7/31/2024 11:21 AM, Takashi Iwai wrote: > > On Wed, 31 Jul 2024 10:46:08 +0200, > > Amadeusz Sławiński wrote: > >> > >> On 6/19/2024 5:28 PM, Takashi Iwai wrote: > >>> For making it easer for applications to create a virtual UMP Endpoint > >>> and UMP blocks, add two API helper functions. > >>> > >>> snd_seq_create_ump_endpoint() creates (unsurprisingly) a UMP Endpoint, > >>> based on the given snd_ump_endpoint_info_t information. The number of > >>> (max) UMP groups belonging to this Endpoint has to be specified. > >>> This function sets up the Endpoint info on the sequencer client, and > >>> creates a MIDI 2.0 UMP port as well as UMP Group ports automatically. > >>> The name of the sequencer client is updated from the Endpoint name, > >>> too. > >>> > >>> After creating a UMP Endpoint, create each UMP Block via > >>> snd_seq_create_ump_block() function with a snd_ump_block_info_t info. > >>> The associated groups for each block have to be specified there. > >>> The port names and capability bits are updated accordingly after > >>> setting each block information. > >>> > >>> Signed-off-by: Takashi Iwai <tiwai@suse.de> > >>> --- > >> > >> ... > >> > >>> + if (*blknames) { > >>> + strlcat(blknames, ", ", sizeof(blknames)); > >>> + strlcat(blknames, (const char *)bp->name, > >>> + sizeof(blknames)); > >> > >> FYI, this seems to introduce build problems on systems that do not > >> have strlcpy: > >> > >> During build: > >> seqmid.c: In function ‘update_group_ports’: > >> seqmid.c:672:33: warning: implicit declaration of function > >> ‘strlcat’; did you mean ‘strncat’? > >> [-Wimplicit-function-declaration] > >> 672 | strlcat(blknames, ", ", > >> sizeof(blknames)); > >> | ^~~~~~~ > >> | strncat > >> > >> And then during linking: > >> /usr/bin/ld: seq/.libs/libseq.a(seqmid.o): in function `update_group_ports': > >> /home/amade/workdir/avs/alsa-lib/src/seq/seqmid.c:672: undefined > >> reference to `strlcat' > >> /usr/bin/ld: /home/amade/workdir/avs/alsa-lib/src/seq/seqmid.c:673: > >> undefined reference to `strlcat' > >> collect2: error: ld returned 1 exit status > > > > Thanks, I'll modify it to avoid strlcat() like below. > > > > > > Takashi > > > > -- 8< -- > > Subject: [PATCH] seq: Avoid strlcat() > > > > strlcat() isn't available in every system, so better to avoid it. > > Rewrite the code without strlcat(). > > > > Fixes: 6167b8ce3e80 ("seq: Add API helper functions for creating UMP Endpoint and Blocks") > > Link: https://lore.kernel.org/0796c157-1ac3-47a3-9d54-ba86f59d64d5@linux.intel.com > > Signed-off-by: Takashi Iwai <tiwai@suse.de> > > --- > > src/seq/seqmid.c | 12 ++++++------ > > 1 file changed, 6 insertions(+), 6 deletions(-) > > > > diff --git a/src/seq/seqmid.c b/src/seq/seqmid.c > > index 08c62d5c24b8..b30db4075254 100644 > > --- a/src/seq/seqmid.c > > +++ b/src/seq/seqmid.c > > @@ -635,6 +635,7 @@ static void update_group_ports(snd_seq_t *seq, snd_ump_endpoint_info_t *ep) > > char blknames[64]; > > char name[64]; > > unsigned int caps = 0; > > + int len; > > blknames[0] = 0; > > for (b = 0; b < ep->num_blocks; b++) { > > @@ -668,14 +669,13 @@ static void update_group_ports(snd_seq_t *seq, snd_ump_endpoint_info_t *ep) > > if (!*bp->name) > > continue; > > - if (*blknames) { > > - strlcat(blknames, ", ", sizeof(blknames)); > > - strlcat(blknames, (const char *)bp->name, > > - sizeof(blknames)); > > - } else { > > + len = strlen(blknames); > > + if (len) > > + snprintf(blknames + len, sizeof(blknames) - len, > > + ", %s", bp->name); > > + else > > snd_strlcpy(blknames, (const char *)bp->name, > > sizeof(blknames)); > > - } > > } > > if (!*blknames) > > Builds now, but still gives warning: > > seqmid.c: In function ‘update_group_ports’: > seqmid.c:675:45: warning: ‘%s’ directive output may be truncated > writing up to 127 bytes into a region of size 61 > [-Wformat-truncation=] > 675 | ", %s", bp->name); > | ^~ > In file included from /usr/include/stdio.h:894, > from ../../include/local.h:28, > from seq_local.h:26, > from seqmid.c:23: > In function ‘snprintf’, > inlined from ‘update_group_ports’ at seqmid.c:674:5: > /usr/include/x86_64-linux-gnu/bits/stdio2.h:71:10: note: > ‘__builtin___snprintf_chk’ output between 3 and 130 bytes into a > destination of size 63 > 71 | return __builtin___snprintf_chk (__s, __n, > __USE_FORTIFY_LEVEL - 1, > | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ > 72 | __glibc_objsize (__s), __fmt, > | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ > 73 | __va_arg_pack ()); > | ~~~~~~~~~~~~~~~~~ The compiler gives too much false positives. Takashi
diff --git a/include/seqmid.h b/include/seqmid.h index 4464c2d3af0b..bf968a5b2c7b 100644 --- a/include/seqmid.h +++ b/include/seqmid.h @@ -520,6 +520,13 @@ int snd_seq_reset_pool_input(snd_seq_t *seq); ((ev)->type = SND_SEQ_EVENT_SYSEX,\ snd_seq_ev_set_variable(ev, datalen, dataptr)) +/* Helper API functions for UMP endpoint and block creations */ +int snd_seq_create_ump_endpoint(snd_seq_t *seq, + const snd_ump_endpoint_info_t *info, + unsigned int num_groups); +int snd_seq_create_ump_block(snd_seq_t *seq, int blkid, + const snd_ump_block_info_t *info); + /** \} */ #ifdef __cplusplus diff --git a/include/ump.h b/include/ump.h index 45b3ad270db7..01363a329fa7 100644 --- a/include/ump.h +++ b/include/ump.h @@ -69,6 +69,9 @@ enum _snd_ump_direction { /** Bit flag for JRTS in Receive */ #define SND_UMP_EP_INFO_PROTO_JRTS_RX 0x0002 +/** Default version passed to UMP Endpoint info */ +#define SND_UMP_EP_INFO_DEFAULT_VERSION 0x0101 + size_t snd_ump_endpoint_info_sizeof(void); /** \hideinitializer * \brief allocate an invalid #snd_ump_endpoint_info_t using standard alloca @@ -125,6 +128,9 @@ enum _snd_ump_block_ui_hint { SND_UMP_BLOCK_UI_HINT_BOTH = 0x03, }; +/** Default MIDI CI version passed to UMP Block info */ +#define SND_UMP_BLOCK_INFO_DEFAULT_MIDI_CI_VERSION 0x01 + size_t snd_ump_block_info_sizeof(void); /** \hideinitializer * \brief allocate an invalid #snd_ump_block_info_t using standard alloca diff --git a/src/seq/seq.c b/src/seq/seq.c index 5eac4848b9c7..ff0468140177 100644 --- a/src/seq/seq.c +++ b/src/seq/seq.c @@ -1042,7 +1042,8 @@ int _snd_seq_open_lconf(snd_seq_t **seqp, const char *name, */ int snd_seq_close(snd_seq_t *seq) { - int err; + int i, err; + assert(seq); err = seq->ops->close(seq); if (seq->dl_handle) @@ -1051,6 +1052,9 @@ int snd_seq_close(snd_seq_t *seq) free(seq->ibuf); free(seq->tmpbuf); free(seq->name); + free(seq->ump_ep); + for (i = 0; i < 16; i++) + free(seq->ump_blks[i]); free(seq); return err; } diff --git a/src/seq/seq_local.h b/src/seq/seq_local.h index 468248062638..263029702739 100644 --- a/src/seq/seq_local.h +++ b/src/seq/seq_local.h @@ -94,6 +94,10 @@ struct _snd_seq { size_t tmpbufsize; /* size of errbuf */ size_t packet_size; /* input packet alignment size */ int midi_version; /* current protocol version */ + + unsigned int num_ump_groups; /* number of UMP groups */ + snd_ump_endpoint_info_t *ump_ep; /* optional UMP info */ + snd_ump_block_info_t *ump_blks[16]; /* optional UMP block info */ }; int snd_seq_hw_open(snd_seq_t **handle, const char *name, int streams, int mode); diff --git a/src/seq/seqmid.c b/src/seq/seqmid.c index 9ec93ee8ade1..d7eac6cafa0e 100644 --- a/src/seq/seqmid.c +++ b/src/seq/seqmid.c @@ -493,3 +493,252 @@ int snd_seq_parse_address(snd_seq_t *seq, snd_seq_addr_t *addr, const char *arg) return 0; } +/** + * \brief create a UMP Endpoint for the given sequencer client + * \param seq sequencer handle + * \param info UMP Endpoint information to initialize + * \param num_groups max number of groups in the endpoint + * \return 0 on success or negative error code + * + * This function initializes the sequencer client to the corresponding + * MIDI 2.0 mode (either MIDI 1.0 or MIDI 2.0 protocol) depending on the + * given snd_ump_endpoint_info_t info. + * + * This function should be called right after opening a sequencer client. + * The client name is updated from the UMP Endpoint name, and a primary + * MIDI 2.0 UMP port and each UMP Group port are created. + * The application should pass each UMP block info via succeeding + * snd_seq_create_ump_block() call. + */ +int snd_seq_create_ump_endpoint(snd_seq_t *seq, + const snd_ump_endpoint_info_t *info, + unsigned int num_groups) +{ + int err, version; + unsigned int i; + snd_seq_port_info_t *pinfo; + + if (seq->ump_ep) + return -EBUSY; + + if (num_groups < 1 || num_groups > SND_UMP_MAX_GROUPS) + return -EINVAL; + + if (!(info->protocol_caps & info->protocol)) { + SNDERR("Inconsistent UMP protocol_caps and protocol\n"); + return -EINVAL; + } + + if (info->protocol & SND_UMP_EP_INFO_PROTO_MIDI2) { + version = SND_SEQ_CLIENT_UMP_MIDI_2_0; + } else if (info->protocol & SND_UMP_EP_INFO_PROTO_MIDI1) { + version = SND_SEQ_CLIENT_UMP_MIDI_1_0; + } else { + SNDERR("Invalid UMP protocol set 0x%x\n", info->protocol); + return -EINVAL; + } + + err = snd_seq_set_client_midi_version(seq, version); + if (err < 0) { + SNDERR("Failed to set to MIDI protocol 0x%x\n", version); + return err; + } + + seq->ump_ep = malloc(sizeof(*info)); + if (!seq->ump_ep) + return -ENOMEM; + + *seq->ump_ep = *info; + if (!seq->ump_ep->version) + seq->ump_ep->version = SND_UMP_EP_INFO_DEFAULT_VERSION; + + if (info->name) { + err = snd_seq_set_client_name(seq, (const char *)info->name); + if (err < 0) + goto error_free; + } + + err = snd_seq_set_ump_endpoint_info(seq, seq->ump_ep); + if (err < 0) { + SNDERR("Failed to set UMP EP info\n"); + goto error_free; + } + + snd_seq_port_info_alloca(&pinfo); + + snd_seq_port_info_set_port(pinfo, 0); + snd_seq_port_info_set_port_specified(pinfo, 1); + snd_seq_port_info_set_name(pinfo, "MIDI 2.0"); + snd_seq_port_info_set_capability(pinfo, + SNDRV_SEQ_PORT_CAP_READ | + SNDRV_SEQ_PORT_CAP_SYNC_READ | + SNDRV_SEQ_PORT_CAP_SUBS_READ | + SNDRV_SEQ_PORT_CAP_WRITE | + SNDRV_SEQ_PORT_CAP_SYNC_WRITE | + SNDRV_SEQ_PORT_CAP_SUBS_WRITE | + SNDRV_SEQ_PORT_CAP_DUPLEX); + snd_seq_port_info_set_type(pinfo, + SND_SEQ_PORT_TYPE_MIDI_GENERIC | + SNDRV_SEQ_PORT_TYPE_MIDI_UMP | + SND_SEQ_PORT_TYPE_APPLICATION | + SNDRV_SEQ_PORT_TYPE_PORT); + snd_seq_port_info_set_ump_group(pinfo, + SND_SEQ_PORT_TYPE_MIDI_GENERIC | + SNDRV_SEQ_PORT_TYPE_MIDI_UMP | + SND_SEQ_PORT_TYPE_APPLICATION | + SNDRV_SEQ_PORT_TYPE_PORT); + err = snd_seq_create_port(seq, pinfo); + if (err < 0) { + SNDERR("Failed to create MIDI 2.0 port\n"); + goto error_free; + } + + for (i = 0; i < num_groups; i++) { + char name[32]; + + snd_seq_port_info_set_port(pinfo, i + 1); + snd_seq_port_info_set_port_specified(pinfo, 1); + sprintf(name, "Group %d", i + 1); + snd_seq_port_info_set_capability(pinfo, 0); /* set later */ + snd_seq_port_info_set_name(pinfo, name); + snd_seq_port_info_set_ump_group(pinfo, i + 1); + err = snd_seq_create_port(seq, pinfo); + if (err < 0) { + SNDERR("Failed to create Group port %d\n", i + 1); + goto error; + } + } + + seq->num_ump_groups = num_groups; + return 0; + + error: + /* delete all ports including port 0 */ + for (i = 0; i <= num_groups; i++) + snd_seq_delete_port(seq, i); + error_free: + free(seq->ump_ep); + seq->ump_ep = NULL; + return err; +} + +/* update each port name and capability from the block list */ +static void update_group_ports(snd_seq_t *seq, snd_ump_endpoint_info_t *ep) +{ + unsigned int i, b; + snd_seq_port_info_t *pinfo; + snd_ump_block_info_t *bp; + + snd_seq_port_info_alloca(&pinfo); + + for (i = 0; i < seq->num_ump_groups; i++) { + char blknames[64]; + char name[64]; + unsigned int caps = 0; + + blknames[0] = 0; + for (b = 0; b < ep->num_blocks; b++) { + bp = seq->ump_blks[b]; + if (!bp) + continue; + if (i < bp->first_group || + i >= bp->first_group + bp->num_groups) + continue; + switch (bp->direction) { + case SNDRV_UMP_DIR_INPUT: + caps |= SNDRV_SEQ_PORT_CAP_READ | + SNDRV_SEQ_PORT_CAP_SYNC_READ | + SNDRV_SEQ_PORT_CAP_SUBS_READ; + break; + case SNDRV_UMP_DIR_OUTPUT: + caps |= SNDRV_SEQ_PORT_CAP_WRITE | + SNDRV_SEQ_PORT_CAP_SYNC_WRITE | + SNDRV_SEQ_PORT_CAP_SUBS_WRITE; + break; + case SNDRV_UMP_DIR_BIDIRECTION: + caps |= SNDRV_SEQ_PORT_CAP_READ | + SNDRV_SEQ_PORT_CAP_SYNC_READ | + SNDRV_SEQ_PORT_CAP_SUBS_READ | + SNDRV_SEQ_PORT_CAP_WRITE | + SNDRV_SEQ_PORT_CAP_SYNC_WRITE | + SNDRV_SEQ_PORT_CAP_SUBS_WRITE | + SNDRV_SEQ_PORT_CAP_DUPLEX; + break; + } + + if (!*bp->name) + continue; + if (*blknames) { + strlcat(blknames, ", ", sizeof(blknames)); + strlcat(blknames, (const char *)bp->name, + sizeof(blknames)); + } else { + snd_strlcpy(blknames, (const char *)bp->name, + sizeof(blknames)); + } + } + + if (!*blknames) + continue; + + snprintf(name, sizeof(name), "Group %d (%s)", i + 1, blknames); + if (snd_seq_get_port_info(seq, i + 1, pinfo) < 0) + continue; + + if (strcmp(name, snd_seq_port_info_get_name(pinfo)) || + snd_seq_port_info_get_capability(pinfo) != caps) { + snd_seq_port_info_set_name(pinfo, name); + snd_seq_port_info_set_capability(pinfo, caps); + snd_seq_set_port_info(seq, i + 1, pinfo); + } + } +} + +/** + * \brief create a UMP block for the given sequencer client + * \param seq sequencer handle + * \param blkid 0-based block id + * \param info UMP block info to initialize + * \return 0 on success or negative error code + * + * This function sets up the UMP block info of the given block id. + * The sequencer port name is updated accordingly with the associated + * block name automatically. + */ +int snd_seq_create_ump_block(snd_seq_t *seq, int blkid, + const snd_ump_block_info_t *info) +{ + snd_ump_block_info_t *bp; + snd_ump_endpoint_info_t *ep = seq->ump_ep; + int err; + + if (!ep) + return -EINVAL; + if (info->first_group >= seq->num_ump_groups || + info->first_group + info->num_groups > seq->num_ump_groups) + return -EINVAL; + if (blkid < 0 || blkid >= (int)ep->num_blocks) + return -EINVAL; + + if (seq->ump_blks[blkid]) + return -EBUSY; + seq->ump_blks[blkid] = bp = malloc(sizeof(*info)); + if (!bp) + return -ENOMEM; + *bp = *info; + + if (!bp->midi_ci_version) + bp->midi_ci_version = SND_UMP_BLOCK_INFO_DEFAULT_MIDI_CI_VERSION; + bp->active = 1; + + err = snd_seq_set_ump_block_info(seq, blkid, bp); + if (err < 0) { + SNDERR("Failed to set UMP EP info\n"); + free(bp); + seq->ump_blks[blkid] = NULL; + return err; + } + + update_group_ports(seq, ep); + return 0; +}
For making it easer for applications to create a virtual UMP Endpoint and UMP blocks, add two API helper functions. snd_seq_create_ump_endpoint() creates (unsurprisingly) a UMP Endpoint, based on the given snd_ump_endpoint_info_t information. The number of (max) UMP groups belonging to this Endpoint has to be specified. This function sets up the Endpoint info on the sequencer client, and creates a MIDI 2.0 UMP port as well as UMP Group ports automatically. The name of the sequencer client is updated from the Endpoint name, too. After creating a UMP Endpoint, create each UMP Block via snd_seq_create_ump_block() function with a snd_ump_block_info_t info. The associated groups for each block have to be specified there. The port names and capability bits are updated accordingly after setting each block information. Signed-off-by: Takashi Iwai <tiwai@suse.de> --- include/seqmid.h | 7 ++ include/ump.h | 6 ++ src/seq/seq.c | 6 +- src/seq/seq_local.h | 4 + src/seq/seqmid.c | 249 ++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 271 insertions(+), 1 deletion(-)