us144mkii: fix moderate bugs - capture robustness, ghost pointer, MIDI cleanup
BUG-09: Buffer partial 64-byte frame remainders across URB completions to prevent silent data loss when USB bulk transfers return incomplete chunks. Adds remainder and combined buffers to tascam_card struct. BUG-10: Distinguish transient USB errors (-EOVERFLOW, -ENOENT, -EPIPE) from fatal ones in capture completion. Resubmit URB on transient errors instead of dropping it, preventing capture stream death on transient USB bandwidth contention or controller glitches. BUG-11: Return playback_frames_consumed from pointer callback during ghost playback instead of always returning 0, providing correct semantics when the callback is queried indirectly. BUG-12: Unanchor MIDI output URB before returning on error path in tascam_midi_out_complete to prevent the URB from remaining stuck in the anchor's pending list.
This commit is contained in:
parent
f6c59c4f9f
commit
ef73de30ec
|
|
@ -172,6 +172,10 @@ struct tascam_card {
|
|||
unsigned int feedback_urb_skip_count;
|
||||
bool running_ghost_playback;
|
||||
|
||||
u8 capture_remainder_buf[63];
|
||||
unsigned int capture_remainder_len;
|
||||
u8 capture_combined_buf[CAPTURE_PACKET_SIZE + 63];
|
||||
|
||||
struct work_struct stop_work;
|
||||
struct work_struct stop_pcm_work;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -46,6 +46,7 @@ static int tascam_capture_prepare(struct snd_pcm_substream *substream)
|
|||
tascam->driver_capture_pos = 0;
|
||||
tascam->capture_frames_processed = 0;
|
||||
tascam->last_cap_period_pos = 0;
|
||||
tascam->capture_remainder_len = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -144,40 +145,64 @@ static void tascam_decode_capture_chunk(const u8 *src, u32 *dst, int frames)
|
|||
* @urb: the completed URB
|
||||
*
|
||||
* Decodes audio data, updates ring buffer, and handles period elapsed.
|
||||
* Handles partial 64-byte frames by buffering remainder across URB completions.
|
||||
* Distinguishes transient USB errors from fatal ones for robustness.
|
||||
*/
|
||||
void capture_urb_complete(struct urb *urb)
|
||||
{
|
||||
struct tascam_card *tascam = urb->context;
|
||||
struct snd_pcm_runtime *runtime;
|
||||
int frames, part1;
|
||||
int frames, part1, total_available, new_remainder;
|
||||
unsigned long flags;
|
||||
bool need_period_elapsed = false;
|
||||
u8 *combined = tascam->capture_combined_buf;
|
||||
|
||||
if (urb->status || !tascam || !tascam->dev)
|
||||
if (!tascam || !tascam->dev)
|
||||
return;
|
||||
|
||||
if (urb->status) {
|
||||
if (urb->status == -EOVERFLOW || urb->status == -ENOENT || urb->status == -EPIPE) {
|
||||
usb_anchor_urb(urb, &tascam->capture_anchor);
|
||||
if (usb_submit_urb(urb, GFP_ATOMIC) < 0) {
|
||||
usb_unanchor_urb(urb);
|
||||
atomic_dec(&tascam->active_urbs);
|
||||
}
|
||||
return;
|
||||
}
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (!tascam->capture_substream || !tascam->capture_substream->runtime)
|
||||
goto exit;
|
||||
|
||||
runtime = tascam->capture_substream->runtime;
|
||||
frames = urb->actual_length / 64;
|
||||
|
||||
memcpy(combined, tascam->capture_remainder_buf, tascam->capture_remainder_len);
|
||||
memcpy(combined + tascam->capture_remainder_len, urb->transfer_buffer, urb->actual_length);
|
||||
total_available = tascam->capture_remainder_len + urb->actual_length;
|
||||
|
||||
frames = total_available / 64;
|
||||
new_remainder = total_available % 64;
|
||||
|
||||
if (frames > 0) {
|
||||
spin_lock_irqsave(&tascam->lock, flags);
|
||||
|
||||
if (!atomic_read(&tascam->capture_active)) {
|
||||
spin_unlock_irqrestore(&tascam->lock, flags);
|
||||
goto exit;
|
||||
tascam->capture_remainder_len = new_remainder;
|
||||
if (new_remainder > 0)
|
||||
memcpy(tascam->capture_remainder_buf, combined + (frames * 64), new_remainder);
|
||||
goto resubmit;
|
||||
}
|
||||
|
||||
u32 *dma = (u32 *)(runtime->dma_area + frames_to_bytes(runtime, tascam->driver_capture_pos));
|
||||
|
||||
if (tascam->driver_capture_pos + frames <= runtime->buffer_size) {
|
||||
tascam_decode_capture_chunk(urb->transfer_buffer, dma, frames);
|
||||
tascam_decode_capture_chunk(combined, dma, frames);
|
||||
} else {
|
||||
part1 = runtime->buffer_size - tascam->driver_capture_pos;
|
||||
tascam_decode_capture_chunk(urb->transfer_buffer, dma, part1);
|
||||
tascam_decode_capture_chunk(urb->transfer_buffer + (part1 * 64),
|
||||
tascam_decode_capture_chunk(combined, dma, part1);
|
||||
tascam_decode_capture_chunk(combined + (part1 * 64),
|
||||
(u32 *)runtime->dma_area, frames - part1);
|
||||
}
|
||||
|
||||
|
|
@ -191,6 +216,11 @@ void capture_urb_complete(struct urb *urb)
|
|||
spin_unlock_irqrestore(&tascam->lock, flags);
|
||||
}
|
||||
|
||||
tascam->capture_remainder_len = new_remainder;
|
||||
if (new_remainder > 0)
|
||||
memcpy(tascam->capture_remainder_buf, combined + (frames * 64), new_remainder);
|
||||
|
||||
resubmit:
|
||||
usb_anchor_urb(urb, &tascam->capture_anchor);
|
||||
if (usb_submit_urb(urb, GFP_ATOMIC) < 0) {
|
||||
usb_unanchor_urb(urb);
|
||||
|
|
@ -203,7 +233,7 @@ void capture_urb_complete(struct urb *urb)
|
|||
|
||||
return;
|
||||
|
||||
exit:
|
||||
exit:
|
||||
usb_unanchor_urb(urb);
|
||||
atomic_dec(&tascam->active_urbs);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ static void tascam_midi_out_complete(struct urb *urb)
|
|||
|
||||
if (urb->status || !sub || !tascam->midi_out_active) {
|
||||
tascam->midi_out_active = false;
|
||||
usb_unanchor_urb(urb);
|
||||
spin_unlock_irqrestore(&tascam->midi_lock, flags);
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -207,8 +207,15 @@ static snd_pcm_uframes_t tascam_playback_pointer(struct snd_pcm_substream *subst
|
|||
unsigned long flags;
|
||||
u64 pos;
|
||||
|
||||
if (!atomic_read(&tascam->playback_active))
|
||||
if (!atomic_read(&tascam->playback_active)) {
|
||||
if (tascam->running_ghost_playback) {
|
||||
spin_lock_irqsave(&tascam->lock, flags);
|
||||
pos = tascam->playback_frames_consumed;
|
||||
spin_unlock_irqrestore(&tascam->lock, flags);
|
||||
return (snd_pcm_uframes_t)pos;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&tascam->lock, flags);
|
||||
pos = tascam->playback_frames_consumed;
|
||||
|
|
|
|||
Loading…
Reference in New Issue