Beispiel #1
0
/**
 * atmel_pcm_dma_irq: SSC interrupt handler for DMAENGINE enabled SSC
 *
 * We use DMAENGINE to send/receive data to/from SSC so this ISR is only to
 * check if any overrun occured.
 */
static void atmel_pcm_dma_irq(u32 ssc_sr,
	struct snd_pcm_substream *substream)
{
	struct atmel_pcm_dma_params *prtd;

	prtd = snd_dmaengine_pcm_get_data(substream);

	if (ssc_sr & prtd->mask->ssc_error) {
		if (snd_pcm_running(substream))
			pr_warn("atmel-pcm: buffer %s on %s (SSC_SR=%#x)\n",
				substream->stream == SNDRV_PCM_STREAM_PLAYBACK
				? "underrun" : "overrun", prtd->name,
				ssc_sr);

		/* stop RX and capture: will be enabled again at restart */
		ssc_writex(prtd->ssc->regs, SSC_CR, prtd->mask->ssc_disable);
		snd_pcm_stream_lock(substream);
		snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN);
		snd_pcm_stream_unlock(substream);

		/* now drain RHR and read status to remove xrun condition */
		ssc_readx(prtd->ssc->regs, SSC_RHR);
		ssc_readx(prtd->ssc->regs, SSC_SR);
	}
}
Beispiel #2
0
/*
 * uni_reader_irq_handler
 * In case of error audio stream is stopped; stop action is protected via PCM
 * stream lock  to avoid race condition with trigger callback.
 */
static irqreturn_t uni_reader_irq_handler(int irq, void *dev_id)
{
	irqreturn_t ret = IRQ_NONE;
	struct uniperif *reader = dev_id;
	unsigned int status;

	if (reader->state == UNIPERIF_STATE_STOPPED) {
		/* Unexpected IRQ: do nothing */
		dev_warn(reader->dev, "unexpected IRQ ");
		return IRQ_HANDLED;
	}

	/* Get interrupt status & clear them immediately */
	status = GET_UNIPERIF_ITS(reader);
	SET_UNIPERIF_ITS_BCLR(reader, status);

	/* Check for fifo overflow error */
	if (unlikely(status & UNIPERIF_ITS_FIFO_ERROR_MASK(reader))) {
		dev_err(reader->dev, "FIFO error detected");

		snd_pcm_stream_lock(reader->substream);
		snd_pcm_stop(reader->substream, SNDRV_PCM_STATE_XRUN);
		snd_pcm_stream_unlock(reader->substream);

		return IRQ_HANDLED;
	}

	return ret;
}
static void dmaengine_pcm_dma_complete(void *arg)
{
	struct snd_pcm_substream *substream = arg;
	struct dmaengine_pcm_runtime_data *prtd;

	snd_pcm_stream_lock(substream);
	if (!substream || !substream->runtime) {
		snd_pcm_stream_unlock(substream);
		return;
	}

	prtd = substream_to_prtd(substream);
	prtd->pos += snd_pcm_lib_period_bytes(substream);
	if (prtd->pos >= snd_pcm_lib_buffer_bytes(substream))
		prtd->pos = 0;

	snd_pcm_stream_unlock(substream);

	snd_pcm_period_elapsed(substream);

#ifdef CONFIG_SND_PXA_SSP_DUMP
	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK
			&& ssp_playback_enable) {
		prtd->playback_transfer_addr =
				substream->runtime->dma_addr + prtd->pos;
		queue_work(ssp_playback_wq, &prtd->playback_dump_work);
	} else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE
			&& ssp_capture_enable) {
		prtd->capture_transfer_addr =
				substream->runtime->dma_addr + prtd->pos;
		queue_work(ssp_capture_wq, &prtd->capture_dump_work);
	}
#endif
}
Beispiel #4
0
/*
 * XRUN detected, and stop the PCM substream
 */
static void snd_atiixp_xrun_dma(struct atiixp *chip, struct atiixp_dma *dma)
{
	if (! dma->substream || ! dma->running)
		return;
	dev_dbg(chip->card->dev, "XRUN detected (DMA %d)\n", dma->ops->type);
	snd_pcm_stream_lock(dma->substream);
	snd_pcm_stop(dma->substream, SNDRV_PCM_STATE_XRUN);
	snd_pcm_stream_unlock(dma->substream);
}
/*
 * XRUN detected, and stop the PCM substream
 */
