Commit 46397622 authored by Takashi Iwai's avatar Takashi Iwai

ALSA: seq: Add UMP support

Starting from this commit, we add the basic support of UMP (Universal
MIDI Packet) events on ALSA sequencer infrastructure.  The biggest
change here is that, for transferring UMP packets that are up to 128
bits, we extend the data payload of ALSA sequencer event record when
the client is declared to support for the new UMP events.

A new event flag bit, SNDRV_SEQ_EVENT_UMP, is defined and it shall be
set for the UMP packet events that have the larger payload of 128
bits, defined as struct snd_seq_ump_event.

For controlling the UMP feature enablement in kernel, a new Kconfig,
CONFIG_SND_SEQ_UMP is introduced.  The extended event for UMP is
available only when this Kconfig item is set.  Similarly, the size of
the internal snd_seq_event_cell also increases (in 4 bytes) when the
Kconfig item is set.  (But the size increase is effective only for
32bit architectures; 64bit archs already have padding there.)
Overall, when CONFIG_SND_SEQ_UMP isn't set, there is no change in the
event and cell, keeping the old sizes.

For applications that want to access the UMP packets, first of all, a
sequencer client has to declare the user-protocol to match with the
latest one via the new SNDRV_SEQ_IOCTL_USER_PVERSION; otherwise it's
treated as if a legacy client without UMP support.

Then the client can switch to the new UMP mode (MIDI 1.0 or MIDI 2.0)
with a new field, midi_version, in snd_seq_client_info.  When switched
to UMP mode (midi_version = 1 or 2), the client can write the UMP
events with SNDRV_SEQ_EVENT_UMP flag.  For reads, the alignment size
is changed from snd_seq_event (28 bytes) to snd_seq_ump_event (32
bytes).  When a UMP sequencer event is delivered to a legacy sequencer
client, it's ignored or handled as an error.

Conceptually, ALSA sequencer client and port correspond to the UMP
Endpoint and Group, respectively; each client may have multiple ports
and each port has the fixed number (16) of channels, total up to 256
channels.

As of this commit, ALSA sequencer core just sends and receives the UMP
events as-is from/to clients.  The automatic conversions between the
legacy events and the new UMP events will be implemented in a later
patch.

