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

📄 pcm_oss.c

📁 是关于linux2.5.1的完全源码
💻 C
📖 第 1 页 / 共 5 页
字号:
/* *  Digital Audio (PCM) abstract layer / OSS compatible *  Copyright (c) by Jaroslav Kysela <perex@suse.cz> * * *   This program is free software; you can redistribute it and/or modify *   it under the terms of the GNU General Public License as published by *   the Free Software Foundation; either version 2 of the License, or *   (at your option) any later version. * *   This program is distributed in the hope that it will be useful, *   but WITHOUT ANY WARRANTY; without even the implied warranty of *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the *   GNU General Public License for more details. * *   You should have received a copy of the GNU General Public License *   along with this program; if not, write to the Free Software *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA * */#if 0#define PLUGIN_DEBUG#endif#include <sound/driver.h>#include <linux/init.h>#include <linux/slab.h>#include <linux/time.h>#include <linux/vmalloc.h>#include <sound/core.h>#include <sound/minors.h>#include <sound/pcm.h>#include <sound/pcm_params.h>#include "pcm_plugin.h"#include <sound/info.h>#include <linux/soundcard.h>#include <sound/initval.h>static int snd_dsp_map[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = 0};static int snd_adsp_map[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = 1};static int snd_nonblock_open;MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>, Abramo Bagnara <abramo@alsa-project.org>");MODULE_DESCRIPTION("PCM OSS emulation for ALSA.");MODULE_LICENSE("GPL");MODULE_PARM(snd_dsp_map, "1-" __MODULE_STRING(SNDRV_CARDS) "i");MODULE_PARM_DESC(snd_dsp_map, "PCM device number assigned to 1st OSS device.");MODULE_PARM_SYNTAX(snd_dsp_map, "default:0,skill:advanced");MODULE_PARM(snd_adsp_map, "1-" __MODULE_STRING(SNDRV_CARDS) "i");MODULE_PARM_DESC(snd_adsp_map, "PCM device number assigned to 2nd OSS device.");MODULE_PARM_SYNTAX(snd_adsp_map, "default:1,skill:advanced");MODULE_PARM(snd_nonblock_open, "i");MODULE_PARM_DESC(snd_nonblock_open, "Don't block opening busy PCM devices.");MODULE_PARM_SYNTAX(snd_nonblock_open, "default:0,skill:advanced");extern int snd_mixer_oss_ioctl_card(snd_card_t *card, unsigned int cmd, unsigned long arg);static int snd_pcm_oss_get_rate(snd_pcm_oss_file_t *pcm_oss_file);static int snd_pcm_oss_get_channels(snd_pcm_oss_file_t *pcm_oss_file);static int snd_pcm_oss_get_format(snd_pcm_oss_file_t *pcm_oss_file);EXPORT_NO_SYMBOLS;static inline mm_segment_t snd_enter_user(void){	mm_segment_t fs = get_fs();	set_fs(get_ds());	return fs;}static inline void snd_leave_user(mm_segment_t fs){	set_fs(fs);}static inline void dec_mod_count(struct module *module){	if (module)		__MOD_DEC_USE_COUNT(module);}int snd_pcm_oss_plugin_clear(snd_pcm_substream_t *substream){	snd_pcm_runtime_t *runtime = substream->runtime;	snd_pcm_plugin_t *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;}int snd_pcm_plugin_insert(snd_pcm_plugin_t *plugin){	snd_pcm_runtime_t *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(snd_pcm_plugin_t *plugin){	snd_pcm_runtime_t *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;}static long snd_pcm_oss_bytes(snd_pcm_substream_t *substream, long frames){	snd_pcm_runtime_t *runtime = substream->runtime;	if (runtime->period_size == runtime->oss.period_bytes)		return frames;	if (runtime->period_size < runtime->oss.period_bytes)		return frames * (runtime->oss.period_bytes / runtime->period_size);	return frames / (runtime->period_size / runtime->oss.period_bytes);}static 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;	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;	default:			return -EINVAL;	}}static int snd_pcm_oss_period_size(snd_pcm_substream_t *substream, 				   snd_pcm_hw_params_t *oss_params,				   snd_pcm_hw_params_t *slave_params){	size_t s;	size_t oss_buffer_size, oss_period_size, oss_periods;	size_t min_period_size, max_period_size;	snd_pcm_runtime_t *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, 0)) * oss_frame_size;	oss_buffer_size = 1 << ld2(oss_buffer_size);	if (atomic_read(&runtime->mmap_count)) {		if (oss_buffer_size > runtime->oss.mmap_bytes)			oss_buffer_size = runtime->oss.mmap_bytes;	}	if (substream->oss.setup &&	    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, 0));	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, 0));	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) {		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, 0);	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, 0);	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.periods = oss_periods;	return 0;}static int snd_pcm_oss_change_params(snd_pcm_substream_t *substream){	snd_pcm_runtime_t *runtime = substream->runtime;	snd_pcm_hw_params_t params, sparams;	snd_pcm_sw_params_t sw_params;	ssize_t oss_buffer_size, oss_period_size;	size_t oss_frame_size;	int err;	int direct;	int format, sformat, n;	unsigned int sformat_mask;	unsigned int mask;	if (atomic_read(&runtime->mmap_count)) {		direct = 1;	} else {		snd_pcm_oss_setup_t *setup = substream->oss.setup;		direct = (setup != NULL && 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);	if (atomic_read(&runtime->mmap_count))		mask = 1 << SNDRV_PCM_ACCESS_MMAP_INTERLEAVED;	else {		mask = 1 << SNDRV_PCM_ACCESS_RW_INTERLEAVED;		if (!direct)			mask |= 1 << 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");		return -EINVAL;	}	snd_pcm_hw_param_near(substream, &sparams, SNDRV_PCM_HW_PARAM_RATE, runtime->oss.rate, 0);	snd_pcm_hw_param_near(substream, &sparams, SNDRV_PCM_HW_PARAM_CHANNELS, runtime->oss.channels, 0);	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 || !(sformat_mask & (1 << sformat))) {		for (sformat = 0; sformat <= SNDRV_PCM_FORMAT_LAST; sformat++) {			if ((sformat_mask & (1 << sformat)) &&			    snd_pcm_oss_format_to(sformat) >= 0)				break;		}		if (sformat > SNDRV_PCM_FORMAT_LAST) {			snd_printd("Cannot find a format!!!\n");			return -EINVAL;		}	}	err = _snd_pcm_hw_param_set(&sparams, SNDRV_PCM_HW_PARAM_FORMAT, sformat, 0);	snd_assert(err >= 0, return err);	if (direct) {		params = sparams;	} 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;	snd_pcm_oss_plugin_clear(substream);	if (!direct) {		/* add necessary plugins */		snd_pcm_oss_plugin_clear(substream);		if ((err = snd_pcm_plug_format_plugins(substream,						       &params, 						       &sparams)) < 0) {			snd_printd("snd_pcm_plug_format_plugins failed: %i\n", err);			snd_pcm_oss_plugin_clear(substream);			return err;		}		if (runtime->oss.plugin_first) {			snd_pcm_plugin_t *plugin;			if ((err = snd_pcm_plugin_build_io(substream, &sparams, &plugin)) < 0) {				snd_printd("snd_pcm_plugin_build_io failed: %i\n", err);				snd_pcm_oss_plugin_clear(substream);				return err;			}			if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {				err = snd_pcm_plugin_append(plugin);			} else {				err = snd_pcm_plugin_insert(plugin);			}			if (err < 0) {				snd_pcm_oss_plugin_clear(substream);				return err;			}		}	}	err = snd_pcm_oss_period_size(substream, &params, &sparams);	if (err < 0)		return err;	n = snd_pcm_plug_slave_size(substream, runtime->oss.period_bytes / oss_frame_size);	err = snd_pcm_hw_param_near(substream, &sparams, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, n, 0);	snd_assert(err >= 0, return err);	err = snd_pcm_hw_param_near(substream, &sparams, SNDRV_PCM_HW_PARAM_PERIODS,				     runtime->oss.periods, 0);	snd_assert(err >= 0, return err);	snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DROP, 0);	if ((err = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_HW_PARAMS, &sparams)) < 0) {		snd_printd("HW_PARAMS failed: %i\n", err);		return err;	}	memset(&sw_params, 0, sizeof(sw_params));	if (runtime->oss.trigger) {		sw_params.start_threshold = 1;	} else {		sw_params.start_threshold = runtime->boundary;	}	if (atomic_read(&runtime->mmap_count))		sw_params.stop_threshold = runtime->boundary;	else		sw_params.stop_threshold = runtime->buffer_size;	sw_params.tstamp_mode = SNDRV_PCM_TSTAMP_NONE;	sw_params.period_step = 1;	sw_params.sleep_min = 0;	sw_params.avail_min = runtime->period_size;	sw_params.xfer_align = 1;	sw_params.silence_threshold = 0;	sw_params.silence_size = 0;	if ((err = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_SW_PARAMS, &sw_params)) < 0) {		snd_printd("SW_PARAMS failed: %i\n", err);		return err;	}	runtime->control->avail_min = runtime->period_size;	runtime->oss.periods = params_periods(&sparams);	oss_period_size = snd_pcm_plug_client_size(substream, params_period_size(&sparams));	snd_assert(oss_period_size >= 0, return -EINVAL);	if (runtime->oss.plugin_first) {		err = snd_pcm_plug_alloc(substream, oss_period_size);		if (err < 0)			return err;	}	oss_period_size *= oss_frame_size;	oss_buffer_size = oss_period_size * runtime->oss.periods;	snd_assert(oss_buffer_size >= 0, return -EINVAL);	runtime->oss.period_bytes = oss_period_size;	runtime->oss.buffer_bytes = oss_buffer_size;	pdprintf("oss: period bytes = %i, buffer bytes = %i\n",		 runtime->oss.period_bytes,		 runtime->oss.buffer_bytes);	pdprintf("slave: period_size = %i, buffer_size = %i\n",		 params_period_size(&sparams),		 params_buffer_size(&sparams));

⌨️ 快捷键说明

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