Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  *   Generic MIDI synth driver for ALSA sequencer
0004  *   Copyright (c) 1998 by Frank van de Pol <fvdpol@coil.demon.nl>
0005  *                         Jaroslav Kysela <perex@perex.cz>
0006  */
0007  
0008 /* 
0009 Possible options for midisynth module:
0010     - automatic opening of midi ports on first received event or subscription
0011       (close will be performed when client leaves)
0012 */
0013 
0014 
0015 #include <linux/init.h>
0016 #include <linux/slab.h>
0017 #include <linux/errno.h>
0018 #include <linux/string.h>
0019 #include <linux/module.h>
0020 #include <linux/mutex.h>
0021 #include <sound/core.h>
0022 #include <sound/rawmidi.h>
0023 #include <sound/seq_kernel.h>
0024 #include <sound/seq_device.h>
0025 #include <sound/seq_midi_event.h>
0026 #include <sound/initval.h>
0027 
0028 MODULE_AUTHOR("Frank van de Pol <fvdpol@coil.demon.nl>, Jaroslav Kysela <perex@perex.cz>");
0029 MODULE_DESCRIPTION("Advanced Linux Sound Architecture sequencer MIDI synth.");
0030 MODULE_LICENSE("GPL");
0031 static int output_buffer_size = PAGE_SIZE;
0032 module_param(output_buffer_size, int, 0644);
0033 MODULE_PARM_DESC(output_buffer_size, "Output buffer size in bytes.");
0034 static int input_buffer_size = PAGE_SIZE;
0035 module_param(input_buffer_size, int, 0644);
0036 MODULE_PARM_DESC(input_buffer_size, "Input buffer size in bytes.");
0037 
0038 /* data for this midi synth driver */
0039 struct seq_midisynth {
0040     struct snd_card *card;
0041     int device;
0042     int subdevice;
0043     struct snd_rawmidi_file input_rfile;
0044     struct snd_rawmidi_file output_rfile;
0045     int seq_client;
0046     int seq_port;
0047     struct snd_midi_event *parser;
0048 };
0049 
0050 struct seq_midisynth_client {
0051     int seq_client;
0052     int num_ports;
0053     int ports_per_device[SNDRV_RAWMIDI_DEVICES];
0054     struct seq_midisynth *ports[SNDRV_RAWMIDI_DEVICES];
0055 };
0056 
0057 static struct seq_midisynth_client *synths[SNDRV_CARDS];
0058 static DEFINE_MUTEX(register_mutex);
0059 
0060 /* handle rawmidi input event (MIDI v1.0 stream) */
0061 static void snd_midi_input_event(struct snd_rawmidi_substream *substream)
0062 {
0063     struct snd_rawmidi_runtime *runtime;
0064     struct seq_midisynth *msynth;
0065     struct snd_seq_event ev;
0066     char buf[16], *pbuf;
0067     long res;
0068 
0069     if (substream == NULL)
0070         return;
0071     runtime = substream->runtime;
0072     msynth = runtime->private_data;
0073     if (msynth == NULL)
0074         return;
0075     memset(&ev, 0, sizeof(ev));
0076     while (runtime->avail > 0) {
0077         res = snd_rawmidi_kernel_read(substream, buf, sizeof(buf));
0078         if (res <= 0)
0079             continue;
0080         if (msynth->parser == NULL)
0081             continue;
0082         pbuf = buf;
0083         while (res-- > 0) {
0084             if (!snd_midi_event_encode_byte(msynth->parser,
0085                             *pbuf++, &ev))
0086                 continue;
0087             ev.source.port = msynth->seq_port;
0088             ev.dest.client = SNDRV_SEQ_ADDRESS_SUBSCRIBERS;
0089             snd_seq_kernel_client_dispatch(msynth->seq_client, &ev, 1, 0);
0090             /* clear event and reset header */
0091             memset(&ev, 0, sizeof(ev));
0092         }
0093     }
0094 }
0095 
0096 static int dump_midi(struct snd_rawmidi_substream *substream, const char *buf, int count)
0097 {
0098     struct snd_rawmidi_runtime *runtime;
0099     int tmp;
0100 
0101     if (snd_BUG_ON(!substream || !buf))
0102         return -EINVAL;
0103     runtime = substream->runtime;
0104     tmp = runtime->avail;
0105     if (tmp < count) {
0106         if (printk_ratelimit())
0107             pr_err("ALSA: seq_midi: MIDI output buffer overrun\n");
0108         return -ENOMEM;
0109     }
0110     if (snd_rawmidi_kernel_write(substream, buf, count) < count)
0111         return -EINVAL;
0112     return 0;
0113 }
0114 
0115 static int event_process_midi(struct snd_seq_event *ev, int direct,
0116                   void *private_data, int atomic, int hop)
0117 {
0118     struct seq_midisynth *msynth = private_data;
0119     unsigned char msg[10];  /* buffer for constructing midi messages */
0120     struct snd_rawmidi_substream *substream;
0121     int len;
0122 
0123     if (snd_BUG_ON(!msynth))
0124         return -EINVAL;
0125     substream = msynth->output_rfile.output;
0126     if (substream == NULL)
0127         return -ENODEV;
0128     if (ev->type == SNDRV_SEQ_EVENT_SYSEX) {    /* special case, to save space */
0129         if ((ev->flags & SNDRV_SEQ_EVENT_LENGTH_MASK) != SNDRV_SEQ_EVENT_LENGTH_VARIABLE) {
0130             /* invalid event */
0131             pr_debug("ALSA: seq_midi: invalid sysex event flags = 0x%x\n", ev->flags);
0132             return 0;
0133         }
0134         snd_seq_dump_var_event(ev, (snd_seq_dump_func_t)dump_midi, substream);
0135         snd_midi_event_reset_decode(msynth->parser);
0136     } else {
0137         if (msynth->parser == NULL)
0138             return -EIO;
0139         len = snd_midi_event_decode(msynth->parser, msg, sizeof(msg), ev);
0140         if (len < 0)
0141             return 0;
0142         if (dump_midi(substream, msg, len) < 0)
0143             snd_midi_event_reset_decode(msynth->parser);
0144     }
0145     return 0;
0146 }
0147 
0148 
0149 static int snd_seq_midisynth_new(struct seq_midisynth *msynth,
0150                  struct snd_card *card,
0151                  int device,
0152                  int subdevice)
0153 {
0154     if (snd_midi_event_new(MAX_MIDI_EVENT_BUF, &msynth->parser) < 0)
0155         return -ENOMEM;
0156     msynth->card = card;
0157     msynth->device = device;
0158     msynth->subdevice = subdevice;
0159     return 0;
0160 }
0161 
0162 /* open associated midi device for input */
0163 static int midisynth_subscribe(void *private_data, struct snd_seq_port_subscribe *info)
0164 {
0165     int err;
0166     struct seq_midisynth *msynth = private_data;
0167     struct snd_rawmidi_runtime *runtime;
0168     struct snd_rawmidi_params params;
0169 
0170     /* open midi port */
0171     err = snd_rawmidi_kernel_open(msynth->card, msynth->device,
0172                       msynth->subdevice,
0173                       SNDRV_RAWMIDI_LFLG_INPUT,
0174                       &msynth->input_rfile);
0175     if (err < 0) {
0176         pr_debug("ALSA: seq_midi: midi input open failed!!!\n");
0177         return err;
0178     }
0179     runtime = msynth->input_rfile.input->runtime;
0180     memset(&params, 0, sizeof(params));
0181     params.avail_min = 1;
0182     params.buffer_size = input_buffer_size;
0183     err = snd_rawmidi_input_params(msynth->input_rfile.input, &params);
0184     if (err < 0) {
0185         snd_rawmidi_kernel_release(&msynth->input_rfile);
0186         return err;
0187     }
0188     snd_midi_event_reset_encode(msynth->parser);
0189     runtime->event = snd_midi_input_event;
0190     runtime->private_data = msynth;
0191     snd_rawmidi_kernel_read(msynth->input_rfile.input, NULL, 0);
0192     return 0;
0193 }
0194 
0195 /* close associated midi device for input */
0196 static int midisynth_unsubscribe(void *private_data, struct snd_seq_port_subscribe *info)
0197 {
0198     int err;
0199     struct seq_midisynth *msynth = private_data;
0200 
0201     if (snd_BUG_ON(!msynth->input_rfile.input))
0202         return -EINVAL;
0203     err = snd_rawmidi_kernel_release(&msynth->input_rfile);
0204     return err;
0205 }
0206 
0207 /* open associated midi device for output */
0208 static int midisynth_use(void *private_data, struct snd_seq_port_subscribe *info)
0209 {
0210     int err;
0211     struct seq_midisynth *msynth = private_data;
0212     struct snd_rawmidi_params params;
0213 
0214     /* open midi port */
0215     err = snd_rawmidi_kernel_open(msynth->card, msynth->device,
0216                       msynth->subdevice,
0217                       SNDRV_RAWMIDI_LFLG_OUTPUT,
0218                       &msynth->output_rfile);
0219     if (err < 0) {
0220         pr_debug("ALSA: seq_midi: midi output open failed!!!\n");
0221         return err;
0222     }
0223     memset(&params, 0, sizeof(params));
0224     params.avail_min = 1;
0225     params.buffer_size = output_buffer_size;
0226     params.no_active_sensing = 1;
0227     err = snd_rawmidi_output_params(msynth->output_rfile.output, &params);
0228     if (err < 0) {
0229         snd_rawmidi_kernel_release(&msynth->output_rfile);
0230         return err;
0231     }
0232     snd_midi_event_reset_decode(msynth->parser);
0233     return 0;
0234 }
0235 
0236 /* close associated midi device for output */
0237 static int midisynth_unuse(void *private_data, struct snd_seq_port_subscribe *info)
0238 {
0239     struct seq_midisynth *msynth = private_data;
0240 
0241     if (snd_BUG_ON(!msynth->output_rfile.output))
0242         return -EINVAL;
0243     snd_rawmidi_drain_output(msynth->output_rfile.output);
0244     return snd_rawmidi_kernel_release(&msynth->output_rfile);
0245 }
0246 
0247 /* delete given midi synth port */
0248 static void snd_seq_midisynth_delete(struct seq_midisynth *msynth)
0249 {
0250     if (msynth == NULL)
0251         return;
0252 
0253     if (msynth->seq_client > 0) {
0254         /* delete port */
0255         snd_seq_event_port_detach(msynth->seq_client, msynth->seq_port);
0256     }
0257 
0258     snd_midi_event_free(msynth->parser);
0259 }
0260 
0261 /* register new midi synth port */
0262 static int
0263 snd_seq_midisynth_probe(struct device *_dev)
0264 {
0265     struct snd_seq_device *dev = to_seq_dev(_dev);
0266     struct seq_midisynth_client *client;
0267     struct seq_midisynth *msynth, *ms;
0268     struct snd_seq_port_info *port;
0269     struct snd_rawmidi_info *info;
0270     struct snd_rawmidi *rmidi = dev->private_data;
0271     int newclient = 0;
0272     unsigned int p, ports;
0273     struct snd_seq_port_callback pcallbacks;
0274     struct snd_card *card = dev->card;
0275     int device = dev->device;
0276     unsigned int input_count = 0, output_count = 0;
0277 
0278     if (snd_BUG_ON(!card || device < 0 || device >= SNDRV_RAWMIDI_DEVICES))
0279         return -EINVAL;
0280     info = kmalloc(sizeof(*info), GFP_KERNEL);
0281     if (! info)
0282         return -ENOMEM;
0283     info->device = device;
0284     info->stream = SNDRV_RAWMIDI_STREAM_OUTPUT;
0285     info->subdevice = 0;
0286     if (snd_rawmidi_info_select(card, info) >= 0)
0287         output_count = info->subdevices_count;
0288     info->stream = SNDRV_RAWMIDI_STREAM_INPUT;
0289     if (snd_rawmidi_info_select(card, info) >= 0) {
0290         input_count = info->subdevices_count;
0291     }
0292     ports = output_count;
0293     if (ports < input_count)
0294         ports = input_count;
0295     if (ports == 0) {
0296         kfree(info);
0297         return -ENODEV;
0298     }
0299     if (ports > (256 / SNDRV_RAWMIDI_DEVICES))
0300         ports = 256 / SNDRV_RAWMIDI_DEVICES;
0301 
0302     mutex_lock(&register_mutex);
0303     client = synths[card->number];
0304     if (client == NULL) {
0305         newclient = 1;
0306         client = kzalloc(sizeof(*client), GFP_KERNEL);
0307         if (client == NULL) {
0308             mutex_unlock(&register_mutex);
0309             kfree(info);
0310             return -ENOMEM;
0311         }
0312         client->seq_client =
0313             snd_seq_create_kernel_client(
0314                 card, 0, "%s", card->shortname[0] ?
0315                 (const char *)card->shortname : "External MIDI");
0316         if (client->seq_client < 0) {
0317             kfree(client);
0318             mutex_unlock(&register_mutex);
0319             kfree(info);
0320             return -ENOMEM;
0321         }
0322     }
0323 
0324     msynth = kcalloc(ports, sizeof(struct seq_midisynth), GFP_KERNEL);
0325     port = kmalloc(sizeof(*port), GFP_KERNEL);
0326     if (msynth == NULL || port == NULL)
0327         goto __nomem;
0328 
0329     for (p = 0; p < ports; p++) {
0330         ms = &msynth[p];
0331 
0332         if (snd_seq_midisynth_new(ms, card, device, p) < 0)
0333             goto __nomem;
0334 
0335         /* declare port */
0336         memset(port, 0, sizeof(*port));
0337         port->addr.client = client->seq_client;
0338         port->addr.port = device * (256 / SNDRV_RAWMIDI_DEVICES) + p;
0339         port->flags = SNDRV_SEQ_PORT_FLG_GIVEN_PORT;
0340         memset(info, 0, sizeof(*info));
0341         info->device = device;
0342         if (p < output_count)
0343             info->stream = SNDRV_RAWMIDI_STREAM_OUTPUT;
0344         else
0345             info->stream = SNDRV_RAWMIDI_STREAM_INPUT;
0346         info->subdevice = p;
0347         if (snd_rawmidi_info_select(card, info) >= 0)
0348             strcpy(port->name, info->subname);
0349         if (! port->name[0]) {
0350             if (info->name[0]) {
0351                 if (ports > 1)
0352                     snprintf(port->name, sizeof(port->name), "%s-%u", info->name, p);
0353                 else
0354                     snprintf(port->name, sizeof(port->name), "%s", info->name);
0355             } else {
0356                 /* last resort */
0357                 if (ports > 1)
0358                     sprintf(port->name, "MIDI %d-%d-%u", card->number, device, p);
0359                 else
0360                     sprintf(port->name, "MIDI %d-%d", card->number, device);
0361             }
0362         }
0363         if ((info->flags & SNDRV_RAWMIDI_INFO_OUTPUT) && p < output_count)
0364             port->capability |= SNDRV_SEQ_PORT_CAP_WRITE | SNDRV_SEQ_PORT_CAP_SYNC_WRITE | SNDRV_SEQ_PORT_CAP_SUBS_WRITE;
0365         if ((info->flags & SNDRV_RAWMIDI_INFO_INPUT) && p < input_count)
0366             port->capability |= SNDRV_SEQ_PORT_CAP_READ | SNDRV_SEQ_PORT_CAP_SYNC_READ | SNDRV_SEQ_PORT_CAP_SUBS_READ;
0367         if ((port->capability & (SNDRV_SEQ_PORT_CAP_WRITE|SNDRV_SEQ_PORT_CAP_READ)) == (SNDRV_SEQ_PORT_CAP_WRITE|SNDRV_SEQ_PORT_CAP_READ) &&
0368             info->flags & SNDRV_RAWMIDI_INFO_DUPLEX)
0369             port->capability |= SNDRV_SEQ_PORT_CAP_DUPLEX;
0370         port->type = SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC
0371             | SNDRV_SEQ_PORT_TYPE_HARDWARE
0372             | SNDRV_SEQ_PORT_TYPE_PORT;
0373         port->midi_channels = 16;
0374         memset(&pcallbacks, 0, sizeof(pcallbacks));
0375         pcallbacks.owner = THIS_MODULE;
0376         pcallbacks.private_data = ms;
0377         pcallbacks.subscribe = midisynth_subscribe;
0378         pcallbacks.unsubscribe = midisynth_unsubscribe;
0379         pcallbacks.use = midisynth_use;
0380         pcallbacks.unuse = midisynth_unuse;
0381         pcallbacks.event_input = event_process_midi;
0382         port->kernel = &pcallbacks;
0383         if (rmidi->ops && rmidi->ops->get_port_info)
0384             rmidi->ops->get_port_info(rmidi, p, port);
0385         if (snd_seq_kernel_client_ctl(client->seq_client, SNDRV_SEQ_IOCTL_CREATE_PORT, port)<0)
0386             goto __nomem;
0387         ms->seq_client = client->seq_client;
0388         ms->seq_port = port->addr.port;
0389     }
0390     client->ports_per_device[device] = ports;
0391     client->ports[device] = msynth;
0392     client->num_ports++;
0393     if (newclient)
0394         synths[card->number] = client;
0395     mutex_unlock(&register_mutex);
0396     kfree(info);
0397     kfree(port);
0398     return 0;   /* success */
0399 
0400       __nomem:
0401     if (msynth != NULL) {
0402             for (p = 0; p < ports; p++)
0403                 snd_seq_midisynth_delete(&msynth[p]);
0404         kfree(msynth);
0405     }
0406     if (newclient) {
0407         snd_seq_delete_kernel_client(client->seq_client);
0408         kfree(client);
0409     }
0410     kfree(info);
0411     kfree(port);
0412     mutex_unlock(&register_mutex);
0413     return -ENOMEM;
0414 }
0415 
0416 /* release midi synth port */
0417 static int
0418 snd_seq_midisynth_remove(struct device *_dev)
0419 {
0420     struct snd_seq_device *dev = to_seq_dev(_dev);
0421     struct seq_midisynth_client *client;
0422     struct seq_midisynth *msynth;
0423     struct snd_card *card = dev->card;
0424     int device = dev->device, p, ports;
0425     
0426     mutex_lock(&register_mutex);
0427     client = synths[card->number];
0428     if (client == NULL || client->ports[device] == NULL) {
0429         mutex_unlock(&register_mutex);
0430         return -ENODEV;
0431     }
0432     ports = client->ports_per_device[device];
0433     client->ports_per_device[device] = 0;
0434     msynth = client->ports[device];
0435     client->ports[device] = NULL;
0436     for (p = 0; p < ports; p++)
0437         snd_seq_midisynth_delete(&msynth[p]);
0438     kfree(msynth);
0439     client->num_ports--;
0440     if (client->num_ports <= 0) {
0441         snd_seq_delete_kernel_client(client->seq_client);
0442         synths[card->number] = NULL;
0443         kfree(client);
0444     }
0445     mutex_unlock(&register_mutex);
0446     return 0;
0447 }
0448 
0449 static struct snd_seq_driver seq_midisynth_driver = {
0450     .driver = {
0451         .name = KBUILD_MODNAME,
0452         .probe = snd_seq_midisynth_probe,
0453         .remove = snd_seq_midisynth_remove,
0454     },
0455     .id = SNDRV_SEQ_DEV_ID_MIDISYNTH,
0456     .argsize = 0,
0457 };
0458 
0459 module_snd_seq_driver(seq_midisynth_driver);