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