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.
This commit is contained in:
parent
4c9ff01806
commit
57cbd3d53f
|
|
@ -18,12 +18,12 @@ static void tascam_midi_out_complete(struct urb *urb)
|
||||||
return;
|
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) {
|
if (count > 0) {
|
||||||
|
tascam->midi_out_buf[0] = 0xE0;
|
||||||
if (count < 8)
|
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;
|
urb->transfer_buffer_length = 9;
|
||||||
|
|
||||||
usb_anchor_urb(urb, &tascam->midi_anchor);
|
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;
|
tascam->midi_output = sub;
|
||||||
if (!tascam->midi_out_active) {
|
if (!tascam->midi_out_active) {
|
||||||
tascam->midi_out_active = true;
|
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) {
|
if (count > 0) {
|
||||||
|
tascam->midi_out_buf[0] = 0xE0;
|
||||||
if (count < 8)
|
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;
|
tascam->midi_out_urb->transfer_buffer_length = 9;
|
||||||
|
|
||||||
usb_anchor_urb(tascam->midi_out_urb, &tascam->midi_anchor);
|
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);
|
spin_unlock_irqrestore(&tascam->midi_lock, flags);
|
||||||
|
|
||||||
if (urb->actual_length == 9 && sub) {
|
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++;
|
len++;
|
||||||
if (len > 0)
|
if (len > 0)
|
||||||
snd_rawmidi_receive(sub, urb->transfer_buffer, len);
|
snd_rawmidi_receive(sub, buf, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
usb_anchor_urb(urb, &tascam->midi_anchor);
|
usb_anchor_urb(urb, &tascam->midi_anchor);
|
||||||
|
|
|
||||||
|
|
@ -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 */
|
/* Re-prepare descriptors with current rate in case hw_params changed */
|
||||||
prepare_urb_descriptors(tascam);
|
prepare_urb_descriptors(tascam);
|
||||||
} else {
|
} else {
|
||||||
submit_urbs(tascam, tascam->feedback_urbs, NUM_FEEDBACK_URBS, &tascam->feedback_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);
|
submit_urbs(tascam, tascam->playback_urbs, NUM_PLAYBACK_URBS, &tascam->playback_anchor) < 0) {
|
||||||
|
ret = -EIO;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
@ -285,15 +287,17 @@ void playback_urb_complete(struct urb *urb)
|
||||||
|
|
||||||
runtime = tascam->playback_substream->runtime;
|
runtime = tascam->playback_substream->runtime;
|
||||||
ptr_bytes = frames_to_bytes(runtime, tascam->driver_playback_pos);
|
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);
|
spin_unlock_irqrestore(&tascam->lock, flags);
|
||||||
|
|
||||||
/* Copy from ALSA Buffer */
|
/* Copy from ALSA Buffer */
|
||||||
if (total_bytes + ptr_bytes > frames_to_bytes(runtime, runtime->buffer_size)) {
|
if (total_bytes + ptr_bytes > buf_size_bytes) {
|
||||||
part1_bytes = frames_to_bytes(runtime, runtime->buffer_size) - ptr_bytes;
|
part1_bytes = buf_size_bytes - ptr_bytes;
|
||||||
memcpy(urb->transfer_buffer, runtime->dma_area + ptr_bytes, part1_bytes);
|
memcpy(urb->transfer_buffer, dma_area + ptr_bytes, part1_bytes);
|
||||||
memcpy(urb->transfer_buffer + part1_bytes, runtime->dma_area, total_bytes - part1_bytes);
|
memcpy(urb->transfer_buffer + part1_bytes, dma_area, total_bytes - part1_bytes);
|
||||||
} else {
|
} 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);
|
spin_lock_irqsave(&tascam->lock, flags);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue