Exemplo n.º 1
0
static irqreturn_t lpass_platform_lpaif_irq(int irq, void *data)
{
	struct snd_pcm_substream *substream = data;
	struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
	struct lpass_data *drvdata =
		snd_soc_platform_get_drvdata(soc_runtime->platform);
	unsigned int interrupts;
	irqreturn_t ret = IRQ_NONE;
	int rv;

	rv = regmap_read(drvdata->lpaif_map,
			LPAIF_IRQSTAT_REG(LPAIF_IRQ_PORT_HOST), &interrupts);
	if (rv) {
		dev_err(soc_runtime->dev, "%s() error reading from irqstat reg: %d\n",
				__func__, rv);
		return IRQ_NONE;
	}
	interrupts &= LPAIF_IRQ_ALL(LPAIF_RDMA_CHAN_MI2S);

	if (interrupts & LPAIF_IRQ_PER(LPAIF_RDMA_CHAN_MI2S)) {
		rv = regmap_write(drvdata->lpaif_map,
				LPAIF_IRQCLEAR_REG(LPAIF_IRQ_PORT_HOST),
				LPAIF_IRQ_PER(LPAIF_RDMA_CHAN_MI2S));
		if (rv) {
			dev_err(soc_runtime->dev, "%s() error writing to irqclear reg: %d\n",
					__func__, rv);
			return IRQ_NONE;
		}
		snd_pcm_period_elapsed(substream);
		ret = IRQ_HANDLED;
	}

	if (interrupts & LPAIF_IRQ_XRUN(LPAIF_RDMA_CHAN_MI2S)) {
		rv = regmap_write(drvdata->lpaif_map,
				LPAIF_IRQCLEAR_REG(LPAIF_IRQ_PORT_HOST),
				LPAIF_IRQ_XRUN(LPAIF_RDMA_CHAN_MI2S));
		if (rv) {
			dev_err(soc_runtime->dev, "%s() error writing to irqclear reg: %d\n",
					__func__, rv);
			return IRQ_NONE;
		}
		dev_warn(soc_runtime->dev, "%s() xrun warning\n", __func__);
		snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN);
		ret = IRQ_HANDLED;
	}

	if (interrupts & LPAIF_IRQ_ERR(LPAIF_RDMA_CHAN_MI2S)) {
		rv = regmap_write(drvdata->lpaif_map,
				LPAIF_IRQCLEAR_REG(LPAIF_IRQ_PORT_HOST),
				LPAIF_IRQ_ERR(LPAIF_RDMA_CHAN_MI2S));
		if (rv) {
			dev_err(soc_runtime->dev, "%s() error writing to irqclear reg: %d\n",
					__func__, rv);
			return IRQ_NONE;
		}
		dev_err(soc_runtime->dev, "%s() bus access error\n", __func__);
		snd_pcm_stop(substream, SNDRV_PCM_STATE_DISCONNECTED);
		ret = IRQ_HANDLED;
	}

	return ret;
}
Exemplo n.º 2
0
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++
 *
 *  Function Name: AUDIO_DRIVER_InterruptPeriodCB
 *
 *  Description: Callback funtion when DMA done, running at
 *  worker thread context (worker_audio_playback)
 *
 *------------------------------------------------------------
 */
