summaryrefslogtreecommitdiffstats
path: root/sound/usb/6fire/midi.c
diff options
context:
space:
mode:
authorDapeng Mi <dapeng1.mi@linux.intel.com>2026-09-17 09:52:33 +0800
committerIngo Molnar <mingo@kernel.org>2026-09-22 11:37:46 +0200
commit0102c8c7fdfc4bd700971daff2b94470f4eafae4 (patch)
tree531306c2299f9a269f0a986e29f17ba972180104 /sound/usb/6fire/midi.c
downloadlinux-stable-0102c8c7fdfc4bd700971daff2b94470f4eafae4.tar.gz
linux-stable-0102c8c7fdfc4bd700971daff2b94470f4eafae4.zip
perf/x86/intel: Rename DMR offcore_rsp attribute to offmodule_rspgrafted
DMR introduces Offmodule Response events in place of the legacy Offcore Response events, but it still exposes the inherited offcore_rsp PMU attribute for programming the corresponding MSR data. Rename the DMR PMU attribute to offmodule_rsp so the sysfs interface matches the underlying event name and avoids user & tooling confusion. Signed-off-by: Dapeng Mi <dapeng1.mi@linux.intel.com> Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Signed-off-by: Ingo Molnar <mingo@kernel.org> Link: https://patch.msgid.link/20260917015234.981153-12-dapeng1.mi@linux.intel.com
Diffstat (limited to 'sound/usb/6fire/midi.c')
-rw-r--r--sound/usb/6fire/midi.c219
1 files changed, 219 insertions, 0 deletions
diff --git a/sound/usb/6fire/midi.c b/sound/usb/6fire/midi.c
new file mode 100644
index 000000000..279b44993
--- /dev/null
+++ b/sound/usb/6fire/midi.c
@@ -0,0 +1,219 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Linux driver for TerraTec DMX 6Fire USB
+ *
+ * Rawmidi driver
+ *
+ * Author: Torsten Schenk <torsten.schenk@zoho.com>
+ * Created: Jan 01, 2011
+ * Copyright: (C) Torsten Schenk
+ */
+
+#include <sound/rawmidi.h>
+
+#include "midi.h"
+#include "chip.h"
+#include "comm.h"
+
+enum {
+ MIDI_BUFSIZE = 64
+};
+
+static void usb6fire_midi_out_handler(struct urb *urb)
+{
+ struct midi_runtime *rt = urb->context;
+ int ret;
+
+ guard(spinlock_irqsave)(&rt->out_lock);
+
+ if (rt->out) {
+ ret = snd_rawmidi_transmit(rt->out, rt->out_buffer + 4,
+ MIDI_BUFSIZE - 4);
+ if (ret > 0) { /* more data available, send next packet */
+ rt->out_buffer[1] = ret + 2;
+ rt->out_buffer[3] = rt->out_serial++;
+ urb->transfer_buffer_length = ret + 4;
+
+ ret = usb_submit_urb(urb, GFP_ATOMIC);
+ if (ret < 0)
+ dev_err(&urb->dev->dev,
+ "midi out urb submit failed: %d\n",
+ ret);
+ } else /* no more data to transmit */
+ rt->out = NULL;
+ }
+}
+
+static void usb6fire_midi_in_received(
+ struct midi_runtime *rt, u8 *data, int length)
+{
+ guard(spinlock_irqsave)(&rt->in_lock);
+ if (rt->in)
+ snd_rawmidi_receive(rt->in, data, length);
+}
+
+static int usb6fire_midi_out_open(struct snd_rawmidi_substream *alsa_sub)
+{
+ return 0;
+}
+
+static int usb6fire_midi_out_close(struct snd_rawmidi_substream *alsa_sub)
+{
+ return 0;
+}
+
+static void usb6fire_midi_out_trigger(
+ struct snd_rawmidi_substream *alsa_sub, int up)
+{
+ struct midi_runtime *rt = alsa_sub->rmidi->private_data;
+ struct urb *urb = rt->out_urb;
+ __s8 ret;
+
+ guard(spinlock_irqsave)(&rt->out_lock);
+ if (up) { /* start transfer */
+ if (rt->out) /* we are already transmitting so just return */
+ return;
+
+ ret = snd_rawmidi_transmit(alsa_sub, rt->out_buffer + 4,
+ MIDI_BUFSIZE - 4);
+ if (ret > 0) {
+ rt->out_buffer[1] = ret + 2;
+ rt->out_buffer[3] = rt->out_serial++;
+ urb->transfer_buffer_length = ret + 4;
+
+ ret = usb_submit_urb(urb, GFP_ATOMIC);
+ if (ret < 0)
+ dev_err(&urb->dev->dev,
+ "midi out urb submit failed: %d\n",
+ ret);
+ else
+ rt->out = alsa_sub;
+ }
+ } else if (rt->out == alsa_sub)
+ rt->out = NULL;
+}
+
+static void usb6fire_midi_out_drain(struct snd_rawmidi_substream *alsa_sub)
+{
+ struct midi_runtime *rt = alsa_sub->rmidi->private_data;
+ int retry = 0;
+
+ while (rt->out && retry++ < 100)
+ msleep(10);
+}
+
+static int usb6fire_midi_in_open(struct snd_rawmidi_substream *alsa_sub)
+{
+ return 0;
+}
+
+static int usb6fire_midi_in_close(struct snd_rawmidi_substream *alsa_sub)
+{
+ return 0;
+}
+
+static void usb6fire_midi_in_trigger(
+ struct snd_rawmidi_substream *alsa_sub, int up)
+{
+ struct midi_runtime *rt = alsa_sub->rmidi->private_data;
+
+ guard(spinlock_irqsave)(&rt->in_lock);
+ if (up)
+ rt->in = alsa_sub;
+ else
+ rt->in = NULL;
+}
+
+static const struct snd_rawmidi_ops out_ops = {
+ .open = usb6fire_midi_out_open,
+ .close = usb6fire_midi_out_close,
+ .trigger = usb6fire_midi_out_trigger,
+ .drain = usb6fire_midi_out_drain
+};
+
+static const struct snd_rawmidi_ops in_ops = {
+ .open = usb6fire_midi_in_open,
+ .close = usb6fire_midi_in_close,
+ .trigger = usb6fire_midi_in_trigger
+};
+
+static void usb6fire_midi_free(struct midi_runtime *rt)
+{
+ if (!rt)
+ return;
+
+ if (rt->chip)
+ rt->chip->midi = NULL;
+
+ usb_free_urb(rt->out_urb);
+ kfree(rt->out_buffer);
+ kfree(rt);
+}
+
+int usb6fire_midi_init(struct sfire_chip *chip)
+{
+ int ret;
+ struct midi_runtime *rt = kzalloc_obj(struct midi_runtime);
+ struct comm_runtime *comm_rt = chip->comm;
+
+ if (!rt)
+ return -ENOMEM;
+
+ rt->out_buffer = kzalloc(MIDI_BUFSIZE, GFP_KERNEL);
+ if (!rt->out_buffer) {
+ ret = -ENOMEM;
+ goto error;
+ }
+
+ rt->out_urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!rt->out_urb) {
+ ret = -ENOMEM;
+ goto error;
+ }
+
+ rt->chip = chip;
+ rt->in_received = usb6fire_midi_in_received;
+ rt->out_buffer[0] = 0x80; /* 'send midi' command */
+ rt->out_buffer[1] = 0x00; /* size of data */
+ rt->out_buffer[2] = 0x00; /* always 0 */
+ spin_lock_init(&rt->in_lock);
+ spin_lock_init(&rt->out_lock);
+
+ comm_rt->init_urb(comm_rt, rt->out_urb, rt->out_buffer, rt,
+ usb6fire_midi_out_handler);
+
+ ret = snd_rawmidi_new(chip->card, "6FireUSB", 0, 1, 1, &rt->instance);
+ if (ret < 0) {
+ dev_err(&chip->dev->dev, "unable to create midi.\n");
+ goto error;
+ }
+ rt->instance->private_data = rt;
+ strscpy(rt->instance->name, "DMX6FireUSB MIDI");
+ rt->instance->info_flags = SNDRV_RAWMIDI_INFO_OUTPUT |
+ SNDRV_RAWMIDI_INFO_INPUT |
+ SNDRV_RAWMIDI_INFO_DUPLEX;
+ snd_rawmidi_set_ops(rt->instance, SNDRV_RAWMIDI_STREAM_OUTPUT,
+ &out_ops);
+ snd_rawmidi_set_ops(rt->instance, SNDRV_RAWMIDI_STREAM_INPUT,
+ &in_ops);
+
+ chip->midi = rt;
+ return 0;
+
+ error:
+ usb6fire_midi_free(rt);
+ return ret;
+}
+
+void usb6fire_midi_abort(struct sfire_chip *chip)
+{
+ struct midi_runtime *rt = chip->midi;
+
+ if (rt)
+ usb_poison_urb(rt->out_urb);
+}
+
+void usb6fire_midi_destroy(struct sfire_chip *chip)
+{
+ usb6fire_midi_free(chip->midi);
+}