diff options
Diffstat (limited to 'sound/usb/pcm.c')
-rw-r--r-- | sound/usb/pcm.c | 301 |
1 files changed, 144 insertions, 157 deletions
diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c index bff92505e408..54d01dfd820f 100644 --- a/sound/usb/pcm.c +++ b/sound/usb/pcm.c @@ -77,10 +77,10 @@ static snd_pcm_uframes_t snd_usb_pcm_pointer(struct snd_pcm_substream *substream if (atomic_read(&subs->stream->chip->shutdown)) return SNDRV_PCM_POS_XRUN; - spin_lock(&subs->lock); - hwptr_done = subs->hwptr_done; - runtime->delay = snd_usb_pcm_delay(subs, runtime); - spin_unlock(&subs->lock); + scoped_guard(spinlock, &subs->lock) { + hwptr_done = subs->hwptr_done; + runtime->delay = snd_usb_pcm_delay(subs, runtime); + } return bytes_to_frames(runtime, hwptr_done); } @@ -560,9 +560,9 @@ int snd_usb_hw_params(struct snd_usb_substream *subs, subs->sync_endpoint); } - mutex_lock(&chip->mutex); - subs->cur_audiofmt = fmt; - mutex_unlock(&chip->mutex); + scoped_guard(mutex, &chip->mutex) { + subs->cur_audiofmt = fmt; + } if (!subs->data_endpoint->need_setup) goto unlock; @@ -611,14 +611,14 @@ int snd_usb_hw_free(struct snd_usb_substream *subs) struct snd_usb_audio *chip = subs->stream->chip; snd_media_stop_pipeline(subs); - mutex_lock(&chip->mutex); - subs->cur_audiofmt = NULL; - mutex_unlock(&chip->mutex); - if (!snd_usb_lock_shutdown(chip)) { + scoped_guard(mutex, &chip->mutex) { + subs->cur_audiofmt = NULL; + } + CLASS(snd_usb_lock, pm)(chip); + if (!pm.err) { if (stop_endpoints(subs, false)) sync_pending_stops(subs); close_endpoints(chip, subs); - snd_usb_unlock_shutdown(chip); } return 0; @@ -675,28 +675,26 @@ static int snd_usb_pcm_prepare(struct snd_pcm_substream *substream) int retry = 0; int ret; - ret = snd_usb_lock_shutdown(chip); - if (ret < 0) - return ret; - if (snd_BUG_ON(!subs->data_endpoint)) { - ret = -EIO; - goto unlock; - } + CLASS(snd_usb_lock, pm)(chip); + if (pm.err < 0) + return pm.err; + if (snd_BUG_ON(!subs->data_endpoint)) + return -EIO; ret = snd_usb_pcm_change_state(subs, UAC3_PD_STATE_D0); if (ret < 0) - goto unlock; + return ret; again: if (subs->sync_endpoint) { ret = snd_usb_endpoint_prepare(chip, subs->sync_endpoint); if (ret < 0) - goto unlock; + return ret; } ret = snd_usb_endpoint_prepare(chip, subs->data_endpoint); if (ret < 0) - goto unlock; + return ret; else if (ret > 0) snd_usb_set_format_quirk(subs, subs->cur_audiofmt); ret = 0; @@ -722,8 +720,7 @@ static int snd_usb_pcm_prepare(struct snd_pcm_substream *substream) goto again; } } - unlock: - snd_usb_unlock_shutdown(chip); + return ret; } @@ -1244,13 +1241,11 @@ static int snd_usb_pcm_open(struct snd_pcm_substream *substream) struct snd_usb_audio *chip = subs->stream->chip; int ret; - mutex_lock(&chip->mutex); - if (subs->opened) { - mutex_unlock(&chip->mutex); - return -EBUSY; + scoped_guard(mutex, &chip->mutex) { + if (subs->opened) + return -EBUSY; + subs->opened = 1; } - subs->opened = 1; - mutex_unlock(&chip->mutex); runtime->hw = snd_usb_hardware; /* need an explicit sync to catch applptr update in low-latency mode */ @@ -1281,9 +1276,9 @@ static int snd_usb_pcm_open(struct snd_pcm_substream *substream) err_resume: snd_usb_autosuspend(subs->stream->chip); err_open: - mutex_lock(&chip->mutex); - subs->opened = 0; - mutex_unlock(&chip->mutex); + scoped_guard(mutex, &chip->mutex) { + subs->opened = 0; + } return ret; } @@ -1298,18 +1293,20 @@ static int snd_usb_pcm_close(struct snd_pcm_substream *substream) snd_media_stop_pipeline(subs); - if (!snd_usb_lock_shutdown(subs->stream->chip)) { + { + CLASS(snd_usb_lock, pm)(subs->stream->chip); + if (pm.err) + return pm.err; ret = snd_usb_pcm_change_state(subs, UAC3_PD_STATE_D1); - snd_usb_unlock_shutdown(subs->stream->chip); if (ret < 0) return ret; } subs->pcm_substream = NULL; snd_usb_autosuspend(subs->stream->chip); - mutex_lock(&chip->mutex); - subs->opened = 0; - mutex_unlock(&chip->mutex); + scoped_guard(mutex, &chip->mutex) { + subs->opened = 0; + } return 0; } @@ -1325,7 +1322,6 @@ static void retire_capture_urb(struct snd_usb_substream *subs, struct snd_pcm_runtime *runtime = subs->pcm_substream->runtime; unsigned int stride, frames, bytes, oldptr; int i, period_elapsed = 0; - unsigned long flags; unsigned char *cp; int current_frame_number; @@ -1358,22 +1354,21 @@ static void retire_capture_urb(struct snd_usb_substream *subs, oldbytes, bytes); } /* update the current pointer */ - spin_lock_irqsave(&subs->lock, flags); - oldptr = subs->hwptr_done; - subs->hwptr_done += bytes; - if (subs->hwptr_done >= subs->buffer_bytes) - subs->hwptr_done -= subs->buffer_bytes; - frames = (bytes + (oldptr % stride)) / stride; - subs->transfer_done += frames; - if (subs->transfer_done >= runtime->period_size) { - subs->transfer_done -= runtime->period_size; - period_elapsed = 1; - } - - /* realign last_frame_number */ - subs->last_frame_number = current_frame_number; + scoped_guard(spinlock_irqsave, &subs->lock) { + oldptr = subs->hwptr_done; + subs->hwptr_done += bytes; + if (subs->hwptr_done >= subs->buffer_bytes) + subs->hwptr_done -= subs->buffer_bytes; + frames = (bytes + (oldptr % stride)) / stride; + subs->transfer_done += frames; + if (subs->transfer_done >= runtime->period_size) { + subs->transfer_done -= runtime->period_size; + period_elapsed = 1; + } - spin_unlock_irqrestore(&subs->lock, flags); + /* realign last_frame_number */ + subs->last_frame_number = current_frame_number; + } /* copy a data chunk */ if (oldptr + bytes > subs->buffer_bytes) { unsigned int bytes1 = subs->buffer_bytes - oldptr; @@ -1533,8 +1528,6 @@ static int prepare_playback_urb(struct snd_usb_substream *subs, int counts; unsigned int transfer_done, frame_limit, avail = 0; int i, stride, period_elapsed = 0; - unsigned long flags; - int err = 0; stride = ep->stride; @@ -1542,106 +1535,101 @@ static int prepare_playback_urb(struct snd_usb_substream *subs, ctx->queued = 0; urb->number_of_packets = 0; - spin_lock_irqsave(&subs->lock, flags); - frame_limit = subs->frame_limit + ep->max_urb_frames; - transfer_done = subs->transfer_done; - - if (subs->lowlatency_playback && - runtime->state != SNDRV_PCM_STATE_DRAINING) { - unsigned int hwptr = subs->hwptr_done / stride; + scoped_guard(spinlock_irqsave, &subs->lock) { + frame_limit = subs->frame_limit + ep->max_urb_frames; + transfer_done = subs->transfer_done; - /* calculate the byte offset-in-buffer of the appl_ptr */ - avail = (runtime->control->appl_ptr - runtime->hw_ptr_base) - % runtime->buffer_size; - if (avail <= hwptr) - avail += runtime->buffer_size; - avail -= hwptr; - } + if (subs->lowlatency_playback && + runtime->state != SNDRV_PCM_STATE_DRAINING) { + unsigned int hwptr = subs->hwptr_done / stride; + + /* calculate the byte offset-in-buffer of the appl_ptr */ + avail = (runtime->control->appl_ptr - runtime->hw_ptr_base) + % runtime->buffer_size; + if (avail <= hwptr) + avail += runtime->buffer_size; + avail -= hwptr; + } - for (i = 0; i < ctx->packets; i++) { - counts = snd_usb_endpoint_next_packet_size(ep, ctx, i, avail); - if (counts < 0) - break; - /* set up descriptor */ - urb->iso_frame_desc[i].offset = frames * stride; - urb->iso_frame_desc[i].length = counts * stride; - frames += counts; - avail -= counts; - urb->number_of_packets++; - transfer_done += counts; - if (transfer_done >= runtime->period_size) { - transfer_done -= runtime->period_size; - frame_limit = 0; - period_elapsed = 1; - if (subs->fmt_type == UAC_FORMAT_TYPE_II) { - if (transfer_done > 0) { - /* FIXME: fill-max mode is not - * supported yet */ - frames -= transfer_done; - counts -= transfer_done; - urb->iso_frame_desc[i].length = - counts * stride; - transfer_done = 0; - } - i++; - if (i < ctx->packets) { - /* add a transfer delimiter */ - urb->iso_frame_desc[i].offset = - frames * stride; - urb->iso_frame_desc[i].length = 0; - urb->number_of_packets++; - } + for (i = 0; i < ctx->packets; i++) { + counts = snd_usb_endpoint_next_packet_size(ep, ctx, i, avail); + if (counts < 0) break; + /* set up descriptor */ + urb->iso_frame_desc[i].offset = frames * stride; + urb->iso_frame_desc[i].length = counts * stride; + frames += counts; + avail -= counts; + urb->number_of_packets++; + transfer_done += counts; + if (transfer_done >= runtime->period_size) { + transfer_done -= runtime->period_size; + frame_limit = 0; + period_elapsed = 1; + if (subs->fmt_type == UAC_FORMAT_TYPE_II) { + if (transfer_done > 0) { + /* FIXME: fill-max mode is not + * supported yet */ + frames -= transfer_done; + counts -= transfer_done; + urb->iso_frame_desc[i].length = + counts * stride; + transfer_done = 0; + } + i++; + if (i < ctx->packets) { + /* add a transfer delimiter */ + urb->iso_frame_desc[i].offset = + frames * stride; + urb->iso_frame_desc[i].length = 0; + urb->number_of_packets++; + } + break; + } } + /* finish at the period boundary or after enough frames */ + if ((period_elapsed || transfer_done >= frame_limit) && + !snd_usb_endpoint_implicit_feedback_sink(ep)) + break; } - /* finish at the period boundary or after enough frames */ - if ((period_elapsed || transfer_done >= frame_limit) && - !snd_usb_endpoint_implicit_feedback_sink(ep)) - break; - } - if (!frames) { - err = -EAGAIN; - goto unlock; - } - - bytes = frames * stride; - subs->transfer_done = transfer_done; - subs->frame_limit = frame_limit; - if (unlikely(ep->cur_format == SNDRV_PCM_FORMAT_DSD_U16_LE && - subs->cur_audiofmt->dsd_dop)) { - fill_playback_urb_dsd_dop(subs, urb, bytes); - } else if (unlikely(ep->cur_format == SNDRV_PCM_FORMAT_DSD_U8 && - subs->cur_audiofmt->dsd_bitrev)) { - fill_playback_urb_dsd_bitrev(subs, urb, bytes); - } else { - /* usual PCM */ - if (!subs->tx_length_quirk) - copy_to_urb(subs, urb, 0, stride, bytes); - else - bytes = copy_to_urb_quirk(subs, urb, stride, bytes); + if (!frames) + return -EAGAIN; + + bytes = frames * stride; + subs->transfer_done = transfer_done; + subs->frame_limit = frame_limit; + if (unlikely(ep->cur_format == SNDRV_PCM_FORMAT_DSD_U16_LE && + subs->cur_audiofmt->dsd_dop)) { + fill_playback_urb_dsd_dop(subs, urb, bytes); + } else if (unlikely(ep->cur_format == SNDRV_PCM_FORMAT_DSD_U8 && + subs->cur_audiofmt->dsd_bitrev)) { + fill_playback_urb_dsd_bitrev(subs, urb, bytes); + } else { + /* usual PCM */ + if (!subs->tx_length_quirk) + copy_to_urb(subs, urb, 0, stride, bytes); + else + bytes = copy_to_urb_quirk(subs, urb, stride, bytes); /* bytes is now amount of outgoing data */ - } + } - subs->last_frame_number = usb_get_current_frame_number(subs->dev); + subs->last_frame_number = usb_get_current_frame_number(subs->dev); - if (subs->trigger_tstamp_pending_update) { - /* this is the first actual URB submitted, - * update trigger timestamp to reflect actual start time - */ - snd_pcm_gettime(runtime, &runtime->trigger_tstamp); - subs->trigger_tstamp_pending_update = false; - } + if (subs->trigger_tstamp_pending_update) { + /* this is the first actual URB submitted, + * update trigger timestamp to reflect actual start time + */ + snd_pcm_gettime(runtime, &runtime->trigger_tstamp); + subs->trigger_tstamp_pending_update = false; + } - if (period_elapsed && !subs->running && subs->lowlatency_playback) { - subs->period_elapsed_pending = 1; - period_elapsed = 0; + if (period_elapsed && !subs->running && subs->lowlatency_playback) { + subs->period_elapsed_pending = 1; + period_elapsed = 0; + } } - unlock: - spin_unlock_irqrestore(&subs->lock, flags); - if (err < 0) - return err; urb->transfer_buffer_length = bytes; if (period_elapsed) { if (in_stream_lock) @@ -1659,24 +1647,23 @@ static int prepare_playback_urb(struct snd_usb_substream *subs, static void retire_playback_urb(struct snd_usb_substream *subs, struct urb *urb) { - unsigned long flags; struct snd_urb_ctx *ctx = urb->context; bool period_elapsed = false; - spin_lock_irqsave(&subs->lock, flags); - if (ctx->queued) { - if (subs->inflight_bytes >= ctx->queued) - subs->inflight_bytes -= ctx->queued; - else - subs->inflight_bytes = 0; - } + scoped_guard(spinlock_irqsave, &subs->lock) { + if (ctx->queued) { + if (subs->inflight_bytes >= ctx->queued) + subs->inflight_bytes -= ctx->queued; + else + subs->inflight_bytes = 0; + } - subs->last_frame_number = usb_get_current_frame_number(subs->dev); - if (subs->running) { - period_elapsed = subs->period_elapsed_pending; - subs->period_elapsed_pending = 0; + subs->last_frame_number = usb_get_current_frame_number(subs->dev); + if (subs->running) { + period_elapsed = subs->period_elapsed_pending; + subs->period_elapsed_pending = 0; + } } - spin_unlock_irqrestore(&subs->lock, flags); if (period_elapsed) snd_pcm_period_elapsed(subs->pcm_substream); } |