sound/pci/echoaudio/midi.c

Source file repositories/reference/linux-study-clean/sound/pci/echoaudio/midi.c

File Facts

System
Linux kernel
Corpus path
sound/pci/echoaudio/midi.c
Extension
.c
Size
8537 bytes
Lines
312
Domain
Driver Families
Bucket
sound/pci
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

if (sent < 0) {
			dev_err(chip->card->dev,
				"write_midi() error %d\n", sent);
			/* retry later */
			sent = 9000;
			chip->midi_full = 1;
		} else if (sent > 0) {
			dev_dbg(chip->card->dev, "%d bytes sent\n", sent);
			snd_rawmidi_transmit_ack(chip->midi_out, sent);
		} else {
			/* Buffer is full. DSP's internal buffer is 64 (128 ?)
			bytes long. Let's wait until half of them are sent */
			dev_dbg(chip->card->dev, "Full\n");
			sent = 32;
			chip->midi_full = 1;
		}
	}

	/* We restart the timer only if there is some data left to send */
	if (!snd_rawmidi_transmit_empty(chip->midi_out) && chip->tinuse) {
		/* The timer will expire slightly after the data has been
		   sent */
		time = (sent << 3) / 25 + 1;	/* 8/25=0.32ms to send a byte */
		mod_timer(&chip->timer, jiffies + (time * HZ + 999) / 1000);
		dev_dbg(chip->card->dev,
			"Timer armed(%d)\n", ((time * HZ + 999) / 1000));
	}
}



static void snd_echo_midi_output_trigger(struct snd_rawmidi_substream *substream,
					 int up)
{
	struct echoaudio *chip = substream->rmidi->private_data;
	bool remove_timer = false;

	dev_dbg(chip->card->dev, "snd_echo_midi_output_trigger(%d)\n", up);
	scoped_guard(spinlock_irq, &chip->lock) {
		if (up) {
			if (!chip->tinuse) {
				timer_setup(&chip->timer, snd_echo_midi_output_write,
					    0);
				chip->tinuse = 1;
			}
		} else {
			if (chip->tinuse) {
				chip->tinuse = 0;
				remove_timer = true;
			}
		}
	}

	if (remove_timer) {
		timer_delete_sync(&chip->timer);
		dev_dbg(chip->card->dev, "Timer removed\n");
		return;
	}

	if (up && !chip->midi_full)
		snd_echo_midi_output_write(&chip->timer);
}



static int snd_echo_midi_output_close(struct snd_rawmidi_substream *substream)
{
	struct echoaudio *chip = substream->rmidi->private_data;

	chip->midi_out = NULL;
	return 0;
}



static const struct snd_rawmidi_ops snd_echo_midi_input = {
	.open = snd_echo_midi_input_open,
	.close = snd_echo_midi_input_close,
	.trigger = snd_echo_midi_input_trigger,
};

static const struct snd_rawmidi_ops snd_echo_midi_output = {
	.open = snd_echo_midi_output_open,
	.close = snd_echo_midi_output_close,
	.trigger = snd_echo_midi_output_trigger,
};



/* <--snd_echo_probe() */

Annotation

Implementation Notes