1da607e19SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 205588d34STakashi Sakamoto /* 305588d34STakashi Sakamoto * oxfw_midi.c - a part of driver for OXFW970/971 based devices 405588d34STakashi Sakamoto * 505588d34STakashi Sakamoto * Copyright (c) 2014 Takashi Sakamoto 605588d34STakashi Sakamoto */ 705588d34STakashi Sakamoto 805588d34STakashi Sakamoto #include "oxfw.h" 905588d34STakashi Sakamoto 1005588d34STakashi Sakamoto static int midi_capture_open(struct snd_rawmidi_substream *substream) 1105588d34STakashi Sakamoto { 1205588d34STakashi Sakamoto struct snd_oxfw *oxfw = substream->rmidi->private_data; 1305588d34STakashi Sakamoto int err; 1405588d34STakashi Sakamoto 158985f4acSTakashi Sakamoto err = snd_oxfw_stream_lock_try(oxfw); 168985f4acSTakashi Sakamoto if (err < 0) 178985f4acSTakashi Sakamoto return err; 188985f4acSTakashi Sakamoto 1905588d34STakashi Sakamoto mutex_lock(&oxfw->mutex); 2005588d34STakashi Sakamoto 213299d2a0STakashi Sakamoto err = snd_oxfw_stream_reserve_duplex(oxfw, &oxfw->tx_stream, 0, 0, 0, 0); 224f380d00STakashi Sakamoto if (err >= 0) { 234a0a0472STakashi Sakamoto ++oxfw->substreams_count; 244f380d00STakashi Sakamoto err = snd_oxfw_stream_start_duplex(oxfw); 2503a954aeSTakashi Sakamoto if (err < 0) 2603a954aeSTakashi Sakamoto --oxfw->substreams_count; 274f380d00STakashi Sakamoto } 2805588d34STakashi Sakamoto 2905588d34STakashi Sakamoto mutex_unlock(&oxfw->mutex); 3005588d34STakashi Sakamoto 318985f4acSTakashi Sakamoto if (err < 0) 328985f4acSTakashi Sakamoto snd_oxfw_stream_lock_release(oxfw); 338985f4acSTakashi Sakamoto 3405588d34STakashi Sakamoto return err; 3505588d34STakashi Sakamoto } 3605588d34STakashi Sakamoto 3705588d34STakashi Sakamoto static int midi_playback_open(struct snd_rawmidi_substream *substream) 3805588d34STakashi Sakamoto { 3905588d34STakashi Sakamoto struct snd_oxfw *oxfw = substream->rmidi->private_data; 4005588d34STakashi Sakamoto int err; 4105588d34STakashi Sakamoto 428985f4acSTakashi Sakamoto err = snd_oxfw_stream_lock_try(oxfw); 438985f4acSTakashi Sakamoto if (err < 0) 448985f4acSTakashi Sakamoto return err; 458985f4acSTakashi Sakamoto 4605588d34STakashi Sakamoto mutex_lock(&oxfw->mutex); 4705588d34STakashi Sakamoto 483299d2a0STakashi Sakamoto err = snd_oxfw_stream_reserve_duplex(oxfw, &oxfw->rx_stream, 0, 0, 0, 0); 494f380d00STakashi Sakamoto if (err >= 0) { 504a0a0472STakashi Sakamoto ++oxfw->substreams_count; 514f380d00STakashi Sakamoto err = snd_oxfw_stream_start_duplex(oxfw); 524f380d00STakashi Sakamoto } 5305588d34STakashi Sakamoto 5405588d34STakashi Sakamoto mutex_unlock(&oxfw->mutex); 5505588d34STakashi Sakamoto 568985f4acSTakashi Sakamoto if (err < 0) 578985f4acSTakashi Sakamoto snd_oxfw_stream_lock_release(oxfw); 588985f4acSTakashi Sakamoto 5905588d34STakashi Sakamoto return err; 6005588d34STakashi Sakamoto } 6105588d34STakashi Sakamoto 6205588d34STakashi Sakamoto static int midi_capture_close(struct snd_rawmidi_substream *substream) 6305588d34STakashi Sakamoto { 6405588d34STakashi Sakamoto struct snd_oxfw *oxfw = substream->rmidi->private_data; 6505588d34STakashi Sakamoto 6605588d34STakashi Sakamoto mutex_lock(&oxfw->mutex); 6705588d34STakashi Sakamoto 684a0a0472STakashi Sakamoto --oxfw->substreams_count; 69779f0dbaSTakashi Sakamoto snd_oxfw_stream_stop_duplex(oxfw); 7005588d34STakashi Sakamoto 7105588d34STakashi Sakamoto mutex_unlock(&oxfw->mutex); 7205588d34STakashi Sakamoto 738985f4acSTakashi Sakamoto snd_oxfw_stream_lock_release(oxfw); 7405588d34STakashi Sakamoto return 0; 7505588d34STakashi Sakamoto } 7605588d34STakashi Sakamoto 7705588d34STakashi Sakamoto static int midi_playback_close(struct snd_rawmidi_substream *substream) 7805588d34STakashi Sakamoto { 7905588d34STakashi Sakamoto struct snd_oxfw *oxfw = substream->rmidi->private_data; 8005588d34STakashi Sakamoto 8105588d34STakashi Sakamoto mutex_lock(&oxfw->mutex); 8205588d34STakashi Sakamoto 834a0a0472STakashi Sakamoto --oxfw->substreams_count; 84779f0dbaSTakashi Sakamoto snd_oxfw_stream_stop_duplex(oxfw); 8505588d34STakashi Sakamoto 8605588d34STakashi Sakamoto mutex_unlock(&oxfw->mutex); 8705588d34STakashi Sakamoto 888985f4acSTakashi Sakamoto snd_oxfw_stream_lock_release(oxfw); 8905588d34STakashi Sakamoto return 0; 9005588d34STakashi Sakamoto } 9105588d34STakashi Sakamoto 9205588d34STakashi Sakamoto static void midi_capture_trigger(struct snd_rawmidi_substream *substrm, int up) 9305588d34STakashi Sakamoto { 9405588d34STakashi Sakamoto struct snd_oxfw *oxfw = substrm->rmidi->private_data; 9505588d34STakashi Sakamoto unsigned long flags; 9605588d34STakashi Sakamoto 9705588d34STakashi Sakamoto spin_lock_irqsave(&oxfw->lock, flags); 9805588d34STakashi Sakamoto 9905588d34STakashi Sakamoto if (up) 10003e2a67eSTakashi Sakamoto amdtp_am824_midi_trigger(&oxfw->tx_stream, 10105588d34STakashi Sakamoto substrm->number, substrm); 10205588d34STakashi Sakamoto else 10303e2a67eSTakashi Sakamoto amdtp_am824_midi_trigger(&oxfw->tx_stream, 10405588d34STakashi Sakamoto substrm->number, NULL); 10505588d34STakashi Sakamoto 10605588d34STakashi Sakamoto spin_unlock_irqrestore(&oxfw->lock, flags); 10705588d34STakashi Sakamoto } 10805588d34STakashi Sakamoto 10905588d34STakashi Sakamoto static void midi_playback_trigger(struct snd_rawmidi_substream *substrm, int up) 11005588d34STakashi Sakamoto { 11105588d34STakashi Sakamoto struct snd_oxfw *oxfw = substrm->rmidi->private_data; 11205588d34STakashi Sakamoto unsigned long flags; 11305588d34STakashi Sakamoto 11405588d34STakashi Sakamoto spin_lock_irqsave(&oxfw->lock, flags); 11505588d34STakashi Sakamoto 11605588d34STakashi Sakamoto if (up) 11703e2a67eSTakashi Sakamoto amdtp_am824_midi_trigger(&oxfw->rx_stream, 11805588d34STakashi Sakamoto substrm->number, substrm); 11905588d34STakashi Sakamoto else 12003e2a67eSTakashi Sakamoto amdtp_am824_midi_trigger(&oxfw->rx_stream, 12105588d34STakashi Sakamoto substrm->number, NULL); 12205588d34STakashi Sakamoto 12305588d34STakashi Sakamoto spin_unlock_irqrestore(&oxfw->lock, flags); 12405588d34STakashi Sakamoto } 12505588d34STakashi Sakamoto 12605588d34STakashi Sakamoto static void set_midi_substream_names(struct snd_oxfw *oxfw, 12705588d34STakashi Sakamoto struct snd_rawmidi_str *str) 12805588d34STakashi Sakamoto { 12905588d34STakashi Sakamoto struct snd_rawmidi_substream *subs; 13005588d34STakashi Sakamoto 13105588d34STakashi Sakamoto list_for_each_entry(subs, &str->substreams, list) { 13205588d34STakashi Sakamoto snprintf(subs->name, sizeof(subs->name), 13305588d34STakashi Sakamoto "%s MIDI %d", 13405588d34STakashi Sakamoto oxfw->card->shortname, subs->number + 1); 13505588d34STakashi Sakamoto } 13605588d34STakashi Sakamoto } 13705588d34STakashi Sakamoto 13805588d34STakashi Sakamoto int snd_oxfw_create_midi(struct snd_oxfw *oxfw) 13905588d34STakashi Sakamoto { 14057eb6799STakashi Iwai static const struct snd_rawmidi_ops capture_ops = { 14139feaf2dSTakashi Sakamoto .open = midi_capture_open, 14239feaf2dSTakashi Sakamoto .close = midi_capture_close, 14339feaf2dSTakashi Sakamoto .trigger = midi_capture_trigger, 14439feaf2dSTakashi Sakamoto }; 14557eb6799STakashi Iwai static const struct snd_rawmidi_ops playback_ops = { 14639feaf2dSTakashi Sakamoto .open = midi_playback_open, 14739feaf2dSTakashi Sakamoto .close = midi_playback_close, 14839feaf2dSTakashi Sakamoto .trigger = midi_playback_trigger, 14939feaf2dSTakashi Sakamoto }; 15005588d34STakashi Sakamoto struct snd_rawmidi *rmidi; 15105588d34STakashi Sakamoto struct snd_rawmidi_str *str; 15232056041STakashi Sakamoto int err; 15305588d34STakashi Sakamoto 15432056041STakashi Sakamoto if (oxfw->midi_input_ports == 0 && oxfw->midi_output_ports == 0) 15505588d34STakashi Sakamoto return 0; 15605588d34STakashi Sakamoto 15705588d34STakashi Sakamoto /* create midi ports */ 15805588d34STakashi Sakamoto err = snd_rawmidi_new(oxfw->card, oxfw->card->driver, 0, 15905588d34STakashi Sakamoto oxfw->midi_output_ports, oxfw->midi_input_ports, 16005588d34STakashi Sakamoto &rmidi); 16105588d34STakashi Sakamoto if (err < 0) 16205588d34STakashi Sakamoto return err; 16305588d34STakashi Sakamoto 16405588d34STakashi Sakamoto snprintf(rmidi->name, sizeof(rmidi->name), 16505588d34STakashi Sakamoto "%s MIDI", oxfw->card->shortname); 16605588d34STakashi Sakamoto rmidi->private_data = oxfw; 16705588d34STakashi Sakamoto 16805588d34STakashi Sakamoto if (oxfw->midi_input_ports > 0) { 16905588d34STakashi Sakamoto rmidi->info_flags |= SNDRV_RAWMIDI_INFO_INPUT; 17005588d34STakashi Sakamoto 17105588d34STakashi Sakamoto snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, 17239feaf2dSTakashi Sakamoto &capture_ops); 17305588d34STakashi Sakamoto 17405588d34STakashi Sakamoto str = &rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT]; 17505588d34STakashi Sakamoto 17605588d34STakashi Sakamoto set_midi_substream_names(oxfw, str); 17705588d34STakashi Sakamoto } 17805588d34STakashi Sakamoto 17905588d34STakashi Sakamoto if (oxfw->midi_output_ports > 0) { 18005588d34STakashi Sakamoto rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT; 18105588d34STakashi Sakamoto 18205588d34STakashi Sakamoto snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, 18339feaf2dSTakashi Sakamoto &playback_ops); 18405588d34STakashi Sakamoto 18505588d34STakashi Sakamoto str = &rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT]; 18605588d34STakashi Sakamoto 18705588d34STakashi Sakamoto set_midi_substream_names(oxfw, str); 18805588d34STakashi Sakamoto } 18905588d34STakashi Sakamoto 19005588d34STakashi Sakamoto if ((oxfw->midi_output_ports > 0) && (oxfw->midi_input_ports > 0)) 19105588d34STakashi Sakamoto rmidi->info_flags |= SNDRV_RAWMIDI_INFO_DUPLEX; 19205588d34STakashi Sakamoto 19305588d34STakashi Sakamoto return 0; 19405588d34STakashi Sakamoto } 195