sound/core/seq/seq_ump_client.c

Source file repositories/reference/linux-study-clean/sound/core/seq/seq_ump_client.c

File Facts

System
Linux kernel
Corpus path
sound/core/seq/seq_ump_client.c
Extension
.c
Size
15561 bytes
Lines
551
Domain
Driver Families
Bucket
sound/core
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

struct seq_ump_input_buffer {
	unsigned char len;		/* total length in words */
	unsigned char pending;		/* pending words */
	unsigned char type;		/* parsed UMP packet type */
	unsigned char group;		/* parsed UMP packet group */
	u32 buf[4];			/* incoming UMP packet */
};

/* sequencer client, per UMP EP (rawmidi) */
struct seq_ump_client {
	struct snd_ump_endpoint *ump;	/* assigned endpoint */
	int seq_client;			/* sequencer client id */
	int opened[2];			/* current opens for each direction */
	rwlock_t output_lock;		/* protects out_rfile output access */
	struct snd_rawmidi_file out_rfile; /* rawmidi for output */
	struct seq_ump_input_buffer input; /* input parser context */
	void *ump_info[SNDRV_UMP_MAX_BLOCKS + 1]; /* shadow of seq client ump_info */
	struct work_struct group_notify_work; /* FB change notification */
};

/* number of 32bit words for each UMP message type */
static unsigned char ump_packet_words[0x10] = {
	1, 1, 1, 2, 2, 4, 1, 1, 2, 2, 2, 3, 3, 4, 4, 4
};

/* conversion between UMP group and seq port;
 * assume the port number is equal with UMP group number (1-based)
 */
static unsigned char ump_group_to_seq_port(unsigned char group)
{
	return group + 1;
}

/* process the incoming rawmidi stream */
static void seq_ump_input_receive(struct snd_ump_endpoint *ump,
				  const u32 *val, int words)
{
	struct seq_ump_client *client = ump->seq_client;
	struct snd_seq_ump_event ev = {};

	if (!client->opened[STR_IN])
		return;

	if (ump_is_groupless_msg(ump_message_type(*val)))
		ev.source.port = 0; /* UMP EP port */
	else
		ev.source.port = ump_group_to_seq_port(ump_message_group(*val));
	ev.dest.client = SNDRV_SEQ_ADDRESS_SUBSCRIBERS;
	ev.flags = SNDRV_SEQ_EVENT_UMP;
	memcpy(ev.ump, val, words << 2);
	snd_seq_kernel_client_dispatch(client->seq_client,
				       (struct snd_seq_event *)&ev,
				       true, 0);
}

/* process an input sequencer event; only deal with UMP types */
static int seq_ump_process_event(struct snd_seq_event *ev, int direct,
				 void *private_data, int atomic, int hop)
{
	struct seq_ump_client *client = private_data;
	struct snd_rawmidi_substream *substream;
	struct snd_seq_ump_event *ump_ev;
	unsigned char type;
	int len;

	guard(read_lock_irqsave)(&client->output_lock);
	substream = client->out_rfile.output;
	if (!substream)
		return -ENODEV;
	if (!snd_seq_ev_is_ump(ev))
		return 0; /* invalid event, skip */
	ump_ev = (struct snd_seq_ump_event *)ev;
	type = ump_message_type(ump_ev->ump[0]);
	len = ump_packet_words[type];
	if (len > 4)
		return 0; // invalid - skip
	snd_rawmidi_kernel_write(substream, ev->data.raw8.d, len << 2);
	return 0;
}

/* open the rawmidi */
static int seq_ump_client_open(struct seq_ump_client *client, int dir)
{
	struct snd_ump_endpoint *ump = client->ump;
	struct snd_rawmidi_file rfile = {};
	int err;

	guard(mutex)(&ump->open_mutex);
	if (dir == STR_OUT && !client->opened[dir]) {
		err = snd_rawmidi_kernel_open(&ump->core, 0,

Annotation

Implementation Notes