/* CAUTION: call it with irq disabled (due to internal call to snd_pcm_update_hw_ptr) */
static inline snd_pcm_uframes_t _ksnd_pcm_avail_update(snd_pcm_substream_t
													   *substream)
{
	snd_pcm_runtime_t *runtime = substream->runtime;
	/*NICK added if to remove real updates which we do not want*/
#if defined(__TDT__) \
 && (defined(FORTIS_HDBOX) \
 || defined(UFS922) \
 || defined(UFC960) \
 || defined(HL101) \
 || defined(VIP1_V2) \
 || defined(VIP2_V1) \
 || defined(OCTAGON1008) \
 || defined(IPBOX9900) \
 || defined(IPBOX99) \
 || defined(IPBOX55) \
 || defined(CUBEREVO_250HD) \
 || defined(CUBEREVO))
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30)
	if (runtime->sleep_min == 0 &&
			_ksnd_pcm_state(substream) == SNDRV_PCM_STATE_RUNNING)
		snd_pcm_update_hw_ptr(substream);
#else
	if (_ksnd_pcm_state(substream) == SNDRV_PCM_STATE_RUNNING)
		snd_pcm_update_hw_ptr(substream);
#endif
#endif
	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
		return snd_pcm_playback_avail(runtime);
	else
		return snd_pcm_capture_avail(runtime);
}
Beispiel #2
0
static irqreturn_t play_irq_handler(int irq, void *dev_id)
{
	struct snd_pcm_substream *substream = (struct snd_pcm_substream *)dev_id;
	struct snd_pcm_runtime   *runtime = substream->runtime;
	struct nx_runtime_data   *rtd = substream->runtime->private_data;
	struct dma_trans 	     *tr  = rtd->dma_tr;

	snd_pcm_uframes_t avail;

	u_int length   = tr->length;
	u_int srcbase  = 0;
#if (DMA_DOUBLE_BUFFER)
	int	  dmapoint = 0;
#endif
	int   ret      = IRQ_HANDLED;

	/* get next buffer point */
	INC_POINT(rtd->buf_point, (frames_to_bytes(runtime, runtime->buffer_size)/length))

	/* check under run and change buffer */
	avail   = snd_pcm_playback_avail(runtime);
	avail  += (length/4);
	srcbase = rtd->buf_base + (rtd->buf_point * length);

	if (avail >= runtime->stop_threshold) {
		unsigned int dma_addr = (rtd->buf_mute.dma_phys & 0xFFFFFFF0);
		srcbase = (rtd->buf_mute.dma_phys & 0xF ? (dma_addr + 0x10): dma_addr);
	}

#if (DMA_DOUBLE_BUFFER)
	dmapoint = rtd->buf_point;
	INC_POINT(dmapoint, (frames_to_bytes(runtime, runtime->buffer_size)/length))
	srcbase = rtd->buf_base + (dmapoint * length);
#endif

	/* DMA transfer */
	tr->srcbase = srcbase;

	if (rtd->dma_run) {
		soc_dma_transfer(tr);
		ret = IRQ_HANDLED;
	} else {
		ret = IRQ_NONE;
	}

	DBGOUT("IRQ(type:%x, ch:%d, bufp:%2d, src:0x%x, dst:0x%x, len:%d) \n",
		tr->tr_type, tr->channel, rtd->buf_point, tr->srcbase, tr->dstbase, length);

	/* call back */
	snd_pcm_period_elapsed(substream);

	return ret;
}
Beispiel #3
0
static int saudio_data_trigger_process(struct saudio_stream *stream,
					   struct saudio_msg *msg)
{
	int32_t result = 0;
	struct sblock blk = { 0 };
	struct cmd_common *common = NULL;
	struct snd_pcm_runtime *runtime = stream->substream->runtime;
	ADEBUG();

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

