File Index
Files and directories
Sign in
FILE

digi00x-midi.c

File preview with syntax highlighting.

linux-6.19.14/sound/firewire/digi00x/digi00x-midi.c C
  1// SPDX-License-Identifier: GPL-2.0-only
  2/*
  3 * digi00x-midi.h - a part of driver for Digidesign Digi 002/003 family
  4 *
  5 * Copyright (c) 2014-2015 Takashi Sakamoto
  6 */
  7
  8#include "digi00x.h"
  9
 10static int midi_open(struct snd_rawmidi_substream *substream)
 11{
 12	struct snd_dg00x *dg00x = substream->rmidi->private_data;
 13	int err;
 14
 15	err = snd_dg00x_stream_lock_try(dg00x);
 16	if (err < 0)
 17		return err;
 18
 19	scoped_guard(mutex, &dg00x->mutex) {
 20		err = snd_dg00x_stream_reserve_duplex(dg00x, 0, 0, 0);
 21		if (err >= 0) {
 22			++dg00x->substreams_counter;
 23			err = snd_dg00x_stream_start_duplex(dg00x);
 24			if (err < 0)
 25				--dg00x->substreams_counter;
 26		}
 27	}
 28	if (err < 0)
 29		snd_dg00x_stream_lock_release(dg00x);
 30
 31	return err;
 32}
 33
 34static int midi_close(struct snd_rawmidi_substream *substream)
 35{
 36	struct snd_dg00x *dg00x = substream->rmidi->private_data;
 37
 38	scoped_guard(mutex, &dg00x->mutex) {
 39		--dg00x->substreams_counter;
 40		snd_dg00x_stream_stop_duplex(dg00x);
 41	}
 42
 43	snd_dg00x_stream_lock_release(dg00x);
 44	return 0;
 45}
 46
 47static void midi_capture_trigger(struct snd_rawmidi_substream *substream,
 48				 int up)
 49{
 50	struct snd_dg00x *dg00x = substream->rmidi->private_data;
 51	unsigned int port;
 52
 53	if (substream->rmidi->device == 0)
 54		port = substream->number;
 55	else
 56		port = 2;
 57
 58	guard(spinlock_irqsave)(&dg00x->lock);
 59
 60	if (up)
 61		amdtp_dot_midi_trigger(&dg00x->tx_stream, port, substream);
 62	else
 63		amdtp_dot_midi_trigger(&dg00x->tx_stream, port, NULL);
 64}
 65
 66static void midi_playback_trigger(struct snd_rawmidi_substream *substream,
 67				  int up)
 68{
 69	struct snd_dg00x *dg00x = substream->rmidi->private_data;
 70	unsigned int port;
 71
 72	if (substream->rmidi->device == 0)
 73		port = substream->number;
 74	else
 75		port = 2;
 76
 77	guard(spinlock_irqsave)(&dg00x->lock);
 78
 79	if (up)
 80		amdtp_dot_midi_trigger(&dg00x->rx_stream, port, substream);
 81	else
 82		amdtp_dot_midi_trigger(&dg00x->rx_stream, port, NULL);
 83}
 84
 85static void set_substream_names(struct snd_dg00x *dg00x,
 86				struct snd_rawmidi *rmidi, bool is_console)
 87{
 88	struct snd_rawmidi_substream *subs;
 89	struct snd_rawmidi_str *str;
 90	int i;
 91
 92	for (i = 0; i < 2; ++i) {
 93		str = &rmidi->streams[i];
 94
 95		list_for_each_entry(subs, &str->substreams, list) {
 96			if (!is_console) {
 97				scnprintf(subs->name, sizeof(subs->name),
 98					  "%s MIDI %d",
 99					  dg00x->card->shortname,
100					  subs->number + 1);
101			} else {
102				scnprintf(subs->name, sizeof(subs->name),
103					  "%s control",
104					  dg00x->card->shortname);
105			}
106		}
107	}
108}
109
110static int add_substream_pair(struct snd_dg00x *dg00x, unsigned int out_ports,
111			      unsigned int in_ports, bool is_console)
112{
113	static const struct snd_rawmidi_ops capture_ops = {
114		.open = midi_open,
115		.close = midi_close,
116		.trigger = midi_capture_trigger,
117	};
118	static const struct snd_rawmidi_ops playback_ops = {
119		.open = midi_open,
120		.close = midi_close,
121		.trigger = midi_playback_trigger,
122	};
123	const char *label;
124	struct snd_rawmidi *rmidi;
125	int err;
126
127	/* Add physical midi ports. */
128	err = snd_rawmidi_new(dg00x->card, dg00x->card->driver, is_console,
129			      out_ports, in_ports, &rmidi);
130	if (err < 0)
131		return err;
132	rmidi->private_data = dg00x;
133
134	if (!is_console)
135		label = "%s control";
136	else
137		label = "%s MIDI";
138	snprintf(rmidi->name, sizeof(rmidi->name), label,
139		 dg00x->card->shortname);
140
141	snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, &playback_ops);
142	snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, &capture_ops);
143
144	rmidi->info_flags |= SNDRV_RAWMIDI_INFO_INPUT |
145			     SNDRV_RAWMIDI_INFO_OUTPUT |
146			     SNDRV_RAWMIDI_INFO_DUPLEX;
147
148	set_substream_names(dg00x, rmidi, is_console);
149
150	return 0;
151}
152
153int snd_dg00x_create_midi_devices(struct snd_dg00x *dg00x)
154{
155	int err;
156
157	/* Add physical midi ports. */
158	err = add_substream_pair(dg00x, DOT_MIDI_OUT_PORTS, DOT_MIDI_IN_PORTS,
159				 false);
160	if (err < 0)
161		return err;
162
163	if (dg00x->is_console)
164		err = add_substream_pair(dg00x, 1, 1, true);
165
166	return err;
167}
~/ Read-only file preview.