static void AUDIO_DRIVER_InterruptPeriodCB(void *pPrivate)
{
	struct snd_pcm_substream *substream =
	    (struct snd_pcm_substream *)pPrivate;
	AUDIO_DRIVER_HANDLE_t drv_handle;
	AUDIO_DRIVER_TYPE_t drv_type;
	struct snd_pcm_runtime *runtime;
	brcm_alsa_chip_t *pChip = NULL;
	int stream_id = 0;

	if (!substream) {
		aError("Invalid substream 0x%p\n", substream);
		return;
	}
	pChip = snd_pcm_substream_chip(substream);

	runtime = substream->runtime;
	if (!runtime) {
		aError("InterruptPeriodCBInvalid runtime 0x%p\n", runtime);
		return;
	}
	drv_handle = substream->runtime->private_data;

	AUDIO_DRIVER_Ctrl(drv_handle, AUDIO_DRIVER_GET_DRV_TYPE,
			  (void *)&drv_type);

	stream_id = StreamIdOfDriver(drv_handle);
	BUG_ON(stream_id < CSL_CAPH_STREAM_NONE ||
		stream_id >= CSL_CAPH_STREAM_TOTAL);

	switch (drv_type) {
	case AUDIO_DRIVER_PLAY_VOICE:
	case AUDIO_DRIVER_PLAY_AUDIO:
	case AUDIO_DRIVER_PLAY_RINGER:
		{
			/*update the PCM read pointer by period size */
			int offset = runtime->period_size;
#if defined(DYNAMIC_DMA_PLAYBACK)
			/*period_size is actually the copy size at dyndma mode*/
			int dmaSize = csl_audio_render_get_dma_size(stream_id);
			if (dmaSize != 0)
				offset = bytes_to_frames(runtime, dmaSize);
#endif
			pChip->streamCtl[substream->number].stream_hw_ptr +=
				offset;
			if (pChip->streamCtl[substream->number].stream_hw_ptr
				> runtime->boundary)
				pChip->streamCtl[substream->number].
				stream_hw_ptr -= runtime->boundary;

			/* send the period elapsed */
			snd_pcm_period_elapsed(substream);

			/* logmsg_ready(substream, AUD_LOG_PCMOUT); */
			common_log_capture(AUD_LOG_PCMOUT, substream);


		}
		break;
	default:
		aWarn("InterruptPeriodCB Invalid driver type\n");
		break;
	}

	return;
}
static void pcm_afe_process_rx_pkt(uint32_t opcode,
		uint32_t token, uint32_t *payload,
		 void *priv)
{
	struct pcm_afe_info *prtd = priv;
	unsigned long dsp_flags;
	struct snd_pcm_substream *substream = NULL;
	struct snd_pcm_runtime *runtime = NULL;
	uint16_t event;

	if (prtd == NULL)
		return;
	substream =  prtd->substream;
	runtime = substream->runtime;
	pr_debug("%s\n", __func__);
	spin_lock_irqsave(&prtd->dsp_lock, dsp_flags);
	switch (opcode) {
	case AFE_EVENT_RT_PROXY_PORT_STATUS: {
		event = (uint16_t)((0xFFFF0000 & payload[0]) >> 0x10);
		switch (event) {
		case AFE_EVENT_RTPORT_START: {
			prtd->dsp_cnt = 0;
			prtd->poll_time = ((unsigned long)((
				snd_pcm_lib_period_bytes(prtd->substream)
					* 1000 * 1000)/(runtime->rate
					* runtime->channels * 2)));
			hrtimer_start(&prtd->hrt,
				ns_to_ktime(0),
				HRTIMER_MODE_REL);
			pr_debug("prtd->poll_time : %d", prtd->poll_time);
			break;
		}
		case AFE_EVENT_RTPORT_STOP:
			pr_debug("%s: event!=0\n", __func__);
			prtd->start = 0;
			snd_pcm_stop(substream, SNDRV_PCM_STATE_SETUP);
			break;
		case AFE_EVENT_RTPORT_LOW_WM:
			pr_debug("%s: Underrun\n", __func__);
			break;
		case AFE_EVENT_RTPORT_HI_WM:
			pr_debug("%s: Overrun\n", __func__);
			break;
		default:
			break;
		}
		break;
	}
	case APR_BASIC_RSP_RESULT: {
		switch (payload[0]) {
		case AFE_PORT_DATA_CMD_RT_PROXY_PORT_READ_V2:
			pr_debug("Read done\n");
			prtd->pcm_irq_pos += snd_pcm_lib_period_bytes
							(prtd->substream);
			snd_pcm_period_elapsed(prtd->substream);
			break;
		default:
			break;
		}
		break;
	}
	default:
		break;
	}
	spin_unlock_irqrestore(&prtd->dsp_lock, dsp_flags);
}
Exemplo n.º 4
0
static void playback_tasklet(unsigned long data)
{
	struct ua101 *ua = (void *)data;
	unsigned long flags;
	unsigned int frames;
	struct ua101_urb *urb;
	bool do_period_elapsed = false;
	int err;

	if (unlikely(!test_bit(USB_PLAYBACK_RUNNING, &ua->states)))
		return;

	/*
	 * Synchronizing the playback rate to the capture rate is done by using
	 * the same sequence of packet sizes for both streams.
	 * Submitting a playback URB therefore requires both a ready URB and
	 * the size of the corresponding capture packet, i.e., both playback
	 * and capture URBs must have been completed.  Since the USB core does
	 * not guarantee that playback and capture complete callbacks are
	 * called alternately, we use two FIFOs for packet sizes and read URBs;
	 * submitting playback URBs is possible as long as both FIFOs are
	 * nonempty.
	 */
	spin_lock_irqsave(&ua->lock, flags);
	while (ua->rate_feedback_count > 0 &&
	       !list_empty(&ua->ready_playback_urbs)) {
		/* take packet size out of FIFO */
		frames = ua->rate_feedback[ua->rate_feedback_start];
		add_with_wraparound(ua, &ua->rate_feedback_start, 1);
		ua->rate_feedback_count--;

		/* take URB out of FIFO */
		urb = list_first_entry(&ua->ready_playback_urbs,
				       struct ua101_urb, ready_list);
		list_del(&urb->ready_list);

		/* fill packet with data or silence */
		urb->urb.iso_frame_desc[0].length =
			frames * ua->playback.frame_bytes;
		if (test_bit(ALSA_PLAYBACK_RUNNING, &ua->states))
			do_period_elapsed |= copy_playback_data(&ua->playback,
								&urb->urb,
								frames);
		else
			memset(urb->urb.transfer_buffer, 0,
			       urb->urb.iso_frame_desc[0].length);

		/* and off you go ... */
		err = usb_submit_urb(&urb->urb, GFP_ATOMIC);
		if (unlikely(err < 0)) {
			spin_unlock_irqrestore(&ua->lock, flags);
			abort_usb_playback(ua);
			abort_alsa_playback(ua);
			dev_err(&ua->dev->dev, "USB request error %d: %s\n",
				err, usb_error_string(err));
			return;
		}
		ua->playback.substream->runtime->delay += frames;
	}
	spin_unlock_irqrestore(&ua->lock, flags);
	if (do_period_elapsed)
		snd_pcm_period_elapsed(ua->playback.substream);
}
Exemplo n.º 5
0
irqreturn_t bcm947xx_i2s_isr(int irq, void *devid)
{
	uint32 intstatus, intmask;
	uint32 intstatus_new = 0;
	uint32 int_errmask = I2S_INT_DESCERR | I2S_INT_DATAERR | I2S_INT_DESC_PROTO_ERR |
	        I2S_INT_SPDIF_PAR_ERR;
	struct snd_pcm *pcm = devid;
	struct snd_soc_pcm_runtime *rtd = pcm->private_data;
	bcm947xx_i2s_info_t *snd_bcm = rtd->dai->cpu_dai->private_data;
	struct snd_pcm_substream *substream;
	struct bcm947xx_runtime_data *brtd;

//	DBG("%s enter\n", __FUNCTION__);

	intstatus = R_REG(snd_bcm->osh, &snd_bcm->regs->intstatus);

	if (BCM947XX_PCM_DEBUG_ON) {
		intmask = R_REG(snd_bcm->osh, &snd_bcm->regs->intmask);
	} else {
		(void)intmask;
	}

//	DBG("%s: intstatus 0x%x intmask 0x%x\n", __FUNCTION__, intstatus, intmask);

	/* Playback. */
	substream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
	if ((brtd = bcm947xx_pcm_brtd_from_running_substream(substream))) {

		if (intstatus & I2S_INT_XMT_INT) {
			/* reclaim descriptors that have been TX'd */
			spin_lock(&brtd->lock);
			dma_getnexttxp(snd_bcm->di[0], HNDDMA_RANGE_TRANSMITTED);
			spin_unlock(&brtd->lock);

			/* clear this bit by writing a "1" back, we've serviced this */
			intstatus_new |= I2S_INT_XMT_INT;

			snd_pcm_period_elapsed(substream);
		
			spin_lock(&brtd->lock);
			snd_BUG_ON(0 == brtd->dma_loaded);
			brtd->dma_loaded--;
			spin_unlock(&brtd->lock);
		}

		if (intstatus & I2S_INT_XMTFIFO_UFLOW) {
			intstatus_new |= I2S_INT_XMTFIFO_UFLOW;
			bcm947xx_dma_abort(substream);
		}
	}

	/* Capture. */
	substream = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream;
	if ((brtd = bcm947xx_pcm_brtd_from_running_substream(substream))) {

		if (intstatus & I2S_INT_RCV_INT) {

			spin_lock(&brtd->lock);
			dma_getnextrxp(snd_bcm->di[0], false);
			spin_unlock(&brtd->lock);

			/* clear this bit by writing a "1" back, we've serviced this */
			intstatus_new |= I2S_INT_RCV_INT;

			snd_pcm_period_elapsed(substream);

			spin_lock(&brtd->lock);
			snd_BUG_ON(0 == brtd->dma_loaded);
			brtd->dma_loaded--;
			spin_unlock(&brtd->lock);
		}

		if (intstatus & I2S_INT_RCVFIFO_OFLOW) {
			intstatus_new |= I2S_INT_RCVFIFO_OFLOW;
			bcm947xx_dma_abort(substream);
		}
	}
	
	/* Common.*/
	if (intstatus & int_errmask) {
		DBG("\n\n%s: Turning off all interrupts due to error\n", __FUNCTION__);
		DBG("%s: intstatus 0x%x intmask 0x%x\n", __FUNCTION__, intstatus, intmask);


		/* something bad happened, turn off all interrupts */
		W_REG(snd_bcm->osh, &snd_bcm->regs->intmask, 0);
	}

	/* Acknowledge interrupts. */
	W_REG(snd_bcm->osh, &snd_bcm->regs->intstatus, intstatus_new);

//	DBG("%s exit\n", __FUNCTION__);

	return IRQ_RETVAL(intstatus);
}
Exemplo n.º 6
0
/* This function is called by the DMA driver. */
static void atmel_ac97c_dma_playback_period_done(void *arg)
{
	struct atmel_ac97c *chip = arg;
	snd_pcm_period_elapsed(chip->playback_substream);
}
Exemplo n.º 7
0
static void compr_event_handler(uint32_t opcode,
		uint32_t token, uint32_t *payload, void *priv)
{
	struct compr_audio *compr = priv;
	struct msm_audio *prtd = &compr->prtd;
	struct snd_pcm_substream *substream = NULL;
	struct snd_pcm_runtime *runtime = NULL;
	struct audio_aio_write_param param;
	struct audio_buffer *buf = NULL;
	int i = 0;

	/*HTC AUDIO Start*/
	if (!(prtd->substream && prtd->substream->runtime)) {
		printk(KERN_WARNING "[AUD] compr_event_handler(), no substream instance, return\n");
		return;
	} else {
		substream = prtd->substream;
		runtime = substream->runtime;
	}
	/*HTC AUDIO End*/
	pr_debug("[AUD]%s opcode =%08x, start %d +++\n", __func__, opcode, atomic_read(&prtd->start));
	switch (opcode) {
	case ASM_DATA_EVENT_WRITE_DONE: {
		uint32_t *ptrmem = (uint32_t *)&param;
		pr_debug("[AUD]%s ASM_DATA_EVENT_WRITE_DONE\n", __func__);
		pr_debug("[AUD]%s Buffer Consumed = 0x%08x\n", __func__, *ptrmem);

		prtd->pcm_irq_pos += prtd->pcm_count;
		if (atomic_read(&prtd->start))
			snd_pcm_period_elapsed(substream);
		atomic_inc(&prtd->out_count);
		wake_up(&the_locks.write_wait);
		if (!atomic_read(&prtd->start)) {
			atomic_set(&prtd->pending_buffer, 1);
			break;
		} else
			atomic_set(&prtd->pending_buffer, 0);

		if (runtime->status->hw_ptr >= runtime->control->appl_ptr)
			break;
		buf = prtd->audio_client->port[IN].buf;
		pr_debug("[AUD]%s:writing %d bytes of buffer[%d] to dsp 2\n",
				__func__, prtd->pcm_count, prtd->out_head);
		pr_debug("[AUD]%s:writing buffer[%d] from 0x%08x\n",
				__func__, prtd->out_head,
				((unsigned int)buf[0].phys
				+ (prtd->out_head * prtd->pcm_count)));

		param.paddr = (unsigned long)buf[0].phys
				+ (prtd->out_head * prtd->pcm_count);
		param.len = prtd->pcm_count;
		param.msw_ts = 0;
		param.lsw_ts = 0;
		param.flags = NO_TIMESTAMP;
		param.uid =  (unsigned long)buf[0].phys
				+ (prtd->out_head * prtd->pcm_count);
		for (i = 0; i < sizeof(struct audio_aio_write_param)/4;
					i++, ++ptrmem)
			pr_debug("[AUD]cmd[%d]=0x%08x\n", i, *ptrmem);
		if (q6asm_async_write(prtd->audio_client,
					&param) < 0)
			pr_err("[AUD]%s:q6asm_async_write failed\n",
				__func__);
		else
			prtd->out_head =
				(prtd->out_head + 1) & (runtime->periods - 1);
		break;
	}
	case ASM_DATA_CMDRSP_EOS:
		pr_debug("[AUD]%s ASM_DATA_CMDRSP_EOS\n", __func__);
		prtd->cmd_ack = 1;
		wake_up(&the_locks.eos_wait);
		break;
	case APR_BASIC_RSP_RESULT: {
		switch (payload[0]) {
		case ASM_SESSION_CMD_RUN: {
			if (!atomic_read(&prtd->pending_buffer))
				break;
			if (runtime->status->hw_ptr >= runtime->control->appl_ptr)
				break;
			pr_debug("[AUD]%s:writing %d bytes"
				" of buffer[%d] to dsp\n",
				__func__, prtd->pcm_count, prtd->out_head);
			buf = prtd->audio_client->port[IN].buf;
			pr_debug("[AUD]%s:writing buffer[%d] from 0x%08x\n",
				__func__, prtd->out_head,
				((unsigned int)buf[0].phys
				+ (prtd->out_head * prtd->pcm_count)));
			param.paddr = (unsigned long)buf[prtd->out_head].phys;
			param.len = prtd->pcm_count;
			param.msw_ts = 0;
			param.lsw_ts = 0;
			param.flags = NO_TIMESTAMP;
			param.uid =  (unsigned long)buf[prtd->out_head].phys;
			if (q6asm_async_write(prtd->audio_client,
						&param) < 0)
				pr_err("[AUD]%s:q6asm_async_write failed\n",
					__func__);
			else
				prtd->out_head =
					(prtd->out_head + 1)
					& (runtime->periods - 1);
			atomic_set(&prtd->pending_buffer, 0);
		}
			break;
		case ASM_STREAM_CMD_FLUSH:
			pr_debug("[AUD]%s: ASM_STREAM_CMD_FLUSH\n", __func__);
			prtd->cmd_ack = 1;
			wake_up(&the_locks.eos_wait);
			break;
		default:
			break;
		}
		break;
	}
	default:
		pr_debug("[AUD]%s: Not Supported Event opcode[0x%x]\n", __func__, opcode);
		break;
	}
	pr_debug("[AUD]%s opcode =%08x, start %d ---\n", __func__, opcode, atomic_read(&prtd->start));
}
static void pcm_afe_process_rx_pkt(uint32_t opcode,
		uint32_t token, uint32_t *payload,
		 void *priv)
{
	struct pcm_afe_info *prtd = priv;
	unsigned long dsp_flags;
	struct snd_pcm_substream *substream = NULL;
	struct snd_pcm_runtime *runtime = NULL;
	uint16_t event;
	uint64_t period_bytes;
	uint64_t bytes_one_sec;

	if (prtd == NULL)
		return;
	substream =  prtd->substream;
	runtime = substream->runtime;
	pr_debug("%s\n", __func__);
	spin_lock_irqsave(&prtd->dsp_lock, dsp_flags);
	switch (opcode) {
	case AFE_EVENT_RT_PROXY_PORT_STATUS: {
		event = (uint16_t)((0xFFFF0000 & payload[0]) >> 0x10);
		switch (event) {
		case AFE_EVENT_RTPORT_START: {
			prtd->dsp_cnt = 0;
			/* Calculate poll time. Split steps to avoid overflow.
			 * Poll time-time corresponding to one period in bytes.
			 * (Samplerate * channelcount * format)=bytes in 1 sec.
			 * Poll time =  (period bytes / bytes in one sec) *
			 * 1000000 micro seconds.
			 * Multiplication by 1000000 is done in two steps to
			 * keep the accuracy of poll time.
			 */
			period_bytes = ((uint64_t)(
				(snd_pcm_lib_period_bytes(prtd->substream)) *
				 1000));
			bytes_one_sec = (runtime->rate * runtime->channels * 2);
			bytes_one_sec = div_u64(bytes_one_sec , 1000);
			prtd->poll_time =
				div_u64(period_bytes, bytes_one_sec);
			pr_debug("prtd->poll_time : %d\n", prtd->poll_time);
			break;
		}
		case AFE_EVENT_RTPORT_STOP:
			pr_debug("%s: event!=0\n", __func__);
			prtd->start = 0;
			snd_pcm_stop(substream, SNDRV_PCM_STATE_SETUP);
			break;
		case AFE_EVENT_RTPORT_LOW_WM:
			pr_debug("%s: Underrun\n", __func__);
			break;
		case AFE_EVENT_RTPORT_HI_WM:
			pr_debug("%s: Overrun\n", __func__);
			break;
		default:
			break;
		}
		break;
	}
	case APR_BASIC_RSP_RESULT: {
		switch (payload[0]) {
		case AFE_PORT_DATA_CMD_RT_PROXY_PORT_READ_V2:
			pr_debug("Read done\n");
			prtd->pcm_irq_pos += snd_pcm_lib_period_bytes
							(prtd->substream);
			snd_pcm_period_elapsed(prtd->substream);
			break;
		default:
			break;
		}
		break;
	}
	default:
		break;
	}
	spin_unlock_irqrestore(&prtd->dsp_lock, dsp_flags);
}
Exemplo n.º 9
0
static int saudio_data_transfer_process(struct saudio_stream *stream,
					struct saudio_msg *msg)
{
	struct snd_pcm_runtime *runtime = stream->substream->runtime;
	struct sblock blk = { 0 };
	int32_t result = 0;
	struct cmd_common *common = NULL;