Along with this commit, bump the sequencer protocol version to 1.0.3.
Reviewed-by: default avatarJaroslav Kysela <perex@perex.cz>
Link: https://lore.kernel.org/r/20230523075358.9672-26-tiwai@suse.deSigned-off-by: default avatarTakashi Iwai <tiwai@suse.de>
parent afb72505
...@@ -65,6 +65,10 @@ ...@@ -65,6 +65,10 @@
#define snd_seq_ev_is_abstime(ev) (snd_seq_ev_timemode_type(ev) == SNDRV_SEQ_TIME_MODE_ABS) #define snd_seq_ev_is_abstime(ev) (snd_seq_ev_timemode_type(ev) == SNDRV_SEQ_TIME_MODE_ABS)
#define snd_seq_ev_is_reltime(ev) (snd_seq_ev_timemode_type(ev) == SNDRV_SEQ_TIME_MODE_REL) #define snd_seq_ev_is_reltime(ev) (snd_seq_ev_timemode_type(ev) == SNDRV_SEQ_TIME_MODE_REL)
/* check whether the given event is a UMP event */
#define snd_seq_ev_is_ump(ev) \
(IS_ENABLED(CONFIG_SND_SEQ_UMP) && ((ev)->flags & SNDRV_SEQ_EVENT_UMP))
/* queue sync port */ /* queue sync port */
#define snd_seq_queue_sync_port(q) ((q) + 16) #define snd_seq_queue_sync_port(q) ((q) + 16)
......
...@@ -75,6 +75,14 @@ int snd_seq_expand_var_event_at(const struct snd_seq_event *event, int count, ...@@ -75,6 +75,14 @@ int snd_seq_expand_var_event_at(const struct snd_seq_event *event, int count,
int snd_seq_dump_var_event(const struct snd_seq_event *event, int snd_seq_dump_var_event(const struct snd_seq_event *event,
snd_seq_dump_func_t func, void *private_data); snd_seq_dump_func_t func, void *private_data);
/* size of the event packet; it can be greater than snd_seq_event size */
static inline size_t snd_seq_event_packet_size(struct snd_seq_event *ev)
{
if (snd_seq_ev_is_ump(ev))
return sizeof(struct snd_seq_ump_event);
return sizeof(struct snd_seq_event);
}
/* interface for OSS emulation */ /* interface for OSS emulation */
int snd_seq_set_queue_tempo(int client, struct snd_seq_queue_tempo *tempo); int snd_seq_set_queue_tempo(int client, struct snd_seq_queue_tempo *tempo);
......
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
#include <sound/asound.h> #include <sound/asound.h>
/** version of the sequencer */ /** version of the sequencer */
#define SNDRV_SEQ_VERSION SNDRV_PROTOCOL_VERSION(1, 0, 2) #define SNDRV_SEQ_VERSION SNDRV_PROTOCOL_VERSION(1, 0, 3)
/** /**
* definition of sequencer event types * definition of sequencer event types
...@@ -174,6 +174,7 @@ struct snd_seq_connect { ...@@ -174,6 +174,7 @@ struct snd_seq_connect {
#define SNDRV_SEQ_PRIORITY_HIGH (1<<4) /* event should be processed before others */ #define SNDRV_SEQ_PRIORITY_HIGH (1<<4) /* event should be processed before others */
#define SNDRV_SEQ_PRIORITY_MASK (1<<4) #define SNDRV_SEQ_PRIORITY_MASK (1<<4)
#define SNDRV_SEQ_EVENT_UMP (1<<5) /* event holds a UMP packet */
/* note event */ /* note event */
struct snd_seq_ev_note { struct snd_seq_ev_note {
...@@ -252,6 +253,19 @@ struct snd_seq_ev_quote { ...@@ -252,6 +253,19 @@ struct snd_seq_ev_quote {
struct snd_seq_event *event; /* quoted event */ struct snd_seq_event *event; /* quoted event */
} __attribute__((packed)); } __attribute__((packed));
union snd_seq_event_data { /* event data... */
struct snd_seq_ev_note note;
struct snd_seq_ev_ctrl control;
struct snd_seq_ev_raw8 raw8;
struct snd_seq_ev_raw32 raw32;
struct snd_seq_ev_ext ext;
struct snd_seq_ev_queue_control queue;
union snd_seq_timestamp time;
struct snd_seq_addr addr;
struct snd_seq_connect connect;
struct snd_seq_result result;
struct snd_seq_ev_quote quote;
};
/* sequencer event */ /* sequencer event */
struct snd_seq_event { struct snd_seq_event {
...@@ -262,25 +276,27 @@ struct snd_seq_event { ...@@ -262,25 +276,27 @@ struct snd_seq_event {
unsigned char queue; /* schedule queue */ unsigned char queue; /* schedule queue */
union snd_seq_timestamp time; /* schedule time */ union snd_seq_timestamp time; /* schedule time */
struct snd_seq_addr source; /* source address */ struct snd_seq_addr source; /* source address */
struct snd_seq_addr dest; /* destination address */ struct snd_seq_addr dest; /* destination address */
union { /* event data... */ union snd_seq_event_data data;
struct snd_seq_ev_note note;
struct snd_seq_ev_ctrl control;
struct snd_seq_ev_raw8 raw8;
struct snd_seq_ev_raw32 raw32;
struct snd_seq_ev_ext ext;
struct snd_seq_ev_queue_control queue;
union snd_seq_timestamp time;
struct snd_seq_addr addr;
struct snd_seq_connect connect;
struct snd_seq_result result;
struct snd_seq_ev_quote quote;
} data;
}; };
/* (compatible) event for UMP-capable clients */
struct snd_seq_ump_event {
snd_seq_event_type_t type; /* event type */
unsigned char flags; /* event flags */
char tag;
unsigned char queue; /* schedule queue */
union snd_seq_timestamp time; /* schedule time */
struct snd_seq_addr source; /* source address */
struct snd_seq_addr dest; /* destination address */
union {
union snd_seq_event_data data;
unsigned int ump[4];
};
};
/* /*
* bounce event - stored as variable size data * bounce event - stored as variable size data
...@@ -344,9 +360,14 @@ struct snd_seq_client_info { ...@@ -344,9 +360,14 @@ struct snd_seq_client_info {
int event_lost; /* number of lost events */ int event_lost; /* number of lost events */
int card; /* RO: card number[kernel] */ int card; /* RO: card number[kernel] */
int pid; /* RO: pid[user] */ int pid; /* RO: pid[user] */
char reserved[56]; /* for future use */ unsigned int midi_version; /* MIDI version */
char reserved[52]; /* for future use */
}; };
/* MIDI version numbers in client info */
#define SNDRV_SEQ_CLIENT_LEGACY_MIDI 0 /* Legacy client */
#define SNDRV_SEQ_CLIENT_UMP_MIDI_1_0 1 /* UMP MIDI 1.0 */
#define SNDRV_SEQ_CLIENT_UMP_MIDI_2_0 2 /* UMP MIDI 2.0 */
/* client pool size */ /* client pool size */
struct snd_seq_client_pool { struct snd_seq_client_pool {
......
...@@ -60,4 +60,11 @@ config SND_SEQ_MIDI_EMUL ...@@ -60,4 +60,11 @@ config SND_SEQ_MIDI_EMUL
config SND_SEQ_VIRMIDI config SND_SEQ_VIRMIDI
tristate tristate
config SND_SEQ_UMP
bool "Support for UMP events"
help
Say Y here to enable the support for handling UMP (Universal MIDI
Packet) events via ALSA sequencer infrastructure, which is an
essential feature for enabling MIDI 2.0 support.
endif # SND_SEQUENCER endif # SND_SEQUENCER
This diff is collapsed.
...@@ -35,6 +35,7 @@ struct snd_seq_client { ...@@ -35,6 +35,7 @@ struct snd_seq_client {
snd_seq_client_type_t type; snd_seq_client_type_t type;
unsigned int accept_input: 1, unsigned int accept_input: 1,
accept_output: 1; accept_output: 1;
unsigned int midi_version;
unsigned int user_pversion; unsigned int user_pversion;
char name[64]; /* client name */ char name[64]; /* client name */
int number; /* client number */ int number; /* client number */
......
...@@ -340,6 +340,7 @@ int snd_seq_event_dup(struct snd_seq_pool *pool, struct snd_seq_event *event, ...@@ -340,6 +340,7 @@ int snd_seq_event_dup(struct snd_seq_pool *pool, struct snd_seq_event *event,
int ncells, err; int ncells, err;
unsigned int extlen; unsigned int extlen;
struct snd_seq_event_cell *cell; struct snd_seq_event_cell *cell;
int size;
*cellp = NULL; *cellp = NULL;
...@@ -357,7 +358,12 @@ int snd_seq_event_dup(struct snd_seq_pool *pool, struct snd_seq_event *event, ...@@ -357,7 +358,12 @@ int snd_seq_event_dup(struct snd_seq_pool *pool, struct snd_seq_event *event,
return err; return err;
/* copy the event */ /* copy the event */
cell->event = *event; size = snd_seq_event_packet_size(event);
memcpy(&cell->ump, event, size);
#if IS_ENABLED(CONFIG_SND_SEQ_UMP)
if (size < sizeof(cell->event))
cell->ump.raw.extra = 0;
#endif
/* decompose */ /* decompose */
if (snd_seq_ev_is_variable(event)) { if (snd_seq_ev_is_variable(event)) {
...@@ -375,7 +381,7 @@ int snd_seq_event_dup(struct snd_seq_pool *pool, struct snd_seq_event *event, ...@@ -375,7 +381,7 @@ int snd_seq_event_dup(struct snd_seq_pool *pool, struct snd_seq_event *event,
tail = NULL; tail = NULL;
while (ncells-- > 0) { while (ncells-- > 0) {
int size = sizeof(struct snd_seq_event); size = sizeof(struct snd_seq_event);
if (len < size) if (len < size)
size = len; size = len;
err = snd_seq_cell_alloc(pool, &tmp, nonblock, file, err = snd_seq_cell_alloc(pool, &tmp, nonblock, file,
......
...@@ -11,9 +11,26 @@ ...@@ -11,9 +11,26 @@
struct snd_info_buffer; struct snd_info_buffer;
/* aliasing for legacy and UMP event packet handling */
union __snd_seq_event {
struct snd_seq_event legacy;
#if IS_ENABLED(CONFIG_SND_SEQ_UMP)
struct snd_seq_ump_event ump;
#endif
struct {
struct snd_seq_event event;
#if IS_ENABLED(CONFIG_SND_SEQ_UMP)
u32 extra;
#endif
} __packed raw;
};
/* container for sequencer event (internal use) */ /* container for sequencer event (internal use) */
struct snd_seq_event_cell { struct snd_seq_event_cell {
struct snd_seq_event event; union {
struct snd_seq_event event;
union __snd_seq_event ump;
};
struct snd_seq_pool *pool; /* used pool */ struct snd_seq_pool *pool; /* used pool */
struct snd_seq_event_cell *next; /* next cell */ struct snd_seq_event_cell *next; /* next cell */
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment