⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pcm_lib.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
 * @r: struct snd_ratdens constriants */int snd_pcm_hw_constraint_ratdens(struct snd_pcm_runtime *runtime, 				  unsigned int cond,				  snd_pcm_hw_param_t var,				  struct snd_pcm_hw_constraint_ratdens *r){	return snd_pcm_hw_rule_add(runtime, cond, var,				   snd_pcm_hw_rule_ratdens, r,				   var, -1);}EXPORT_SYMBOL(snd_pcm_hw_constraint_ratdens);static int snd_pcm_hw_rule_msbits(struct snd_pcm_hw_params *params,				  struct snd_pcm_hw_rule *rule){	unsigned int l = (unsigned long) rule->private;	int width = l & 0xffff;	unsigned int msbits = l >> 16;	struct snd_interval *i = hw_param_interval(params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS);	if (snd_interval_single(i) && snd_interval_value(i) == width)		params->msbits = msbits;	return 0;}/** * snd_pcm_hw_constraint_msbits * @runtime: PCM runtime instance * @cond: condition bits * @width: sample bits width * @msbits: msbits width */int snd_pcm_hw_constraint_msbits(struct snd_pcm_runtime *runtime, 				 unsigned int cond,				 unsigned int width,				 unsigned int msbits){	unsigned long l = (msbits << 16) | width;	return snd_pcm_hw_rule_add(runtime, cond, -1,				    snd_pcm_hw_rule_msbits,				    (void*) l,				    SNDRV_PCM_HW_PARAM_SAMPLE_BITS, -1);}EXPORT_SYMBOL(snd_pcm_hw_constraint_msbits);static int snd_pcm_hw_rule_step(struct snd_pcm_hw_params *params,				struct snd_pcm_hw_rule *rule){	unsigned long step = (unsigned long) rule->private;	return snd_interval_step(hw_param_interval(params, rule->var), 0, step);}/** * snd_pcm_hw_constraint_step * @runtime: PCM runtime instance * @cond: condition bits * @var: hw_params variable to apply the step constraint * @step: step size */int snd_pcm_hw_constraint_step(struct snd_pcm_runtime *runtime,			       unsigned int cond,			       snd_pcm_hw_param_t var,			       unsigned long step){	return snd_pcm_hw_rule_add(runtime, cond, var, 				   snd_pcm_hw_rule_step, (void *) step,				   var, -1);}EXPORT_SYMBOL(snd_pcm_hw_constraint_step);static int snd_pcm_hw_rule_pow2(struct snd_pcm_hw_params *params, struct snd_pcm_hw_rule *rule){	static int pow2_sizes[] = {		1<<0, 1<<1, 1<<2, 1<<3, 1<<4, 1<<5, 1<<6, 1<<7,		1<<8, 1<<9, 1<<10, 1<<11, 1<<12, 1<<13, 1<<14, 1<<15,		1<<16, 1<<17, 1<<18, 1<<19, 1<<20, 1<<21, 1<<22, 1<<23,		1<<24, 1<<25, 1<<26, 1<<27, 1<<28, 1<<29, 1<<30	};	return snd_interval_list(hw_param_interval(params, rule->var),				 ARRAY_SIZE(pow2_sizes), pow2_sizes, 0);}		/** * snd_pcm_hw_constraint_pow2 * @runtime: PCM runtime instance * @cond: condition bits * @var: hw_params variable to apply the power-of-2 constraint */int snd_pcm_hw_constraint_pow2(struct snd_pcm_runtime *runtime,			       unsigned int cond,			       snd_pcm_hw_param_t var){	return snd_pcm_hw_rule_add(runtime, cond, var, 				   snd_pcm_hw_rule_pow2, NULL,				   var, -1);}EXPORT_SYMBOL(snd_pcm_hw_constraint_pow2);static void _snd_pcm_hw_param_any(struct snd_pcm_hw_params *params,				  snd_pcm_hw_param_t var){	if (hw_is_mask(var)) {		snd_mask_any(hw_param_mask(params, var));		params->cmask |= 1 << var;		params->rmask |= 1 << var;		return;	}	if (hw_is_interval(var)) {		snd_interval_any(hw_param_interval(params, var));		params->cmask |= 1 << var;		params->rmask |= 1 << var;		return;	}	snd_BUG();}void _snd_pcm_hw_params_any(struct snd_pcm_hw_params *params){	unsigned int k;	memset(params, 0, sizeof(*params));	for (k = SNDRV_PCM_HW_PARAM_FIRST_MASK; k <= SNDRV_PCM_HW_PARAM_LAST_MASK; k++)		_snd_pcm_hw_param_any(params, k);	for (k = SNDRV_PCM_HW_PARAM_FIRST_INTERVAL; k <= SNDRV_PCM_HW_PARAM_LAST_INTERVAL; k++)		_snd_pcm_hw_param_any(params, k);	params->info = ~0U;}EXPORT_SYMBOL(_snd_pcm_hw_params_any);/** * snd_pcm_hw_param_value * @params: the hw_params instance * @var: parameter to retrieve * @dir: pointer to the direction (-1,0,1) or NULL * * Return the value for field PAR if it's fixed in configuration space  *  defined by PARAMS. Return -EINVAL otherwise */int snd_pcm_hw_param_value(const struct snd_pcm_hw_params *params,			   snd_pcm_hw_param_t var, int *dir){	if (hw_is_mask(var)) {		const struct snd_mask *mask = hw_param_mask_c(params, var);		if (!snd_mask_single(mask))			return -EINVAL;		if (dir)			*dir = 0;		return snd_mask_value(mask);	}	if (hw_is_interval(var)) {		const struct snd_interval *i = hw_param_interval_c(params, var);		if (!snd_interval_single(i))			return -EINVAL;		if (dir)			*dir = i->openmin;		return snd_interval_value(i);	}	return -EINVAL;}EXPORT_SYMBOL(snd_pcm_hw_param_value);void _snd_pcm_hw_param_setempty(struct snd_pcm_hw_params *params,				snd_pcm_hw_param_t var){	if (hw_is_mask(var)) {		snd_mask_none(hw_param_mask(params, var));		params->cmask |= 1 << var;		params->rmask |= 1 << var;	} else if (hw_is_interval(var)) {		snd_interval_none(hw_param_interval(params, var));		params->cmask |= 1 << var;		params->rmask |= 1 << var;	} else {		snd_BUG();	}}EXPORT_SYMBOL(_snd_pcm_hw_param_setempty);static int _snd_pcm_hw_param_first(struct snd_pcm_hw_params *params,				   snd_pcm_hw_param_t var){	int changed;	if (hw_is_mask(var))		changed = snd_mask_refine_first(hw_param_mask(params, var));	else if (hw_is_interval(var))		changed = snd_interval_refine_first(hw_param_interval(params, var));	else		return -EINVAL;	if (changed) {		params->cmask |= 1 << var;		params->rmask |= 1 << var;	}	return changed;}/** * snd_pcm_hw_param_first * @pcm: PCM instance * @params: the hw_params instance * @var: parameter to retrieve * @dir: pointer to the direction (-1,0,1) or NULL * * Inside configuration space defined by PARAMS remove from PAR all  * values > minimum. Reduce configuration space accordingly. * Return the minimum. */int snd_pcm_hw_param_first(struct snd_pcm_substream *pcm, 			   struct snd_pcm_hw_params *params, 			   snd_pcm_hw_param_t var, int *dir){	int changed = _snd_pcm_hw_param_first(params, var);	if (changed < 0)		return changed;	if (params->rmask) {		int err = snd_pcm_hw_refine(pcm, params);		snd_assert(err >= 0, return err);	}	return snd_pcm_hw_param_value(params, var, dir);}EXPORT_SYMBOL(snd_pcm_hw_param_first);static int _snd_pcm_hw_param_last(struct snd_pcm_hw_params *params,				  snd_pcm_hw_param_t var){	int changed;	if (hw_is_mask(var))		changed = snd_mask_refine_last(hw_param_mask(params, var));	else if (hw_is_interval(var))		changed = snd_interval_refine_last(hw_param_interval(params, var));	else		return -EINVAL;	if (changed) {		params->cmask |= 1 << var;		params->rmask |= 1 << var;	}	return changed;}/** * snd_pcm_hw_param_last * @pcm: PCM instance * @params: the hw_params instance * @var: parameter to retrieve * @dir: pointer to the direction (-1,0,1) or NULL * * Inside configuration space defined by PARAMS remove from PAR all  * values < maximum. Reduce configuration space accordingly. * Return the maximum. */int snd_pcm_hw_param_last(struct snd_pcm_substream *pcm, 			  struct snd_pcm_hw_params *params,			  snd_pcm_hw_param_t var, int *dir){	int changed = _snd_pcm_hw_param_last(params, var);	if (changed < 0)		return changed;	if (params->rmask) {		int err = snd_pcm_hw_refine(pcm, params);		snd_assert(err >= 0, return err);	}	return snd_pcm_hw_param_value(params, var, dir);}EXPORT_SYMBOL(snd_pcm_hw_param_last);/** * snd_pcm_hw_param_choose * @pcm: PCM instance * @params: the hw_params instance * * Choose one configuration from configuration space defined by PARAMS * The configuration chosen is that obtained fixing in this order: * first access, first format, first subformat, min channels, * min rate, min period time, max buffer size, min tick time */int snd_pcm_hw_params_choose(struct snd_pcm_substream *pcm,			     struct snd_pcm_hw_params *params){	static int vars[] = {		SNDRV_PCM_HW_PARAM_ACCESS,		SNDRV_PCM_HW_PARAM_FORMAT,		SNDRV_PCM_HW_PARAM_SUBFORMAT,		SNDRV_PCM_HW_PARAM_CHANNELS,		SNDRV_PCM_HW_PARAM_RATE,		SNDRV_PCM_HW_PARAM_PERIOD_TIME,		SNDRV_PCM_HW_PARAM_BUFFER_SIZE,		SNDRV_PCM_HW_PARAM_TICK_TIME,		-1	};	int err, *v;	for (v = vars; *v != -1; v++) {		if (*v != SNDRV_PCM_HW_PARAM_BUFFER_SIZE)			err = snd_pcm_hw_param_first(pcm, params, *v, NULL);		else			err = snd_pcm_hw_param_last(pcm, params, *v, NULL);		snd_assert(err >= 0, return err);	}	return 0;}static int snd_pcm_lib_ioctl_reset(struct snd_pcm_substream *substream,				   void *arg){	struct snd_pcm_runtime *runtime = substream->runtime;	unsigned long flags;	snd_pcm_stream_lock_irqsave(substream, flags);	if (snd_pcm_running(substream) &&	    snd_pcm_update_hw_ptr(substream) >= 0)		runtime->status->hw_ptr %= runtime->buffer_size;	else		runtime->status->hw_ptr = 0;	snd_pcm_stream_unlock_irqrestore(substream, flags);	return 0;}static int snd_pcm_lib_ioctl_channel_info(struct snd_pcm_substream *substream,					  void *arg){	struct snd_pcm_channel_info *info = arg;	struct snd_pcm_runtime *runtime = substream->runtime;	int width;	if (!(runtime->info & SNDRV_PCM_INFO_MMAP)) {		info->offset = -1;		return 0;	}	width = snd_pcm_format_physical_width(runtime->format);	if (width < 0)		return width;	info->offset = 0;	switch (runtime->access) {	case SNDRV_PCM_ACCESS_MMAP_INTERLEAVED:	case SNDRV_PCM_ACCESS_RW_INTERLEAVED:		info->first = info->channel * width;		info->step = runtime->channels * width;		break;	case SNDRV_PCM_ACCESS_MMAP_NONINTERLEAVED:	case SNDRV_PCM_ACCESS_RW_NONINTERLEAVED:	{		size_t size = runtime->dma_bytes / runtime->channels;		info->first = info->channel * size * 8;		info->step = width;		break;	}	default:		snd_BUG();		break;	}	return 0;}/** * snd_pcm_lib_ioctl - a generic PCM ioctl callback * @substream: the pcm substream instance * @cmd: ioctl command * @arg: ioctl argument * * Processes the generic ioctl commands for PCM. * Can be passed as the ioctl callback for PCM ops. * * Returns zero if successful, or a negative error code on failure. */int snd_pcm_lib_ioctl(struct snd_pcm_substream *substream,		      unsigned int cmd, void *arg){	switch (cmd) {	case SNDRV_PCM_IOCTL1_INFO:		return 0;	case SNDRV_PCM_IOCTL1_RESET:		return snd_pcm_lib_ioctl_reset(substream, arg);	case SNDRV_PCM_IOCTL1_CHANNEL_INFO:		return snd_pcm_lib_ioctl_channel_info(substream, arg);	}	return -ENXIO;}EXPORT_SYMBOL(snd_pcm_lib_ioctl);/* *  Conditions */static void snd_pcm_system_tick_set(struct snd_pcm_substream *substream, 				    unsigned long ticks){	struct snd_pcm_runtime *runtime = substream->runtime;	if (ticks == 0)		del_timer(&runtime->tick_timer);	else {		ticks += (1000000 / HZ) - 1;		ticks /= (1000000 / HZ);		mod_timer(&runtime->tick_timer, jiffies + ticks);	}}/* Temporary alias */void snd_pcm_tick_set(struct snd_pcm_substream *substream, unsigned long ticks){	snd_pcm_system_tick_set(substream, ticks);}void snd_pcm_tick_prepare(struct snd_pcm_substream *substream){	struct snd_pcm_runtime *runtime = substream->runtime;	snd_pcm_uframes_t frames = ULONG_MAX;	snd_pcm_uframes_t avail, dist;	unsigned int ticks;	u_int64_t n;	u_int32_t r;	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {		if (runtime->silence_size >= runtime->boundary) {			frames = 1;		} else if (runtime->silence_size > 0 &&			   runtime->silence_filled < runtime->buffer_size) {			snd_pcm_sframes_t noise_dist;			noise_dist = snd_pcm_playback_hw_avail(runtime) + runtime->silence_filled;			if (noise_dist > (snd_pcm_sframes_t)runtime->silence_threshold)				frames = noise_dist - runtime->silence_threshold;		}		avail = snd_pcm_playback_avail(runtime);	} else {		avail = snd_pcm_capture_avail(runtime);	}	if (avail < runtime->control->avail_min) {		snd_pcm_sframes_t n = runtime->control->avail_min - avail;		if (n > 0 && frames > (snd_pcm_uframes_t)n)			frames = n;	}	if (avail < runtime->buffer_size) {		snd_pcm_sframes_t n = runtime->buffer_size - avail;		if (n > 0 && frames > (snd_pcm_uframes_t)n)			frames = n;	}	if (frames == ULONG_MAX) {		snd_pcm_tick_set(substream, 0);		return;	}	dist = runtime->status->hw_ptr - runtime->hw_ptr_base;	/* Distance to next interrupt */	dist = runtime->period_size - dist % runtime->period_size;	if (dist <= frames) {		snd_pcm_tick_set(substream, 0);		return;	}	/* the base time is us */	n = frames;	n *= 1000000;	div64_32(&n, runtime->tick_time * runtime->rate, &r);	ticks = n + (r > 0 ? 1 : 0);	if (ticks < runtime->sleep_min)		ticks = runtime->sleep_min;	snd_pcm_tick_set(substream, (unsigned long) ticks);}void snd_pcm_tick_elapsed(struct snd_pcm_substream *substream){	struct snd_pcm_runtime *runtime;	unsigned long flags;		snd_assert(substream != NULL, return);	runtime = substream->runtime;	snd_assert(runtime != NULL, return);	snd_pcm_stream_lock_irqsave(substream, flags);	if (!snd_pcm_running(substream) ||	    snd_pcm_update_hw_ptr(substream) < 0)		goto _end;	if (runtime->sleep_min)		snd_pcm_tick_prepare(substream); _end:	snd_pcm_stream_unlock_irqrestore(substream, flags);}/** * snd_pcm_period_elapsed - update the pcm status for the next period * @substream: the pcm substream instance * * This function is called from the interrupt handler when the * PCM has processed the period size.  It will update the current * pointer, set up the tick, wake up sleepers, etc. * * Even if more than one periods have elapsed since the last call, you * have to call this only once. */void snd_pcm_period_elapsed(struct snd_pcm_substream *substream){	struct snd_pcm_runtime *runtime;	unsigned long flags;	snd_assert(substream != NULL, return);	runtime = substream->runtime;	snd_assert(runtime != NULL, return);	if (runtime->transfer_ack_begin)		runtime->transfer_ack_begin(substream);	snd_pcm_stream_lock_irqsave(substream, flags);	if (!snd_pcm_running(substream) ||	    snd_pcm_update_hw_ptr_interrupt(substream) < 0)		goto _end;	if (substream->timer_running)		snd_timer_interrupt(substream->timer, 1);	if (runtime->sleep_min)		snd_pcm_tick_prepare(substream); _end:	snd_pcm_stream_unlock_irqrestore(substream, flags);	if (runtime->transfer_ack_end)		runtime->transfer_ack_end(substream);	kill_fasync(&runtime->fasync, SIGIO, POLL_IN);}EXPORT_SYMBOL(snd_pcm_period_elapsed);static int snd_pcm_lib_write_transfer(struct snd_pcm_substream *substream,				      unsigned int hwoff,				      unsigned long data, unsigned int off,				      snd_pcm_uframes_t frames){	struct snd_pcm_runtime *runtime = substream->runtime;	int err;	char __user *buf = (char __user *) data + frames_to_bytes(runtime, off);	if (substream->ops->copy) {		if ((err = substream->ops->copy(substream, -1, hwoff, buf, frames)) < 0)

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -