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