	int32_t elapsed_blks = 0;
	int32_t periods_avail;
	int32_t periods_tosend;
	int32_t cur_blk_count = 0;

	cur_blk_count = sblock_get_free_count(stream->dst, stream->channel);

	elapsed_blks =
	    (cur_blk_count + stream->last_getblk_count - stream->blk_count) -
	    stream->last_elapsed_count;

	if (stream->stream_id == SNDRV_PCM_STREAM_PLAYBACK) {
		periods_avail = snd_pcm_playback_avail(runtime) /
		    runtime->period_size;
	} else {
		periods_avail = snd_pcm_capture_avail(runtime) /
		    runtime->period_size;
	}

	periods_tosend = stream->periods_avail - periods_avail;
	if (periods_tosend > 0) {
		stream->periods_tosend += periods_tosend;
	}

	if (stream->periods_tosend) {
		while (stream->periods_tosend) {
			result =
			    sblock_get(stream->dst, stream->channel, &blk, 0);
			if (result) {
				break;
			}
			stream->last_getblk_count++;
			common = (struct cmd_common *)blk.addr;
			blk.length =
			    frames_to_bytes(runtime, runtime->period_size);
			common->command = SAUDIO_DATA_PCM;
			common->sub_cmd = stream->stream_id;
			common->reserved1 =
			    stream->substream->dma_buffer.addr +
			    stream->period * blk.length;

			sblock_send(stream->dst, stream->channel, &blk);

			stream->periods_tosend--;
			stream->period++;
			stream->period = stream->period % runtime->periods;
		}

	} else {
		pr_debug("saudio.c: saudio no data to send ");
		if (sblock_get_free_count(stream->dst, stream->channel) ==
		    SAUDIO_STREAM_BLOCK_COUNT) {
			pr_debug
			    ("saudio.c: saudio no data to send and  is empty ");
			result =
			    sblock_get(stream->dst, stream->channel, &blk, 0);
			if (result) {
				ETRACE("saudio.c: no data and no blk\n");
			} else {
				stream->last_getblk_count++;
				common = (struct cmd_common *)blk.addr;
				common->command = SAUDIO_DATA_SILENCE;
				common->sub_cmd = stream->stream_id;

				sblock_send(stream->dst, stream->channel, &blk);
				stream->last_elapsed_count++;
				schedule_timeout_interruptible(msecs_to_jiffies(5));
			}
		}
	}

	while (elapsed_blks > 0) {
		elapsed_blks--;
		stream->hwptr_done++;
		stream->hwptr_done %= runtime->periods;
		snd_pcm_period_elapsed(stream->substream);
		stream->periods_avail++;
		stream->last_elapsed_count++;
	}

