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