162 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * dice_midi.c - a part of driver for Dice based devices4 *5 * Copyright (c) 2014 Takashi Sakamoto6 */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, 0, 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 else62 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 else79 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 scnprintf(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