	pr_debug("saudio.c:stream->periods_avail is %d,block count is %d",
		 stream->periods_avail, sblock_get_free_count(stream->dst,
							      stream->channel));

	stream->periods_tosend = runtime->periods - stream->periods_avail;

	ADEBUG();

	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->period++;
		stream->period = stream->period % runtime->periods;
		stream->periods_tosend--;
	}

	pr_debug(":sblock_getblock_count trigger is %d \n",
		 stream->last_getblk_count);

	return result;
}
    static int
vaudio_snd_trigger (struct snd_pcm_substream* substream, int cmd)
{
    const NkVaudio          chip = snd_pcm_substream_chip(substream);
    const int               stream_id = substream->pstr->stream;
    const int               dev = substream->pcm->device;
    struct vaudio_stream*   s = &chip->s[dev][stream_id];
    struct snd_pcm_runtime* runtime = substream->runtime;
    NkVaudioCtrl*           ctrl  = s->ctrl;
    NkDevVlink*             vlink = chip->vlink;

    ADEBUG();
	/* Local interrupts are already disabled in the midlevel code */
    switch (cmd) {
    case SNDRV_PCM_TRIGGER_START:
	    /* Requested stream startup */
	s->active = 1;
	if (stream_id == SNDRV_PCM_STREAM_PLAYBACK) {
	    s->periods_avail = snd_pcm_playback_avail(runtime) /
				  runtime->period_size;
	} else {
	    s->periods_avail = snd_pcm_capture_avail(runtime) /
				  runtime->period_size;
	}
	s->periods_tosend = runtime->periods - s->periods_avail;
	while (s->periods_tosend) {
	    if (vaudio_send_data(s) < 0) break;
	    s->periods_tosend--;
	}
	ctrl->command = NK_VAUDIO_COMMAND_START;
	nkops.nk_xirq_trigger(ctrl->cxirq, vlink->s_id);
	    /* This command is asynchronous, no waiting on down() */
	return 0;

    case SNDRV_PCM_TRIGGER_STOP:
	    /* Requested stream shutdown */
	s->active = 0;
	ctrl->command = NK_VAUDIO_COMMAND_STOP;
	nkops.nk_xirq_trigger(ctrl->cxirq, vlink->s_id);
	    /* This command is asynchronous, no waiting on down() */
	return 0;

    default:
	break;
    }
    return -EINVAL;
}
Beispiel #5
0
static void _ksnd_pcm_mmap_begin(snd_pcm_substream_t *substream,
								 snd_pcm_uframes_t *offset,
								 snd_pcm_uframes_t *frames)
{
	snd_pcm_runtime_t *runtime = substream->runtime;
	snd_pcm_uframes_t avail, f, cont, appl_ptr;
	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
		avail = snd_pcm_playback_avail(runtime);
	else
		avail = snd_pcm_capture_avail(runtime);
	f = *frames;
	if (f > avail)
		f = avail;
	cont =
		runtime->buffer_size -
		runtime->control->appl_ptr % runtime->buffer_size;
	if (f > cont)
		f = cont;
	appl_ptr = runtime->control->appl_ptr;
	*frames = f;
	*offset = appl_ptr % runtime->buffer_size;
}
Beispiel #6
0
static int _ksnd_pcm_wait(snd_pcm_substream_t *substream, int timeout)
{
	snd_pcm_runtime_t *runtime = substream->runtime;
	snd_pcm_uframes_t avail;
	int res = 1; /* success is a positive integer */
	snd_pcm_stream_lock_irq(substream);
	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
		avail = snd_pcm_playback_avail(runtime);
	else
		avail = snd_pcm_capture_avail(runtime);
	if (avail < runtime->control->avail_min)
	{
		wait_queue_t wait;
		long jiffies;
		if (timeout >= 0)
			jiffies = (timeout * HZ) / 1000;
		else
			jiffies = 10 * HZ;
		init_waitqueue_entry(&wait, current);
		add_wait_queue(&runtime->sleep, &wait);
		do
		{
			if (signal_pending(current))
			{
				res = -ERESTARTSYS;
				break;
			}
			set_current_state(TASK_INTERRUPTIBLE);
			snd_pcm_stream_unlock_irq(substream);
			jiffies = schedule_timeout(jiffies);
			snd_pcm_stream_lock_irq(substream);
			if (jiffies == 0)
			{
				if (timeout < 0)
				{
					snd_printd("ksnd: [hw:%d,%d] playback write error "
							   "(DMA or IRQ trouble?)\n",
							   substream->pcm->card->number,
							   substream->pcm->device);
					jiffies = 10 * HZ;
				}
				else
				{
					res = 0; /* timeout */
				}
			}
			switch (_ksnd_pcm_state(substream))
			{
				case SNDRV_PCM_STATE_SETUP:
				case SNDRV_PCM_STATE_XRUN:
				case SNDRV_PCM_STATE_DRAINING:
					res = -EPIPE;
					break;
				case SNDRV_PCM_STATE_SUSPENDED:
					printk("%s: result ESTRPIPE %d\n",
						   __FUNCTION__, __LINE__);
					res = -ESTRPIPE;
					break;
				case SNDRV_PCM_STATE_PAUSED:
					printk("%s: Waiting for buffer %d\n",
						   __FUNCTION__, __LINE__);
					break;
				default:
					break;
			}
			if (1 != res)
				break;
			if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
				avail = snd_pcm_playback_avail(runtime);
			else
				avail = snd_pcm_capture_avail(runtime);
		}
		while (avail < runtime->control->avail_min);
		remove_wait_queue(&runtime->sleep, &wait);
	}
	snd_pcm_stream_unlock_irq(substream);
	return res;
}
Beispiel #7
0
static int _ksnd_pcm_writei1(snd_pcm_substream_t *substream,
							 unsigned long data,
							 snd_pcm_uframes_t size,
							 int srcchannels, transfer_f transfer)
{
	snd_pcm_runtime_t *runtime = substream->runtime;
	snd_pcm_uframes_t xfer = 0;
	snd_pcm_uframes_t offset = 0;
	int err = 0;
	if (size == 0)
		return 0;
	snd_pcm_stream_lock_irq(substream);
	switch (_ksnd_pcm_state(substream))
	{
		case SNDRV_PCM_STATE_PREPARED:
		case SNDRV_PCM_STATE_RUNNING:
		case SNDRV_PCM_STATE_PAUSED:
			break;
		case SNDRV_PCM_STATE_XRUN:
			err = -EPIPE;
			goto _end_unlock;
		case SNDRV_PCM_STATE_SUSPENDED:
			err = -ESTRPIPE;
			goto _end_unlock;
		default:
			err = -EBADFD;
			goto _end_unlock;
	}
	while (size > 0)
	{
		snd_pcm_uframes_t frames, appl_ptr, appl_ofs;
		snd_pcm_uframes_t avail;
		snd_pcm_uframes_t cont;
		avail = _ksnd_pcm_avail_update(substream);
#if defined(__TDT__) && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30))
		// attribute xfer_align is not used any more
		/* #warning Do we have to check the values 'size' and 'avail'? */
		if ((avail < runtime->control->avail_min) && (size > avail))
		{
#else
		if (((avail < runtime->control->avail_min && size > avail) ||
				(size >= runtime->xfer_align
				 && avail < runtime->xfer_align)))
		{
#endif
			int res;
			snd_pcm_stream_unlock_irq(substream);
			do
			{
				res = _ksnd_pcm_wait(substream, 10000);
			}
			while (res == 0 &&
					_ksnd_pcm_state(substream) !=
					SNDRV_PCM_STATE_PREPARED
					&& _ksnd_pcm_state(substream) !=
					SNDRV_PCM_STATE_PAUSED);
			snd_pcm_stream_lock_irq(substream);
			if (res == 0)   /* timeout */
			{
				if (_ksnd_pcm_state(substream) ==
						SNDRV_PCM_STATE_SUSPENDED)
				{
					err = -ESTRPIPE;
					goto _end_unlock;
				}
				else
				{
					snd_printd("playback write error "
							   "(DMA or IRQ trouble?)\n");
					err = -EIO;
					goto _end_unlock;
				}
			}
			else if (res < 0)       /* error */
			{
				err = res;
				goto _end_unlock;
			}
			avail = snd_pcm_playback_avail(runtime);
		}
		frames = size > avail ? avail : size;
		cont = runtime->buffer_size - runtime->control->appl_ptr % runtime->buffer_size;
		if (frames > cont)
			frames = cont;
		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);
		err = transfer(substream, appl_ofs, data, offset, frames, srcchannels);
		snd_pcm_stream_lock_irq(substream);
		if (err < 0)
			goto _end;
		switch (_ksnd_pcm_state(substream))
		{
			case SNDRV_PCM_STATE_XRUN:
				err = -EPIPE;
				goto _end_unlock;
			case SNDRV_PCM_STATE_SUSPENDED:
				err = -ESTRPIPE;
				goto _end_unlock;
			default:
				break;
		}
		appl_ptr += frames;
		if (appl_ptr >= runtime->boundary)
		{
			runtime->control->appl_ptr = 0;
		}
		else
		{
			runtime->control->appl_ptr = appl_ptr;
		}
		if (substream->ops->ack)
			substream->ops->ack(substream);
		offset += frames;
		size -= frames;
		xfer += frames;
		if (_ksnd_pcm_state(substream) == SNDRV_PCM_STATE_PREPARED &&
				snd_pcm_playback_hw_avail(runtime) >= (snd_pcm_sframes_t) runtime->start_threshold)
		{
			err = snd_pcm_start(substream);
			if (err < 0)
				goto _end_unlock;
		}
	}
_end_unlock:
	snd_pcm_stream_unlock_irq(substream);
_end:
	return xfer > 0 ? (snd_pcm_sframes_t) xfer : err;
}