	return 0;
}
Exemplo n.º 10
0
static void ivtv_alsa_announce_pcm_data(struct snd_ivtv_card *itvsc,
					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("ivtv alsa announce ptr=%p data=%p num_bytes=%zu\n", itvsc,
		pcm_data, num_bytes);

	substream = itvsc->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 = itvsc->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);

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

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

	snd_pcm_stream_unlock(substream);

	if (period_elapsed)
		snd_pcm_period_elapsed(substream);
}
Exemplo n.º 11
0
static void snd_msnd_eval_dsp_msg(struct snd_msnd *chip, u16 wMessage)
{
	switch (HIBYTE(wMessage)) {
	case HIMT_PLAY_DONE: {
		if (chip->banksPlayed < 3)
			snd_printdd("%08X: HIMT_PLAY_DONE: %i\n",
				(unsigned)jiffies, LOBYTE(wMessage));

		if (chip->last_playbank == LOBYTE(wMessage)) {
			snd_printdd("chip.last_playbank == LOBYTE(wMessage)\n");
			break;
		}
		chip->banksPlayed++;

		if (test_bit(F_WRITING, &chip->flags))
			snd_msnd_DAPQ(chip, 0);

		chip->last_playbank = LOBYTE(wMessage);
		chip->playDMAPos += chip->play_period_bytes;
		if (chip->playDMAPos > chip->playLimit)
			chip->playDMAPos = 0;
		snd_pcm_period_elapsed(chip->playback_substream);

		break;
	}
	case HIMT_RECORD_DONE:
		if (chip->last_recbank == LOBYTE(wMessage))
			break;
		chip->last_recbank = LOBYTE(wMessage);
		chip->captureDMAPos += chip->capturePeriodBytes;
		if (chip->captureDMAPos > (chip->captureLimit))
			chip->captureDMAPos = 0;

		if (test_bit(F_READING, &chip->flags))
			snd_msnd_DARQ(chip, chip->last_recbank);

		snd_pcm_period_elapsed(chip->capture_substream);
		break;

	case HIMT_DSP:
		switch (LOBYTE(wMessage)) {
#ifndef MSND_CLASSIC
		case HIDSP_PLAY_UNDER:
#endif
		case HIDSP_INT_PLAY_UNDER:
			snd_printd(KERN_WARNING LOGNAME ": Play underflow %i\n",
				chip->banksPlayed);
			if (chip->banksPlayed > 2)
				clear_bit(F_WRITING, &chip->flags);
			break;

		case HIDSP_INT_RECORD_OVER:
			snd_printd(KERN_WARNING LOGNAME ": Record overflow\n");
			clear_bit(F_READING, &chip->flags);
			break;

		default:
			snd_printd(KERN_WARNING LOGNAME
				   ": DSP message %d 0x%02x\n",
				   LOBYTE(wMessage), LOBYTE(wMessage));
			break;
		}
		break;

	case HIMT_MIDI_IN_UCHAR:
		if (chip->msndmidi_mpu)
			snd_msndmidi_input_read(chip->msndmidi_mpu);
		break;

	default:
		snd_printd(KERN_WARNING LOGNAME ": HIMT message %d 0x%02x\n",
			   HIBYTE(wMessage), HIBYTE(wMessage));
		break;
	}
}
Exemplo n.º 12
0
Arquivo: atiixp.c Projeto: 3null/linux
/*
 * the period ack.  update the substream.
 */
static void snd_atiixp_update_dma(struct atiixp *chip, struct atiixp_dma *dma)
{
	if (! dma->substream || ! dma->running)
		return;
	snd_pcm_period_elapsed(dma->substream);
}
Exemplo n.º 13
0
static void ep93xx_pcm_period_elapsed(unsigned long data)
{
	struct snd_pcm_substream *substream = (struct snd_pcm_substream *)data;
	snd_pcm_period_elapsed(substream);
}
    static void
vaudio_intr_data (void* cookie, NkXIrq xirq)
{
    struct vaudio_stream* s = (struct vaudio_stream*) cookie;
    NkDevRing*   ring   = s->ring;
    nku32_f	 oresp  = s->resp;
    const nku32_f mask   = ring->imask;
    const nku32_f nresp  = ring->iresp;
    bool	 trigger = 0;
#if VAUDIO_PROC_SYNC
    if (vaudio_sync_force_close &&
        s->stream->pcm->device == 0 &&
        s->stream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE) {
        while (vaudio_send_data(s) >= 0);
        // memset(s->stream->dma_buffer.area, 0, NK_VAUDIO_MAX_RING_SIZE);
        return;
    }
#endif
    (void) xirq;
    if (s->active) {
	struct snd_pcm_runtime* runtime = s->stream->runtime;
	int periods_avail;
	int periods_tosend;

	if (s->stream_id == SNDRV_PCM_STREAM_PLAYBACK) {
	    periods_avail = snd_pcm_playback_avail(runtime) /
				    runtime->period_size;
	} else {
	    periods_avail = snd_pcm_capture_avail(runtime) /
				    runtime->period_size;
	}
	DTRACE ("%d %d %d\n",
		s->periods_avail, periods_avail, s->periods_tosend);
	periods_tosend = s->periods_avail - periods_avail;
	if (periods_tosend > 0) {
	    s->periods_tosend += periods_tosend;
	}
	s->periods_avail = periods_avail;
	while (s->periods_tosend) {
	    const int res = vaudio_send_data(s);
	    if (res < 0) break;
	    if (res == 1) trigger = 1;
	    s->periods_tosend--;
	}
    }
    while (oresp != nresp) {
	NkRingDesc*  desc = s->rbase + (oresp & mask);

	if (desc->status == (nku32_f) NK_VAUDIO_STATUS_ERROR) {
	    snd_pcm_stop(s->stream, SNDRV_PCM_STATE_XRUN);
	} else {
	    if (s->active) {
		struct snd_pcm_runtime* runtime = s->stream->runtime;

		s->hwptr_done++;
		s->hwptr_done %= runtime->periods;
		snd_pcm_period_elapsed(s->stream);
		s->periods_avail++;
	    }
	}
	oresp++;
    }
    s->resp = oresp;
    if (trigger) {
	nkops.nk_xirq_trigger(ring->cxirq, s->vaudio->vlink->s_id);
    }
}
Exemplo n.º 15
0
static void atmel_ac97c_dma_capture_period_done(void *arg)
{
	struct atmel_ac97c *chip = arg;
	snd_pcm_period_elapsed(chip->capture_substream);
}
Exemplo n.º 16
0
/* This function is called by the DMA driver. */
static void atmel_abdac_dma_period_done(void *arg)
{
	struct atmel_abdac *dac = arg;
	snd_pcm_period_elapsed(dac->substream);
}
Exemplo n.º 17
0
static irqreturn_t atmel_ac97c_interrupt(int irq, void *dev)
{
	struct atmel_ac97c	*chip  = (struct atmel_ac97c *)dev;
	irqreturn_t		retval = IRQ_NONE;
	u32			sr     = ac97c_readl(chip, SR);
	u32			casr   = ac97c_readl(chip, CASR);
	u32			cosr   = ac97c_readl(chip, COSR);
	u32			camr   = ac97c_readl(chip, CAMR);

	if (sr & AC97C_SR_CAEVT) {
		struct snd_pcm_runtime *runtime;
		int offset, next_period, block_size;
		dev_dbg(&chip->pdev->dev, "channel A event%s%s%s%s%s%s\n",
				casr & AC97C_CSR_OVRUN   ? " OVRUN"   : "",
				casr & AC97C_CSR_RXRDY   ? " RXRDY"   : "",
				casr & AC97C_CSR_UNRUN   ? " UNRUN"   : "",
				casr & AC97C_CSR_TXEMPTY ? " TXEMPTY" : "",
				casr & AC97C_CSR_TXRDY   ? " TXRDY"   : "",
				!casr                    ? " NONE"    : "");
		if (!cpu_is_at32ap7000()) {
			if ((casr & camr) & AC97C_CSR_ENDTX) {
				runtime = chip->playback_substream->runtime;
				block_size = frames_to_bytes(runtime,
						runtime->period_size);
				chip->playback_period++;

				if (chip->playback_period == runtime->periods)
					chip->playback_period = 0;
				next_period = chip->playback_period + 1;
				if (next_period == runtime->periods)
					next_period = 0;

				offset = block_size * next_period;

				writel(runtime->dma_addr + offset,
						chip->regs + ATMEL_PDC_TNPR);
				writel(block_size / 2,
						chip->regs + ATMEL_PDC_TNCR);

				snd_pcm_period_elapsed(
						chip->playback_substream);
			}
			if ((casr & camr) & AC97C_CSR_ENDRX) {
				runtime = chip->capture_substream->runtime;
				block_size = frames_to_bytes(runtime,
						runtime->period_size);
				chip->capture_period++;

				if (chip->capture_period == runtime->periods)
					chip->capture_period = 0;
				next_period = chip->capture_period + 1;
				if (next_period == runtime->periods)
					next_period = 0;

				offset = block_size * next_period;

				writel(runtime->dma_addr + offset,
						chip->regs + ATMEL_PDC_RNPR);
				writel(block_size / 2,
						chip->regs + ATMEL_PDC_RNCR);
				snd_pcm_period_elapsed(chip->capture_substream);
			}
		}
		retval = IRQ_HANDLED;
	}

	if (sr & AC97C_SR_COEVT) {
		dev_info(&chip->pdev->dev, "codec channel event%s%s%s%s%s\n",
				cosr & AC97C_CSR_OVRUN   ? " OVRUN"   : "",
				cosr & AC97C_CSR_RXRDY   ? " RXRDY"   : "",
				cosr & AC97C_CSR_TXEMPTY ? " TXEMPTY" : "",
				cosr & AC97C_CSR_TXRDY   ? " TXRDY"   : "",
				!cosr                    ? " NONE"    : "");
		retval = IRQ_HANDLED;
	}

	if (retval == IRQ_NONE) {
		dev_err(&chip->pdev->dev, "spurious interrupt sr 0x%08x "
				"casr 0x%08x cosr 0x%08x\n", sr, casr, cosr);
	}

	return retval;
}
/*
 * intel_alsa_ifx_dma_capture_complete - End of capture callback
 * called in DMA Complete Tasklet context
 * This Callback has in charge of re-programming a new read request to
 * Intel MID I2S Driver if the stream has not been Closed.
 * It calls also the snd_pcm_period_elapsed if the stream is not
 * PAUSED or SUSPENDED to inform ALSA Kernel that the Ring Buffer
 * period has been received properly
 *
 * Input parameters
 *		@param : pointer to a structure
 * Output parameters
 *		@ret_val : status
 */
