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

📄 pcm_oss.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
	else		v = snd_pcm_hw_param_first(pcm, params, var, dir);	snd_assert(v >= 0, return -EINVAL);	return v;}static int _snd_pcm_hw_param_set(struct snd_pcm_hw_params *params,				 snd_pcm_hw_param_t var, unsigned int val,				 int dir){	int changed;	if (hw_is_mask(var)) {		struct snd_mask *m = hw_param_mask(params, var);		if (val == 0 && dir < 0) {			changed = -EINVAL;			snd_mask_none(m);		} else {			if (dir > 0)				val++;			else if (dir < 0)				val--;			changed = snd_mask_refine_set(hw_param_mask(params, var), val);		}	} else if (hw_is_interval(var)) {		struct snd_interval *i = hw_param_interval(params, var);		if (val == 0 && dir < 0) {			changed = -EINVAL;			snd_interval_none(i);		} else if (dir == 0)			changed = snd_interval_refine_set(i, val);		else {			struct snd_interval t;			t.openmin = 1;			t.openmax = 1;			t.empty = 0;			t.integer = 0;			if (dir < 0) {				t.min = val - 1;				t.max = val;			} else {				t.min = val;				t.max = val+1;			}			changed = snd_interval_refine(i, &t);		}	} else		return -EINVAL;	if (changed) {		params->cmask |= 1 << var;		params->rmask |= 1 << var;	}	return changed;}/** * snd_pcm_hw_param_set * @pcm: PCM instance * @params: the hw_params instance * @var: parameter to retrieve * @val: value to set * @dir: pointer to the direction (-1,0,1) or NULL * * Inside configuration space defined by PARAMS remove from PAR all  * values != VAL. Reduce configuration space accordingly. *  Return VAL or -EINVAL if the configuration space is empty */static int snd_pcm_hw_param_set(struct snd_pcm_substream *pcm,				struct snd_pcm_hw_params *params,				snd_pcm_hw_param_t var, unsigned int val,				int dir){	int changed = _snd_pcm_hw_param_set(params, var, val, dir);	if (changed < 0)		return changed;	if (params->rmask) {		int err = snd_pcm_hw_refine(pcm, params);		if (err < 0)			return err;	}	return snd_pcm_hw_param_value(params, var, NULL);}static int _snd_pcm_hw_param_setinteger(struct snd_pcm_hw_params *params,					snd_pcm_hw_param_t var){	int changed;	changed = snd_interval_setinteger(hw_param_interval(params, var));	if (changed) {		params->cmask |= 1 << var;		params->rmask |= 1 << var;	}	return changed;}	/* * plugin */#ifdef CONFIG_SND_PCM_OSS_PLUGINSstatic int snd_pcm_oss_plugin_clear(struct snd_pcm_substream *substream){	struct snd_pcm_runtime *runtime = substream->runtime;	struct snd_pcm_plugin *plugin, *next;		plugin = runtime->oss.plugin_first;	while (plugin) {		next = plugin->next;		snd_pcm_plugin_free(plugin);		plugin = next;	}	runtime->oss.plugin_first = runtime->oss.plugin_last = NULL;	return 0;}static int snd_pcm_plugin_insert(struct snd_pcm_plugin *plugin){	struct snd_pcm_runtime *runtime = plugin->plug->runtime;	plugin->next = runtime->oss.plugin_first;	plugin->prev = NULL;	if (runtime->oss.plugin_first) {		runtime->oss.plugin_first->prev = plugin;		runtime->oss.plugin_first = plugin;	} else {		runtime->oss.plugin_last =		runtime->oss.plugin_first = plugin;	}	return 0;}int snd_pcm_plugin_append(struct snd_pcm_plugin *plugin){	struct snd_pcm_runtime *runtime = plugin->plug->runtime;	plugin->next = NULL;	plugin->prev = runtime->oss.plugin_last;	if (runtime->oss.plugin_last) {		runtime->oss.plugin_last->next = plugin;		runtime->oss.plugin_last = plugin;	} else {		runtime->oss.plugin_last =		runtime->oss.plugin_first = plugin;	}	return 0;}#endif /* CONFIG_SND_PCM_OSS_PLUGINS */static long snd_pcm_oss_bytes(struct snd_pcm_substream *substream, long frames){	struct snd_pcm_runtime *runtime = substream->runtime;	long buffer_size = snd_pcm_lib_buffer_bytes(substream);	long bytes = frames_to_bytes(runtime, frames);	if (buffer_size == runtime->oss.buffer_bytes)		return bytes;#if BITS_PER_LONG >= 64	return runtime->oss.buffer_bytes * bytes / buffer_size;#else	{		u64 bsize = (u64)runtime->oss.buffer_bytes * (u64)bytes;		u32 rem;		div64_32(&bsize, buffer_size, &rem);		return (long)bsize;	}#endif}static long snd_pcm_alsa_frames(struct snd_pcm_substream *substream, long bytes){	struct snd_pcm_runtime *runtime = substream->runtime;	long buffer_size = snd_pcm_lib_buffer_bytes(substream);	if (buffer_size == runtime->oss.buffer_bytes)		return bytes_to_frames(runtime, bytes);	return bytes_to_frames(runtime, (buffer_size * bytes) / runtime->oss.buffer_bytes);}/* define extended formats in the recent OSS versions (if any) *//* linear formats */#define AFMT_S32_LE      0x00001000#define AFMT_S32_BE      0x00002000#define AFMT_S24_LE      0x00008000#define AFMT_S24_BE      0x00010000#define AFMT_S24_PACKED  0x00040000/* other supported formats */#define AFMT_FLOAT       0x00004000#define AFMT_SPDIF_RAW   0x00020000/* unsupported formats */#define AFMT_AC3         0x00000400#define AFMT_VORBIS      0x00000800static int snd_pcm_oss_format_from(int format){	switch (format) {	case AFMT_MU_LAW:	return SNDRV_PCM_FORMAT_MU_LAW;	case AFMT_A_LAW:	return SNDRV_PCM_FORMAT_A_LAW;	case AFMT_IMA_ADPCM:	return SNDRV_PCM_FORMAT_IMA_ADPCM;	case AFMT_U8:		return SNDRV_PCM_FORMAT_U8;	case AFMT_S16_LE:	return SNDRV_PCM_FORMAT_S16_LE;	case AFMT_S16_BE:	return SNDRV_PCM_FORMAT_S16_BE;	case AFMT_S8:		return SNDRV_PCM_FORMAT_S8;	case AFMT_U16_LE:	return SNDRV_PCM_FORMAT_U16_LE;	case AFMT_U16_BE:	return SNDRV_PCM_FORMAT_U16_BE;	case AFMT_MPEG:		return SNDRV_PCM_FORMAT_MPEG;	case AFMT_S32_LE:	return SNDRV_PCM_FORMAT_S32_LE;	case AFMT_S32_BE:	return SNDRV_PCM_FORMAT_S32_BE;	case AFMT_S24_LE:	return SNDRV_PCM_FORMAT_S24_LE;	case AFMT_S24_BE:	return SNDRV_PCM_FORMAT_S24_BE;	case AFMT_S24_PACKED:	return SNDRV_PCM_FORMAT_S24_3LE;	case AFMT_FLOAT:	return SNDRV_PCM_FORMAT_FLOAT;	case AFMT_SPDIF_RAW:	return SNDRV_PCM_FORMAT_IEC958_SUBFRAME;	default:		return SNDRV_PCM_FORMAT_U8;	}}static int snd_pcm_oss_format_to(int format){	switch (format) {	case SNDRV_PCM_FORMAT_MU_LAW:	return AFMT_MU_LAW;	case SNDRV_PCM_FORMAT_A_LAW:	return AFMT_A_LAW;	case SNDRV_PCM_FORMAT_IMA_ADPCM:	return AFMT_IMA_ADPCM;	case SNDRV_PCM_FORMAT_U8:		return AFMT_U8;	case SNDRV_PCM_FORMAT_S16_LE:	return AFMT_S16_LE;	case SNDRV_PCM_FORMAT_S16_BE:	return AFMT_S16_BE;	case SNDRV_PCM_FORMAT_S8:		return AFMT_S8;	case SNDRV_PCM_FORMAT_U16_LE:	return AFMT_U16_LE;	case SNDRV_PCM_FORMAT_U16_BE:	return AFMT_U16_BE;	case SNDRV_PCM_FORMAT_MPEG:		return AFMT_MPEG;	case SNDRV_PCM_FORMAT_S32_LE:	return AFMT_S32_LE;	case SNDRV_PCM_FORMAT_S32_BE:	return AFMT_S32_BE;	case SNDRV_PCM_FORMAT_S24_LE:	return AFMT_S24_LE;	case SNDRV_PCM_FORMAT_S24_BE:	return AFMT_S24_BE;	case SNDRV_PCM_FORMAT_S24_3LE:	return AFMT_S24_PACKED;	case SNDRV_PCM_FORMAT_FLOAT:	return AFMT_FLOAT;	case SNDRV_PCM_FORMAT_IEC958_SUBFRAME: return AFMT_SPDIF_RAW;	default:			return -EINVAL;	}}static int snd_pcm_oss_period_size(struct snd_pcm_substream *substream, 				   struct snd_pcm_hw_params *oss_params,				   struct snd_pcm_hw_params *slave_params){	size_t s;	size_t oss_buffer_size, oss_period_size, oss_periods;	size_t min_period_size, max_period_size;	struct snd_pcm_runtime *runtime = substream->runtime;	size_t oss_frame_size;	oss_frame_size = snd_pcm_format_physical_width(params_format(oss_params)) *			 params_channels(oss_params) / 8;	oss_buffer_size = snd_pcm_plug_client_size(substream,						   snd_pcm_hw_param_value_max(slave_params, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, NULL)) * oss_frame_size;	oss_buffer_size = 1 << ld2(oss_buffer_size);	if (atomic_read(&substream->mmap_count)) {		if (oss_buffer_size > runtime->oss.mmap_bytes)			oss_buffer_size = runtime->oss.mmap_bytes;	}	if (substream->oss.setup.period_size > 16)		oss_period_size = substream->oss.setup.period_size;	else if (runtime->oss.fragshift) {		oss_period_size = 1 << runtime->oss.fragshift;		if (oss_period_size > oss_buffer_size / 2)			oss_period_size = oss_buffer_size / 2;	} else {		int sd;		size_t bytes_per_sec = params_rate(oss_params) * snd_pcm_format_physical_width(params_format(oss_params)) * params_channels(oss_params) / 8;		oss_period_size = oss_buffer_size;		do {			oss_period_size /= 2;		} while (oss_period_size > bytes_per_sec);		if (runtime->oss.subdivision == 0) {			sd = 4;			if (oss_period_size / sd > 4096)				sd *= 2;			if (oss_period_size / sd < 4096)				sd = 1;		} else			sd = runtime->oss.subdivision;		oss_period_size /= sd;		if (oss_period_size < 16)			oss_period_size = 16;	}	min_period_size = snd_pcm_plug_client_size(substream,						   snd_pcm_hw_param_value_min(slave_params, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, NULL));	min_period_size *= oss_frame_size;	min_period_size = 1 << (ld2(min_period_size - 1) + 1);	if (oss_period_size < min_period_size)		oss_period_size = min_period_size;	max_period_size = snd_pcm_plug_client_size(substream,						   snd_pcm_hw_param_value_max(slave_params, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, NULL));	max_period_size *= oss_frame_size;	max_period_size = 1 << ld2(max_period_size);	if (oss_period_size > max_period_size)		oss_period_size = max_period_size;	oss_periods = oss_buffer_size / oss_period_size;	if (substream->oss.setup.periods > 1)		oss_periods = substream->oss.setup.periods;	s = snd_pcm_hw_param_value_max(slave_params, SNDRV_PCM_HW_PARAM_PERIODS, NULL);	if (runtime->oss.maxfrags && s > runtime->oss.maxfrags)		s = runtime->oss.maxfrags;	if (oss_periods > s)		oss_periods = s;	s = snd_pcm_hw_param_value_min(slave_params, SNDRV_PCM_HW_PARAM_PERIODS, NULL);	if (s < 2)		s = 2;	if (oss_periods < s)		oss_periods = s;	while (oss_period_size * oss_periods > oss_buffer_size)		oss_period_size /= 2;	snd_assert(oss_period_size >= 16, return -EINVAL);	runtime->oss.period_bytes = oss_period_size;	runtime->oss.period_frames = 1;	runtime->oss.periods = oss_periods;	return 0;}static int choose_rate(struct snd_pcm_substream *substream,		       struct snd_pcm_hw_params *params, unsigned int best_rate){	struct snd_interval *it;	struct snd_pcm_hw_params *save;	unsigned int rate, prev;	save = kmalloc(sizeof(*save), GFP_KERNEL);	if (save == NULL)		return -ENOMEM;	*save = *params;	it = hw_param_interval(save, SNDRV_PCM_HW_PARAM_RATE);	/* try multiples of the best rate */	rate = best_rate;	for (;;) {		if (it->max < rate || (it->max == rate && it->openmax))			break;		if (it->min < rate || (it->min == rate && !it->openmin)) {			int ret;			ret = snd_pcm_hw_param_set(substream, params,						   SNDRV_PCM_HW_PARAM_RATE,						   rate, 0);			if (ret == (int)rate) {				kfree(save);				return rate;			}			*params = *save;		}		prev = rate;		rate += best_rate;		if (rate <= prev)			break;	}	/* not found, use the nearest rate */	kfree(save);	return snd_pcm_hw_param_near(substream, params, SNDRV_PCM_HW_PARAM_RATE, best_rate, NULL);}static int snd_pcm_oss_change_params(struct snd_pcm_substream *substream){	struct snd_pcm_runtime *runtime = substream->runtime;	struct snd_pcm_hw_params *params, *sparams;	struct snd_pcm_sw_params *sw_params;	ssize_t oss_buffer_size, oss_period_size;	size_t oss_frame_size;	int err;	int direct;	int format, sformat, n;	struct snd_mask sformat_mask;	struct snd_mask mask;	if (mutex_lock_interruptible(&runtime->oss.params_lock))		return -EINTR;	sw_params = kmalloc(sizeof(*sw_params), GFP_KERNEL);	params = kmalloc(sizeof(*params), GFP_KERNEL);	sparams = kmalloc(sizeof(*sparams), GFP_KERNEL);	if (!sw_params || !params || !sparams) {		snd_printd("No memory\n");		err = -ENOMEM;		goto failure;	}	if (atomic_read(&substream->mmap_count))		direct = 1;	else		direct = substream->oss.setup.direct;	_snd_pcm_hw_params_any(sparams);	_snd_pcm_hw_param_setinteger(sparams, SNDRV_PCM_HW_PARAM_PERIODS);	_snd_pcm_hw_param_min(sparams, SNDRV_PCM_HW_PARAM_PERIODS, 2, 0);	snd_mask_none(&mask);	if (atomic_read(&substream->mmap_count))		snd_mask_set(&mask, SNDRV_PCM_ACCESS_MMAP_INTERLEAVED);	else {		snd_mask_set(&mask, SNDRV_PCM_ACCESS_RW_INTERLEAVED);		if (!direct)			snd_mask_set(&mask, SNDRV_PCM_ACCESS_RW_NONINTERLEAVED);	}	err = snd_pcm_hw_param_mask(substream, sparams, SNDRV_PCM_HW_PARAM_ACCESS, &mask);	if (err < 0) {		snd_printd("No usable accesses\n");		err = -EINVAL;		goto failure;	}	choose_rate(substream, sparams, runtime->oss.rate);	snd_pcm_hw_param_near(substream, sparams, SNDRV_PCM_HW_PARAM_CHANNELS, runtime->oss.channels, NULL);	format = snd_pcm_oss_format_from(runtime->oss.format);	sformat_mask = *hw_param_mask(sparams, SNDRV_PCM_HW_PARAM_FORMAT);	if (direct)		sformat = format;	else		sformat = snd_pcm_plug_slave_format(format, &sformat_mask);	if (sformat < 0 || !snd_mask_test(&sformat_mask, sformat)) {		for (sformat = 0; sformat <= SNDRV_PCM_FORMAT_LAST; sformat++) {			if (snd_mask_test(&sformat_mask, sformat) &&			    snd_pcm_oss_format_to(sformat) >= 0)				break;		}		if (sformat > SNDRV_PCM_FORMAT_LAST) {			snd_printd("Cannot find a format!!!\n");			err = -EINVAL;			goto failure;		}	}	err = _snd_pcm_hw_param_set(sparams, SNDRV_PCM_HW_PARAM_FORMAT, sformat, 0);	snd_assert(err >= 0, goto failure);	if (direct) {		memcpy(params, sparams, sizeof(*params));	} else {		_snd_pcm_hw_params_any(params);		_snd_pcm_hw_param_set(params, SNDRV_PCM_HW_PARAM_ACCESS,				      SNDRV_PCM_ACCESS_RW_INTERLEAVED, 0);		_snd_pcm_hw_param_set(params, SNDRV_PCM_HW_PARAM_FORMAT,				      snd_pcm_oss_format_from(runtime->oss.format), 0);		_snd_pcm_hw_param_set(params, SNDRV_PCM_HW_PARAM_CHANNELS,				      runtime->oss.channels, 0);		_snd_pcm_hw_param_set(params, SNDRV_PCM_HW_PARAM_RATE,				      runtime->oss.rate, 0);		pdprintf("client: access = %i, format = %i, channels = %i, rate = %i\n",			 params_access(params), params_format(params),			 params_channels(params), params_rate(params));	}	pdprintf("slave: access = %i, format = %i, channels = %i, rate = %i\n",		 params_access(sparams), params_format(sparams),		 params_channels(sparams), params_rate(sparams));	oss_frame_size = snd_pcm_format_physical_width(params_format(params)) *			 params_channels(params) / 8;#ifdef CONFIG_SND_PCM_OSS_PLUGINS

⌨️ 快捷键说明

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