In all the callbacks, the private data that you've set for the rawmidi device can be accessed as substream->rmidi->private_data.
If there is more than one port, your callbacks can determine the port index from the struct snd_rawmidi_substream data passed to each callback:
struct snd_rawmidi_substream *substream; int index = substream->number;
static int snd_xxx_open(struct snd_rawmidi_substream *substream);
This is called when a substream is opened. You can initialize the hardware here, but you shouldn't start transmitting/receiving data yet.
static int snd_xxx_close(struct snd_rawmidi_substream *substream);
Guess what.
The open
and close
callbacks of a rawmidi device are serialized with a mutex,
and can sleep.
static void snd_xxx_output_trigger(struct snd_rawmidi_substream *substream, int up);
This is called with a nonzero up
parameter when there is some data in the substream buffer that
must be transmitted.
To read data from the buffer, call
snd_rawmidi_transmit_peek
. It will
return the number of bytes that have been read; this will be
less than the number of bytes requested when there are no more
data in the buffer.
After the data have been transmitted successfully, call
snd_rawmidi_transmit_ack
to remove the
data from the substream buffer:
unsigned char data; while (snd_rawmidi_transmit_peek(substream, &data, 1) == 1) { if (snd_mychip_try_to_transmit(data)) snd_rawmidi_transmit_ack(substream, 1); else break; /* hardware FIFO full */ }
If you know beforehand that the hardware will accept data, you
can use the snd_rawmidi_transmit
function
which reads some data and removes them from the buffer at once:
while (snd_mychip_transmit_possible()) { unsigned char data; if (snd_rawmidi_transmit(substream, &data, 1) != 1) break; /* no more data */ snd_mychip_transmit(data); }
If you know beforehand how many bytes you can accept, you can
use a buffer size greater than one with the
snd_rawmidi_transmit*
functions.
The trigger
callback must not sleep. If
the hardware FIFO is full before the substream buffer has been
emptied, you have to continue transmitting data later, either
in an interrupt handler, or with a timer if the hardware
doesn't have a MIDI transmit interrupt.
The trigger
callback is called with a
zero up
parameter when the transmission
of data should be aborted.
static void snd_xxx_input_trigger(struct snd_rawmidi_substream *substream, int up);
This is called with a nonzero up
parameter to enable receiving data, or with a zero
up
parameter do disable receiving data.
The trigger
callback must not sleep; the
actual reading of data from the device is usually done in an
interrupt handler.
When data reception is enabled, your interrupt handler should
call snd_rawmidi_receive
for all received
data:
void snd_mychip_midi_interrupt(...) { while (mychip_midi_available()) { unsigned char data; data = mychip_midi_read(); snd_rawmidi_receive(substream, &data, 1); } }
static void snd_xxx_drain(struct snd_rawmidi_substream *substream);
This is only used with output substreams. This function should wait until all data read from the substream buffer have been transmitted. This ensures that the device can be closed and the driver unloaded without losing data.
This callback is optional. If you do not set
drain
in the struct snd_rawmidi_ops
structure, ALSA will simply wait for 50 milliseconds
instead.