From 57cbd3d53fde4387f95f4174390cc992ff013e26 Mon Sep 17 00:00:00 2001 From: Marvin Date: Wed, 22 Apr 2026 19:26:32 -0300 Subject: [PATCH] Fix critical bugs: MIDI byte order, trigger error handling, playback race condition - BUG-01: Fix MIDI output packet format - header 0xE0 must be at index 0 per spec, not index 8. Shift payload to indices 1-8. - BUG-02: Skip header byte (index 0) when parsing incoming MIDI packets so ALSA does not receive spurious Active Sensing events. - BUG-03: Check return values of submit_urbs in playback trigger; report -EIO to ALSA if URB submission fails. - BUG-04: Cache runtime->dma_area and buffer size under spinlock before releasing it, eliminating race condition on concurrent close/hw_params. --- us144mkii_midi.c | 17 +++++++++-------- us144mkii_playback.c | 18 +++++++++++------- 2 files changed, 20 insertions(+), 15 deletions(-) diff --git a/us144mkii_midi.c b/us144mkii_midi.c index 97a24ca..134e19e 100644 --- a/us144mkii_midi.c +++ b/us144mkii_midi.c @@ -18,12 +18,12 @@ static void tascam_midi_out_complete(struct urb *urb) return; } - count = snd_rawmidi_transmit(sub, tascam->midi_out_buf, 8); + count = snd_rawmidi_transmit(sub, tascam->midi_out_buf + 1, 8); if (count > 0) { + tascam->midi_out_buf[0] = 0xE0; if (count < 8) - memset(tascam->midi_out_buf + count, 0xFD, 8 - count); + memset(tascam->midi_out_buf + 1 + count, 0xFD, 8 - count); - tascam->midi_out_buf[8] = 0xE0; urb->transfer_buffer_length = 9; usb_anchor_urb(urb, &tascam->midi_anchor); @@ -49,12 +49,12 @@ static void tascam_midi_output_trigger(struct snd_rawmidi_substream *sub, int up tascam->midi_output = sub; if (!tascam->midi_out_active) { tascam->midi_out_active = true; - count = snd_rawmidi_transmit(sub, tascam->midi_out_buf, 8); + count = snd_rawmidi_transmit(sub, tascam->midi_out_buf + 1, 8); if (count > 0) { + tascam->midi_out_buf[0] = 0xE0; if (count < 8) - memset(tascam->midi_out_buf + count, 0xFD, 8 - count); + memset(tascam->midi_out_buf + 1 + count, 0xFD, 8 - count); - tascam->midi_out_buf[8] = 0xE0; tascam->midi_out_urb->transfer_buffer_length = 9; usb_anchor_urb(tascam->midi_out_urb, &tascam->midi_anchor); @@ -87,10 +87,11 @@ static void tascam_midi_in_complete(struct urb *urb) spin_unlock_irqrestore(&tascam->midi_lock, flags); if (urb->actual_length == 9 && sub) { - while (len < 8 && ((u8 *)urb->transfer_buffer)[len] != 0xFD) + u8 *buf = (u8 *)urb->transfer_buffer + 1; + while (len < 8 && buf[len] != 0xFD) len++; if (len > 0) - snd_rawmidi_receive(sub, urb->transfer_buffer, len); + snd_rawmidi_receive(sub, buf, len); } usb_anchor_urb(urb, &tascam->midi_anchor); diff --git a/us144mkii_playback.c b/us144mkii_playback.c index 97cf491..402cbbb 100644 --- a/us144mkii_playback.c +++ b/us144mkii_playback.c @@ -179,8 +179,10 @@ static int tascam_playback_trigger(struct snd_pcm_substream *substream, int cmd) /* Re-prepare descriptors with current rate in case hw_params changed */ prepare_urb_descriptors(tascam); } else { - submit_urbs(tascam, tascam->feedback_urbs, NUM_FEEDBACK_URBS, &tascam->feedback_anchor); - submit_urbs(tascam, tascam->playback_urbs, NUM_PLAYBACK_URBS, &tascam->playback_anchor); + if (submit_urbs(tascam, tascam->feedback_urbs, NUM_FEEDBACK_URBS, &tascam->feedback_anchor) < 0 || + submit_urbs(tascam, tascam->playback_urbs, NUM_PLAYBACK_URBS, &tascam->playback_anchor) < 0) { + ret = -EIO; + } } } break; @@ -285,15 +287,17 @@ void playback_urb_complete(struct urb *urb) runtime = tascam->playback_substream->runtime; ptr_bytes = frames_to_bytes(runtime, tascam->driver_playback_pos); + void *dma_area = runtime->dma_area; + size_t buf_size_bytes = frames_to_bytes(runtime, runtime->buffer_size); spin_unlock_irqrestore(&tascam->lock, flags); /* Copy from ALSA Buffer */ - if (total_bytes + ptr_bytes > frames_to_bytes(runtime, runtime->buffer_size)) { - part1_bytes = frames_to_bytes(runtime, runtime->buffer_size) - ptr_bytes; - memcpy(urb->transfer_buffer, runtime->dma_area + ptr_bytes, part1_bytes); - memcpy(urb->transfer_buffer + part1_bytes, runtime->dma_area, total_bytes - part1_bytes); + if (total_bytes + ptr_bytes > buf_size_bytes) { + part1_bytes = buf_size_bytes - ptr_bytes; + memcpy(urb->transfer_buffer, dma_area + ptr_bytes, part1_bytes); + memcpy(urb->transfer_buffer + part1_bytes, dma_area, total_bytes - part1_bytes); } else { - memcpy(urb->transfer_buffer, runtime->dma_area + ptr_bytes, total_bytes); + memcpy(urb->transfer_buffer, dma_area + ptr_bytes, total_bytes); } spin_lock_irqsave(&tascam->lock, flags);