Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * digi00x-midi.h - a part of driver for Digidesign Digi 002/003 family
0004  *
0005  * Copyright (c) 2014-2015 Takashi Sakamoto
0006  */
0007 
0008 #include "digi00x.h"
0009 
0010 static int midi_open(struct snd_rawmidi_substream *substream)
0011 {
0012     struct snd_dg00x *dg00x = substream->rmidi->private_data;
0013     int err;
0014 
0015     err = snd_dg00x_stream_lock_try(dg00x);
0016     if (err < 0)
0017         return err;
0018 
0019     mutex_lock(&dg00x->mutex);
0020     err = snd_dg00x_stream_reserve_duplex(dg00x, 0, 0, 0);
0021     if (err >= 0) {
0022         ++dg00x->substreams_counter;
0023         err = snd_dg00x_stream_start_duplex(dg00x);
0024         if (err < 0)
0025             --dg00x->substreams_counter;
0026     }
0027     mutex_unlock(&dg00x->mutex);
0028     if (err < 0)
0029         snd_dg00x_stream_lock_release(dg00x);
0030 
0031     return err;
0032 }
0033 
0034 static int midi_close(struct snd_rawmidi_substream *substream)
0035 {
0036     struct snd_dg00x *dg00x = substream->rmidi->private_data;
0037 
0038     mutex_lock(&dg00x->mutex);
0039     --dg00x->substreams_counter;
0040     snd_dg00x_stream_stop_duplex(dg00x);
0041     mutex_unlock(&dg00x->mutex);
0042 
0043     snd_dg00x_stream_lock_release(dg00x);
0044     return 0;
0045 }
0046 
0047 static void midi_capture_trigger(struct snd_rawmidi_substream *substream,
0048                  int up)
0049 {
0050     struct snd_dg00x *dg00x = substream->rmidi->private_data;
0051     unsigned int port;
0052     unsigned long flags;
0053 
0054     if (substream->rmidi->device == 0)
0055         port = substream->number;
0056     else
0057         port = 2;
0058 
0059     spin_lock_irqsave(&dg00x->lock, flags);
0060 
0061     if (up)
0062         amdtp_dot_midi_trigger(&dg00x->tx_stream, port, substream);
0063     else
0064         amdtp_dot_midi_trigger(&dg00x->tx_stream, port, NULL);
0065 
0066     spin_unlock_irqrestore(&dg00x->lock, flags);
0067 }
0068 
0069 static void midi_playback_trigger(struct snd_rawmidi_substream *substream,
0070                   int up)
0071 {
0072     struct snd_dg00x *dg00x = substream->rmidi->private_data;
0073     unsigned int port;
0074     unsigned long flags;
0075 
0076     if (substream->rmidi->device == 0)
0077         port = substream->number;
0078     else
0079         port = 2;
0080 
0081     spin_lock_irqsave(&dg00x->lock, flags);
0082 
0083     if (up)
0084         amdtp_dot_midi_trigger(&dg00x->rx_stream, port, substream);
0085     else
0086         amdtp_dot_midi_trigger(&dg00x->rx_stream, port, NULL);
0087 
0088     spin_unlock_irqrestore(&dg00x->lock, flags);
0089 }
0090 
0091 static void set_substream_names(struct snd_dg00x *dg00x,
0092                 struct snd_rawmidi *rmidi, bool is_console)
0093 {
0094     struct snd_rawmidi_substream *subs;
0095     struct snd_rawmidi_str *str;
0096     int i;
0097 
0098     for (i = 0; i < 2; ++i) {
0099         str = &rmidi->streams[i];
0100 
0101         list_for_each_entry(subs, &str->substreams, list) {
0102             if (!is_console) {
0103                 snprintf(subs->name, sizeof(subs->name),
0104                      "%s MIDI %d",
0105                      dg00x->card->shortname,
0106                      subs->number + 1);
0107             } else {
0108                 snprintf(subs->name, sizeof(subs->name),
0109                      "%s control",
0110                      dg00x->card->shortname);
0111             }
0112         }
0113     }
0114 }
0115 
0116 static int add_substream_pair(struct snd_dg00x *dg00x, unsigned int out_ports,
0117                   unsigned int in_ports, bool is_console)
0118 {
0119     static const struct snd_rawmidi_ops capture_ops = {
0120         .open = midi_open,
0121         .close = midi_close,
0122         .trigger = midi_capture_trigger,
0123     };
0124     static const struct snd_rawmidi_ops playback_ops = {
0125         .open = midi_open,
0126         .close = midi_close,
0127         .trigger = midi_playback_trigger,
0128     };
0129     const char *label;
0130     struct snd_rawmidi *rmidi;
0131     int err;
0132 
0133     /* Add physical midi ports. */
0134     err = snd_rawmidi_new(dg00x->card, dg00x->card->driver, is_console,
0135                   out_ports, in_ports, &rmidi);
0136     if (err < 0)
0137         return err;
0138     rmidi->private_data = dg00x;
0139 
0140     if (!is_console)
0141         label = "%s control";
0142     else
0143         label = "%s MIDI";
0144     snprintf(rmidi->name, sizeof(rmidi->name), label,
0145          dg00x->card->shortname);
0146 
0147     snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, &playback_ops);
0148     snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, &capture_ops);
0149 
0150     rmidi->info_flags |= SNDRV_RAWMIDI_INFO_INPUT |
0151                  SNDRV_RAWMIDI_INFO_OUTPUT |
0152                  SNDRV_RAWMIDI_INFO_DUPLEX;
0153 
0154     set_substream_names(dg00x, rmidi, is_console);
0155 
0156     return 0;
0157 }
0158 
0159 int snd_dg00x_create_midi_devices(struct snd_dg00x *dg00x)
0160 {
0161     int err;
0162 
0163     /* Add physical midi ports. */
0164     err = add_substream_pair(dg00x, DOT_MIDI_OUT_PORTS, DOT_MIDI_IN_PORTS,
0165                  false);
0166     if (err < 0)
0167         return err;
0168 
0169     if (dg00x->is_console)
0170         err = add_substream_pair(dg00x, 1, 1, true);
0171 
0172     return err;
0173 }