int ksnd_pcm_writei(ksnd_pcm_t *kpcm,
					int *data, unsigned int size, unsigned int srcchannels)
{
	snd_pcm_substream_t *substream = kpcm->substream;
	snd_pcm_runtime_t *runtime;
	int err;
	transfer_f out_func = 0;
	runtime = substream->runtime;
	if (substream->pcm->card->number == 2)
	{
		out_func = _ksnd_pcm_IEC60958_transfer;
	}
	else
	{
		out_func = _ksnd_pcm_write_transfer;
	}
	if (_ksnd_pcm_state(substream) == SNDRV_PCM_STATE_OPEN)
		return -EBADFD;
	if (runtime->access != SNDRV_PCM_ACCESS_RW_INTERLEAVED
			&& runtime->channels > 1)
		return -EINVAL;
	if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK)
		return -EINVAL;
	if (size == 0)
		return 0;
	do
	{
		err =
			_ksnd_pcm_writei1(substream, (unsigned long)data, size,
							  srcchannels, out_func);
		if (err < 0)
		{
			if (err == -EAGAIN)
			{
				continue;
			}
			if (err == -EPIPE)
			{
				printk("ALSA Aud underrun for hw:%d,%d\n",
					   substream->pcm->card->number,
					   substream->pcm->device);
				if ((err = ksnd_pcm_prepare(kpcm)) < 0)
					return err;
				continue;
			}
			return err;
		}
		else
		{
			data += samples_to_bytes(runtime, err * srcchannels);
			size -= err;
		}
	}
	while (size > 0);
	return 0;
}
    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);
    }
}
Beispiel #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(msecs_to_jiffies(1));
			}
		}
	}

	while (elapsed_blks) {
		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;
}