sound/core/seq/seq_virmidi.c
Source file repositories/reference/linux-study-clean/sound/core/seq/seq_virmidi.c
File Facts
- System
- Linux kernel
- Corpus path
sound/core/seq/seq_virmidi.c- Extension
.c- Size
- 13493 bytes
- Lines
- 526
- Domain
- Driver Families
- Bucket
- sound/core
- Inferred role
- Driver Families: exported/initcall integration point
- Status
- integration 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.
- 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.
- Exports symbols or registers init work; inspect boot/module ordering and who consumes the exported contract.
- Allocates kernel memory; connect allocation flags and lifetime to context constraints.
- Defines or uses C structs; map object ownership, embedded links, reference counts, and lock ownership.
Dependency Surface
linux/init.hlinux/wait.hlinux/module.hlinux/slab.hsound/core.hsound/rawmidi.hsound/info.hsound/control.hsound/minors.hsound/seq_kernel.hsound/seq_midi_event.hsound/seq_virmidi.h
Detected Declarations
function snd_virmidi_init_eventfunction dump_to_rawmidifunction snd_virmidi_dev_receive_eventfunction snd_virmidi_event_inputfunction snd_virmidi_input_triggerfunction snd_vmidi_output_workfunction snd_virmidi_output_triggerfunction snd_virmidi_input_openfunction snd_virmidi_output_openfunction snd_virmidi_input_closefunction scoped_guardfunction snd_virmidi_output_closefunction snd_virmidi_output_drainfunction snd_virmidi_subscribefunction snd_virmidi_unsubscribefunction snd_virmidi_usefunction snd_virmidi_unusefunction snd_virmidi_dev_attach_seqfunction snd_virmidi_dev_detach_seqfunction snd_virmidi_dev_registerfunction snd_virmidi_dev_unregisterfunction snd_virmidi_freefunction snd_virmidi_newexport snd_virmidi_new
Annotated Snippet
if (ev->type == SNDRV_SEQ_EVENT_SYSEX) {
if ((ev->flags & SNDRV_SEQ_EVENT_LENGTH_MASK) != SNDRV_SEQ_EVENT_LENGTH_VARIABLE)
continue;
snd_seq_dump_var_event(ev, dump_to_rawmidi, vmidi->substream);
snd_midi_event_reset_decode(vmidi->parser);
} else {
len = snd_midi_event_decode(vmidi->parser, msg, sizeof(msg), ev);
if (len > 0)
snd_rawmidi_receive(vmidi->substream, msg, len);
}
}
if (atomic)
read_unlock(&rdev->filelist_lock);
else
up_read(&rdev->filelist_sem);
return 0;
}
/*
* event handler of virmidi port
*/
static int snd_virmidi_event_input(struct snd_seq_event *ev, int direct,
void *private_data, int atomic, int hop)
{
struct snd_virmidi_dev *rdev;
rdev = private_data;
if (!(rdev->flags & SNDRV_VIRMIDI_USE))
return 0; /* ignored */
return snd_virmidi_dev_receive_event(rdev, ev, atomic);
}
/*
* trigger rawmidi stream for input
*/
static void snd_virmidi_input_trigger(struct snd_rawmidi_substream *substream, int up)
{
struct snd_virmidi *vmidi = substream->runtime->private_data;
WRITE_ONCE(vmidi->trigger, !!up);
}
/* process rawmidi bytes and send events;
* we need no lock here for vmidi->event since it's handled only in this work
*/
static void snd_vmidi_output_work(struct work_struct *work)
{
struct snd_virmidi *vmidi;
struct snd_rawmidi_substream *substream;
unsigned char input;
int ret;
vmidi = container_of(work, struct snd_virmidi, output_work);
substream = vmidi->substream;
/* discard the outputs in dispatch mode unless subscribed */
if (vmidi->seq_mode == SNDRV_VIRMIDI_SEQ_DISPATCH &&
!(vmidi->rdev->flags & SNDRV_VIRMIDI_SUBSCRIBE)) {
snd_rawmidi_proceed(substream);
return;
}
while (READ_ONCE(vmidi->trigger)) {
if (snd_rawmidi_transmit(substream, &input, 1) != 1)
break;
if (!snd_midi_event_encode_byte(vmidi->parser, input,
&vmidi->event))
continue;
if (vmidi->event.type != SNDRV_SEQ_EVENT_NONE) {
ret = snd_seq_kernel_client_dispatch(vmidi->client,
&vmidi->event,
false, 0);
vmidi->event.type = SNDRV_SEQ_EVENT_NONE;
if (ret < 0)
break;
}
/* rawmidi input might be huge, allow to have a break */
cond_resched();
}
}
/*
* trigger rawmidi stream for output
*/
static void snd_virmidi_output_trigger(struct snd_rawmidi_substream *substream, int up)
{
struct snd_virmidi *vmidi = substream->runtime->private_data;
WRITE_ONCE(vmidi->trigger, !!up);
Annotation
- Immediate include surface: `linux/init.h`, `linux/wait.h`, `linux/module.h`, `linux/slab.h`, `sound/core.h`, `sound/rawmidi.h`, `sound/info.h`, `sound/control.h`.
- Detected declarations: `function snd_virmidi_init_event`, `function dump_to_rawmidi`, `function snd_virmidi_dev_receive_event`, `function snd_virmidi_event_input`, `function snd_virmidi_input_trigger`, `function snd_vmidi_output_work`, `function snd_virmidi_output_trigger`, `function snd_virmidi_input_open`, `function snd_virmidi_output_open`, `function snd_virmidi_input_close`.
- Atlas domain: Driver Families / sound/core.
- Implementation status: integration implementation candidate.
Implementation Notes
- This generated page is the file-by-file coverage layer; curated subsystem chapters should link here when they synthesize a multi-file control flow.
- Core OS pages should be promoted from atlas-only to deep-reviewed when they explain data structures, invariants, locking, lifecycle, and C implementation snippets.
- Driver-family pages are intentionally pattern-oriented unless they are part of the selected PCIe/NVMe representative device path.