Пример #1
0
static void transfer_done_callback(unsigned long param)
{
    int result;
    struct ksnd_pcm_streaming *streaming = (struct ksnd_pcm_streaming *)param;
    snd_pcm_sframes_t commited_frames;

    BUG_ON(streaming->magic != magic_good);
    BUG_ON(test_bit(FLAG_BUSY, &streaming->flags) != 1);

    // Check if the transfer wasn't stopped by any chance...

    if (test_bit(FLAG_STOPPED, &streaming->flags))
        return;

    // "Commit" playback data

    commited_frames = ksnd_pcm_mmap_commit(streaming->playback_handle,
                                           streaming->playback_offset, streaming->playback_frames);
    if (commited_frames < 0 ||
            (snd_pcm_uframes_t)commited_frames != streaming->playback_frames) {
        ERROR("Playback XRUN!\n");
        result = ksnd_pcm_prepare(streaming->playback_handle);
        if (result != 0) {
            ERROR("Can't recover from playback XRUN!\n");
            return;
        }
    }

    // "Commit" captured data

    commited_frames = ksnd_pcm_mmap_commit(streaming->capture_handle,
                                           streaming->capture_offset, streaming->playback_frames);
    if (commited_frames < 0 ||
            (snd_pcm_uframes_t)commited_frames != streaming->playback_frames) {
        ERROR("Capture XRUN!\n");
        result = ksnd_pcm_prepare(streaming->capture_handle);
        if (result != 0) {
            ERROR("Can't recover from capture XRUN!\n");
            return;
        }
        ksnd_pcm_start(streaming->capture_handle);
    }

    // Release the lock

    clear_bit(FLAG_BUSY, &streaming->flags);

    // If another data period has been received in meantime, trigger it not
    // (period_captured_callback could be skipped because of transfer	in progress)

    if (ksnd_pcm_avail_update(streaming->capture_handle) >=
            streaming->capture_handle->substream->runtime->period_size)
        period_captured_callback(streaming->capture_handle->substream);
}
Пример #2
0
////////////////////////////////////////////////////////////////////////////
///
/// Take a PCM player that has reported an error and try to get it running again.
///
PlayerStatus_t PcmPlayer_Ksound_c::DeployUnderrunRecovery()
{
        int Result;
        
	Result = ksnd_pcm_prepare(SoundcardHandle);
	if (Result < 0) {
		PCMPLAYER_ERROR("Can't recovery from underrun (%d) for %s\n", -Result, Identity);
		return PlayerError;
	}
	
	return PlayerNoError;
}
Пример #3
0
int ksnd_pcm_mute(ksnd_pcm_t *kpcm, unsigned int push)
{
	int err;
	snd_pcm_substream_t *substream = kpcm->substream;
	if (push == 0)
	{
		err = ksnd_pcm_prepare(kpcm);
		if (err < 0)
			return err;
		ksnd_pcm_start(kpcm);
	}
	else
	{
		_ksnd_pcm_pause(substream, push);
		_ksnd_pcm_drop(substream);
	}
	return 0;
}
Пример #4
0
int ksnd_pcm_set_params(ksnd_pcm_t *pcm,
						int nrchannels, int sampledepth, int samplerate,
						int periodsize, int buffersize)
{
	snd_pcm_substream_t *substream = pcm->substream;
	snd_pcm_runtime_t *runtime = substream->runtime;
	snd_pcm_hw_params_t *hw_params = NULL;
	snd_pcm_sw_params_t *sw_params = NULL;
	int err;
	int format;
	snd_mask_t mask;
	int i;
	void *hwbuf;
	err = ksnd_pcm_hw_params_malloc(&hw_params);
	if (0 != err)
		goto failure;
	sw_params = kmalloc(sizeof(*sw_params), GFP_KERNEL);
	if (!sw_params)
	{
		err = -ENOMEM;
		goto failure;
	}
	switch (sampledepth)
	{
		case 16:
			format = SNDRV_PCM_FORMAT_S16_LE;
			break;
		case 24:
			sampledepth = 32;
		/*FALLTHRU*/
		case 32:
			format = SNDRV_PCM_FORMAT_S32_LE;
			break;
		default:
			snd_printd("%s Unsupported sampledepth %d\n",
					   __FUNCTION__, sampledepth);
			err = -EINVAL;
			goto failure;
	}
	err = ksnd_pcm_hw_params_any(pcm, hw_params);
	if (snd_BUG_ON(err < 0))
		goto failure;
	_snd_pcm_hw_param_setinteger(hw_params, SNDRV_PCM_HW_PARAM_PERIODS);
	_snd_pcm_hw_param_min(hw_params, SNDRV_PCM_HW_PARAM_PERIODS, 2, 0);
	snd_mask_none(&mask);
	snd_mask_set(&mask, SNDRV_PCM_ACCESS_RW_INTERLEAVED);
	err =
		snd_pcm_hw_param_mask(substream, hw_params,
							  SNDRV_PCM_HW_PARAM_ACCESS, &mask);
	if (err < 0)
	{
		err = -EINVAL;
		goto failure;
	}
	err =
		snd_pcm_hw_param_set(substream, hw_params, SNDRV_PCM_HW_PARAM_RATE,
							 samplerate, 0);
	if (snd_BUG_ON(err < 0))
		goto failure;
	err =
		snd_pcm_hw_param_near(substream, hw_params,
							  SNDRV_PCM_HW_PARAM_CHANNELS, nrchannels,
							  NULL);
	if (snd_BUG_ON(err < 0))
		goto failure;
	err =
		snd_pcm_hw_param_near(substream, hw_params,
							  SNDRV_PCM_HW_PARAM_FORMAT, format, 0);
	if (snd_BUG_ON(err < 0))
		goto failure;
	err =
		snd_pcm_hw_param_near(substream, hw_params,
							  SNDRV_PCM_HW_PARAM_PERIOD_SIZE, periodsize,
							  NULL);
	if (snd_BUG_ON(err < 0))
		goto failure;
	err =
		snd_pcm_hw_param_near(substream, hw_params,
							  SNDRV_PCM_HW_PARAM_BUFFER_SIZE, buffersize,
							  NULL);
	if (snd_BUG_ON(err < 0))
		goto failure;
	_ksnd_pcm_drop(substream);
	/*now we re-use the 61937 control to enable the HW sync mechanism */
	if (0 != (err = ksnd_pcm_hw_params(pcm, hw_params) < 0))
	{
		snd_printd("HW_PARAMS failed: for %d:%d code is %i\n",
				   substream->pcm->card->number, substream->pcm->device,
				   err);
		goto failure;
	}
	memset(sw_params, 0, sizeof(*sw_params));
	sw_params->start_threshold =
		(runtime->buffer_size - (runtime->period_size * 2));
	sw_params->stop_threshold = runtime->buffer_size;
	sw_params->period_step = 1;
	sw_params->sleep_min = 0;
	sw_params->avail_min = runtime->period_size;
	sw_params->tstamp_mode = SNDRV_PCM_TSTAMP_ENABLE;
	sw_params->silence_threshold = runtime->period_size;
	sw_params->silence_size = runtime->period_size;
	if ((err =
				snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_SW_PARAMS,
									 sw_params)) < 0)
	{
		snd_printd("SW_PARAMS failed: for %d:%d code is %i\n",
				   substream->pcm->card->number, substream->pcm->device,
				   err);
		goto failure;
	}
	if ((err = ksnd_pcm_prepare(pcm)) < 0)
		goto failure;
	if (pcm->hwareas[0].addr)
		iounmap(pcm->hwareas[0].addr);
	hwbuf = ioremap_nocache(runtime->dma_addr, runtime->dma_bytes);
	for (i = 0; i < nrchannels; i++)
	{
		pcm->hwareas[i].addr = hwbuf;
		pcm->hwareas[i].first = i * sampledepth;
		pcm->hwareas[i].step = nrchannels * sampledepth;
	}
	nrchannels = _ksnd_pcm_hw_param_value(hw_params, SNDRV_PCM_HW_PARAM_CHANNELS, 0);
	samplerate = _ksnd_pcm_hw_param_value(hw_params, SNDRV_PCM_HW_PARAM_RATE, 0);
	periodsize = _ksnd_pcm_hw_param_value(hw_params, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, 0);
	buffersize = _ksnd_pcm_hw_param_value(hw_params, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, 0);
	printk(KERN_DEBUG "ksound: Set parameters for hw:%d,%d to %d x %dhz with period %d (of %d)\n",
		   substream->pcm->card->number, substream->pcm->device,
		   nrchannels, samplerate, periodsize, buffersize);
	err = 0;
failure:
	if (hw_params)
		ksnd_pcm_hw_params_free(hw_params);
	if (sw_params)
		kfree(sw_params);
	return err;
}
Пример #5
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;
}