^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * tascam-midi.c - a part of driver for TASCAM FireWire series
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Copyright (c) 2015 Takashi Sakamoto
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) #include "tascam.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) static int midi_capture_open(struct snd_rawmidi_substream *substream)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) /* Do nothing. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) static int midi_playback_open(struct snd_rawmidi_substream *substream)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) struct snd_tscm *tscm = substream->rmidi->private_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) snd_fw_async_midi_port_init(&tscm->out_ports[substream->number]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) static int midi_capture_close(struct snd_rawmidi_substream *substream)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) /* Do nothing. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) static int midi_playback_close(struct snd_rawmidi_substream *substream)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) static void midi_playback_drain(struct snd_rawmidi_substream *substream)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) struct snd_tscm *tscm = substream->rmidi->private_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) snd_fw_async_midi_port_finish(&tscm->out_ports[substream->number]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) static void midi_capture_trigger(struct snd_rawmidi_substream *substrm, int up)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) struct snd_tscm *tscm = substrm->rmidi->private_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) spin_lock_irqsave(&tscm->lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) if (up)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) tscm->tx_midi_substreams[substrm->number] = substrm;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) tscm->tx_midi_substreams[substrm->number] = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) spin_unlock_irqrestore(&tscm->lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) static void midi_playback_trigger(struct snd_rawmidi_substream *substrm, int up)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) struct snd_tscm *tscm = substrm->rmidi->private_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) spin_lock_irqsave(&tscm->lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) if (up)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) snd_fw_async_midi_port_run(&tscm->out_ports[substrm->number],
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) substrm);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) spin_unlock_irqrestore(&tscm->lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) int snd_tscm_create_midi_devices(struct snd_tscm *tscm)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) static const struct snd_rawmidi_ops capture_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) .open = midi_capture_open,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) .close = midi_capture_close,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) .trigger = midi_capture_trigger,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) static const struct snd_rawmidi_ops playback_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) .open = midi_playback_open,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) .close = midi_playback_close,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) .drain = midi_playback_drain,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) .trigger = midi_playback_trigger,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) struct snd_rawmidi *rmidi;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) struct snd_rawmidi_str *stream;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) struct snd_rawmidi_substream *subs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) err = snd_rawmidi_new(tscm->card, tscm->card->driver, 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) tscm->spec->midi_playback_ports,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) tscm->spec->midi_capture_ports,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) &rmidi);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) if (err < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) snprintf(rmidi->name, sizeof(rmidi->name),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) "%s MIDI", tscm->card->shortname);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) rmidi->private_data = tscm;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) rmidi->info_flags |= SNDRV_RAWMIDI_INFO_INPUT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) &capture_ops);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) stream = &rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) /* Set port names for MIDI input. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) list_for_each_entry(subs, &stream->substreams, list) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) /* TODO: support virtual MIDI ports. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) if (subs->number < tscm->spec->midi_capture_ports) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) /* Hardware MIDI ports. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) snprintf(subs->name, sizeof(subs->name),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) "%s MIDI %d",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) tscm->card->shortname, subs->number + 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) &playback_ops);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) stream = &rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) /* Set port names for MIDI ourput. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) list_for_each_entry(subs, &stream->substreams, list) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) if (subs->number < tscm->spec->midi_playback_ports) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) /* Hardware MIDI ports only. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) snprintf(subs->name, sizeof(subs->name),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) "%s MIDI %d",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) tscm->card->shortname, subs->number + 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) rmidi->info_flags |= SNDRV_RAWMIDI_INFO_DUPLEX;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) }