static void loopback_bytepos_update(struct loopback_pcm *dpcm, unsigned int delta, unsigned int cmd) { unsigned int count; unsigned long last_pos; last_pos = byte_pos(dpcm, dpcm->irq_pos); dpcm->irq_pos += delta * dpcm->pcm_bps; count = byte_pos(dpcm, dpcm->irq_pos) - last_pos; if (!count) return; if (cmd == BYTEPOS_UPDATE_CLEAR) clear_capture_buf(dpcm, count); else if (cmd == BYTEPOS_UPDATE_COPY) copy_play_buf(dpcm->cable->streams[SNDRV_PCM_STREAM_PLAYBACK], dpcm->cable->streams[SNDRV_PCM_STREAM_CAPTURE], count); dpcm->buf_pos += count; dpcm->buf_pos %= dpcm->pcm_buffer_size; if (dpcm->irq_pos >= dpcm->period_size_frac) { dpcm->irq_pos %= dpcm->period_size_frac; dpcm->period_update_pending = 1; } }
static unsigned int loopback_pos_update(struct loopback_cable *cable) { struct loopback_pcm *dpcm_play = cable->streams[SNDRV_PCM_STREAM_PLAYBACK]; struct loopback_pcm *dpcm_capt = cable->streams[SNDRV_PCM_STREAM_CAPTURE]; unsigned long delta_play = 0, delta_capt = 0; unsigned int running, count1, count2; unsigned long flags; spin_lock_irqsave(&cable->lock, flags); running = cable->running ^ cable->pause; if (running & (1 << SNDRV_PCM_STREAM_PLAYBACK)) { delta_play = jiffies - dpcm_play->last_jiffies; dpcm_play->last_jiffies += delta_play; } if (running & (1 << SNDRV_PCM_STREAM_CAPTURE)) { delta_capt = jiffies - dpcm_capt->last_jiffies; dpcm_capt->last_jiffies += delta_capt; } if (delta_play == 0 && delta_capt == 0) goto unlock; if (delta_play > delta_capt) { count1 = bytepos_delta(dpcm_play, delta_play - delta_capt); bytepos_finish(dpcm_play, count1); delta_play = delta_capt; } else if (delta_play < delta_capt) { count1 = bytepos_delta(dpcm_capt, delta_capt - delta_play); clear_capture_buf(dpcm_capt, count1); bytepos_finish(dpcm_capt, count1); delta_capt = delta_play; } if (delta_play == 0 && delta_capt == 0) goto unlock; /* note delta_capt == delta_play at this moment */ count1 = bytepos_delta(dpcm_play, delta_play); count2 = bytepos_delta(dpcm_capt, delta_capt); if (count1 < count2) { dpcm_capt->last_drift = count2 - count1; count1 = count2; } else if (count1 > count2) { dpcm_play->last_drift = count1 - count2; } copy_play_buf(dpcm_play, dpcm_capt, count1); bytepos_finish(dpcm_play, count1); bytepos_finish(dpcm_capt, count1); unlock: spin_unlock_irqrestore(&cable->lock, flags); return running; }