static void snd_atiixp_xrun_dma(struct atiixp_modem *chip,
				struct atiixp_dma *dma)
{
	if (! dma->substream || ! dma->running)
		return;
	snd_printdd("atiixp-modem: XRUN detected (DMA %d)\n", dma->ops->type);
	snd_pcm_stream_lock(dma->substream);
	snd_pcm_stop(dma->substream, SNDRV_PCM_STATE_XRUN);
	snd_pcm_stream_unlock(dma->substream);
}
Beispiel #6
0
static irqreturn_t stm32_sai_isr(int irq, void *devid)
{
	struct stm32_sai_sub_data *sai = (struct stm32_sai_sub_data *)devid;
	struct snd_pcm_substream *substream = sai->substream;
	struct platform_device *pdev = sai->pdev;
	unsigned int sr, imr, flags;
	snd_pcm_state_t status = SNDRV_PCM_STATE_RUNNING;

	regmap_read(sai->regmap, STM_SAI_IMR_REGX, &imr);
	regmap_read(sai->regmap, STM_SAI_SR_REGX, &sr);

	flags = sr & imr;
	if (!flags)
		return IRQ_NONE;

	regmap_update_bits(sai->regmap, STM_SAI_CLRFR_REGX, SAI_XCLRFR_MASK,
			   SAI_XCLRFR_MASK);

	if (flags & SAI_XIMR_OVRUDRIE) {
		dev_err(&pdev->dev, "IT %s\n",
			STM_SAI_IS_PLAYBACK(sai) ? "underrun" : "overrun");
		status = SNDRV_PCM_STATE_XRUN;
	}

	if (flags & SAI_XIMR_MUTEDETIE)
		dev_dbg(&pdev->dev, "IT mute detected\n");

	if (flags & SAI_XIMR_WCKCFGIE) {
		dev_err(&pdev->dev, "IT wrong clock configuration\n");
		status = SNDRV_PCM_STATE_DISCONNECTED;
	}

	if (flags & SAI_XIMR_CNRDYIE)
		dev_warn(&pdev->dev, "IT Codec not ready\n");

	if (flags & SAI_XIMR_AFSDETIE) {
		dev_warn(&pdev->dev, "IT Anticipated frame synchro\n");
		status = SNDRV_PCM_STATE_XRUN;
	}

	if (flags & SAI_XIMR_LFSDETIE) {
		dev_warn(&pdev->dev, "IT Late frame synchro\n");
		status = SNDRV_PCM_STATE_XRUN;
	}

	if (status != SNDRV_PCM_STATE_RUNNING) {
		snd_pcm_stream_lock(substream);
		snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN);
		snd_pcm_stream_unlock(substream);
	}

	return IRQ_HANDLED;
}
Beispiel #7
0
void pxa2xx_pcm_dma_irq(int dma_ch, void *dev_id)
{
	struct snd_pcm_substream *substream = dev_id;
	int dcsr;

	dcsr = DCSR(dma_ch);
	DCSR(dma_ch) = dcsr & ~DCSR_STOPIRQEN;

	if (dcsr & DCSR_ENDINTR) {
		snd_pcm_period_elapsed(substream);
	} else {
		printk(KERN_ERR "DMA error on channel %d (DCSR=%#x)\n",
			dma_ch, dcsr);
		snd_pcm_stream_lock(substream);
		snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN);
		snd_pcm_stream_unlock(substream);
	}
}
Beispiel #8
0
static inline void handle_audio_data(struct urb *urb, int *period_elapsed)
{
	struct poseidon_audio *pa = urb->context;
	struct snd_pcm_runtime *runtime = pa->capture_pcm_substream->runtime;

	int stride	= runtime->frame_bits >> 3;
	int len		= urb->actual_length / stride;
	unsigned char *cp	= urb->transfer_buffer;
	unsigned int oldptr	= pa->rcv_position;

	if (urb->actual_length == AUDIO_BUF_SIZE - 4)
		len -= (AUDIO_TRAILER_SIZE / stride);

	/* do the copy */
	if (oldptr + len >= runtime->buffer_size) {
		unsigned int cnt = runtime->buffer_size - oldptr;

		memcpy(runtime->dma_area + oldptr * stride, cp, cnt * stride);
		memcpy(runtime->dma_area, (cp + cnt * stride),
					(len * stride - cnt * stride));
	} else
		memcpy(runtime->dma_area + oldptr * stride, cp, len * stride);

	/* update the statas */
	snd_pcm_stream_lock(pa->capture_pcm_substream);
	pa->rcv_position	+= len;
	if (pa->rcv_position >= runtime->buffer_size)
		pa->rcv_position -= runtime->buffer_size;

	pa->copied_position += (len);
	if (pa->copied_position >= runtime->period_size) {
		pa->copied_position -= runtime->period_size;
		*period_elapsed = 1;
	}
	snd_pcm_stream_unlock(pa->capture_pcm_substream);
}
static void cx231xx_audio_isocirq(struct urb *urb)
{
	struct cx231xx *dev = urb->context;
	int i;
	unsigned int oldptr;
	int period_elapsed = 0;
	int status;
	unsigned char *cp;
	unsigned int stride;
	struct snd_pcm_substream *substream;
	struct snd_pcm_runtime *runtime;

	if (dev->state & DEV_DISCONNECTED)
		return;

	switch (urb->status) {
	case 0:		/* success */
	case -ETIMEDOUT:	/* NAK */
		break;
	case -ECONNRESET:	/* kill */
	case -ENOENT:
	case -ESHUTDOWN:
		return;
	default:		/* error */
		dprintk("urb completition error %d.\n", urb->status);
		break;
	}

	if (atomic_read(&dev->stream_started) == 0)
		return;

	if (dev->adev.capture_pcm_substream) {
		substream = dev->adev.capture_pcm_substream;
		runtime = substream->runtime;
		stride = runtime->frame_bits >> 3;

		for (i = 0; i < urb->number_of_packets; i++) {
			int length = urb->iso_frame_desc[i].actual_length /
				     stride;
			cp = (unsigned char *)urb->transfer_buffer +
					      urb->iso_frame_desc[i].offset;

			if (!length)
				continue;

			oldptr = dev->adev.hwptr_done_capture;
			if (oldptr + length >= runtime->buffer_size) {
				unsigned int cnt;

				cnt = runtime->buffer_size - oldptr;
				memcpy(runtime->dma_area + oldptr * stride, cp,
				       cnt * stride);
				memcpy(runtime->dma_area, cp + cnt * stride,
				       length * stride - cnt * stride);
			} else {
				memcpy(runtime->dma_area + oldptr * stride, cp,
				       length * stride);
			}

			snd_pcm_stream_lock(substream);

			dev->adev.hwptr_done_capture += length;
			if (dev->adev.hwptr_done_capture >=
						runtime->buffer_size)
				dev->adev.hwptr_done_capture -=
						runtime->buffer_size;

			dev->adev.capture_transfer_done += length;
			if (dev->adev.capture_transfer_done >=
				runtime->period_size) {
				dev->adev.capture_transfer_done -=
						runtime->period_size;
				period_elapsed = 1;
			}
			snd_pcm_stream_unlock(substream);
		}
		if (period_elapsed)
			snd_pcm_period_elapsed(substream);
	}
Beispiel #10
0
static void usbtv_audio_urb_received(struct urb *urb)
{
	struct usbtv *chip = urb->context;
	struct snd_pcm_substream *substream = chip->snd_substream;
	struct snd_pcm_runtime *runtime = substream->runtime;
	size_t i, frame_bytes, chunk_length, buffer_pos, period_pos;
	int period_elapsed;
	void *urb_current;

	switch (urb->status) {
	case 0:
	case -ETIMEDOUT:
		break;
	case -ENOENT:
	case -EPROTO:
	case -ECONNRESET:
	case -ESHUTDOWN:
		return;
	default:
		dev_warn(chip->dev, "unknown audio urb status %i\n",
			urb->status);
	}

	if (!atomic_read(&chip->snd_stream))
		return;

	frame_bytes = runtime->frame_bits >> 3;
	chunk_length = USBTV_CHUNK / frame_bytes;

	buffer_pos = chip->snd_buffer_pos;
	period_pos = chip->snd_period_pos;
	period_elapsed = 0;

	for (i = 0; i < urb->actual_length; i += USBTV_CHUNK_SIZE) {
		urb_current = urb->transfer_buffer + i + USBTV_AUDIO_HDRSIZE;

		if (buffer_pos + chunk_length >= runtime->buffer_size) {
			size_t cnt = (runtime->buffer_size - buffer_pos) *
				frame_bytes;
			memcpy(runtime->dma_area + buffer_pos * frame_bytes,
				urb_current, cnt);
			memcpy(runtime->dma_area, urb_current + cnt,
				chunk_length * frame_bytes - cnt);
		} else {
			memcpy(runtime->dma_area + buffer_pos * frame_bytes,
				urb_current, chunk_length * frame_bytes);
		}

		buffer_pos += chunk_length;
		period_pos += chunk_length;

		if (buffer_pos >= runtime->buffer_size)
			buffer_pos -= runtime->buffer_size;

		if (period_pos >= runtime->period_size) {
			period_pos -= runtime->period_size;
			period_elapsed = 1;
		}
	}

	snd_pcm_stream_lock(substream);

	chip->snd_buffer_pos = buffer_pos;
	chip->snd_period_pos = period_pos;

	snd_pcm_stream_unlock(substream);

	if (period_elapsed)
		snd_pcm_period_elapsed(substream);

	usb_submit_urb(urb, GFP_ATOMIC);
}
Beispiel #11
0
void smi2021_audio(struct smi2021 *smi2021, u8 *data, int len)
{
	struct snd_pcm_runtime *runtime;
	u8 offset;
	int new_offset = 0;

	int skip;
	unsigned int stride, oldptr, headptr;

	int diff = 0;
	int samples = 0;
	bool period_elapsed = false;


	if (smi2021->udev == NULL)
		return;

	if (atomic_read(&smi2021->adev_capturing) == 0)
		return;

	if (smi2021->pcm_substream == NULL)
		return;

	runtime = smi2021->pcm_substream->runtime;
	if (!runtime || !runtime->dma_area)
		return;

	offset = smi2021->pcm_read_offset;
	stride = runtime->frame_bits >> 3;

	if (stride == 0)
		return;

	diff = smi2021->pcm_write_ptr;

	/*
	 * Check that the end of the last buffer was correct.
	 * If not correct, we mark any partial frames in buffer as complete
	 */
	headptr = smi2021->pcm_write_ptr - offset - 4;
	if (smi2021->pcm_write_ptr > 10
	    && runtime->dma_area[headptr] != 0x00) {
		skip = stride - (smi2021->pcm_write_ptr % stride);
		snd_pcm_stream_lock(smi2021->pcm_substream);
		smi2021->pcm_write_ptr += skip;

		if (smi2021->pcm_write_ptr >= runtime->dma_bytes)
			smi2021->pcm_write_ptr -= runtime->dma_bytes;

		snd_pcm_stream_unlock(smi2021->pcm_substream);
		offset = smi2021->pcm_read_offset = 0;
	}
	/*
	 * The device is actually sending 24Bit pcm data
	 * with 0x00 as the header byte before each sample.
	 * We look for this byte to make sure we did not
	 * loose any bytes during transfer.
	 */
	while (len > stride && (data[offset] != 0x00 ||
			data[offset + (stride / 2)] != 0x00)) {
		new_offset++;
		data++;
		len--;
	}

	if (len <= stride) {
		/* We exhausted the buffer looking for 0x00 */
		smi2021->pcm_read_offset = 0;
		return;
	}
	if (new_offset != 0) {
		/*
		 * This buffer can not be appended to the current buffer,
		 * so we mark any partial frames in the buffer as complete.
		 */
		skip = stride - (smi2021->pcm_write_ptr % stride);
		snd_pcm_stream_lock(smi2021->pcm_substream);
		smi2021->pcm_write_ptr += skip;

		if (smi2021->pcm_write_ptr >= runtime->dma_bytes)
			smi2021->pcm_write_ptr -= runtime->dma_bytes;

		snd_pcm_stream_unlock(smi2021->pcm_substream);

		offset = smi2021->pcm_read_offset = new_offset % (stride / 2);

	}

	oldptr = smi2021->pcm_write_ptr;
	if (oldptr + len >= runtime->dma_bytes) {
		unsigned int cnt = runtime->dma_bytes - oldptr;
		memcpy(runtime->dma_area + oldptr, data, cnt);
		memcpy(runtime->dma_area, data + cnt, len - cnt);
	} else {
		memcpy(runtime->dma_area + oldptr, data, len);
	}

	snd_pcm_stream_lock(smi2021->pcm_substream);
	smi2021->pcm_write_ptr += len;

	if (smi2021->pcm_write_ptr >= runtime->dma_bytes)
		smi2021->pcm_write_ptr -= runtime->dma_bytes;

	samples = smi2021->pcm_write_ptr - diff;
	if (samples < 0)
		samples += runtime->dma_bytes;

	samples /= (stride / 2);

	smi2021->pcm_complete_samples += samples;
	if (smi2021->pcm_complete_samples / 2 >= runtime->period_size) {
		smi2021->pcm_complete_samples -= runtime->period_size * 2;
		period_elapsed = true;
	}
	snd_pcm_stream_unlock(smi2021->pcm_substream);

	if (period_elapsed)
		snd_pcm_period_elapsed(smi2021->pcm_substream);

}
Beispiel #12
0
static int tm6000_fillbuf(struct tm6000_core *core, char *buf, int size)
{
	struct snd_tm6000_card *chip = core->adev;
	struct snd_pcm_substream *substream = chip->substream;
	struct snd_pcm_runtime *runtime;
	int period_elapsed = 0;
	unsigned int stride, buf_pos;
	int length;

	if (atomic_read(&core->stream_started) == 0)
		return 0;

	if (!size || !substream) {
		dprintk(1, "substream was NULL\n");
		return -EINVAL;
	}

	runtime = substream->runtime;
	if (!runtime || !runtime->dma_area) {
		dprintk(1, "runtime was NULL\n");
		return -EINVAL;
	}

	buf_pos = chip->buf_pos;
	stride = runtime->frame_bits >> 3;

	if (stride == 0) {
		dprintk(1, "stride is zero\n");
		return -EINVAL;
	}

	length = size / stride;
	if (length == 0) {
		dprintk(1, "%s: length was zero\n", __func__);
		return -EINVAL;
	}

	dprintk(1, "Copying %d bytes at %p[%d] - buf size=%d x %d\n", size,
		runtime->dma_area, buf_pos,
		(unsigned int)runtime->buffer_size, stride);

	if (buf_pos + length >= runtime->buffer_size) {
		unsigned int cnt = runtime->buffer_size - buf_pos;
		memcpy(runtime->dma_area + buf_pos * stride, buf, cnt * stride);
		memcpy(runtime->dma_area, buf + cnt * stride,
			length * stride - cnt * stride);
	} else
		memcpy(runtime->dma_area + buf_pos * stride, buf,
			length * stride);

#ifndef NO_PCM_LOCK
       snd_pcm_stream_lock(substream);
#endif

	chip->buf_pos += length;
	if (chip->buf_pos >= runtime->buffer_size)
		chip->buf_pos -= runtime->buffer_size;

	chip->period_pos += length;
	if (chip->period_pos >= runtime->period_size) {
		chip->period_pos -= runtime->period_size;
		period_elapsed = 1;
	}

#ifndef NO_PCM_LOCK
       snd_pcm_stream_unlock(substream);
#endif

	if (period_elapsed)
		snd_pcm_period_elapsed(substream);

	return 0;
}
Beispiel #13
0
/*
 * uni_player_irq_handler
 * In case of error audio stream is stopped; stop action is protected via PCM
 * stream lock to avoid race condition with trigger callback.
 */
static irqreturn_t uni_player_irq_handler(int irq, void *dev_id)
{
	irqreturn_t ret = IRQ_NONE;
	struct uniperif *player = dev_id;
	unsigned int status;
	unsigned int tmp;

	if (player->state == UNIPERIF_STATE_STOPPED) {
		/* Unexpected IRQ: do nothing */
		return IRQ_NONE;
	}

	/* Get interrupt status & clear them immediately */
	status = GET_UNIPERIF_ITS(player);
	SET_UNIPERIF_ITS_BCLR(player, status);

	/* Check for fifo error (underrun) */
	if (unlikely(status & UNIPERIF_ITS_FIFO_ERROR_MASK(player))) {
		dev_err(player->dev, "FIFO underflow error detected\n");

		/* Interrupt is just for information when underflow recovery */
		if (player->underflow_enabled) {
			/* Update state to underflow */
			player->state = UNIPERIF_STATE_UNDERFLOW;

		} else {
			/* Disable interrupt so doesn't continually fire */
			SET_UNIPERIF_ITM_BCLR_FIFO_ERROR(player);

			/* Stop the player */
			snd_pcm_stream_lock(player->substream);
			snd_pcm_stop(player->substream, SNDRV_PCM_STATE_XRUN);
			snd_pcm_stream_unlock(player->substream);
		}

		ret = IRQ_HANDLED;
	}

	/* Check for dma error (overrun) */
	if (unlikely(status & UNIPERIF_ITS_DMA_ERROR_MASK(player))) {
		dev_err(player->dev, "DMA error detected\n");

		/* Disable interrupt so doesn't continually fire */
		SET_UNIPERIF_ITM_BCLR_DMA_ERROR(player);

		/* Stop the player */
		snd_pcm_stream_lock(player->substream);
		snd_pcm_stop(player->substream, SNDRV_PCM_STATE_XRUN);
		snd_pcm_stream_unlock(player->substream);

		ret = IRQ_HANDLED;
	}

	/* Check for underflow recovery done */
	if (unlikely(status & UNIPERIF_ITM_UNDERFLOW_REC_DONE_MASK(player))) {
		if (!player->underflow_enabled) {
			dev_err(player->dev,
				"unexpected Underflow recovering\n");
			return -EPERM;
		}
		/* Read the underflow recovery duration */
		tmp = GET_UNIPERIF_STATUS_1_UNDERFLOW_DURATION(player);
		dev_dbg(player->dev, "Underflow recovered (%d LR clocks max)\n",
			tmp);

		/* Clear the underflow recovery duration */
		SET_UNIPERIF_BIT_CONTROL_CLR_UNDERFLOW_DURATION(player);

		/* Update state to started */
		player->state = UNIPERIF_STATE_STARTED;

		ret = IRQ_HANDLED;
	}

	/* Check if underflow recovery failed */
	if (unlikely(status &
		     UNIPERIF_ITM_UNDERFLOW_REC_FAILED_MASK(player))) {
		dev_err(player->dev, "Underflow recovery failed\n");

		/* Stop the player */
		snd_pcm_stream_lock(player->substream);
		snd_pcm_stop(player->substream, SNDRV_PCM_STATE_XRUN);
		snd_pcm_stream_unlock(player->substream);

		ret = IRQ_HANDLED;
	}

	return ret;
}
Beispiel #14
0
void cx18_alsa_announce_pcm_data(struct snd_cx18_card *cxsc, u8 *pcm_data,
				 size_t num_bytes)
{
	struct snd_pcm_substream *substream;
	struct snd_pcm_runtime *runtime;
	unsigned int oldptr;
	unsigned int stride;
	int period_elapsed = 0;
	int length;

	dprintk("cx18 alsa announce ptr=%p data=%p num_bytes=%zu\n", cxsc,
		pcm_data, num_bytes);

	substream = cxsc->capture_pcm_substream;
	if (substream == NULL) {
		dprintk("substream was NULL\n");
		return;
	}

	runtime = substream->runtime;
	if (runtime == NULL) {
		dprintk("runtime was NULL\n");
		return;
	}

	stride = runtime->frame_bits >> 3;
	if (stride == 0) {
		dprintk("stride is zero\n");
		return;
	}

	length = num_bytes / stride;
	if (length == 0) {
		dprintk("%s: length was zero\n", __func__);
		return;
	}

	if (runtime->dma_area == NULL) {
		dprintk("dma area was NULL - ignoring\n");
		return;
	}

	oldptr = cxsc->hwptr_done_capture;
	if (oldptr + length >= runtime->buffer_size) {
		unsigned int cnt =
			runtime->buffer_size - oldptr;
		memcpy(runtime->dma_area + oldptr * stride, pcm_data,
		       cnt * stride);
		memcpy(runtime->dma_area, pcm_data + cnt * stride,
		       length * stride - cnt * stride);
	} else {
		memcpy(runtime->dma_area + oldptr * stride, pcm_data,
		       length * stride);
	}
	snd_pcm_stream_lock(substream);

	cxsc->hwptr_done_capture += length;
	if (cxsc->hwptr_done_capture >=
	    runtime->buffer_size)
		cxsc->hwptr_done_capture -=
			runtime->buffer_size;

	cxsc->capture_transfer_done += length;
	if (cxsc->capture_transfer_done >=
	    runtime->period_size) {
		cxsc->capture_transfer_done -=
			runtime->period_size;
		period_elapsed = 1;
	}

	snd_pcm_stream_unlock(substream);

	if (period_elapsed)
		snd_pcm_period_elapsed(substream);
}