linux/sound/firewire/fireface/ff-midi.c
<<
>>
Prefs
   1/*
   2 * ff-midi.c - a part of driver for RME Fireface series
   3 *
   4 * Copyright (c) 2015-2017 Takashi Sakamoto
   5 *
   6 * Licensed under the terms of the GNU General Public License, version 2.
   7 */
   8
   9#include "ff.h"
  10
  11static int midi_capture_open(struct snd_rawmidi_substream *substream)
  12{
  13        /* Do nothing. */
  14        return 0;
  15}
  16
  17static int midi_playback_open(struct snd_rawmidi_substream *substream)
  18{
  19        struct snd_ff *ff = substream->rmidi->private_data;
  20
  21        /* Initialize internal status. */
  22        ff->running_status[substream->number] = 0;
  23        ff->rx_midi_error[substream->number] = false;
  24
  25        ACCESS_ONCE(ff->rx_midi_substreams[substream->number]) = substream;
  26
  27        return 0;
  28}
  29
  30static int midi_capture_close(struct snd_rawmidi_substream *substream)
  31{
  32        /* Do nothing. */
  33        return 0;
  34}
  35
  36static int midi_playback_close(struct snd_rawmidi_substream *substream)
  37{
  38        struct snd_ff *ff = substream->rmidi->private_data;
  39
  40        cancel_work_sync(&ff->rx_midi_work[substream->number]);
  41        ACCESS_ONCE(ff->rx_midi_substreams[substream->number]) = NULL;
  42
  43        return 0;
  44}
  45
  46static void midi_capture_trigger(struct snd_rawmidi_substream *substream,
  47                                 int up)
  48{
  49        struct snd_ff *ff = substream->rmidi->private_data;
  50        unsigned long flags;
  51
  52        spin_lock_irqsave(&ff->lock, flags);
  53
  54        if (up)
  55                ACCESS_ONCE(ff->tx_midi_substreams[substream->number]) =
  56                                                                substream;
  57        else
  58                ACCESS_ONCE(ff->tx_midi_substreams[substream->number]) = NULL;
  59
  60        spin_unlock_irqrestore(&ff->lock, flags);
  61}
  62
  63static void midi_playback_trigger(struct snd_rawmidi_substream *substream,
  64                                  int up)
  65{
  66        struct snd_ff *ff = substream->rmidi->private_data;
  67        unsigned long flags;
  68
  69        spin_lock_irqsave(&ff->lock, flags);
  70
  71        if (up || !ff->rx_midi_error[substream->number])
  72                schedule_work(&ff->rx_midi_work[substream->number]);
  73
  74        spin_unlock_irqrestore(&ff->lock, flags);
  75}
  76
  77static void set_midi_substream_names(struct snd_rawmidi_str *stream,
  78                                     const char *const name)
  79{
  80        struct snd_rawmidi_substream *substream;
  81
  82        list_for_each_entry(substream, &stream->substreams, list) {
  83                snprintf(substream->name, sizeof(substream->name),
  84                         "%s MIDI %d", name, substream->number + 1);
  85        }
  86}
  87
  88int snd_ff_create_midi_devices(struct snd_ff *ff)
  89{
  90        static const struct snd_rawmidi_ops midi_capture_ops = {
  91                .open           = midi_capture_open,
  92                .close          = midi_capture_close,
  93                .trigger        = midi_capture_trigger,
  94        };
  95        static const struct snd_rawmidi_ops midi_playback_ops = {
  96                .open           = midi_playback_open,
  97                .close          = midi_playback_close,
  98                .trigger        = midi_playback_trigger,
  99        };
 100        struct snd_rawmidi *rmidi;
 101        struct snd_rawmidi_str *stream;
 102        int err;
 103
 104        err = snd_rawmidi_new(ff->card, ff->card->driver, 0,
 105                              ff->spec->midi_out_ports, ff->spec->midi_in_ports,
 106                              &rmidi);
 107        if (err < 0)
 108                return err;
 109
 110        snprintf(rmidi->name, sizeof(rmidi->name),
 111                 "%s MIDI", ff->card->shortname);
 112        rmidi->private_data = ff;
 113
 114        rmidi->info_flags |= SNDRV_RAWMIDI_INFO_INPUT;
 115        snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT,
 116                            &midi_capture_ops);
 117        stream = &rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT];
 118        set_midi_substream_names(stream, ff->card->shortname);
 119
 120        rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT;
 121        snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT,
 122                            &midi_playback_ops);
 123        stream = &rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT];
 124        set_midi_substream_names(stream, ff->card->shortname);
 125
 126        rmidi->info_flags |= SNDRV_RAWMIDI_INFO_DUPLEX;
 127
 128        return 0;
 129}
 130