mirror of
https://github.com/torvalds/linux.git
synced 2026-07-28 18:21:24 +02:00
ALSA: usx2y: Drain pending US-428 pipe-4 output commands
The US-428 pipe-4 output path submits at most one pending p4out entry from the shared-memory ring per input interrupt. If userspace queues more than one command before the interrupt handler runs, later commands remain pending until later input interrupts, even when async pipe-4 URBs are available. Drain pending entries while idle async URBs are available. Copy each command into the existing per-URB async buffer before submission, so the submitted transfer does not depend on a userspace-mapped ring slot remaining unchanged after p4out_sent is advanced. Also update p4out_sent only after usb_submit_urb() succeeds, so a failed submission is not reported as sent. This keeps the shared-memory ABI unchanged and fixes only the local queue-draining behavior. Signed-off-by: Cássio Gabriel <cassiogabrielcontato@gmail.com> Link: https://patch.msgid.link/20260519-alsa-usx2y-p4out-drain-v1-1-8f0a4550bae2@gmail.com Signed-off-by: Takashi Iwai <tiwai@suse.de>
This commit is contained in:
parent
0c09413bde
commit
18977c0dd7
|
|
@ -180,7 +180,7 @@ static void i_usx2y_in04_int(struct urb *urb)
|
|||
struct usx2ydev *usx2y = urb->context;
|
||||
struct us428ctls_sharedmem *us428ctls = usx2y->us428ctls_sharedmem;
|
||||
struct us428_p4out *p4out;
|
||||
int i, j, n, diff, send;
|
||||
int i, j, n, diff, send, len;
|
||||
|
||||
usx2y->in04_int_calls++;
|
||||
|
||||
|
|
@ -222,24 +222,31 @@ static void i_usx2y_in04_int(struct urb *urb)
|
|||
} while (!err && usx2y->us04->submitted < usx2y->us04->len);
|
||||
}
|
||||
} else {
|
||||
if (us428ctls && us428ctls->p4out_last >= 0 && us428ctls->p4out_last < N_US428_P4OUT_BUFS) {
|
||||
if (us428ctls->p4out_last != us428ctls->p4out_sent) {
|
||||
send = us428ctls->p4out_sent + 1;
|
||||
if (send >= N_US428_P4OUT_BUFS)
|
||||
send = 0;
|
||||
for (j = 0; j < URBS_ASYNC_SEQ && !err; ++j) {
|
||||
if (!usx2y->as04.urb[j]->status) {
|
||||
p4out = us428ctls->p4out + send; // FIXME if more than 1 p4out is new, 1 gets lost.
|
||||
usb_fill_bulk_urb(usx2y->as04.urb[j], usx2y->dev,
|
||||
usb_sndbulkpipe(usx2y->dev, 0x04), &p4out->val.vol,
|
||||
p4out->type == ELT_LIGHT ? sizeof(struct us428_lights) : 5,
|
||||
i_usx2y_out04_int, usx2y);
|
||||
err = usb_submit_urb(usx2y->as04.urb[j], GFP_ATOMIC);
|
||||
while (us428ctls &&
|
||||
us428ctls->p4out_last >= 0 &&
|
||||
us428ctls->p4out_last < N_US428_P4OUT_BUFS &&
|
||||
us428ctls->p4out_last != us428ctls->p4out_sent) {
|
||||
for (j = 0; j < URBS_ASYNC_SEQ && !err; ++j) {
|
||||
if (!usx2y->as04.urb[j]->status) {
|
||||
send = us428ctls->p4out_sent + 1;
|
||||
if (send >= N_US428_P4OUT_BUFS)
|
||||
send = 0;
|
||||
|
||||
p4out = us428ctls->p4out + send;
|
||||
len = p4out->type == ELT_LIGHT ?
|
||||
sizeof(struct us428_lights) : 5;
|
||||
memcpy(usx2y->as04.urb[j]->transfer_buffer,
|
||||
&p4out->val.vol, len);
|
||||
usx2y->as04.urb[j]->transfer_buffer_length = len;
|
||||
err = usb_submit_urb(usx2y->as04.urb[j], GFP_ATOMIC);
|
||||
if (!err)
|
||||
us428ctls->p4out_sent = send;
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (j >= URBS_ASYNC_SEQ || err)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user