int intel_alsa_ifx_dma_capture_complete(void *param)
{
	struct intel_alsa_ssp_dma_buf *sb_rx;
	struct intel_alsa_ifx_stream_info *str_info;
	bool call_back = false;
	bool reset_index = false;

	WARN(!param, "ALSA IFX: ERROR param NULL\n");
	if (!param)
		return -EBUSY;

	str_info = param;
	sb_rx = &(str_info->dma_slot);

	if (test_and_clear_bit(INTEL_ALSA_SSP_STREAM_RUNNING, &str_info->stream_status)) {
			if (test_and_clear_bit(INTEL_ALSA_SSP_STREAM_DROPPED, &str_info->stream_status)) {
				if (test_bit(INTEL_ALSA_SSP_STREAM_STARTED, &str_info->stream_status)) {
					/*
					 * the stream has been dropped and
					 * restarted before the callback occurs
					 * in this case the we have to reprogram the requests
					 * to SSP driver and reset the stream's indexes
					 */
					call_back = true;
					reset_index = true;
				} else
					call_back = false;
			} else {
				if (test_bit(INTEL_ALSA_SSP_STREAM_STARTED, &str_info->stream_status)) {
					/*
					 * the stream is on going
					 */
					call_back = true;
				} else {
					WARN(1, "ALSA_IFX: FCT %s spurious"
						"playback DMA complete 1 ?!\n",
						__func__);
					return -EBUSY;
				}
			}
		} else {
			WARN(1, "ALSA_IFX: FCT %s spurious playback DMA complete 2 ?!\n",
					__func__);
			return -EBUSY;
		}

	if (call_back == true) {
		pr_debug("ALSA_IFX: playback (REQ=%d,CB=%d): PLAYBACK_DMA_REQ_COMPLETE\n",
				sb_rx->period_req_index,
				sb_rx->period_cb_index);

		if (reset_index) {
			sb_rx->period_cb_index = 0;
			sb_rx->period_req_index = 0;
		} else if (++(sb_rx->period_cb_index) >= sb_rx->period_index_max)
			sb_rx->period_cb_index = 0;

		/*
		 * Launch the next Playback request if no
		 * CLOSE has been requested
		 */
		intel_alsa_ifx_dma_capture_req(str_info);
		/*
		 * Call the snd_pcm_period_elapsed to inform ALSA kernel
		 * that a ring buffer period has been played
		 */
		snd_pcm_period_elapsed(str_info->substream);

	}
	return 0;
} /* intel_alsa_ifx_dma_capture_complete */
Exemplo n.º 19
0
static void aml_i2s_timer_callback(unsigned long data)
{
    struct snd_pcm_substream *substream = (struct snd_pcm_substream *)data;
    struct snd_pcm_runtime *runtime = substream->runtime;
    struct aml_runtime_data *prtd = runtime->private_data;
    audio_stream_t *s = &prtd->s;

    unsigned int last_ptr, size = 0;
    if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
        if (s->active == 1) {
            spin_lock(&s->lock);
            if (s->device_type == AML_AUDIO_I2SOUT) {
                last_ptr = read_i2s_rd_ptr();
            } else {
                last_ptr = read_iec958_rd_ptr();
            }
            if (last_ptr < s->last_ptr) {
                size = runtime->dma_bytes + last_ptr - (s->last_ptr);
            } else {
                size = last_ptr - (s->last_ptr);
            }
            s->last_ptr = last_ptr;
            s->size += bytes_to_frames(substream->runtime, size);
            if (s->size >= runtime->period_size) {
                s->size %= runtime->period_size;
                spin_unlock(&s->lock);
                snd_pcm_period_elapsed(substream);
                spin_lock(&s->lock);
            }
            mod_timer(&prtd->timer, jiffies + 1);
            spin_unlock(&s->lock);
        } else {
            mod_timer(&prtd->timer, jiffies + 1);
        }
    } else {
        if (s->active == 1) {
            spin_lock(&s->lock);
            if (s->device_type == AML_AUDIO_I2SIN) {
                last_ptr = audio_in_i2s_wr_ptr() ;
            } else {
                last_ptr = audio_in_spdif_wr_ptr();
            }
            if (last_ptr < s->last_ptr) {
                size = runtime->dma_bytes + (last_ptr - (s->last_ptr)) / 2;
            } else if (last_ptr == s->last_ptr) {
                if (s->xrun_num++ > 100) {
                    printk(KERN_INFO "alsa capture long time no data, quit xrun!\n");
                    s->xrun_num = 0;
                    s->size = runtime->period_size;
                }
            } else {
                size = (last_ptr - (s->last_ptr)) / 2;
            }
            s->last_ptr = last_ptr;
            s->size += bytes_to_frames(substream->runtime, size);
            if (s->size >= runtime->period_size) {
                s->size %= runtime->period_size;
                spin_unlock(&s->lock);
                snd_pcm_period_elapsed(substream);
                spin_lock(&s->lock);
            }
            mod_timer(&prtd->timer, jiffies + 1);
            spin_unlock(&s->lock);
        } else {
            mod_timer(&prtd->timer, jiffies + 1);
        }
    }
}
Exemplo n.º 20
0
static irqreturn_t oxygen_interrupt(int dummy, void *dev_id)
{
	struct oxygen *chip = dev_id;
	unsigned int status, clear, elapsed_streams, i;

	status = oxygen_read16(chip, OXYGEN_INTERRUPT_STATUS);
	if (!status)
		return IRQ_NONE;

	spin_lock(&chip->reg_lock);

	clear = status & (OXYGEN_CHANNEL_A |
			  OXYGEN_CHANNEL_B |
			  OXYGEN_CHANNEL_C |
			  OXYGEN_CHANNEL_SPDIF |
			  OXYGEN_CHANNEL_MULTICH |
			  OXYGEN_CHANNEL_AC97 |
			  OXYGEN_INT_SPDIF_IN_DETECT |
			  OXYGEN_INT_GPIO |
			  OXYGEN_INT_AC97);
	if (clear) {
		if (clear & OXYGEN_INT_SPDIF_IN_DETECT)
			chip->interrupt_mask &= ~OXYGEN_INT_SPDIF_IN_DETECT;
		oxygen_write16(chip, OXYGEN_INTERRUPT_MASK,
			       chip->interrupt_mask & ~clear);
		oxygen_write16(chip, OXYGEN_INTERRUPT_MASK,
			       chip->interrupt_mask);
	}

	elapsed_streams = status & chip->pcm_running;

	spin_unlock(&chip->reg_lock);

	for (i = 0; i < PCM_COUNT; ++i)
		if ((elapsed_streams & (1 << i)) && chip->streams[i])
			snd_pcm_period_elapsed(chip->streams[i]);

	if (status & OXYGEN_INT_SPDIF_IN_DETECT) {
		spin_lock(&chip->reg_lock);
		i = oxygen_read32(chip, OXYGEN_SPDIF_CONTROL);
		if (i & (OXYGEN_SPDIF_SENSE_INT | OXYGEN_SPDIF_LOCK_INT |
			 OXYGEN_SPDIF_RATE_INT)) {
			/* write the interrupt bit(s) to clear */
			oxygen_write32(chip, OXYGEN_SPDIF_CONTROL, i);
			schedule_work(&chip->spdif_input_bits_work);
		}
		spin_unlock(&chip->reg_lock);
	}

	if (status & OXYGEN_INT_GPIO)
		schedule_work(&chip->gpio_work);

	if (status & OXYGEN_INT_MIDI) {
		if (chip->midi)
			snd_mpu401_uart_interrupt(0, chip->midi->private_data);
		else
			oxygen_read_uart(chip);
	}

	if (status & OXYGEN_INT_AC97)
		wake_up(&chip->ac97_waitqueue);

	return IRQ_HANDLED;
}
static void aml_pcm_timer_callback(unsigned long data)
{
    struct snd_pcm_substream *substream = (struct snd_pcm_substream *)data;
    struct snd_pcm_runtime *runtime = substream->runtime;
    struct aml_runtime_data *prtd = runtime->private_data;
		audio_stream_t *s = &prtd->s;

    unsigned int last_ptr, size;
	if(substream->stream == SNDRV_PCM_STREAM_PLAYBACK){
				if(s->active == 1){
						spin_lock(&s->lock);
						last_ptr = read_i2s_rd_ptr();
						if (last_ptr < s->last_ptr) {
				        size = runtime->dma_bytes + last_ptr - (s->last_ptr);
				    } else {
				        size = last_ptr - (s->last_ptr);
				    }
    				s->last_ptr = last_ptr;
    				s->size += bytes_to_frames(substream->runtime, size);
    				if (s->size >= runtime->period_size) {
				        s->size %= runtime->period_size;
				        spin_unlock(&s->lock);
				        snd_pcm_period_elapsed(substream);
				        spin_lock(&s->lock);
				    }
				    mod_timer(&prtd->timer, jiffies + 1);
					//codec_power = 1;
   					spin_unlock(&s->lock);
				}else{
					
						 mod_timer(&prtd->timer, jiffies + 1);
						// codec_power = 0;
				 
				}
			  
		}else{
				if(s->active == 1){
						spin_lock(&s->lock);
						last_ptr = (audio_in_i2s_wr_ptr() - s->I2S_addr) / 2;
						if (last_ptr < s->last_ptr) {
				        size = runtime->dma_bytes + last_ptr - (s->last_ptr);
				    } else {
				        size = last_ptr - (s->last_ptr);
				    }
    				s->last_ptr = last_ptr;
    				s->size += bytes_to_frames(substream->runtime, size);
    				if (s->size >= runtime->period_size) {
				        s->size %= runtime->period_size;
				        spin_unlock(&s->lock);
				        snd_pcm_period_elapsed(substream);
				        spin_lock(&s->lock);
				    }
				    mod_timer(&prtd->timer, jiffies + 1);
   					spin_unlock(&s->lock);
				}else{
						 mod_timer(&prtd->timer, jiffies + 1);
				}
		}  
	/*	if((codec_power==0) && (num==500))
		{
			num=0;
	   		flag=1;	
			schedule_work(&aml_pcm_work.aml_codec_workqueue);
		}
	   else if((codec_power==1) && (num <= 500))
	   	{
	   		num=0;
			flag = 0;
	   	}
	   else if((codec_power==0) && (num<500))
	   	{ 	
	   	    if(flag==1)
	   	    {}
			else
			{
				num++;
			}
	   	} */
}
Exemplo n.º 22
0
/*
 * Interrupt handler
 */
