linux/sound/firewire/oxfw/oxfw-midi.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * oxfw_midi.c - a part of driver for OXFW970/971 based devices
   4 *
   5 * Copyright (c) 2014 Takashi Sakamoto
   6 */
   7
   8#include "oxfw.h"
   9
  10static int midi_capture_open(struct snd_rawmidi_substream *substream)
  11{
  12        struct snd_oxfw *oxfw = substream->rmidi->private_data;
  13        int err;
  14
  15        err = snd_oxfw_stream_lock_try(oxfw);
  16        if (err < 0)
  17                return err;
  18
  19        mutex_lock(&oxfw->mutex);
  20
  21        err = snd_oxfw_stream_reserve_duplex(oxfw, &oxfw->tx_stream, 0, 0);
  22        if (err >= 0) {
  23                ++oxfw->substreams_count;
  24                err = snd_oxfw_stream_start_duplex(oxfw);
  25                if (err < 0)
  26                        --oxfw->substreams_count;
  27        }
  28
  29        mutex_unlock(&oxfw->mutex);
  30
  31        if (err < 0)
  32                snd_oxfw_stream_lock_release(oxfw);
  33
  34        return err;
  35}
  36
  37static int midi_playback_open(struct snd_rawmidi_substream *substream)
  38{
  39        struct snd_oxfw *oxfw = substream->rmidi->private_data;
  40        int err;
  41
  42        err = snd_oxfw_stream_lock_try(oxfw);
  43        if (err < 0)
  44                return err;
  45
  46        mutex_lock(&oxfw->mutex);
  47
  48        err = snd_oxfw_stream_reserve_duplex(oxfw, &oxfw->rx_stream, 0, 0);
  49        if (err >= 0) {
  50                ++oxfw->substreams_count;
  51                err = snd_oxfw_stream_start_duplex(oxfw);
  52        }
  53
  54        mutex_unlock(&oxfw->mutex);
  55
  56        if (err < 0)
  57                snd_oxfw_stream_lock_release(oxfw);
  58
  59        return err;
  60}
  61
  62static int midi_capture_close(struct snd_rawmidi_substream *substream)
  63{
  64        struct snd_oxfw *oxfw = substream->rmidi->private_data;
  65
  66        mutex_lock(&oxfw->mutex);
  67
  68        --oxfw->substreams_count;
  69        snd_oxfw_stream_stop_duplex(oxfw);
  70
  71        mutex_unlock(&oxfw->mutex);
  72
  73        snd_oxfw_stream_lock_release(oxfw);
  74        return 0;
  75}
  76
  77static int midi_playback_close(struct snd_rawmidi_substream *substream)
  78{
  79        struct snd_oxfw *oxfw = substream->rmidi->private_data;
  80
  81        mutex_lock(&oxfw->mutex);
  82
  83        --oxfw->substreams_count;
  84        snd_oxfw_stream_stop_duplex(oxfw);
  85
  86        mutex_unlock(&oxfw->mutex);
  87
  88        snd_oxfw_stream_lock_release(oxfw);
  89        return 0;
  90}
  91
  92static void midi_capture_trigger(struct snd_rawmidi_substream *substrm, int up)
  93{
  94        struct snd_oxfw *oxfw = substrm->rmidi->private_data;
  95        unsigned long flags;
  96
  97        spin_lock_irqsave(&oxfw->lock, flags);
  98
  99        if (up)
 100                amdtp_am824_midi_trigger(&oxfw->tx_stream,
 101                                         substrm->number, substrm);
 102        else
 103                amdtp_am824_midi_trigger(&oxfw->tx_stream,
 104                                         substrm->number, NULL);
 105
 106        spin_unlock_irqrestore(&oxfw->lock, flags);
 107}
 108
 109static void midi_playback_trigger(struct snd_rawmidi_substream *substrm, int up)
 110{
 111        struct snd_oxfw *oxfw = substrm->rmidi->private_data;
 112        unsigned long flags;
 113
 114        spin_lock_irqsave(&oxfw->lock, flags);
 115
 116        if (up)
 117                amdtp_am824_midi_trigger(&oxfw->rx_stream,
 118                                         substrm->number, substrm);
 119        else
 120                amdtp_am824_midi_trigger(&oxfw->rx_stream,
 121                                         substrm->number, NULL);
 122
 123        spin_unlock_irqrestore(&oxfw->lock, flags);
 124}
 125
 126static void set_midi_substream_names(struct snd_oxfw *oxfw,
 127                                     struct snd_rawmidi_str *str)
 128{
 129        struct snd_rawmidi_substream *subs;
 130
 131        list_for_each_entry(subs, &str->substreams, list) {
 132                snprintf(subs->name, sizeof(subs->name),
 133                         "%s MIDI %d",
 134                         oxfw->card->shortname, subs->number + 1);
 135        }
 136}
 137
 138int snd_oxfw_create_midi(struct snd_oxfw *oxfw)
 139{
 140        static const struct snd_rawmidi_ops capture_ops = {
 141                .open           = midi_capture_open,
 142                .close          = midi_capture_close,
 143                .trigger        = midi_capture_trigger,
 144        };
 145        static const struct snd_rawmidi_ops playback_ops = {
 146                .open           = midi_playback_open,
 147                .close          = midi_playback_close,
 148                .trigger        = midi_playback_trigger,
 149        };
 150        struct snd_rawmidi *rmidi;
 151        struct snd_rawmidi_str *str;
 152        int err;
 153
 154        if (oxfw->midi_input_ports == 0 && oxfw->midi_output_ports == 0)
 155                return 0;
 156
 157        /* create midi ports */
 158        err = snd_rawmidi_new(oxfw->card, oxfw->card->driver, 0,
 159                              oxfw->midi_output_ports, oxfw->midi_input_ports,
 160                              &rmidi);
 161        if (err < 0)
 162                return err;
 163
 164        snprintf(rmidi->name, sizeof(rmidi->name),
 165                 "%s MIDI", oxfw->card->shortname);
 166        rmidi->private_data = oxfw;
 167
 168        if (oxfw->midi_input_ports > 0) {
 169                rmidi->info_flags |= SNDRV_RAWMIDI_INFO_INPUT;
 170
 171                snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT,
 172                                    &capture_ops);
 173
 174                str = &rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT];
 175
 176                set_midi_substream_names(oxfw, str);
 177        }
 178
 179        if (oxfw->midi_output_ports > 0) {
 180                rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT;
 181
 182                snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT,
 183                                    &playback_ops);
 184
 185                str = &rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT];
 186
 187                set_midi_substream_names(oxfw, str);
 188        }
 189
 190        if ((oxfw->midi_output_ports > 0) && (oxfw->midi_input_ports > 0))
 191                rmidi->info_flags |= SNDRV_RAWMIDI_INFO_DUPLEX;
 192
 193        return 0;
 194}
 195