linux/sound/firewire/motu/motu-midi.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * motu-midi.h - a part of driver for MOTU FireWire series
   4 *
   5 * Copyright (c) 2015-2017 Takashi Sakamoto <o-takashi@sakamocchi.jp>
   6 */
   7#include "motu.h"
   8
   9static int midi_open(struct snd_rawmidi_substream *substream)
  10{
  11        struct snd_motu *motu = substream->rmidi->private_data;
  12        int err;
  13
  14        err = snd_motu_stream_lock_try(motu);
  15        if (err < 0)
  16                return err;
  17
  18        mutex_lock(&motu->mutex);
  19
  20        err = snd_motu_stream_reserve_duplex(motu, 0);
  21        if (err >= 0) {
  22                ++motu->substreams_counter;
  23                err = snd_motu_stream_start_duplex(motu);
  24                if (err < 0)
  25                        --motu->substreams_counter;
  26        }
  27
  28        mutex_unlock(&motu->mutex);
  29
  30        if (err < 0)
  31                snd_motu_stream_lock_release(motu);
  32
  33        return err;
  34}
  35
  36static int midi_close(struct snd_rawmidi_substream *substream)
  37{
  38        struct snd_motu *motu = substream->rmidi->private_data;
  39
  40        mutex_lock(&motu->mutex);
  41
  42        --motu->substreams_counter;
  43        snd_motu_stream_stop_duplex(motu);
  44
  45        mutex_unlock(&motu->mutex);
  46
  47        snd_motu_stream_lock_release(motu);
  48        return 0;
  49}
  50
  51static void midi_capture_trigger(struct snd_rawmidi_substream *substrm, int up)
  52{
  53        struct snd_motu *motu = substrm->rmidi->private_data;
  54        unsigned long flags;
  55
  56        spin_lock_irqsave(&motu->lock, flags);
  57
  58        if (up)
  59                amdtp_motu_midi_trigger(&motu->tx_stream, substrm->number,
  60                                        substrm);
  61        else
  62                amdtp_motu_midi_trigger(&motu->tx_stream, substrm->number,
  63                                        NULL);
  64
  65        spin_unlock_irqrestore(&motu->lock, flags);
  66}
  67
  68static void midi_playback_trigger(struct snd_rawmidi_substream *substrm, int up)
  69{
  70        struct snd_motu *motu = substrm->rmidi->private_data;
  71        unsigned long flags;
  72
  73        spin_lock_irqsave(&motu->lock, flags);
  74
  75        if (up)
  76                amdtp_motu_midi_trigger(&motu->rx_stream, substrm->number,
  77                                        substrm);
  78        else
  79                amdtp_motu_midi_trigger(&motu->rx_stream, substrm->number,
  80                                        NULL);
  81
  82        spin_unlock_irqrestore(&motu->lock, flags);
  83}
  84
  85static void set_midi_substream_names(struct snd_motu *motu,
  86                                     struct snd_rawmidi_str *str)
  87{
  88        struct snd_rawmidi_substream *subs;
  89
  90        list_for_each_entry(subs, &str->substreams, list) {
  91                snprintf(subs->name, sizeof(subs->name),
  92                         "%s MIDI %d", motu->card->shortname, subs->number + 1);
  93        }
  94}
  95
  96int snd_motu_create_midi_devices(struct snd_motu *motu)
  97{
  98        static const struct snd_rawmidi_ops capture_ops = {
  99                .open           = midi_open,
 100                .close          = midi_close,
 101                .trigger        = midi_capture_trigger,
 102        };
 103        static const struct snd_rawmidi_ops playback_ops = {
 104                .open           = midi_open,
 105                .close          = midi_close,
 106                .trigger        = midi_playback_trigger,
 107        };
 108        struct snd_rawmidi *rmidi;
 109        struct snd_rawmidi_str *str;
 110        int err;
 111
 112        /* create midi ports */
 113        err = snd_rawmidi_new(motu->card, motu->card->driver, 0, 1, 1, &rmidi);
 114        if (err < 0)
 115                return err;
 116
 117        snprintf(rmidi->name, sizeof(rmidi->name),
 118                 "%s MIDI", motu->card->shortname);
 119        rmidi->private_data = motu;
 120
 121        rmidi->info_flags |= SNDRV_RAWMIDI_INFO_INPUT |
 122                             SNDRV_RAWMIDI_INFO_OUTPUT |
 123                             SNDRV_RAWMIDI_INFO_DUPLEX;
 124
 125        snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT,
 126                            &capture_ops);
 127        str = &rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT];
 128        set_midi_substream_names(motu, str);
 129
 130        snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT,
 131                            &playback_ops);
 132        str = &rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT];
 133        set_midi_substream_names(motu, str);
 134
 135        return 0;
 136}
 137