]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - sound/core/pcm_lib.c
ALSA: Kill snd_assert() in sound/core/*
[linux-2.6-omap-h63xx.git] / sound / core / pcm_lib.c
index 9fefcaa2c324e5a4c740a9653945185a212e5374..6ea5cfb83998ad04fa0678ab522b4e734a737180 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *  Digital Audio (PCM) abstract layer
- *  Copyright (c) by Jaroslav Kysela <perex@suse.cz>
+ *  Copyright (c) by Jaroslav Kysela <perex@perex.cz>
  *                   Abramo Bagnara <abramo@alsa-project.org>
  *
  *
@@ -20,7 +20,6 @@
  *
  */
 
-#include <sound/driver.h>
 #include <linux/slab.h>
 #include <linux/time.h>
 #include <sound/core.h>
@@ -86,7 +85,8 @@ void snd_pcm_playback_silence(struct snd_pcm_substream *substream, snd_pcm_ufram
                }
                frames = runtime->buffer_size - runtime->silence_filled;
        }
-       snd_assert(frames <= runtime->buffer_size, return);
+       if (snd_BUG_ON(frames > runtime->buffer_size))
+               return;
        if (frames == 0)
                return;
        ofs = runtime->silence_start % runtime->buffer_size;
@@ -97,7 +97,7 @@ void snd_pcm_playback_silence(struct snd_pcm_substream *substream, snd_pcm_ufram
                        if (substream->ops->silence) {
                                int err;
                                err = substream->ops->silence(substream, -1, ofs, transfer);
-                               snd_assert(err >= 0, );
+                               snd_BUG_ON(err < 0);
                        } else {
                                char *hwbuf = runtime->dma_area + frames_to_bytes(runtime, ofs);
                                snd_pcm_format_set_silence(runtime->format, hwbuf, transfer * runtime->channels);
@@ -109,7 +109,7 @@ void snd_pcm_playback_silence(struct snd_pcm_substream *substream, snd_pcm_ufram
                                for (c = 0; c < channels; ++c) {
                                        int err;
                                        err = substream->ops->silence(substream, c, ofs, transfer);
-                                       snd_assert(err >= 0, );
+                                       snd_BUG_ON(err < 0);
                                }
                        } else {
                                size_t dma_csize = runtime->dma_bytes / channels;
@@ -145,11 +145,11 @@ static inline snd_pcm_uframes_t snd_pcm_update_hw_ptr_pos(struct snd_pcm_substre
 {
        snd_pcm_uframes_t pos;
 
+       if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE)
+               snd_pcm_gettime(runtime, (struct timespec *)&runtime->status->tstamp);
        pos = substream->ops->pointer(substream);
        if (pos == SNDRV_PCM_POS_XRUN)
                return pos; /* XRUN */
-       if (runtime->tstamp_mode & SNDRV_PCM_TSTAMP_MMAP)
-               getnstimeofday((struct timespec *)&runtime->status->tstamp);
 #ifdef CONFIG_SND_DEBUG
        if (pos >= runtime->buffer_size) {
                snd_printk(KERN_ERR  "BUG: stream = %i, pos = 0x%lx, buffer size = 0x%lx, period size = 0x%lx\n", substream->stream, pos, runtime->buffer_size, runtime->period_size);
@@ -355,7 +355,7 @@ static inline unsigned int muldiv32(unsigned int a, unsigned int b,
 {
        u_int64_t n = (u_int64_t) a * b;
        if (c == 0) {
-               snd_assert(n > 0, );
+               snd_BUG_ON(!n);
                *r = 0;
                return UINT_MAX;
        }
@@ -381,7 +381,8 @@ static inline unsigned int muldiv32(unsigned int a, unsigned int b,
 int snd_interval_refine(struct snd_interval *i, const struct snd_interval *v)
 {
        int changed = 0;
-       snd_assert(!snd_interval_empty(i), return -EINVAL);
+       if (snd_BUG_ON(snd_interval_empty(i)))
+               return -EINVAL;
        if (i->min < v->min) {
                i->min = v->min;
                i->openmin = v->openmin;
@@ -424,7 +425,8 @@ EXPORT_SYMBOL(snd_interval_refine);
 
 static int snd_interval_refine_first(struct snd_interval *i)
 {
-       snd_assert(!snd_interval_empty(i), return -EINVAL);
+       if (snd_BUG_ON(snd_interval_empty(i)))
+               return -EINVAL;
        if (snd_interval_single(i))
                return 0;
        i->max = i->min;
@@ -436,7 +438,8 @@ static int snd_interval_refine_first(struct snd_interval *i)
 
 static int snd_interval_refine_last(struct snd_interval *i)
 {
-       snd_assert(!snd_interval_empty(i), return -EINVAL);
+       if (snd_BUG_ON(snd_interval_empty(i)))
+               return -EINVAL;
        if (snd_interval_single(i))
                return 0;
        i->min = i->max;
@@ -890,7 +893,8 @@ int snd_pcm_hw_rule_add(struct snd_pcm_runtime *runtime, unsigned int cond,
        c->private = private;
        k = 0;
        while (1) {
-               snd_assert(k < ARRAY_SIZE(c->deps), return -EINVAL);
+               if (snd_BUG_ON(k >= ARRAY_SIZE(c->deps)))
+                       return -EINVAL;
                c->deps[k++] = dep;
                if (dep < 0)
                        break;
@@ -1139,7 +1143,7 @@ EXPORT_SYMBOL(snd_pcm_hw_constraint_step);
 
 static int snd_pcm_hw_rule_pow2(struct snd_pcm_hw_params *params, struct snd_pcm_hw_rule *rule)
 {
-       static int pow2_sizes[] = {
+       static unsigned int pow2_sizes[] = {
                1<<0, 1<<1, 1<<2, 1<<3, 1<<4, 1<<5, 1<<6, 1<<7,
                1<<8, 1<<9, 1<<10, 1<<11, 1<<12, 1<<13, 1<<14, 1<<15,
                1<<16, 1<<17, 1<<18, 1<<19, 1<<20, 1<<21, 1<<22, 1<<23,
@@ -1286,7 +1290,8 @@ int snd_pcm_hw_param_first(struct snd_pcm_substream *pcm,
                return changed;
        if (params->rmask) {
                int err = snd_pcm_hw_refine(pcm, params);
-               snd_assert(err >= 0, return err);
+               if (snd_BUG_ON(err < 0))
+                       return err;
        }
        return snd_pcm_hw_param_value(params, var, dir);
 }
@@ -1331,7 +1336,8 @@ int snd_pcm_hw_param_last(struct snd_pcm_substream *pcm,
                return changed;
        if (params->rmask) {
                int err = snd_pcm_hw_refine(pcm, params);
-               snd_assert(err >= 0, return err);
+               if (snd_BUG_ON(err < 0))
+                       return err;
        }
        return snd_pcm_hw_param_value(params, var, dir);
 }
@@ -1369,7 +1375,8 @@ int snd_pcm_hw_params_choose(struct snd_pcm_substream *pcm,
                        err = snd_pcm_hw_param_first(pcm, params, *v, NULL);
                else
                        err = snd_pcm_hw_param_last(pcm, params, *v, NULL);
-               snd_assert(err >= 0, return err);
+               if (snd_BUG_ON(err < 0))
+                       return err;
        }
        return 0;
 }
@@ -1451,108 +1458,13 @@ int snd_pcm_lib_ioctl(struct snd_pcm_substream *substream,
 
 EXPORT_SYMBOL(snd_pcm_lib_ioctl);
 
-/*
- *  Conditions
- */
-
-static void snd_pcm_system_tick_set(struct snd_pcm_substream *substream, 
-                                   unsigned long ticks)
-{
-       struct snd_pcm_runtime *runtime = substream->runtime;
-       if (ticks == 0)
-               del_timer(&runtime->tick_timer);
-       else {
-               ticks += (1000000 / HZ) - 1;
-               ticks /= (1000000 / HZ);
-               mod_timer(&runtime->tick_timer, jiffies + ticks);
-       }
-}
-
-/* Temporary alias */
-void snd_pcm_tick_set(struct snd_pcm_substream *substream, unsigned long ticks)
-{
-       snd_pcm_system_tick_set(substream, ticks);
-}
-
-void snd_pcm_tick_prepare(struct snd_pcm_substream *substream)
-{
-       struct snd_pcm_runtime *runtime = substream->runtime;
-       snd_pcm_uframes_t frames = ULONG_MAX;
-       snd_pcm_uframes_t avail, dist;
-       unsigned int ticks;
-       u_int64_t n;
-       u_int32_t r;
-       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-               if (runtime->silence_size >= runtime->boundary) {
-                       frames = 1;
-               } else if (runtime->silence_size > 0 &&
-                          runtime->silence_filled < runtime->buffer_size) {
-                       snd_pcm_sframes_t noise_dist;
-                       noise_dist = snd_pcm_playback_hw_avail(runtime) + runtime->silence_filled;
-                       if (noise_dist > (snd_pcm_sframes_t)runtime->silence_threshold)
-                               frames = noise_dist - runtime->silence_threshold;
-               }
-               avail = snd_pcm_playback_avail(runtime);
-       } else {
-               avail = snd_pcm_capture_avail(runtime);
-       }
-       if (avail < runtime->control->avail_min) {
-               snd_pcm_sframes_t n = runtime->control->avail_min - avail;
-               if (n > 0 && frames > (snd_pcm_uframes_t)n)
-                       frames = n;
-       }
-       if (avail < runtime->buffer_size) {
-               snd_pcm_sframes_t n = runtime->buffer_size - avail;
-               if (n > 0 && frames > (snd_pcm_uframes_t)n)
-                       frames = n;
-       }
-       if (frames == ULONG_MAX) {
-               snd_pcm_tick_set(substream, 0);
-               return;
-       }
-       dist = runtime->status->hw_ptr - runtime->hw_ptr_base;
-       /* Distance to next interrupt */
-       dist = runtime->period_size - dist % runtime->period_size;
-       if (dist <= frames) {
-               snd_pcm_tick_set(substream, 0);
-               return;
-       }
-       /* the base time is us */
-       n = frames;
-       n *= 1000000;
-       div64_32(&n, runtime->tick_time * runtime->rate, &r);
-       ticks = n + (r > 0 ? 1 : 0);
-       if (ticks < runtime->sleep_min)
-               ticks = runtime->sleep_min;
-       snd_pcm_tick_set(substream, (unsigned long) ticks);
-}
-
-void snd_pcm_tick_elapsed(struct snd_pcm_substream *substream)
-{
-       struct snd_pcm_runtime *runtime;
-       unsigned long flags;
-       
-       snd_assert(substream != NULL, return);
-       runtime = substream->runtime;
-       snd_assert(runtime != NULL, return);
-
-       snd_pcm_stream_lock_irqsave(substream, flags);
-       if (!snd_pcm_running(substream) ||
-           snd_pcm_update_hw_ptr(substream) < 0)
-               goto _end;
-       if (runtime->sleep_min)
-               snd_pcm_tick_prepare(substream);
- _end:
-       snd_pcm_stream_unlock_irqrestore(substream, flags);
-}
-
 /**
  * snd_pcm_period_elapsed - update the pcm status for the next period
  * @substream: the pcm substream instance
  *
  * This function is called from the interrupt handler when the
  * PCM has processed the period size.  It will update the current
- * pointer, set up the tick, wake up sleepers, etc.
+ * pointer, wake up sleepers, etc.
  *
  * Even if more than one periods have elapsed since the last call, you
  * have to call this only once.
@@ -1562,9 +1474,9 @@ void snd_pcm_period_elapsed(struct snd_pcm_substream *substream)
        struct snd_pcm_runtime *runtime;
        unsigned long flags;
 
-       snd_assert(substream != NULL, return);
+       if (PCM_RUNTIME_CHECK(substream))
+               return;
        runtime = substream->runtime;
-       snd_assert(runtime != NULL, return);
 
        if (runtime->transfer_ack_begin)
                runtime->transfer_ack_begin(substream);
@@ -1576,8 +1488,6 @@ void snd_pcm_period_elapsed(struct snd_pcm_substream *substream)
 
        if (substream->timer_running)
                snd_timer_interrupt(substream->timer, 1);
-       if (runtime->sleep_min)
-               snd_pcm_tick_prepare(substream);
  _end:
        snd_pcm_stream_unlock_irqrestore(substream, flags);
        if (runtime->transfer_ack_end)
@@ -1587,6 +1497,71 @@ void snd_pcm_period_elapsed(struct snd_pcm_substream *substream)
 
 EXPORT_SYMBOL(snd_pcm_period_elapsed);
 
+/*
+ * Wait until avail_min data becomes available
+ * Returns a negative error code if any error occurs during operation.
+ * The available space is stored on availp.  When err = 0 and avail = 0
+ * on the capture stream, it indicates the stream is in DRAINING state.
+ */
+static int wait_for_avail_min(struct snd_pcm_substream *substream,
+                             snd_pcm_uframes_t *availp)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       int is_playback = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
+       wait_queue_t wait;
+       int err = 0;
+       snd_pcm_uframes_t avail = 0;
+       long tout;
+
+       init_waitqueue_entry(&wait, current);
+       add_wait_queue(&runtime->sleep, &wait);
+       for (;;) {
+               if (signal_pending(current)) {
+                       err = -ERESTARTSYS;
+                       break;
+               }
+               set_current_state(TASK_INTERRUPTIBLE);
+               snd_pcm_stream_unlock_irq(substream);
+               tout = schedule_timeout(msecs_to_jiffies(10000));
+               snd_pcm_stream_lock_irq(substream);
+               switch (runtime->status->state) {
+               case SNDRV_PCM_STATE_SUSPENDED:
+                       err = -ESTRPIPE;
+                       goto _endloop;
+               case SNDRV_PCM_STATE_XRUN:
+                       err = -EPIPE;
+                       goto _endloop;
+               case SNDRV_PCM_STATE_DRAINING:
+                       if (is_playback)
+                               err = -EPIPE;
+                       else 
+                               avail = 0; /* indicate draining */
+                       goto _endloop;
+               case SNDRV_PCM_STATE_OPEN:
+               case SNDRV_PCM_STATE_SETUP:
+               case SNDRV_PCM_STATE_DISCONNECTED:
+                       err = -EBADFD;
+                       goto _endloop;
+               }
+               if (!tout) {
+                       snd_printd("%s write error (DMA or IRQ trouble?)\n",
+                                  is_playback ? "playback" : "capture");
+                       err = -EIO;
+                       break;
+               }
+               if (is_playback)
+                       avail = snd_pcm_playback_avail(runtime);
+               else
+                       avail = snd_pcm_capture_avail(runtime);
+               if (avail >= runtime->control->avail_min)
+                       break;
+       }
+ _endloop:
+       remove_wait_queue(&runtime->sleep, &wait);
+       *availp = avail;
+       return err;
+}
+       
 static int snd_pcm_lib_write_transfer(struct snd_pcm_substream *substream,
                                      unsigned int hwoff,
                                      unsigned long data, unsigned int off,
@@ -1600,7 +1575,6 @@ static int snd_pcm_lib_write_transfer(struct snd_pcm_substream *substream,
                        return err;
        } else {
                char *hwbuf = runtime->dma_area + frames_to_bytes(runtime, hwoff);
-               snd_assert(runtime->dma_area, return -EFAULT);
                if (copy_from_user(hwbuf, buf, frames_to_bytes(runtime, frames)))
                        return -EFAULT;
        }
@@ -1624,8 +1598,6 @@ static snd_pcm_sframes_t snd_pcm_lib_write1(struct snd_pcm_substream *substream,
 
        if (size == 0)
                return 0;
-       if (size > runtime->xfer_align)
-               size -= size % runtime->xfer_align;
 
        snd_pcm_stream_lock_irq(substream);
        switch (runtime->status->state) {
@@ -1648,89 +1620,26 @@ static snd_pcm_sframes_t snd_pcm_lib_write1(struct snd_pcm_substream *substream,
                snd_pcm_uframes_t frames, appl_ptr, appl_ofs;
                snd_pcm_uframes_t avail;
                snd_pcm_uframes_t cont;
-               if (runtime->sleep_min == 0 && runtime->status->state == SNDRV_PCM_STATE_RUNNING)
+               if (runtime->status->state == SNDRV_PCM_STATE_RUNNING)
                        snd_pcm_update_hw_ptr(substream);
                avail = snd_pcm_playback_avail(runtime);
-               if (((avail < runtime->control->avail_min && size > avail) ||
-                  (size >= runtime->xfer_align && avail < runtime->xfer_align))) {
-                       wait_queue_t wait;
-                       enum { READY, SIGNALED, ERROR, SUSPENDED, EXPIRED, DROPPED } state;
-                       long tout;
-
+               if (!avail) {
                        if (nonblock) {
                                err = -EAGAIN;
                                goto _end_unlock;
                        }
-
-                       init_waitqueue_entry(&wait, current);
-                       add_wait_queue(&runtime->sleep, &wait);
-                       while (1) {
-                               if (signal_pending(current)) {
-                                       state = SIGNALED;
-                                       break;
-                               }
-                               set_current_state(TASK_INTERRUPTIBLE);
-                               snd_pcm_stream_unlock_irq(substream);
-                               tout = schedule_timeout(10 * HZ);
-                               snd_pcm_stream_lock_irq(substream);
-                               if (tout == 0) {
-                                       if (runtime->status->state != SNDRV_PCM_STATE_PREPARED &&
-                                           runtime->status->state != SNDRV_PCM_STATE_PAUSED) {
-                                               state = runtime->status->state == SNDRV_PCM_STATE_SUSPENDED ? SUSPENDED : EXPIRED;
-                                               break;
-                                       }
-                               }
-                               switch (runtime->status->state) {
-                               case SNDRV_PCM_STATE_XRUN:
-                               case SNDRV_PCM_STATE_DRAINING:
-                                       state = ERROR;
-                                       goto _end_loop;
-                               case SNDRV_PCM_STATE_SUSPENDED:
-                                       state = SUSPENDED;
-                                       goto _end_loop;
-                               case SNDRV_PCM_STATE_SETUP:
-                                       state = DROPPED;
-                                       goto _end_loop;
-                               default:
-                                       break;
-                               }
-                               avail = snd_pcm_playback_avail(runtime);
-                               if (avail >= runtime->control->avail_min) {
-                                       state = READY;
-                                       break;
-                               }
-                       }
-                      _end_loop:
-                       remove_wait_queue(&runtime->sleep, &wait);
-
-                       switch (state) {
-                       case ERROR:
-                               err = -EPIPE;
-                               goto _end_unlock;
-                       case SUSPENDED:
-                               err = -ESTRPIPE;
-                               goto _end_unlock;
-                       case SIGNALED:
-                               err = -ERESTARTSYS;
-                               goto _end_unlock;
-                       case EXPIRED:
-                               snd_printd("playback write error (DMA or IRQ trouble?)\n");
-                               err = -EIO;
-                               goto _end_unlock;
-                       case DROPPED:
-                               err = -EBADFD;
+                       err = wait_for_avail_min(substream, &avail);
+                       if (err < 0)
                                goto _end_unlock;
-                       default:
-                               break;
-                       }
                }
-               if (avail > runtime->xfer_align)
-                       avail -= avail % runtime->xfer_align;
                frames = size > avail ? avail : size;
                cont = runtime->buffer_size - runtime->control->appl_ptr % runtime->buffer_size;
                if (frames > cont)
                        frames = cont;
-               snd_assert(frames != 0, snd_pcm_stream_unlock_irq(substream); return -EINVAL);
+               if (snd_BUG_ON(!frames)) {
+                       snd_pcm_stream_unlock_irq(substream);
+                       return -EINVAL;
+               }
                appl_ptr = runtime->control->appl_ptr;
                appl_ofs = appl_ptr % runtime->buffer_size;
                snd_pcm_stream_unlock_irq(substream);
@@ -1763,9 +1672,6 @@ static snd_pcm_sframes_t snd_pcm_lib_write1(struct snd_pcm_substream *substream,
                        if (err < 0)
                                goto _end_unlock;
                }
-               if (runtime->sleep_min &&
-                   runtime->status->state == SNDRV_PCM_STATE_RUNNING)
-                       snd_pcm_tick_prepare(substream);
        }
  _end_unlock:
        snd_pcm_stream_unlock_irq(substream);
@@ -1773,18 +1679,30 @@ static snd_pcm_sframes_t snd_pcm_lib_write1(struct snd_pcm_substream *substream,
        return xfer > 0 ? (snd_pcm_sframes_t)xfer : err;
 }
 
-snd_pcm_sframes_t snd_pcm_lib_write(struct snd_pcm_substream *substream, const void __user *buf, snd_pcm_uframes_t size)
+/* sanity-check for read/write methods */
+static int pcm_sanity_check(struct snd_pcm_substream *substream)
 {
        struct snd_pcm_runtime *runtime;
-       int nonblock;
-
-       snd_assert(substream != NULL, return -ENXIO);
+       if (PCM_RUNTIME_CHECK(substream))
+               return -ENXIO;
        runtime = substream->runtime;
-       snd_assert(runtime != NULL, return -ENXIO);
-       snd_assert(substream->ops->copy != NULL || runtime->dma_area != NULL, return -EINVAL);
+       if (snd_BUG_ON(!substream->ops->copy && !runtime->dma_area))
+               return -EINVAL;
        if (runtime->status->state == SNDRV_PCM_STATE_OPEN)
                return -EBADFD;
+       return 0;
+}
 
+snd_pcm_sframes_t snd_pcm_lib_write(struct snd_pcm_substream *substream, const void __user *buf, snd_pcm_uframes_t size)
+{
+       struct snd_pcm_runtime *runtime;
+       int nonblock;
+       int err;
+
+       err = pcm_sanity_check(substream);
+       if (err < 0)
+               return err;
+       runtime = substream->runtime;
        nonblock = !!(substream->f_flags & O_NONBLOCK);
 
        if (runtime->access != SNDRV_PCM_ACCESS_RW_INTERLEAVED &&
@@ -1807,7 +1725,8 @@ static int snd_pcm_lib_writev_transfer(struct snd_pcm_substream *substream,
        int channels = runtime->channels;
        int c;
        if (substream->ops->copy) {
-               snd_assert(substream->ops->silence != NULL, return -EINVAL);
+               if (snd_BUG_ON(!substream->ops->silence))
+                       return -EINVAL;
                for (c = 0; c < channels; ++c, ++bufs) {
                        if (*bufs == NULL) {
                                if ((err = substream->ops->silence(substream, c, hwoff, frames)) < 0)
@@ -1821,7 +1740,6 @@ static int snd_pcm_lib_writev_transfer(struct snd_pcm_substream *substream,
        } else {
                /* default transfer behaviour */
                size_t dma_csize = runtime->dma_bytes / channels;
-               snd_assert(runtime->dma_area, return -EFAULT);
                for (c = 0; c < channels; ++c, ++bufs) {
                        char *hwbuf = runtime->dma_area + (c * dma_csize) + samples_to_bytes(runtime, hwoff);
                        if (*bufs == NULL) {
@@ -1842,14 +1760,12 @@ snd_pcm_sframes_t snd_pcm_lib_writev(struct snd_pcm_substream *substream,
 {
        struct snd_pcm_runtime *runtime;
        int nonblock;
+       int err;
 
-       snd_assert(substream != NULL, return -ENXIO);
+       err = pcm_sanity_check(substream);
+       if (err < 0)
+               return err;
        runtime = substream->runtime;
-       snd_assert(runtime != NULL, return -ENXIO);
-       snd_assert(substream->ops->copy != NULL || runtime->dma_area != NULL, return -EINVAL);
-       if (runtime->status->state == SNDRV_PCM_STATE_OPEN)
-               return -EBADFD;
-
        nonblock = !!(substream->f_flags & O_NONBLOCK);
 
        if (runtime->access != SNDRV_PCM_ACCESS_RW_NONINTERLEAVED)
@@ -1873,7 +1789,6 @@ static int snd_pcm_lib_read_transfer(struct snd_pcm_substream *substream,
                        return err;
        } else {
                char *hwbuf = runtime->dma_area + frames_to_bytes(runtime, hwoff);
-               snd_assert(runtime->dma_area, return -EFAULT);
                if (copy_to_user(buf, hwbuf, frames_to_bytes(runtime, frames)))
                        return -EFAULT;
        }
@@ -1893,8 +1808,6 @@ static snd_pcm_sframes_t snd_pcm_lib_read1(struct snd_pcm_substream *substream,
 
        if (size == 0)
                return 0;
-       if (size > runtime->xfer_align)
-               size -= size % runtime->xfer_align;
 
        snd_pcm_stream_lock_irq(substream);
        switch (runtime->status->state) {
@@ -1924,96 +1837,33 @@ static snd_pcm_sframes_t snd_pcm_lib_read1(struct snd_pcm_substream *substream,
                snd_pcm_uframes_t frames, appl_ptr, appl_ofs;
                snd_pcm_uframes_t avail;
                snd_pcm_uframes_t cont;
-               if (runtime->sleep_min == 0 && runtime->status->state == SNDRV_PCM_STATE_RUNNING)
+               if (runtime->status->state == SNDRV_PCM_STATE_RUNNING)
                        snd_pcm_update_hw_ptr(substream);
-             __draining:
                avail = snd_pcm_capture_avail(runtime);
-               if (runtime->status->state == SNDRV_PCM_STATE_DRAINING) {
-                       if (avail < runtime->xfer_align) {
-                               err = -EPIPE;
+               if (!avail) {
+                       if (runtime->status->state ==
+                           SNDRV_PCM_STATE_DRAINING) {
+                               snd_pcm_stop(substream, SNDRV_PCM_STATE_SETUP);
                                goto _end_unlock;
                        }
-               } else if ((avail < runtime->control->avail_min && size > avail) ||
-                          (size >= runtime->xfer_align && avail < runtime->xfer_align)) {
-                       wait_queue_t wait;
-                       enum { READY, SIGNALED, ERROR, SUSPENDED, EXPIRED, DROPPED } state;
-                       long tout;
-
                        if (nonblock) {
                                err = -EAGAIN;
                                goto _end_unlock;
                        }
-
-                       init_waitqueue_entry(&wait, current);
-                       add_wait_queue(&runtime->sleep, &wait);
-                       while (1) {
-                               if (signal_pending(current)) {
-                                       state = SIGNALED;
-                                       break;
-                               }
-                               set_current_state(TASK_INTERRUPTIBLE);
-                               snd_pcm_stream_unlock_irq(substream);
-                               tout = schedule_timeout(10 * HZ);
-                               snd_pcm_stream_lock_irq(substream);
-                               if (tout == 0) {
-                                       if (runtime->status->state != SNDRV_PCM_STATE_PREPARED &&
-                                           runtime->status->state != SNDRV_PCM_STATE_PAUSED) {
-                                               state = runtime->status->state == SNDRV_PCM_STATE_SUSPENDED ? SUSPENDED : EXPIRED;
-                                               break;
-                                       }
-                               }
-                               switch (runtime->status->state) {
-                               case SNDRV_PCM_STATE_XRUN:
-                                       state = ERROR;
-                                       goto _end_loop;
-                               case SNDRV_PCM_STATE_SUSPENDED:
-                                       state = SUSPENDED;
-                                       goto _end_loop;
-                               case SNDRV_PCM_STATE_DRAINING:
-                                       goto __draining;
-                               case SNDRV_PCM_STATE_SETUP:
-                                       state = DROPPED;
-                                       goto _end_loop;
-                               default:
-                                       break;
-                               }
-                               avail = snd_pcm_capture_avail(runtime);
-                               if (avail >= runtime->control->avail_min) {
-                                       state = READY;
-                                       break;
-                               }
-                       }
-                      _end_loop:
-                       remove_wait_queue(&runtime->sleep, &wait);
-
-                       switch (state) {
-                       case ERROR:
-                               err = -EPIPE;
-                               goto _end_unlock;
-                       case SUSPENDED:
-                               err = -ESTRPIPE;
-                               goto _end_unlock;
-                       case SIGNALED:
-                               err = -ERESTARTSYS;
-                               goto _end_unlock;
-                       case EXPIRED:
-                               snd_printd("capture read error (DMA or IRQ trouble?)\n");
-                               err = -EIO;
-                               goto _end_unlock;
-                       case DROPPED:
-                               err = -EBADFD;
+                       err = wait_for_avail_min(substream, &avail);
+                       if (err < 0)
                                goto _end_unlock;
-                       default:
-                               break;
-                       }
+                       if (!avail)
+                               continue; /* draining */
                }
-               if (avail > runtime->xfer_align)
-                       avail -= avail % runtime->xfer_align;
                frames = size > avail ? avail : size;
                cont = runtime->buffer_size - runtime->control->appl_ptr % runtime->buffer_size;
                if (frames > cont)
                        frames = cont;
-               snd_assert(frames != 0, snd_pcm_stream_unlock_irq(substream); return -EINVAL);
+               if (snd_BUG_ON(!frames)) {
+                       snd_pcm_stream_unlock_irq(substream);
+                       return -EINVAL;
+               }
                appl_ptr = runtime->control->appl_ptr;
                appl_ofs = appl_ptr % runtime->buffer_size;
                snd_pcm_stream_unlock_irq(substream);
@@ -2040,9 +1890,6 @@ static snd_pcm_sframes_t snd_pcm_lib_read1(struct snd_pcm_substream *substream,
                offset += frames;
                size -= frames;
                xfer += frames;
-               if (runtime->sleep_min &&
-                   runtime->status->state == SNDRV_PCM_STATE_RUNNING)
-                       snd_pcm_tick_prepare(substream);
        }
  _end_unlock:
        snd_pcm_stream_unlock_irq(substream);
@@ -2054,14 +1901,12 @@ snd_pcm_sframes_t snd_pcm_lib_read(struct snd_pcm_substream *substream, void __u
 {
        struct snd_pcm_runtime *runtime;
        int nonblock;
+       int err;
        
-       snd_assert(substream != NULL, return -ENXIO);
+       err = pcm_sanity_check(substream);
+       if (err < 0)
+               return err;
        runtime = substream->runtime;
-       snd_assert(runtime != NULL, return -ENXIO);
-       snd_assert(substream->ops->copy != NULL || runtime->dma_area != NULL, return -EINVAL);
-       if (runtime->status->state == SNDRV_PCM_STATE_OPEN)
-               return -EBADFD;
-
        nonblock = !!(substream->f_flags & O_NONBLOCK);
        if (runtime->access != SNDRV_PCM_ACCESS_RW_INTERLEAVED)
                return -EINVAL;
@@ -2091,7 +1936,6 @@ static int snd_pcm_lib_readv_transfer(struct snd_pcm_substream *substream,
                }
        } else {
                snd_pcm_uframes_t dma_csize = runtime->dma_bytes / channels;
-               snd_assert(runtime->dma_area, return -EFAULT);
                for (c = 0; c < channels; ++c, ++bufs) {
                        char *hwbuf;
                        char __user *buf;
@@ -2113,11 +1957,12 @@ snd_pcm_sframes_t snd_pcm_lib_readv(struct snd_pcm_substream *substream,
 {
        struct snd_pcm_runtime *runtime;
        int nonblock;
+       int err;
 
-       snd_assert(substream != NULL, return -ENXIO);
+       err = pcm_sanity_check(substream);
+       if (err < 0)
+               return err;
        runtime = substream->runtime;
-       snd_assert(runtime != NULL, return -ENXIO);
-       snd_assert(substream->ops->copy != NULL || runtime->dma_area != NULL, return -EINVAL);
        if (runtime->status->state == SNDRV_PCM_STATE_OPEN)
                return -EBADFD;