static irqreturn_t snd_ps3_interrupt(int irq, void *dev_id)
{

	uint32_t port_intr;
	int underflow_occured = 0;
	struct snd_ps3_card_info *card = dev_id;

	if (!card->running) {
		update_reg(PS3_AUDIO_AX_IS, 0);
		update_reg(PS3_AUDIO_INTR_0, 0);
		return IRQ_HANDLED;
	}

	port_intr = read_reg(PS3_AUDIO_AX_IS);
	/*
	 *serial buffer empty detected (every 4 times),
	 *program next dma and kick it
	 */
	if (port_intr & PS3_AUDIO_AX_IE_ASOBEIE(0)) {
		write_reg(PS3_AUDIO_AX_IS, PS3_AUDIO_AX_IE_ASOBEIE(0));
		if (port_intr & PS3_AUDIO_AX_IE_ASOBUIE(0)) {
			write_reg(PS3_AUDIO_AX_IS, port_intr);
			underflow_occured = 1;
		}
		if (card->silent) {
			/* we are still in silent time */
			snd_ps3_program_dma(card,
				(underflow_occured) ?
				SND_PS3_DMA_FILLTYPE_SILENT_FIRSTFILL :
				SND_PS3_DMA_FILLTYPE_SILENT_RUNNING);
			snd_ps3_kick_dma(card);
			card->silent--;
		} else {
			snd_ps3_program_dma(card,
				(underflow_occured) ?
				SND_PS3_DMA_FILLTYPE_FIRSTFILL :
				SND_PS3_DMA_FILLTYPE_RUNNING);
			snd_ps3_kick_dma(card);
			snd_pcm_period_elapsed(card->substream);
		}
	} else if (port_intr & PS3_AUDIO_AX_IE_ASOBUIE(0)) {
		write_reg(PS3_AUDIO_AX_IS, PS3_AUDIO_AX_IE_ASOBUIE(0));
		/*
		 * serial out underflow, but buffer empty not detected.
		 * in this case, fill fifo with 0 to recover.  After
		 * filling dummy data, serial automatically start to
		 * consume them and then will generate normal buffer
		 * empty interrupts.
		 * If both buffer underflow and buffer empty are occured,
		 * it is better to do nomal data transfer than empty one
		 */
		snd_ps3_program_dma(card,
				    SND_PS3_DMA_FILLTYPE_SILENT_FIRSTFILL);
		snd_ps3_kick_dma(card);
		snd_ps3_program_dma(card,
				    SND_PS3_DMA_FILLTYPE_SILENT_FIRSTFILL);
		snd_ps3_kick_dma(card);
	}
	/* clear interrupt cause */
	return IRQ_HANDLED;
};
Exemplo n.º 23
0
static void capture_urb_complete(struct urb *urb)
{
	struct ua101 *ua = urb->context;
	struct ua101_stream *stream = &ua->capture;
	unsigned long flags;
	unsigned int frames, write_ptr;
	bool do_period_elapsed;
	int err;

	if (unlikely(urb->status == -ENOENT ||		/* unlinked */
		     urb->status == -ENODEV ||		/* device removed */
		     urb->status == -ECONNRESET ||	/* unlinked */
		     urb->status == -ESHUTDOWN))	/* device disabled */
		goto stream_stopped;

	if (urb->status >= 0 && urb->iso_frame_desc[0].status >= 0)
		frames = urb->iso_frame_desc[0].actual_length /
			stream->frame_bytes;
	else
		frames = 0;

	spin_lock_irqsave(&ua->lock, flags);

	if (frames > 0 && test_bit(ALSA_CAPTURE_RUNNING, &ua->states))
		do_period_elapsed = copy_capture_data(stream, urb, frames);
	else
		do_period_elapsed = false;

	if (test_bit(USB_CAPTURE_RUNNING, &ua->states)) {
		err = usb_submit_urb(urb, GFP_ATOMIC);
		if (unlikely(err < 0)) {
			spin_unlock_irqrestore(&ua->lock, flags);
			dev_err(&ua->dev->dev, "USB request error %d: %s\n",
				err, usb_error_string(err));
			goto stream_stopped;
		}

		/* append packet size to FIFO */
		write_ptr = ua->rate_feedback_start;
		add_with_wraparound(ua, &write_ptr, ua->rate_feedback_count);
		ua->rate_feedback[write_ptr] = frames;
		if (ua->rate_feedback_count < ua->playback.queue_length) {
			ua->rate_feedback_count++;
			if (ua->rate_feedback_count ==
						ua->playback.queue_length)
				wake_up(&ua->rate_feedback_wait);
		} else {
			/*
			 * Ring buffer overflow; this happens when the playback
			 * stream is not running.  Throw away the oldest entry,
			 * so that the playback stream, when it starts, sees
			 * the most recent packet sizes.
			 */
			add_with_wraparound(ua, &ua->rate_feedback_start, 1);
		}
		if (test_bit(USB_PLAYBACK_RUNNING, &ua->states) &&
		    !list_empty(&ua->ready_playback_urbs))
			tasklet_schedule(&ua->playback_tasklet);
	}

	spin_unlock_irqrestore(&ua->lock, flags);

	if (do_period_elapsed)
		snd_pcm_period_elapsed(stream->substream);

	return;

stream_stopped:
	abort_usb_playback(ua);
	abort_usb_capture(ua);
	abort_alsa_playback(ua);
	abort_alsa_capture(ua);
}
Exemplo n.º 24
0
irqreturn_t snd_emu10k1_interrupt(int irq, void *dev_id)
{
	struct snd_emu10k1 *emu = dev_id;
	unsigned int status, status2, orig_status, orig_status2;
	int handled = 0;
	int timeout = 0;

	while (((status = inl(emu->port + IPR)) != 0) && (timeout < 1000)) {
		timeout++;
		orig_status = status;
		handled = 1;
		if ((status & 0xffffffff) == 0xffffffff) {
			snd_printk(KERN_INFO "snd-emu10k1: Suspected sound card removal\n");
			break;
		}
		if (status & IPR_PCIERROR) {
			snd_printk(KERN_ERR "interrupt: PCI error\n");
			snd_emu10k1_intr_disable(emu, INTE_PCIERRORENABLE);
			status &= ~IPR_PCIERROR;
		}
		if (status & (IPR_VOLINCR|IPR_VOLDECR|IPR_MUTE)) {
			if (emu->hwvol_interrupt)
				emu->hwvol_interrupt(emu, status);
			else
				snd_emu10k1_intr_disable(emu, INTE_VOLINCRENABLE|INTE_VOLDECRENABLE|INTE_MUTEENABLE);
			status &= ~(IPR_VOLINCR|IPR_VOLDECR|IPR_MUTE);
		}
		if (status & IPR_CHANNELLOOP) {
			int voice;
			int voice_max = status & IPR_CHANNELNUMBERMASK;
			u32 val;
			struct snd_emu10k1_voice *pvoice = emu->voices;

			val = snd_emu10k1_ptr_read(emu, CLIPL, 0);
			for (voice = 0; voice <= voice_max; voice++) {
				if (voice == 0x20)
					val = snd_emu10k1_ptr_read(emu, CLIPH, 0);
				if (val & 1) {
					if (pvoice->use && pvoice->interrupt != NULL) {
						pvoice->interrupt(emu, pvoice);
						snd_emu10k1_voice_intr_ack(emu, voice);
					} else {
						snd_emu10k1_voice_intr_disable(emu, voice);
					}
				}
				val >>= 1;
				pvoice++;
			}
			val = snd_emu10k1_ptr_read(emu, HLIPL, 0);
			for (voice = 0; voice <= voice_max; voice++) {
				if (voice == 0x20)
					val = snd_emu10k1_ptr_read(emu, HLIPH, 0);
				if (val & 1) {
					if (pvoice->use && pvoice->interrupt != NULL) {
						pvoice->interrupt(emu, pvoice);
						snd_emu10k1_voice_half_loop_intr_ack(emu, voice);
					} else {
						snd_emu10k1_voice_half_loop_intr_disable(emu, voice);
					}
				}
				val >>= 1;
				pvoice++;
			}
			status &= ~IPR_CHANNELLOOP;
		}
		status &= ~IPR_CHANNELNUMBERMASK;
		if (status & (IPR_ADCBUFFULL|IPR_ADCBUFHALFFULL)) {
			if (emu->capture_interrupt)
				emu->capture_interrupt(emu, status);
			else
				snd_emu10k1_intr_disable(emu, INTE_ADCBUFENABLE);
			status &= ~(IPR_ADCBUFFULL|IPR_ADCBUFHALFFULL);
		}
		if (status & (IPR_MICBUFFULL|IPR_MICBUFHALFFULL)) {
			if (emu->capture_mic_interrupt)
				emu->capture_mic_interrupt(emu, status);
			else
				snd_emu10k1_intr_disable(emu, INTE_MICBUFENABLE);
			status &= ~(IPR_MICBUFFULL|IPR_MICBUFHALFFULL);
		}
		if (status & (IPR_EFXBUFFULL|IPR_EFXBUFHALFFULL)) {
			if (emu->capture_efx_interrupt)
				emu->capture_efx_interrupt(emu, status);
			else
				snd_emu10k1_intr_disable(emu, INTE_EFXBUFENABLE);
			status &= ~(IPR_EFXBUFFULL|IPR_EFXBUFHALFFULL);
		}
		if (status & (IPR_MIDITRANSBUFEMPTY|IPR_MIDIRECVBUFEMPTY)) {
			if (emu->midi.interrupt)
				emu->midi.interrupt(emu, status);
			else
				snd_emu10k1_intr_disable(emu, INTE_MIDITXENABLE|INTE_MIDIRXENABLE);
			status &= ~(IPR_MIDITRANSBUFEMPTY|IPR_MIDIRECVBUFEMPTY);
		}
		if (status & (IPR_A_MIDITRANSBUFEMPTY2|IPR_A_MIDIRECVBUFEMPTY2)) {
			if (emu->midi2.interrupt)
				emu->midi2.interrupt(emu, status);
			else
				snd_emu10k1_intr_disable(emu, INTE_A_MIDITXENABLE2|INTE_A_MIDIRXENABLE2);
			status &= ~(IPR_A_MIDITRANSBUFEMPTY2|IPR_A_MIDIRECVBUFEMPTY2);
		}
		if (status & IPR_INTERVALTIMER) {
			if (emu->timer)
				snd_timer_interrupt(emu->timer, emu->timer->sticks);
			else
				snd_emu10k1_intr_disable(emu, INTE_INTERVALTIMERENB);
			status &= ~IPR_INTERVALTIMER;
		}
		if (status & (IPR_GPSPDIFSTATUSCHANGE|IPR_CDROMSTATUSCHANGE)) {
			if (emu->spdif_interrupt)
				emu->spdif_interrupt(emu, status);
			else
				snd_emu10k1_intr_disable(emu, INTE_GPSPDIFENABLE|INTE_CDSPDIFENABLE);
			status &= ~(IPR_GPSPDIFSTATUSCHANGE|IPR_CDROMSTATUSCHANGE);
		}
		if (status & IPR_FXDSP) {
			if (emu->dsp_interrupt)
				emu->dsp_interrupt(emu);
			else
				snd_emu10k1_intr_disable(emu, INTE_FXDSPENABLE);
			status &= ~IPR_FXDSP;
		}
		if (status & IPR_P16V) {
			while ((status2 = inl(emu->port + IPR2)) != 0) {
				u32 mask = INTE2_PLAYBACK_CH_0_LOOP;  /* Full Loop */
				struct snd_emu10k1_voice *pvoice = &(emu->p16v_voices[0]);
				struct snd_emu10k1_voice *cvoice = &(emu->p16v_capture_voice);

				//printk(KERN_INFO "status2=0x%x\n", status2);
				orig_status2 = status2;
				if(status2 & mask) {
					if(pvoice->use) {
						snd_pcm_period_elapsed(pvoice->epcm->substream);
					} else { 
						snd_printk(KERN_ERR "p16v: status: 0x%08x, mask=0x%08x, pvoice=%p, use=%d\n", status2, mask, pvoice, pvoice->use);
					}
				}
				if(status2 & 0x110000) {
					//printk(KERN_INFO "capture int found\n");
					if(cvoice->use) {
						//printk(KERN_INFO "capture period_elapsed\n");
						snd_pcm_period_elapsed(cvoice->epcm->substream);
					}
				}
				outl(orig_status2, emu->port + IPR2); /* ack all */
			}
			status &= ~IPR_P16V;
		}

		if (status) {
			unsigned int bits;
			snd_printk(KERN_ERR "emu10k1: unhandled interrupt: 0x%08x\n", status);
			//make sure any interrupts we don't handle are disabled:
			bits = INTE_FXDSPENABLE |
				INTE_PCIERRORENABLE |
				INTE_VOLINCRENABLE |
				INTE_VOLDECRENABLE |
				INTE_MUTEENABLE |
				INTE_MICBUFENABLE |
				INTE_ADCBUFENABLE |
				INTE_EFXBUFENABLE |
				INTE_GPSPDIFENABLE |
				INTE_CDSPDIFENABLE |
				INTE_INTERVALTIMERENB |
				INTE_MIDITXENABLE |
				INTE_MIDIRXENABLE;
			if (emu->audigy)
				bits |= INTE_A_MIDITXENABLE2 | INTE_A_MIDIRXENABLE2;
			snd_emu10k1_intr_disable(emu, bits);
		}
		outl(orig_status, emu->port + IPR); /* ack all */
	}
Exemplo n.º 25
0
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;

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

	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);
	}
