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

📄 pcm_native.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
/* *  Digital Audio (PCM) abstract layer *  Copyright (c) by Jaroslav Kysela <perex@perex.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 * */#include <sound/driver.h>#include <linux/mm.h>#include <linux/file.h>#include <linux/slab.h>#include <linux/time.h>#include <linux/latency.h>#include <linux/uio.h>#include <sound/core.h>#include <sound/control.h>#include <sound/info.h>#include <sound/pcm.h>#include <sound/pcm_params.h>#include <sound/timer.h>#include <sound/minors.h>#include <asm/io.h>/* *  Compatibility */struct snd_pcm_hw_params_old {	unsigned int flags;	unsigned int masks[SNDRV_PCM_HW_PARAM_SUBFORMAT -			   SNDRV_PCM_HW_PARAM_ACCESS + 1];	struct snd_interval intervals[SNDRV_PCM_HW_PARAM_TICK_TIME -					SNDRV_PCM_HW_PARAM_SAMPLE_BITS + 1];	unsigned int rmask;	unsigned int cmask;	unsigned int info;	unsigned int msbits;	unsigned int rate_num;	unsigned int rate_den;	snd_pcm_uframes_t fifo_size;	unsigned char reserved[64];};#ifdef CONFIG_SND_SUPPORT_OLD_API#define SNDRV_PCM_IOCTL_HW_REFINE_OLD _IOWR('A', 0x10, struct snd_pcm_hw_params_old)#define SNDRV_PCM_IOCTL_HW_PARAMS_OLD _IOWR('A', 0x11, struct snd_pcm_hw_params_old)static int snd_pcm_hw_refine_old_user(struct snd_pcm_substream *substream,				      struct snd_pcm_hw_params_old __user * _oparams);static int snd_pcm_hw_params_old_user(struct snd_pcm_substream *substream,				      struct snd_pcm_hw_params_old __user * _oparams);#endifstatic int snd_pcm_open(struct file *file, struct snd_pcm *pcm, int stream);/* * */DEFINE_RWLOCK(snd_pcm_link_rwlock);EXPORT_SYMBOL(snd_pcm_link_rwlock);static DECLARE_RWSEM(snd_pcm_link_rwsem);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);}int snd_pcm_info(struct snd_pcm_substream *substream, struct snd_pcm_info *info){	struct snd_pcm_runtime *runtime;	struct snd_pcm *pcm = substream->pcm;	struct snd_pcm_str *pstr = substream->pstr;	snd_assert(substream != NULL, return -ENXIO);	memset(info, 0, sizeof(*info));	info->card = pcm->card->number;	info->device = pcm->device;	info->stream = substream->stream;	info->subdevice = substream->number;	strlcpy(info->id, pcm->id, sizeof(info->id));	strlcpy(info->name, pcm->name, sizeof(info->name));	info->dev_class = pcm->dev_class;	info->dev_subclass = pcm->dev_subclass;	info->subdevices_count = pstr->substream_count;	info->subdevices_avail = pstr->substream_count - pstr->substream_opened;	strlcpy(info->subname, substream->name, sizeof(info->subname));	runtime = substream->runtime;	/* AB: FIXME!!! This is definitely nonsense */	if (runtime) {		info->sync = runtime->sync;		substream->ops->ioctl(substream, SNDRV_PCM_IOCTL1_INFO, info);	}	return 0;}int snd_pcm_info_user(struct snd_pcm_substream *substream,		      struct snd_pcm_info __user * _info){	struct snd_pcm_info *info;	int err;	info = kmalloc(sizeof(*info), GFP_KERNEL);	if (! info)		return -ENOMEM;	err = snd_pcm_info(substream, info);	if (err >= 0) {		if (copy_to_user(_info, info, sizeof(*info)))			err = -EFAULT;	}	kfree(info);	return err;}#undef RULES_DEBUG#ifdef RULES_DEBUG#define HW_PARAM(v) [SNDRV_PCM_HW_PARAM_##v] = #vchar *snd_pcm_hw_param_names[] = {	HW_PARAM(ACCESS),	HW_PARAM(FORMAT),	HW_PARAM(SUBFORMAT),	HW_PARAM(SAMPLE_BITS),	HW_PARAM(FRAME_BITS),	HW_PARAM(CHANNELS),	HW_PARAM(RATE),	HW_PARAM(PERIOD_TIME),	HW_PARAM(PERIOD_SIZE),	HW_PARAM(PERIOD_BYTES),	HW_PARAM(PERIODS),	HW_PARAM(BUFFER_TIME),	HW_PARAM(BUFFER_SIZE),	HW_PARAM(BUFFER_BYTES),	HW_PARAM(TICK_TIME),};#endifint snd_pcm_hw_refine(struct snd_pcm_substream *substream, 		      struct snd_pcm_hw_params *params){	unsigned int k;	struct snd_pcm_hardware *hw;	struct snd_interval *i = NULL;	struct snd_mask *m = NULL;	struct snd_pcm_hw_constraints *constrs = &substream->runtime->hw_constraints;	unsigned int rstamps[constrs->rules_num];	unsigned int vstamps[SNDRV_PCM_HW_PARAM_LAST_INTERVAL + 1];	unsigned int stamp = 2;	int changed, again;	params->info = 0;	params->fifo_size = 0;	if (params->rmask & (1 << SNDRV_PCM_HW_PARAM_SAMPLE_BITS))		params->msbits = 0;	if (params->rmask & (1 << SNDRV_PCM_HW_PARAM_RATE)) {		params->rate_num = 0;		params->rate_den = 0;	}	for (k = SNDRV_PCM_HW_PARAM_FIRST_MASK; k <= SNDRV_PCM_HW_PARAM_LAST_MASK; k++) {		m = hw_param_mask(params, k);		if (snd_mask_empty(m))			return -EINVAL;		if (!(params->rmask & (1 << k)))			continue;#ifdef RULES_DEBUG		printk("%s = ", snd_pcm_hw_param_names[k]);		printk("%04x%04x%04x%04x -> ", m->bits[3], m->bits[2], m->bits[1], m->bits[0]);#endif		changed = snd_mask_refine(m, constrs_mask(constrs, k));#ifdef RULES_DEBUG		printk("%04x%04x%04x%04x\n", m->bits[3], m->bits[2], m->bits[1], m->bits[0]);#endif		if (changed)			params->cmask |= 1 << k;		if (changed < 0)			return changed;	}	for (k = SNDRV_PCM_HW_PARAM_FIRST_INTERVAL; k <= SNDRV_PCM_HW_PARAM_LAST_INTERVAL; k++) {		i = hw_param_interval(params, k);		if (snd_interval_empty(i))			return -EINVAL;		if (!(params->rmask & (1 << k)))			continue;#ifdef RULES_DEBUG		printk("%s = ", snd_pcm_hw_param_names[k]);		if (i->empty)			printk("empty");		else			printk("%c%u %u%c", 			       i->openmin ? '(' : '[', i->min,			       i->max, i->openmax ? ')' : ']');		printk(" -> ");#endif		changed = snd_interval_refine(i, constrs_interval(constrs, k));#ifdef RULES_DEBUG		if (i->empty)			printk("empty\n");		else 			printk("%c%u %u%c\n", 			       i->openmin ? '(' : '[', i->min,			       i->max, i->openmax ? ')' : ']');#endif		if (changed)			params->cmask |= 1 << k;		if (changed < 0)			return changed;	}	for (k = 0; k < constrs->rules_num; k++)		rstamps[k] = 0;	for (k = 0; k <= SNDRV_PCM_HW_PARAM_LAST_INTERVAL; k++) 		vstamps[k] = (params->rmask & (1 << k)) ? 1 : 0;	do {		again = 0;		for (k = 0; k < constrs->rules_num; k++) {			struct snd_pcm_hw_rule *r = &constrs->rules[k];			unsigned int d;			int doit = 0;			if (r->cond && !(r->cond & params->flags))				continue;			for (d = 0; r->deps[d] >= 0; d++) {				if (vstamps[r->deps[d]] > rstamps[k]) {					doit = 1;					break;				}			}			if (!doit)				continue;#ifdef RULES_DEBUG			printk("Rule %d [%p]: ", k, r->func);			if (r->var >= 0) {				printk("%s = ", snd_pcm_hw_param_names[r->var]);				if (hw_is_mask(r->var)) {					m = hw_param_mask(params, r->var);					printk("%x", *m->bits);				} else {					i = hw_param_interval(params, r->var);					if (i->empty)						printk("empty");					else						printk("%c%u %u%c", 						       i->openmin ? '(' : '[', i->min,						       i->max, i->openmax ? ')' : ']');				}			}#endif			changed = r->func(params, r);#ifdef RULES_DEBUG			if (r->var >= 0) {				printk(" -> ");				if (hw_is_mask(r->var))					printk("%x", *m->bits);				else {					if (i->empty)						printk("empty");					else						printk("%c%u %u%c", 						       i->openmin ? '(' : '[', i->min,						       i->max, i->openmax ? ')' : ']');				}			}			printk("\n");#endif			rstamps[k] = stamp;			if (changed && r->var >= 0) {				params->cmask |= (1 << r->var);				vstamps[r->var] = stamp;				again = 1;			}			if (changed < 0)				return changed;			stamp++;		}	} while (again);	if (!params->msbits) {		i = hw_param_interval(params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS);		if (snd_interval_single(i))			params->msbits = snd_interval_value(i);	}	if (!params->rate_den) {		i = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);		if (snd_interval_single(i)) {			params->rate_num = snd_interval_value(i);			params->rate_den = 1;		}	}	hw = &substream->runtime->hw;	if (!params->info)		params->info = hw->info;	if (!params->fifo_size)		params->fifo_size = hw->fifo_size;	params->rmask = 0;	return 0;}EXPORT_SYMBOL(snd_pcm_hw_refine);static int snd_pcm_hw_refine_user(struct snd_pcm_substream *substream,				  struct snd_pcm_hw_params __user * _params){	struct snd_pcm_hw_params *params;	int err;	params = kmalloc(sizeof(*params), GFP_KERNEL);	if (!params) {		err = -ENOMEM;		goto out;	}	if (copy_from_user(params, _params, sizeof(*params))) {		err = -EFAULT;		goto out;	}	err = snd_pcm_hw_refine(substream, params);	if (copy_to_user(_params, params, sizeof(*params))) {		if (!err)			err = -EFAULT;	}out:	kfree(params);	return err;}static int period_to_usecs(struct snd_pcm_runtime *runtime){	int usecs;	if (! runtime->rate)		return -1; /* invalid */	/* take 75% of period time as the deadline */	usecs = (750000 / runtime->rate) * runtime->period_size;	usecs += ((750000 % runtime->rate) * runtime->period_size) /		runtime->rate;	return usecs;}static int snd_pcm_hw_params(struct snd_pcm_substream *substream,			     struct snd_pcm_hw_params *params){	struct snd_pcm_runtime *runtime;	int err, usecs;	unsigned int bits;	snd_pcm_uframes_t frames;	snd_assert(substream != NULL, return -ENXIO);	runtime = substream->runtime;	snd_assert(runtime != NULL, return -ENXIO);	snd_pcm_stream_lock_irq(substream);	switch (runtime->status->state) {	case SNDRV_PCM_STATE_OPEN:	case SNDRV_PCM_STATE_SETUP:	case SNDRV_PCM_STATE_PREPARED:		break;	default:		snd_pcm_stream_unlock_irq(substream);		return -EBADFD;	}	snd_pcm_stream_unlock_irq(substream);#if defined(CONFIG_SND_PCM_OSS) || defined(CONFIG_SND_PCM_OSS_MODULE)	if (!substream->oss.oss)#endif		if (atomic_read(&substream->mmap_count))			return -EBADFD;	params->rmask = ~0U;	err = snd_pcm_hw_refine(substream, params);	if (err < 0)		goto _error;	err = snd_pcm_hw_params_choose(substream, params);	if (err < 0)		goto _error;	if (substream->ops->hw_params != NULL) {		err = substream->ops->hw_params(substream, params);		if (err < 0)			goto _error;	}	runtime->access = params_access(params);	runtime->format = params_format(params);	runtime->subformat = params_subformat(params);	runtime->channels = params_channels(params);	runtime->rate = params_rate(params);	runtime->period_size = params_period_size(params);	runtime->periods = params_periods(params);	runtime->buffer_size = params_buffer_size(params);	runtime->tick_time = params_tick_time(params);	runtime->info = params->info;	runtime->rate_num = params->rate_num;	runtime->rate_den = params->rate_den;	bits = snd_pcm_format_physical_width(runtime->format);	runtime->sample_bits = bits;	bits *= runtime->channels;	runtime->frame_bits = bits;	frames = 1;	while (bits % 8 != 0) {		bits *= 2;		frames *= 2;	}	runtime->byte_align = bits / 8;	runtime->min_align = frames;	/* Default sw params */	runtime->tstamp_mode = SNDRV_PCM_TSTAMP_NONE;	runtime->period_step = 1;	runtime->sleep_min = 0;	runtime->control->avail_min = runtime->period_size;	runtime->xfer_align = runtime->period_size;	runtime->start_threshold = 1;	runtime->stop_threshold = runtime->buffer_size;	runtime->silence_threshold = 0;	runtime->silence_size = 0;	runtime->boundary = runtime->buffer_size;	while (runtime->boundary * 2 <= LONG_MAX - runtime->buffer_size)		runtime->boundary *= 2;	snd_pcm_timer_resolution_change(substream);	runtime->status->state = SNDRV_PCM_STATE_SETUP;	remove_acceptable_latency(substream->latency_id);	if ((usecs = period_to_usecs(runtime)) >= 0)		set_acceptable_latency(substream->latency_id, usecs);	return 0; _error:	/* hardware might be unuseable from this time,	   so we force application to retry to set	   the correct hardware parameter settings */	runtime->status->state = SNDRV_PCM_STATE_OPEN;	if (substream->ops->hw_free != NULL)		substream->ops->hw_free(substream);	return err;}static int snd_pcm_hw_params_user(struct snd_pcm_substream *substream,				  struct snd_pcm_hw_params __user * _params){	struct snd_pcm_hw_params *params;	int err;	params = kmalloc(sizeof(*params), GFP_KERNEL);	if (!params) {		err = -ENOMEM;		goto out;

⌨️ 快捷键说明

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