Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * ff-midi.c - a part of driver for RME Fireface series
0004  *
0005  * Copyright (c) 2015-2017 Takashi Sakamoto
0006  */
0007 
0008 #include "ff.h"
0009 
0010 static int midi_capture_open(struct snd_rawmidi_substream *substream)
0011 {
0012     /* Do nothing. */
0013     return 0;
0014 }
0015 
0016 static int midi_playback_open(struct snd_rawmidi_substream *substream)
0017 {
0018     struct snd_ff *ff = substream->rmidi->private_data;
0019 
0020     /* Initialize internal status. */
0021     ff->on_sysex[substream->number] = 0;
0022     ff->rx_midi_error[substream->number] = false;
0023 
0024     WRITE_ONCE(ff->rx_midi_substreams[substream->number], substream);
0025 
0026     return 0;
0027 }
0028 
0029 static int midi_capture_close(struct snd_rawmidi_substream *substream)
0030 {
0031     /* Do nothing. */
0032     return 0;
0033 }
0034 
0035 static int midi_playback_close(struct snd_rawmidi_substream *substream)
0036 {
0037     struct snd_ff *ff = substream->rmidi->private_data;
0038 
0039     cancel_work_sync(&ff->rx_midi_work[substream->number]);
0040     WRITE_ONCE(ff->rx_midi_substreams[substream->number], NULL);
0041 
0042     return 0;
0043 }
0044 
0045 static void midi_capture_trigger(struct snd_rawmidi_substream *substream,
0046                  int up)
0047 {
0048     struct snd_ff *ff = substream->rmidi->private_data;
0049     unsigned long flags;
0050 
0051     spin_lock_irqsave(&ff->lock, flags);
0052 
0053     if (up)
0054         WRITE_ONCE(ff->tx_midi_substreams[substream->number],
0055                substream);
0056     else
0057         WRITE_ONCE(ff->tx_midi_substreams[substream->number], NULL);
0058 
0059     spin_unlock_irqrestore(&ff->lock, flags);
0060 }
0061 
0062 static void midi_playback_trigger(struct snd_rawmidi_substream *substream,
0063                   int up)
0064 {
0065     struct snd_ff *ff = substream->rmidi->private_data;
0066     unsigned long flags;
0067 
0068     spin_lock_irqsave(&ff->lock, flags);
0069 
0070     if (up || !ff->rx_midi_error[substream->number])
0071         schedule_work(&ff->rx_midi_work[substream->number]);
0072 
0073     spin_unlock_irqrestore(&ff->lock, flags);
0074 }
0075 
0076 static void set_midi_substream_names(struct snd_rawmidi_str *stream,
0077                      const char *const name)
0078 {
0079     struct snd_rawmidi_substream *substream;
0080 
0081     list_for_each_entry(substream, &stream->substreams, list) {
0082         snprintf(substream->name, sizeof(substream->name),
0083              "%s MIDI %d", name, substream->number + 1);
0084     }
0085 }
0086 
0087 int snd_ff_create_midi_devices(struct snd_ff *ff)
0088 {
0089     static const struct snd_rawmidi_ops midi_capture_ops = {
0090         .open       = midi_capture_open,
0091         .close      = midi_capture_close,
0092         .trigger    = midi_capture_trigger,
0093     };
0094     static const struct snd_rawmidi_ops midi_playback_ops = {
0095         .open       = midi_playback_open,
0096         .close      = midi_playback_close,
0097         .trigger    = midi_playback_trigger,
0098     };
0099     struct snd_rawmidi *rmidi;
0100     struct snd_rawmidi_str *stream;
0101     int err;
0102 
0103     err = snd_rawmidi_new(ff->card, ff->card->driver, 0,
0104                   ff->spec->midi_out_ports, ff->spec->midi_in_ports,
0105                   &rmidi);
0106     if (err < 0)
0107         return err;
0108 
0109     snprintf(rmidi->name, sizeof(rmidi->name),
0110          "%s MIDI", ff->card->shortname);
0111     rmidi->private_data = ff;
0112 
0113     rmidi->info_flags |= SNDRV_RAWMIDI_INFO_INPUT;
0114     snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT,
0115                 &midi_capture_ops);
0116     stream = &rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT];
0117     set_midi_substream_names(stream, ff->card->shortname);
0118 
0119     rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT;
0120     snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT,
0121                 &midi_playback_ops);
0122     stream = &rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT];
0123     set_midi_substream_names(stream, ff->card->shortname);
0124 
0125     rmidi->info_flags |= SNDRV_RAWMIDI_INFO_DUPLEX;
0126 
0127     return 0;
0128 }