summary |
shortlog |
log |
commit | commitdiff |
tree
raw |
patch |
inline | side by side (from parent 1:
d6ca69d)
The impulse and monitor handling in submit_audio_out_urb() isn't
protected thus this can be racy with the capture stream handling.
This patch extends the range to protect via each stream's spinlock
(now the whole submit_audio_*_urb() are covered), and take the capture
stream lock additionally for the impulse and monitor handling part.
Tested-by: Chris Rorvick <chris@rorvick.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
/*
Find a free URB and submit it.
/*
Find a free URB and submit it.
+ must be called in line6pcm->in.lock context
*/
static int submit_audio_in_urb(struct snd_line6_pcm *line6pcm)
{
int index;
*/
static int submit_audio_in_urb(struct snd_line6_pcm *line6pcm)
{
int index;
int i, urb_size;
int ret;
struct urb *urb_in;
int i, urb_size;
int ret;
struct urb *urb_in;
- spin_lock_irqsave(&line6pcm->in.lock, flags);
index =
find_first_zero_bit(&line6pcm->in.active_urbs, LINE6_ISO_BUFFERS);
if (index < 0 || index >= LINE6_ISO_BUFFERS) {
index =
find_first_zero_bit(&line6pcm->in.active_urbs, LINE6_ISO_BUFFERS);
if (index < 0 || index >= LINE6_ISO_BUFFERS) {
- spin_unlock_irqrestore(&line6pcm->in.lock, flags);
dev_err(line6pcm->line6->ifcdev, "no free URB found\n");
return -EINVAL;
}
dev_err(line6pcm->line6->ifcdev, "no free URB found\n");
return -EINVAL;
}
dev_err(line6pcm->line6->ifcdev,
"URB in #%d submission failed (%d)\n", index, ret);
dev_err(line6pcm->line6->ifcdev,
"URB in #%d submission failed (%d)\n", index, ret);
- spin_unlock_irqrestore(&line6pcm->in.lock, flags);
*/
int line6_submit_audio_in_all_urbs(struct snd_line6_pcm *line6pcm)
{
*/
int line6_submit_audio_in_all_urbs(struct snd_line6_pcm *line6pcm)
{
+ unsigned long flags;
+ int ret = 0, i;
+ spin_lock_irqsave(&line6pcm->in.lock, flags);
for (i = 0; i < LINE6_ISO_BUFFERS; ++i) {
ret = submit_audio_in_urb(line6pcm);
if (ret < 0)
for (i = 0; i < LINE6_ISO_BUFFERS; ++i) {
ret = submit_audio_in_urb(line6pcm);
if (ret < 0)
+ spin_unlock_irqrestore(&line6pcm->in.lock, flags);
+ return ret;
line6pcm->in.bytes += length;
if (line6pcm->in.bytes >= line6pcm->in.period) {
line6pcm->in.bytes %= line6pcm->in.period;
line6pcm->in.bytes += length;
if (line6pcm->in.bytes >= line6pcm->in.period) {
line6pcm->in.bytes %= line6pcm->in.period;
+ spin_unlock(&line6pcm->in.lock);
snd_pcm_period_elapsed(substream);
snd_pcm_period_elapsed(substream);
+ spin_lock(&line6pcm->in.lock);
if (test_and_clear_bit(index, &line6pcm->in.unlink_urbs))
shutdown = 1;
if (test_and_clear_bit(index, &line6pcm->in.unlink_urbs))
shutdown = 1;
- spin_unlock_irqrestore(&line6pcm->in.lock, flags);
-
if (!shutdown) {
submit_audio_in_urb(line6pcm);
if (!shutdown) {
submit_audio_in_urb(line6pcm);
&line6pcm->flags))
line6_capture_check_period(line6pcm, length);
}
&line6pcm->flags))
line6_capture_check_period(line6pcm, length);
}
+
+ spin_unlock_irqrestore(&line6pcm->in.lock, flags);
}
/* open capture callback */
}
/* open capture callback */
/*
Find a free URB, prepare audio data, and submit URB.
/*
Find a free URB, prepare audio data, and submit URB.
+ must be called in line6pcm->out.lock context
*/
static int submit_audio_out_urb(struct snd_line6_pcm *line6pcm)
{
int index;
*/
static int submit_audio_out_urb(struct snd_line6_pcm *line6pcm)
{
int index;
int i, urb_size, urb_frames;
int ret;
const int bytes_per_frame = line6pcm->properties->bytes_per_frame;
int i, urb_size, urb_frames;
int ret;
const int bytes_per_frame = line6pcm->properties->bytes_per_frame;
(USB_INTERVALS_PER_SECOND / LINE6_ISO_INTERVAL);
struct urb *urb_out;
(USB_INTERVALS_PER_SECOND / LINE6_ISO_INTERVAL);
struct urb *urb_out;
- spin_lock_irqsave(&line6pcm->out.lock, flags);
index =
find_first_zero_bit(&line6pcm->out.active_urbs, LINE6_ISO_BUFFERS);
if (index < 0 || index >= LINE6_ISO_BUFFERS) {
index =
find_first_zero_bit(&line6pcm->out.active_urbs, LINE6_ISO_BUFFERS);
if (index < 0 || index >= LINE6_ISO_BUFFERS) {
- spin_unlock_irqrestore(&line6pcm->out.lock, flags);
dev_err(line6pcm->line6->ifcdev, "no free URB found\n");
return -EINVAL;
}
dev_err(line6pcm->line6->ifcdev, "no free URB found\n");
return -EINVAL;
}
if (urb_size == 0) {
/* can't determine URB size */
if (urb_size == 0) {
/* can't determine URB size */
- spin_unlock_irqrestore(&line6pcm->out.lock, flags);
dev_err(line6pcm->line6->ifcdev, "driver bug: urb_size = 0\n");
return -EINVAL;
}
dev_err(line6pcm->line6->ifcdev, "driver bug: urb_size = 0\n");
return -EINVAL;
}
urb_out->transfer_buffer_length);
}
urb_out->transfer_buffer_length);
}
- if (line6pcm->prev_fbuf != NULL) {
+ spin_lock_nested(&line6pcm->in.lock, SINGLE_DEPTH_NESTING);
+ if (line6pcm->prev_fbuf) {
if (line6pcm->flags & LINE6_BITS_PCM_IMPULSE) {
create_impulse_test_signal(line6pcm, urb_out,
bytes_per_frame);
if (line6pcm->flags & LINE6_BITS_PCM_IMPULSE) {
create_impulse_test_signal(line6pcm, urb_out,
bytes_per_frame);
+ spin_unlock(&line6pcm->in.lock);
ret = usb_submit_urb(urb_out, GFP_ATOMIC);
ret = usb_submit_urb(urb_out, GFP_ATOMIC);
dev_err(line6pcm->line6->ifcdev,
"URB out #%d submission failed (%d)\n", index, ret);
dev_err(line6pcm->line6->ifcdev,
"URB out #%d submission failed (%d)\n", index, ret);
- spin_unlock_irqrestore(&line6pcm->out.lock, flags);
*/
int line6_submit_audio_out_all_urbs(struct snd_line6_pcm *line6pcm)
{
*/
int line6_submit_audio_out_all_urbs(struct snd_line6_pcm *line6pcm)
{
+ unsigned long flags;
+ int ret = 0, i;
+ spin_lock_irqsave(&line6pcm->out.lock, flags);
for (i = 0; i < LINE6_ISO_BUFFERS; ++i) {
ret = submit_audio_out_urb(line6pcm);
if (ret < 0)
for (i = 0; i < LINE6_ISO_BUFFERS; ++i) {
ret = submit_audio_out_urb(line6pcm);
if (ret < 0)
+ spin_unlock_irqrestore(&line6pcm->out.lock, flags);
+ return ret;
if (test_and_clear_bit(index, &line6pcm->out.unlink_urbs))
shutdown = 1;
if (test_and_clear_bit(index, &line6pcm->out.unlink_urbs))
shutdown = 1;
- spin_unlock_irqrestore(&line6pcm->out.lock, flags);
-
if (!shutdown) {
submit_audio_out_urb(line6pcm);
if (!shutdown) {
submit_audio_out_urb(line6pcm);
line6pcm->out.bytes += length;
if (line6pcm->out.bytes >= line6pcm->out.period) {
line6pcm->out.bytes %= line6pcm->out.period;
line6pcm->out.bytes += length;
if (line6pcm->out.bytes >= line6pcm->out.period) {
line6pcm->out.bytes %= line6pcm->out.period;
+ spin_unlock(&line6pcm->out.lock);
snd_pcm_period_elapsed(substream);
snd_pcm_period_elapsed(substream);
+ spin_lock(&line6pcm->out.lock);
+ spin_unlock_irqrestore(&line6pcm->out.lock, flags);
}
/* open playback callback */
}
/* open playback callback */