Exemplo n.º 26
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);

	snd_pcm_stream_lock(substream);

	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;
	}

	snd_pcm_stream_unlock(substream);

	if (period_elapsed)
		snd_pcm_period_elapsed(substream);

	return 0;
}
Exemplo n.º 27
0
static void bf5xx_dma_irq(void *data)
{
	struct snd_pcm_substream *pcm = data;
	snd_pcm_period_elapsed(pcm);
}
static irqreturn_t hi3630_intr_pcm_hdmi_handle(int irq, void *dev_id)
{
	struct snd_pcm *pcm = dev_id;
	struct snd_pcm_substream *substream = NULL;
	struct snd_pcm_runtime *runtime = NULL;
	struct hi3630_hdmi_runtime_data *prtd = NULL;
	struct hi3630_hdmi_data *pdata = NULL;
	unsigned int rt_period_size = 0;
	unsigned int num_periods = 0;
	unsigned int irs = 0;
	unsigned int dma_cur = HDMI_DMA_A;
	unsigned int dma_next = HDMI_DMA_A;
	snd_pcm_uframes_t avail = 0;

	BUG_ON(NULL == pcm);
	substream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
	if (NULL == substream) {
		loge("substream is NULL\n");
		return IRQ_HANDLED;
	}

	runtime = substream->runtime;
	prtd = runtime->private_data;
	pdata = prtd->pdata;
	rt_period_size = runtime->period_size;
	num_periods = runtime->periods;

	irs = hi3630_hdmi_reg_read(pdata, HI3630_ASP_INT_STATE) & HDMI_DMA_MASK;

	if (0 == irs) {
		logw("not hdmi dma irq\n");
		return IRQ_HANDLED;
	}

	spin_lock(&prtd->lock);
	prtd->period_cur = (prtd->period_cur + 1) % num_periods;
	spin_unlock(&prtd->lock);

	snd_pcm_period_elapsed(substream);

	spin_lock(&prtd->lock);

	if (STATUS_HDMI_STOP == prtd->status) {
		logd("stop dma, irs = %#x\n", irs);
		hi3630_hdmi_reg_write(pdata, HI3630_ASP_INT_CLR, irs);
		spin_unlock(&prtd->lock);
		return IRQ_HANDLED;
	}

	if (0 != ((1 << HDMI_DMA_A) & irs)) {
		hi3630_hdmi_reg_write(pdata, HI3630_ASP_INT_CLR, HDMI_DMA_A_MASK);
		dma_cur = HDMI_DMA_A;
		dma_next = HDMI_DMA_B;
	} else {
		hi3630_hdmi_reg_write(pdata, HI3630_ASP_INT_CLR, HDMI_DMA_B_MASK);
		dma_cur = HDMI_DMA_B;
		dma_next = HDMI_DMA_A;
	}

	avail = snd_pcm_playback_hw_avail(runtime);

	if(avail < rt_period_size) {
		logd("Run out of data\n");
		prtd->two_dma_flag = false;
	} else {
		/* config & enable DMA */
		config_hdmi_dma(prtd, dma_cur);
		hi3630_hdmi_enable_dma(pdata, dma_cur);
		prtd->period_next = (prtd->period_next + 1) % num_periods;
		if ((!prtd->two_dma_flag) && (avail >= rt_period_size * 2)) {
			/* config & enable DMA */
			config_hdmi_dma(prtd, dma_next);
			hi3630_hdmi_enable_dma(pdata, dma_next);
			prtd->period_next = (prtd->period_next + 1) % num_periods;
			prtd->two_dma_flag = true;
		}
	}

	spin_unlock(&prtd->lock);

	return IRQ_HANDLED;
}
Exemplo n.º 29
0
static void dummy_hrtimer_pcm_elapsed(unsigned long priv)
{
	struct dummy_hrtimer_pcm *dpcm = (struct dummy_hrtimer_pcm *)priv;
	if (atomic_read(&dpcm->running))
		snd_pcm_period_elapsed(dpcm->substream);
}
irqreturn_t snd_mixart_interrupt(int irq, void *dev_id)
{
	struct mixart_mgr *mgr = dev_id;
	int err;
	struct mixart_msg resp;

	u32 msg;
	u32 it_reg;

	spin_lock(&mgr->lock);

	it_reg = readl_le(MIXART_REG(mgr, MIXART_PCI_OMISR_OFFSET));
	if( !(it_reg & MIXART_OIDI) ) {
		/* this device did not cause the interrupt */
		spin_unlock(&mgr->lock);
		return IRQ_NONE;
	}

	/* mask all interrupts */
	writel_le(MIXART_HOST_ALL_INTERRUPT_MASKED, MIXART_REG(mgr, MIXART_PCI_OMIMR_OFFSET));

	/* outdoorbell register clear */
	it_reg = readl(MIXART_REG(mgr, MIXART_PCI_ODBR_OFFSET));
	writel(it_reg, MIXART_REG(mgr, MIXART_PCI_ODBR_OFFSET));

	/* clear interrupt */
	writel_le( MIXART_OIDI, MIXART_REG(mgr, MIXART_PCI_OMISR_OFFSET) );

	/* process interrupt */
	while (retrieve_msg_frame(mgr, &msg)) {

		switch (msg & MSG_TYPE_MASK) {
		case MSG_TYPE_COMMAND:
			resp.message_id = 0;
			resp.data = mixart_msg_data;
			resp.size = sizeof(mixart_msg_data);
			err = get_msg(mgr, &resp, msg & ~MSG_TYPE_MASK);
			if( err < 0 ) {
				snd_printk(KERN_ERR "interrupt: error(%d) reading mf %x\n", err, msg);
				break;
			}

			if(resp.message_id == MSG_SERVICES_TIMER_NOTIFY) {
				int i;
				struct mixart_timer_notify *notify;
				notify = (struct mixart_timer_notify *)mixart_msg_data;

				for(i=0; i<notify->stream_count; i++) {

					u32 buffer_id = notify->streams[i].buffer_id;
					unsigned int chip_number =  (buffer_id & MIXART_NOTIFY_CARD_MASK) >> MIXART_NOTIFY_CARD_OFFSET; /* card0 to 3 */
					unsigned int pcm_number  =  (buffer_id & MIXART_NOTIFY_PCM_MASK ) >> MIXART_NOTIFY_PCM_OFFSET;  /* pcm0 to 3  */
					unsigned int sub_number  =   buffer_id & MIXART_NOTIFY_SUBS_MASK;             /* 0 to MIXART_PLAYBACK_STREAMS */
					unsigned int is_capture  = ((buffer_id & MIXART_NOTIFY_CAPT_MASK) != 0);      /* playback == 0 / capture == 1 */

					struct snd_mixart *chip  = mgr->chip[chip_number];
					struct mixart_stream *stream;

					if ((chip_number >= mgr->num_cards) || (pcm_number >= MIXART_PCM_TOTAL) || (sub_number >= MIXART_PLAYBACK_STREAMS)) {
						snd_printk(KERN_ERR "error MSG_SERVICES_TIMER_NOTIFY buffer_id (%x) pos(%d)\n",
							   buffer_id, notify->streams[i].sample_pos_low_part);
						break;
					}

					if (is_capture)
						stream = &chip->capture_stream[pcm_number];
					else
						stream = &chip->playback_stream[pcm_number][sub_number];

					if (stream->substream && (stream->status == MIXART_STREAM_STATUS_RUNNING)) {
						struct snd_pcm_runtime *runtime = stream->substream->runtime;
						int elapsed = 0;
						u64 sample_count = ((u64)notify->streams[i].sample_pos_high_part) << 32;
						sample_count |= notify->streams[i].sample_pos_low_part;

						while (1) {
							u64 new_elapse_pos = stream->abs_period_elapsed +  runtime->period_size;

							if (new_elapse_pos > sample_count) {
								break; /* while */
							}
							else {
								elapsed = 1;
								stream->buf_periods++;
								if (stream->buf_periods >= runtime->periods)
									stream->buf_periods = 0;

								stream->abs_period_elapsed = new_elapse_pos;
							}
						}
						stream->buf_period_frag = (u32)( sample_count - stream->abs_period_elapsed );

						if(elapsed) {
							spin_unlock(&mgr->lock);
							snd_pcm_period_elapsed(stream->substream);
							spin_lock(&mgr->lock);
						}
					}
				}
				break;
			}
			if(resp.message_id == MSG_SERVICES_REPORT_TRACES) {
				if(resp.size > 1) {
#ifndef __BIG_ENDIAN
					/* Traces are text: the swapped msg_data has to be swapped back ! */
					int i;
					for(i=0; i<(resp.size/4); i++) {
						(mixart_msg_data)[i] = cpu_to_be32((mixart_msg_data)[i]);
					}
#endif
					((char*)mixart_msg_data)[resp.size - 1] = 0;
					snd_printdd("MIXART TRACE : %s\n", (char*)mixart_msg_data);
				}
				break;
			}

			snd_printdd("command %x not handled\n", resp.message_id);
			break;

		case MSG_TYPE_NOTIFY:
			if(msg & MSG_CANCEL_NOTIFY_MASK) {
				msg &= ~MSG_CANCEL_NOTIFY_MASK;
				snd_printk(KERN_ERR "canceled notification %x !\n", msg);
			}
			/* no break, continue ! */
		case MSG_TYPE_ANSWER:
			/* answer or notification to a message we are waiting for*/
			spin_lock(&mgr->msg_lock);
			if( (msg & ~MSG_TYPE_MASK) == mgr->pending_event ) {
				wake_up(&mgr->msg_sleep);
				mgr->pending_event = 0;
			}
			/* answer to a message we did't want to wait for */
			else {
				mgr->msg_fifo[mgr->msg_fifo_writeptr] = msg;
				mgr->msg_fifo_writeptr++;
				mgr->msg_fifo_writeptr %= MSG_FIFO_SIZE;
				tasklet_schedule(&mgr->msg_taskq);
			}
			spin_unlock(&mgr->msg_lock);
			break;
		case MSG_TYPE_REQUEST:
		default:
			snd_printdd("interrupt received request %x\n", msg);
			/* TODO : are there things to do here ? */
			break;
		} /* switch on msg type */
	} /* while there are msgs */