}
 }
 
-/* increase the appl_ptr; returns the processed frames */
+/* update to the given appl_ptr and call ack callback if needed;
+ * when an error is returned, take back to the original value
+ */
+static int apply_appl_ptr(struct snd_pcm_substream *substream,
+                         snd_pcm_uframes_t appl_ptr)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       snd_pcm_uframes_t old_appl_ptr = runtime->control->appl_ptr;
+       int ret;
+
+       runtime->control->appl_ptr = appl_ptr;
+       if (substream->ops->ack) {
+               ret = substream->ops->ack(substream);
+               if (ret < 0) {
+                       runtime->control->appl_ptr = old_appl_ptr;
+                       return ret;
+               }
+       }
+       return 0;
+}
+
+/* increase the appl_ptr; returns the processed frames or a negative error */
 static snd_pcm_sframes_t forward_appl_ptr(struct snd_pcm_substream *substream,
                                          snd_pcm_uframes_t frames,
                                           snd_pcm_sframes_t avail)
 {
        struct snd_pcm_runtime *runtime = substream->runtime;
        snd_pcm_sframes_t appl_ptr;
+       int ret;
 
        if (avail <= 0)
                return 0;
        appl_ptr = runtime->control->appl_ptr + frames;
        if (appl_ptr >= (snd_pcm_sframes_t)runtime->boundary)
                appl_ptr -= runtime->boundary;
-       runtime->control->appl_ptr = appl_ptr;
-       return frames;
+       ret = apply_appl_ptr(substream, appl_ptr);
+       return ret < 0 ? ret : frames;
 }
 
-/* decrease the appl_ptr; returns the processed frames */
+/* decrease the appl_ptr; returns the processed frames or a negative error */
 static snd_pcm_sframes_t rewind_appl_ptr(struct snd_pcm_substream *substream,
                                         snd_pcm_uframes_t frames,
                                         snd_pcm_sframes_t avail)
 {
        struct snd_pcm_runtime *runtime = substream->runtime;
        snd_pcm_sframes_t appl_ptr;
+       int ret;
 
        if (avail <= 0)
                return 0;
        appl_ptr = runtime->control->appl_ptr - frames;
        if (appl_ptr < 0)
                appl_ptr += runtime->boundary;
-       runtime->control->appl_ptr = appl_ptr;
-       return frames;
+       ret = apply_appl_ptr(substream, appl_ptr);
+       return ret < 0 ? ret : frames;
 }
 
 static snd_pcm_sframes_t snd_pcm_playback_rewind(struct snd_pcm_substream *substream,
                        return err;
        }
        snd_pcm_stream_lock_irq(substream);
-       if (!(sync_ptr.flags & SNDRV_PCM_SYNC_PTR_APPL))
-               control->appl_ptr = sync_ptr.c.control.appl_ptr;
-       else
+       if (!(sync_ptr.flags & SNDRV_PCM_SYNC_PTR_APPL)) {
+               err = apply_appl_ptr(substream, sync_ptr.c.control.appl_ptr);
+               if (err < 0) {
+                       snd_pcm_stream_unlock_irq(substream);
+                       return err;
+               }
+       } else {
                sync_ptr.c.control.appl_ptr = control->appl_ptr;
+       }
        if (!(sync_ptr.flags & SNDRV_PCM_SYNC_PTR_AVAIL_MIN))
                control->avail_min = sync_ptr.c.control.avail_min;
        else