Path: blob/master/sound/firewire/digi00x/digi00x-midi.c
29266 views
// SPDX-License-Identifier: GPL-2.0-only1/*2* digi00x-midi.h - a part of driver for Digidesign Digi 002/003 family3*4* Copyright (c) 2014-2015 Takashi Sakamoto5*/67#include "digi00x.h"89static int midi_open(struct snd_rawmidi_substream *substream)10{11struct snd_dg00x *dg00x = substream->rmidi->private_data;12int err;1314err = snd_dg00x_stream_lock_try(dg00x);15if (err < 0)16return err;1718scoped_guard(mutex, &dg00x->mutex) {19err = snd_dg00x_stream_reserve_duplex(dg00x, 0, 0, 0);20if (err >= 0) {21++dg00x->substreams_counter;22err = snd_dg00x_stream_start_duplex(dg00x);23if (err < 0)24--dg00x->substreams_counter;25}26}27if (err < 0)28snd_dg00x_stream_lock_release(dg00x);2930return err;31}3233static int midi_close(struct snd_rawmidi_substream *substream)34{35struct snd_dg00x *dg00x = substream->rmidi->private_data;3637scoped_guard(mutex, &dg00x->mutex) {38--dg00x->substreams_counter;39snd_dg00x_stream_stop_duplex(dg00x);40}4142snd_dg00x_stream_lock_release(dg00x);43return 0;44}4546static void midi_capture_trigger(struct snd_rawmidi_substream *substream,47int up)48{49struct snd_dg00x *dg00x = substream->rmidi->private_data;50unsigned int port;5152if (substream->rmidi->device == 0)53port = substream->number;54else55port = 2;5657guard(spinlock_irqsave)(&dg00x->lock);5859if (up)60amdtp_dot_midi_trigger(&dg00x->tx_stream, port, substream);61else62amdtp_dot_midi_trigger(&dg00x->tx_stream, port, NULL);63}6465static void midi_playback_trigger(struct snd_rawmidi_substream *substream,66int up)67{68struct snd_dg00x *dg00x = substream->rmidi->private_data;69unsigned int port;7071if (substream->rmidi->device == 0)72port = substream->number;73else74port = 2;7576guard(spinlock_irqsave)(&dg00x->lock);7778if (up)79amdtp_dot_midi_trigger(&dg00x->rx_stream, port, substream);80else81amdtp_dot_midi_trigger(&dg00x->rx_stream, port, NULL);82}8384static void set_substream_names(struct snd_dg00x *dg00x,85struct snd_rawmidi *rmidi, bool is_console)86{87struct snd_rawmidi_substream *subs;88struct snd_rawmidi_str *str;89int i;9091for (i = 0; i < 2; ++i) {92str = &rmidi->streams[i];9394list_for_each_entry(subs, &str->substreams, list) {95if (!is_console) {96scnprintf(subs->name, sizeof(subs->name),97"%s MIDI %d",98dg00x->card->shortname,99subs->number + 1);100} else {101scnprintf(subs->name, sizeof(subs->name),102"%s control",103dg00x->card->shortname);104}105}106}107}108109static int add_substream_pair(struct snd_dg00x *dg00x, unsigned int out_ports,110unsigned int in_ports, bool is_console)111{112static const struct snd_rawmidi_ops capture_ops = {113.open = midi_open,114.close = midi_close,115.trigger = midi_capture_trigger,116};117static const struct snd_rawmidi_ops playback_ops = {118.open = midi_open,119.close = midi_close,120.trigger = midi_playback_trigger,121};122const char *label;123struct snd_rawmidi *rmidi;124int err;125126/* Add physical midi ports. */127err = snd_rawmidi_new(dg00x->card, dg00x->card->driver, is_console,128out_ports, in_ports, &rmidi);129if (err < 0)130return err;131rmidi->private_data = dg00x;132133if (!is_console)134label = "%s control";135else136label = "%s MIDI";137snprintf(rmidi->name, sizeof(rmidi->name), label,138dg00x->card->shortname);139140snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, &playback_ops);141snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, &capture_ops);142143rmidi->info_flags |= SNDRV_RAWMIDI_INFO_INPUT |144SNDRV_RAWMIDI_INFO_OUTPUT |145SNDRV_RAWMIDI_INFO_DUPLEX;146147set_substream_names(dg00x, rmidi, is_console);148149return 0;150}151152int snd_dg00x_create_midi_devices(struct snd_dg00x *dg00x)153{154int err;155156/* Add physical midi ports. */157err = add_substream_pair(dg00x, DOT_MIDI_OUT_PORTS, DOT_MIDI_IN_PORTS,158false);159if (err < 0)160return err;161162if (dg00x->is_console)163err = add_substream_pair(dg00x, 1, 1, true);164165return err;166}167168169