root/sound/usb/6fire/midi.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. usb6fire_midi_out_handler
  2. usb6fire_midi_in_received
  3. usb6fire_midi_out_open
  4. usb6fire_midi_out_close
  5. usb6fire_midi_out_trigger
  6. usb6fire_midi_out_drain
  7. usb6fire_midi_in_open
  8. usb6fire_midi_in_close
  9. usb6fire_midi_in_trigger
  10. usb6fire_midi_init
  11. usb6fire_midi_abort
  12. usb6fire_midi_destroy

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /*
   3  * Linux driver for TerraTec DMX 6Fire USB
   4  *
   5  * Rawmidi driver
   6  *
   7  * Author:      Torsten Schenk <torsten.schenk@zoho.com>
   8  * Created:     Jan 01, 2011
   9  * Copyright:   (C) Torsten Schenk
  10  */
  11 
  12 #include <sound/rawmidi.h>
  13 
  14 #include "midi.h"
  15 #include "chip.h"
  16 #include "comm.h"
  17 
  18 enum {
  19         MIDI_BUFSIZE = 64
  20 };
  21 
  22 static void usb6fire_midi_out_handler(struct urb *urb)
  23 {
  24         struct midi_runtime *rt = urb->context;
  25         int ret;
  26         unsigned long flags;
  27 
  28         spin_lock_irqsave(&rt->out_lock, flags);
  29 
  30         if (rt->out) {
  31                 ret = snd_rawmidi_transmit(rt->out, rt->out_buffer + 4,
  32                                 MIDI_BUFSIZE - 4);
  33                 if (ret > 0) { /* more data available, send next packet */
  34                         rt->out_buffer[1] = ret + 2;
  35                         rt->out_buffer[3] = rt->out_serial++;
  36                         urb->transfer_buffer_length = ret + 4;
  37 
  38                         ret = usb_submit_urb(urb, GFP_ATOMIC);
  39                         if (ret < 0)
  40                                 dev_err(&urb->dev->dev,
  41                                         "midi out urb submit failed: %d\n",
  42                                         ret);
  43                 } else /* no more data to transmit */
  44                         rt->out = NULL;
  45         }
  46         spin_unlock_irqrestore(&rt->out_lock, flags);
  47 }
  48 
  49 static void usb6fire_midi_in_received(
  50                 struct midi_runtime *rt, u8 *data, int length)
  51 {
  52         unsigned long flags;
  53 
  54         spin_lock_irqsave(&rt->in_lock, flags);
  55         if (rt->in)
  56                 snd_rawmidi_receive(rt->in, data, length);
  57         spin_unlock_irqrestore(&rt->in_lock, flags);
  58 }
  59 
  60 static int usb6fire_midi_out_open(struct snd_rawmidi_substream *alsa_sub)
  61 {
  62         return 0;
  63 }
  64 
  65 static int usb6fire_midi_out_close(struct snd_rawmidi_substream *alsa_sub)
  66 {
  67         return 0;
  68 }
  69 
  70 static void usb6fire_midi_out_trigger(
  71                 struct snd_rawmidi_substream *alsa_sub, int up)
  72 {
  73         struct midi_runtime *rt = alsa_sub->rmidi->private_data;
  74         struct urb *urb = &rt->out_urb;
  75         __s8 ret;
  76         unsigned long flags;
  77 
  78         spin_lock_irqsave(&rt->out_lock, flags);
  79         if (up) { /* start transfer */
  80                 if (rt->out) { /* we are already transmitting so just return */
  81                         spin_unlock_irqrestore(&rt->out_lock, flags);
  82                         return;
  83                 }
  84 
  85                 ret = snd_rawmidi_transmit(alsa_sub, rt->out_buffer + 4,
  86                                 MIDI_BUFSIZE - 4);
  87                 if (ret > 0) {
  88                         rt->out_buffer[1] = ret + 2;
  89                         rt->out_buffer[3] = rt->out_serial++;
  90                         urb->transfer_buffer_length = ret + 4;
  91 
  92                         ret = usb_submit_urb(urb, GFP_ATOMIC);
  93                         if (ret < 0)
  94                                 dev_err(&urb->dev->dev,
  95                                         "midi out urb submit failed: %d\n",
  96                                         ret);
  97                         else
  98                                 rt->out = alsa_sub;
  99                 }
 100         } else if (rt->out == alsa_sub)
 101                 rt->out = NULL;
 102         spin_unlock_irqrestore(&rt->out_lock, flags);
 103 }
 104 
 105 static void usb6fire_midi_out_drain(struct snd_rawmidi_substream *alsa_sub)
 106 {
 107         struct midi_runtime *rt = alsa_sub->rmidi->private_data;
 108         int retry = 0;
 109 
 110         while (rt->out && retry++ < 100)
 111                 msleep(10);
 112 }
 113 
 114 static int usb6fire_midi_in_open(struct snd_rawmidi_substream *alsa_sub)
 115 {
 116         return 0;
 117 }
 118 
 119 static int usb6fire_midi_in_close(struct snd_rawmidi_substream *alsa_sub)
 120 {
 121         return 0;
 122 }
 123 
 124 static void usb6fire_midi_in_trigger(
 125                 struct snd_rawmidi_substream *alsa_sub, int up)
 126 {
 127         struct midi_runtime *rt = alsa_sub->rmidi->private_data;
 128         unsigned long flags;
 129 
 130         spin_lock_irqsave(&rt->in_lock, flags);
 131         if (up)
 132                 rt->in = alsa_sub;
 133         else
 134                 rt->in = NULL;
 135         spin_unlock_irqrestore(&rt->in_lock, flags);
 136 }
 137 
 138 static const struct snd_rawmidi_ops out_ops = {
 139         .open = usb6fire_midi_out_open,
 140         .close = usb6fire_midi_out_close,
 141         .trigger = usb6fire_midi_out_trigger,
 142         .drain = usb6fire_midi_out_drain
 143 };
 144 
 145 static const struct snd_rawmidi_ops in_ops = {
 146         .open = usb6fire_midi_in_open,
 147         .close = usb6fire_midi_in_close,
 148         .trigger = usb6fire_midi_in_trigger
 149 };
 150 
 151 int usb6fire_midi_init(struct sfire_chip *chip)
 152 {
 153         int ret;
 154         struct midi_runtime *rt = kzalloc(sizeof(struct midi_runtime),
 155                         GFP_KERNEL);
 156         struct comm_runtime *comm_rt = chip->comm;
 157 
 158         if (!rt)
 159                 return -ENOMEM;
 160 
 161         rt->out_buffer = kzalloc(MIDI_BUFSIZE, GFP_KERNEL);
 162         if (!rt->out_buffer) {
 163                 kfree(rt);
 164                 return -ENOMEM;
 165         }
 166 
 167         rt->chip = chip;
 168         rt->in_received = usb6fire_midi_in_received;
 169         rt->out_buffer[0] = 0x80; /* 'send midi' command */
 170         rt->out_buffer[1] = 0x00; /* size of data */
 171         rt->out_buffer[2] = 0x00; /* always 0 */
 172         spin_lock_init(&rt->in_lock);
 173         spin_lock_init(&rt->out_lock);
 174 
 175         comm_rt->init_urb(comm_rt, &rt->out_urb, rt->out_buffer, rt,
 176                         usb6fire_midi_out_handler);
 177 
 178         ret = snd_rawmidi_new(chip->card, "6FireUSB", 0, 1, 1, &rt->instance);
 179         if (ret < 0) {
 180                 kfree(rt->out_buffer);
 181                 kfree(rt);
 182                 dev_err(&chip->dev->dev, "unable to create midi.\n");
 183                 return ret;
 184         }
 185         rt->instance->private_data = rt;
 186         strcpy(rt->instance->name, "DMX6FireUSB MIDI");
 187         rt->instance->info_flags = SNDRV_RAWMIDI_INFO_OUTPUT |
 188                         SNDRV_RAWMIDI_INFO_INPUT |
 189                         SNDRV_RAWMIDI_INFO_DUPLEX;
 190         snd_rawmidi_set_ops(rt->instance, SNDRV_RAWMIDI_STREAM_OUTPUT,
 191                         &out_ops);
 192         snd_rawmidi_set_ops(rt->instance, SNDRV_RAWMIDI_STREAM_INPUT,
 193                         &in_ops);
 194 
 195         chip->midi = rt;
 196         return 0;
 197 }
 198 
 199 void usb6fire_midi_abort(struct sfire_chip *chip)
 200 {
 201         struct midi_runtime *rt = chip->midi;
 202 
 203         if (rt)
 204                 usb_poison_urb(&rt->out_urb);
 205 }
 206 
 207 void usb6fire_midi_destroy(struct sfire_chip *chip)
 208 {
 209         struct midi_runtime *rt = chip->midi;
 210 
 211         kfree(rt->out_buffer);
 212         kfree(rt);
 213         chip->midi = NULL;
 214 }

/* [<][>][^][v][top][bottom][index][help] */