linux/sound/firewire/dice/dice-midi.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * dice_midi.c - a part of driver for Dice based devices
   4 *
   5 * Copyright (c) 2014 Takashi Sakamoto
   6 */
   7#include "dice.h"
   8
   9static int midi_open(struct snd_rawmidi_substream *substream)
  10{
  11        struct snd_dice *dice = substream->rmidi->private_data;
  12        int err;
  13
  14        err = snd_dice_stream_lock_try(dice);
  15        if (err < 0)
  16                return err;
  17
  18        mutex_lock(&dice->mutex);
  19
  20        err = snd_dice_stream_reserve_duplex(dice, 0);
  21        if (err >= 0) {
  22                ++dice->substreams_counter;
  23                err = snd_dice_stream_start_duplex(dice);
  24                if (err < 0)
  25                        --dice->substreams_counter;
  26        }
  27
  28        mutex_unlock(&dice->mutex);
  29
  30        if (err < 0)
  31                snd_dice_stream_lock_release(dice);
  32
  33        return err;
  34}
  35
  36static int midi_close(struct snd_rawmidi_substream *substream)
  37{
  38        struct snd_dice *dice = substream->rmidi->private_data;
  39
  40        mutex_lock(&dice->mutex);
  41
  42        --dice->substreams_counter;
  43        snd_dice_stream_stop_duplex(dice);
  44
  45        mutex_unlock(&dice->mutex);
  46
  47        snd_dice_stream_lock_release(dice);
  48        return 0;
  49}
  50
  51static void midi_capture_trigger(struct snd_rawmidi_substream *substrm, int up)
  52{
  53        struct snd_dice *dice = substrm->rmidi->private_data;
  54        unsigned long flags;
  55
  56        spin_lock_irqsave(&dice->lock, flags);
  57
  58        if (up)
  59                amdtp_am824_midi_trigger(&dice->tx_stream[0],
  60                                          substrm->number, substrm);
  61        else
  62                amdtp_am824_midi_trigger(&dice->tx_stream[0],
  63                                          substrm->number, NULL);
  64
  65        spin_unlock_irqrestore(&dice->lock, flags);
  66}
  67
  68static void midi_playback_trigger(struct snd_rawmidi_substream *substrm, int up)
  69{
  70        struct snd_dice *dice = substrm->rmidi->private_data;
  71        unsigned long flags;
  72
  73        spin_lock_irqsave(&dice->lock, flags);
  74
  75        if (up)
  76                amdtp_am824_midi_trigger(&dice->rx_stream[0],
  77                                         substrm->number, substrm);
  78        else
  79                amdtp_am824_midi_trigger(&dice->rx_stream[0],
  80                                         substrm->number, NULL);
  81
  82        spin_unlock_irqrestore(&dice->lock, flags);
  83}
  84
  85static void set_midi_substream_names(struct snd_dice *dice,
  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", dice->card->shortname, subs->number + 1);
  93        }
  94}
  95
  96int snd_dice_create_midi(struct snd_dice *dice)
  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        unsigned int midi_in_ports, midi_out_ports;
 111        int i;
 112        int err;
 113
 114        midi_in_ports = 0;
 115        midi_out_ports = 0;
 116        for (i = 0; i < MAX_STREAMS; ++i) {
 117                midi_in_ports = max(midi_in_ports, dice->tx_midi_ports[i]);
 118                midi_out_ports = max(midi_out_ports, dice->rx_midi_ports[i]);
 119        }
 120
 121        if (midi_in_ports + midi_out_ports == 0)
 122                return 0;
 123
 124        /* create midi ports */
 125        err = snd_rawmidi_new(dice->card, dice->card->driver, 0,
 126                              midi_out_ports, midi_in_ports,
 127                              &rmidi);
 128        if (err < 0)
 129                return err;
 130
 131        snprintf(rmidi->name, sizeof(rmidi->name),
 132                 "%s MIDI", dice->card->shortname);
 133        rmidi->private_data = dice;
 134
 135        if (midi_in_ports > 0) {
 136                rmidi->info_flags |= SNDRV_RAWMIDI_INFO_INPUT;
 137
 138                snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT,
 139                                    &capture_ops);
 140
 141                str = &rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT];
 142
 143                set_midi_substream_names(dice, str);
 144        }
 145
 146        if (midi_out_ports > 0) {
 147                rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT;
 148
 149                snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT,
 150                                    &playback_ops);
 151
 152                str = &rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT];
 153
 154                set_midi_substream_names(dice, str);
 155        }
 156
 157        if ((midi_out_ports > 0) && (midi_in_ports > 0))
 158                rmidi->info_flags |= SNDRV_RAWMIDI_INFO_DUPLEX;
 159
 160        return 0;
 161}
 162