pcm_native.c

来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 2,359 行 · 第 1/5 页

C
2,359
字号
			break;		}		/* Fall through */	case SNDRV_PCM_STATE_XRUN:	       _xrun_recovery:		snd_pcm_change_state(substream, 				     snd_pcm_capture_avail(runtime) > 0 ?				     SNDRV_PCM_STATE_DRAINING : SNDRV_PCM_STATE_SETUP);		break;	case SNDRV_PCM_STATE_SUSPENDED:		snd_pcm_stream_unlock_irq(substream);		res = snd_power_wait(card, SNDRV_CTL_POWER_D0, substream->ffile);		snd_pcm_stream_lock_irq(substream);		if (res >= 0)			goto _xrun_recovery;		break;	default: 		break; 	}	snd_pcm_stream_unlock_irq(substream);	snd_power_unlock(card);	return res;}static int snd_pcm_capture_drop(snd_pcm_substream_t * substream){	snd_pcm_runtime_t *runtime = substream->runtime;	snd_card_t *card = substream->pcm->card;	int res = 0;	snd_power_lock(card);	snd_pcm_stream_lock_irq(substream);	switch (runtime->status->state) {	case SNDRV_PCM_STATE_OPEN:		res = -EBADFD;		break;	case SNDRV_PCM_STATE_SETUP:		break;	case SNDRV_PCM_STATE_PAUSED:		snd_pcm_pause(substream, 0);		/* Fall through */	case SNDRV_PCM_STATE_RUNNING:		snd_pcm_stop(substream, SNDRV_PCM_STATE_SETUP);		break;	case SNDRV_PCM_STATE_SUSPENDED:		snd_pcm_stream_unlock_irq(substream);		res = snd_power_wait(card, SNDRV_CTL_POWER_D0, substream->ffile);		snd_pcm_stream_lock_irq(substream);		if (res < 0)			goto _end;		/* Fall through */	case SNDRV_PCM_STATE_PREPARED:	case SNDRV_PCM_STATE_DRAINING:	case SNDRV_PCM_STATE_XRUN:		snd_pcm_change_state(substream, SNDRV_PCM_STATE_SETUP);		break;	default: 		break; 	}	runtime->control->appl_ptr = runtime->status->hw_ptr;       _end:	snd_pcm_stream_unlock_irq(substream);	snd_power_unlock(card);	return res;}/* WARNING: Don't forget to fput back the file */extern int snd_major;static struct file *snd_pcm_file_fd(int fd){	struct file *file;	struct inode *inode;	unsigned short minor;	file = fget(fd);	if (!file)		return NULL;	inode = file->f_dentry->d_inode;	if (!S_ISCHR(inode->i_mode) ||	    imajor(inode) != snd_major) {		fput(file);		return NULL;	}	minor = iminor(inode);	if (minor >= 256 || 	    minor % SNDRV_MINOR_DEVICES < SNDRV_MINOR_PCM_PLAYBACK) {		fput(file);		return NULL;	}	return file;}static int snd_pcm_link(snd_pcm_substream_t *substream, int fd){	int res = 0;	struct file *file;	snd_pcm_file_t *pcm_file;	snd_pcm_substream_t *substream1;	snd_pcm_stream_lock_irq(substream);	if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) {		snd_pcm_stream_unlock_irq(substream);		return -EBADFD;	}	snd_pcm_stream_unlock_irq(substream);	file = snd_pcm_file_fd(fd);	if (!file)		return -EBADFD;	pcm_file = file->private_data;	substream1 = pcm_file->substream;	down_write(&snd_pcm_link_rwsem);	write_lock_irq(&snd_pcm_link_rwlock);	if (substream->runtime->status->state != substream1->runtime->status->state) {		res = -EBADFD;		goto _end;	}	if (snd_pcm_stream_linked(substream1)) {		res = -EALREADY;		goto _end;	}	if (!snd_pcm_stream_linked(substream)) {		substream->group = kmalloc(sizeof(snd_pcm_group_t), GFP_ATOMIC);		if (substream->group == NULL) {			res = -ENOMEM;			goto _end;		}		spin_lock_init(&substream->group->lock);		INIT_LIST_HEAD(&substream->group->substreams);		list_add_tail(&substream->link_list, &substream->group->substreams);	}	list_add_tail(&substream1->link_list, &substream->group->substreams);	substream1->group = substream->group; _end:	write_unlock_irq(&snd_pcm_link_rwlock);	up_write(&snd_pcm_link_rwsem);	fput(file);	return res;}static void relink_to_local(snd_pcm_substream_t *substream){	substream->group = &substream->self_group;	INIT_LIST_HEAD(&substream->self_group.substreams);	list_add_tail(&substream->link_list, &substream->self_group.substreams);}static int snd_pcm_unlink(snd_pcm_substream_t *substream){	struct list_head *pos;	int res = 0, count = 0;	down_write(&snd_pcm_link_rwsem);	write_lock_irq(&snd_pcm_link_rwlock);	if (!snd_pcm_stream_linked(substream)) {		res = -EALREADY;		goto _end;	}	list_del(&substream->link_list);	snd_pcm_group_for_each(pos, substream) {		if (++count > 1)			break;	}	if (count == 1) {	/* detach the last stream, too */		snd_pcm_group_for_each(pos, substream) {			relink_to_local(snd_pcm_group_substream_entry(pos));			break;		}		kfree(substream->group);	}	relink_to_local(substream);       _end:	write_unlock_irq(&snd_pcm_link_rwlock);	up_write(&snd_pcm_link_rwsem);	return res;}static int snd_pcm_hw_rule_mul(snd_pcm_hw_params_t *params,			       snd_pcm_hw_rule_t *rule){	snd_interval_t t;	snd_interval_mul(hw_param_interval_c(params, rule->deps[0]),		     hw_param_interval_c(params, rule->deps[1]), &t);	return snd_interval_refine(hw_param_interval(params, rule->var), &t);}static int snd_pcm_hw_rule_div(snd_pcm_hw_params_t *params,			       snd_pcm_hw_rule_t *rule){	snd_interval_t t;	snd_interval_div(hw_param_interval_c(params, rule->deps[0]),		     hw_param_interval_c(params, rule->deps[1]), &t);	return snd_interval_refine(hw_param_interval(params, rule->var), &t);}static int snd_pcm_hw_rule_muldivk(snd_pcm_hw_params_t *params,				   snd_pcm_hw_rule_t *rule){	snd_interval_t t;	snd_interval_muldivk(hw_param_interval_c(params, rule->deps[0]),			 hw_param_interval_c(params, rule->deps[1]),			 (unsigned long) rule->private, &t);	return snd_interval_refine(hw_param_interval(params, rule->var), &t);}static int snd_pcm_hw_rule_mulkdiv(snd_pcm_hw_params_t *params,				   snd_pcm_hw_rule_t *rule){	snd_interval_t t;	snd_interval_mulkdiv(hw_param_interval_c(params, rule->deps[0]),			 (unsigned long) rule->private,			 hw_param_interval_c(params, rule->deps[1]), &t);	return snd_interval_refine(hw_param_interval(params, rule->var), &t);}static int snd_pcm_hw_rule_format(snd_pcm_hw_params_t *params,				  snd_pcm_hw_rule_t *rule){	unsigned int k;	snd_interval_t *i = hw_param_interval(params, rule->deps[0]);	snd_mask_t m;	snd_mask_t *mask = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);	snd_mask_any(&m);	for (k = 0; k <= SNDRV_PCM_FORMAT_LAST; ++k) {		int bits;		if (! snd_mask_test(mask, k))			continue;		bits = snd_pcm_format_physical_width(k);		if (bits <= 0)			continue; /* ignore invalid formats */		if ((unsigned)bits < i->min || (unsigned)bits > i->max)			snd_mask_reset(&m, k);	}	return snd_mask_refine(mask, &m);}static int snd_pcm_hw_rule_sample_bits(snd_pcm_hw_params_t *params,				       snd_pcm_hw_rule_t *rule){	snd_interval_t t;	unsigned int k;	t.min = UINT_MAX;	t.max = 0;	t.openmin = 0;	t.openmax = 0;	for (k = 0; k <= SNDRV_PCM_FORMAT_LAST; ++k) {		int bits;		if (! snd_mask_test(hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT), k))			continue;		bits = snd_pcm_format_physical_width(k);		if (bits <= 0)			continue; /* ignore invalid formats */		if (t.min > (unsigned)bits)			t.min = bits;		if (t.max < (unsigned)bits)			t.max = bits;	}	t.integer = 1;	return snd_interval_refine(hw_param_interval(params, rule->var), &t);}#if SNDRV_PCM_RATE_5512 != 1 << 0 || SNDRV_PCM_RATE_192000 != 1 << 12#error "Change this table"#endifstatic unsigned int rates[] = { 5512, 8000, 11025, 16000, 22050, 32000, 44100,                                 48000, 64000, 88200, 96000, 176400, 192000 };static int snd_pcm_hw_rule_rate(snd_pcm_hw_params_t *params,				snd_pcm_hw_rule_t *rule){	snd_pcm_hardware_t *hw = rule->private;	return snd_interval_list(hw_param_interval(params, rule->var),				 ARRAY_SIZE(rates), rates, hw->rates);}		static int snd_pcm_hw_rule_buffer_bytes_max(snd_pcm_hw_params_t *params,					    snd_pcm_hw_rule_t *rule){	snd_interval_t t;	snd_pcm_substream_t *substream = rule->private;	t.min = 0;	t.max = substream->buffer_bytes_max;	t.openmin = 0;	t.openmax = 0;	t.integer = 1;	return snd_interval_refine(hw_param_interval(params, rule->var), &t);}		int snd_pcm_hw_constraints_init(snd_pcm_substream_t *substream){	snd_pcm_runtime_t *runtime = substream->runtime;	snd_pcm_hw_constraints_t *constrs = &runtime->hw_constraints;	int k, err;	for (k = SNDRV_PCM_HW_PARAM_FIRST_MASK; k <= SNDRV_PCM_HW_PARAM_LAST_MASK; k++) {		snd_mask_any(constrs_mask(constrs, k));	}	for (k = SNDRV_PCM_HW_PARAM_FIRST_INTERVAL; k <= SNDRV_PCM_HW_PARAM_LAST_INTERVAL; k++) {		snd_interval_any(constrs_interval(constrs, k));	}	snd_interval_setinteger(constrs_interval(constrs, SNDRV_PCM_HW_PARAM_CHANNELS));	snd_interval_setinteger(constrs_interval(constrs, SNDRV_PCM_HW_PARAM_BUFFER_SIZE));	snd_interval_setinteger(constrs_interval(constrs, SNDRV_PCM_HW_PARAM_BUFFER_BYTES));	snd_interval_setinteger(constrs_interval(constrs, SNDRV_PCM_HW_PARAM_SAMPLE_BITS));	snd_interval_setinteger(constrs_interval(constrs, SNDRV_PCM_HW_PARAM_FRAME_BITS));	err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_FORMAT,				   snd_pcm_hw_rule_format, NULL,				   SNDRV_PCM_HW_PARAM_SAMPLE_BITS, -1);	if (err < 0)		return err;	err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_SAMPLE_BITS, 				  snd_pcm_hw_rule_sample_bits, NULL,				  SNDRV_PCM_HW_PARAM_FORMAT, 				  SNDRV_PCM_HW_PARAM_SAMPLE_BITS, -1);	if (err < 0)		return err;	err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_SAMPLE_BITS, 				  snd_pcm_hw_rule_div, NULL,				  SNDRV_PCM_HW_PARAM_FRAME_BITS, SNDRV_PCM_HW_PARAM_CHANNELS, -1);	if (err < 0)		return err;	err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_FRAME_BITS, 				  snd_pcm_hw_rule_mul, NULL,				  SNDRV_PCM_HW_PARAM_SAMPLE_BITS, SNDRV_PCM_HW_PARAM_CHANNELS, -1);	if (err < 0)		return err;	err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_FRAME_BITS, 				  snd_pcm_hw_rule_mulkdiv, (void*) 8,				  SNDRV_PCM_HW_PARAM_PERIOD_BYTES, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, -1);	if (err < 0)		return err;	err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_FRAME_BITS, 				  snd_pcm_hw_rule_mulkdiv, (void*) 8,				  SNDRV_PCM_HW_PARAM_BUFFER_BYTES, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, -1);	if (err < 0)		return err;	err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, 				  snd_pcm_hw_rule_div, NULL,				  SNDRV_PCM_HW_PARAM_FRAME_BITS, SNDRV_PCM_HW_PARAM_SAMPLE_BITS, -1);	if (err < 0)		return err;	err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, 				  snd_pcm_hw_rule_mulkdiv, (void*) 1000000,				  SNDRV_PCM_HW_PARAM_PERIOD_SIZE, SNDRV_PCM_HW_PARAM_PERIOD_TIME, -1);	if (err < 0)		return err;	err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, 				  snd_pcm_hw_rule_mulkdiv, (void*) 1000000,				  SNDRV_PCM_HW_PARAM_BUFFER_SIZE, SNDRV_PCM_HW_PARAM_BUFFER_TIME, -1);	if (err < 0)		return err;	err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_PERIODS, 				  snd_pcm_hw_rule_div, NULL,				  SNDRV_PCM_HW_PARAM_BUFFER_SIZE, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, -1);	if (err < 0)		return err;	err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, 				  snd_pcm_hw_rule_div, NULL,				  SNDRV_PCM_HW_PARAM_BUFFER_SIZE, SNDRV_PCM_HW_PARAM_PERIODS, -1);	if (err < 0)		return err;	err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, 				  snd_pcm_hw_rule_mulkdiv, (void*) 8,				  SNDRV_PCM_HW_PARAM_PERIOD_BYTES, SNDRV_PCM_HW_PARAM_FRAME_BITS, -1);	if (err < 0)		return err;	err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, 				  snd_pcm_hw_rule_muldivk, (void*) 1000000,				  SNDRV_PCM_HW_PARAM_PERIOD_TIME, SNDRV_PCM_HW_PARAM_RATE, -1);	if (err < 0)		return err;	err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, 				  snd_pcm_hw_rule_mul, NULL,				  SNDRV_PCM_HW_PARAM_PERIOD_SIZE, SNDRV_PCM_HW_PARAM_PERIODS, -1);	if (err < 0)		return err;	err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, 				  snd_pcm_hw_rule_mulkdiv, (void*) 8,				  SNDRV_PCM_HW_PARAM_BUFFER_BYTES, SNDRV_PCM_HW_PARAM_FRAME_BITS, -1);	if (err < 0)		return err;	err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, 				  snd_pcm_hw_rule_muldivk, (void*) 1000000,				  SNDRV_PCM_HW_PARAM_BUFFER_TIME, SNDRV_PCM_HW_PARAM_RATE, -1);	if (err < 0)		return err;	err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 				  snd_pcm_hw_rule_muldivk, (void*) 8,				  SNDRV_PCM_HW_PARAM_PERIOD_SIZE, SNDRV_PCM_HW_PARAM_FRAME_BITS, -1);	if (err < 0)		return err;	err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 				  snd_pcm_hw_rule_muldivk, (void*) 8,				  SNDRV_PCM_HW_PARAM_BUFFER_SIZE, SNDRV_PCM_HW_PARAM_FRAME_BITS, -1);	if (err < 0)		return err;	err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_TIME, 				  snd_pcm_hw_rule_mulkdiv, (void*) 1000000,				  SNDRV_PCM_HW_PARAM_PERIOD_SIZE, SNDRV_PCM_HW_PARAM_RATE, -1);	if (err < 0)		return err;	err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_TIME, 				  snd_pcm_hw_rule_mulkdiv, (void*) 1000000,				  SNDRV_PCM_HW_PARAM_BUFFER_SIZE, SNDRV_PCM_HW_PARAM_RATE, -1);	if (err < 0)		return err;	return 0;}int snd_pcm_hw_constraints_complete(snd_pcm_substream_t *substream){	snd_pcm_runtime_t *runtime = substream->runtime;	snd_pcm_hardware_t *hw = &runtime->hw;	int err;	unsigned int mask = 0;        if (hw->info & SNDRV_PCM_INFO_INTERLEAVED)		mask |= 1 << SNDRV_PCM_ACCESS_RW_INTERLEAVED;        if (hw->info & SNDRV_PCM_INFO_NONINTERLEAVED)		mask |= 1 << SNDRV_PCM_ACCESS_RW_NONINTERLEAVED;	if (hw->info & SNDRV_PCM_INFO_MMAP) {		if (hw->info & SNDRV_PCM_INFO_INTERLEAVED)			mask |= 1 << SNDRV_PCM_ACCESS_MMAP_INTERLEAVED;		if (hw->info & SNDRV_PCM_INFO_NONINTERLEAVED)			mask |= 1 << SNDRV_PCM_ACCESS_MMAP_NONINTERLEAVED;		if (hw->info & SNDRV_PCM_INFO_COMPLEX)			mask |= 1 << SNDRV_PCM_ACCESS_MMAP_COMPLEX;	}	err = snd_pcm_hw_constraint_mask(runtime, SNDRV_PCM_HW_PARAM_ACCESS, mask);	snd_assert(err >= 0, return -EINVAL);	err = snd_pcm_hw_constraint_mask64(runtime, SNDRV_PCM_HW_PARAM_FORMAT, hw->formats);	snd_assert(err >= 0, return -EINVAL);	err = snd_pcm_hw_constraint_mask(runtime, SNDRV_PCM_HW_PARAM_SUBFORMAT, 1 << SNDRV_PCM_SUBFORMAT_STD);	snd_assert(err >= 0, return -EINVAL);	err = snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_CHANNELS,					   hw->channels_min, hw->channels_max);	snd_assert(err >= 0, return -EINVAL);	err = snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_RATE,					   hw->rate_min, hw->rate_max);	snd_assert(err >= 0, return -EINVAL);	err = snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_PERIOD_BYTES,					   hw->period_bytes_min, hw->period_bytes_max);	snd_assert(err >= 0, return -EINVAL);	err = snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_PERIODS,					   hw->periods_min, hw->periods_max);	snd_assert(err >= 0, return -EINVAL);	err = snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_BYTES,					   hw->period_bytes_min, hw->buffer_bytes_max);	snd_assert(err >= 0, return -EINVAL);	err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 				  snd_pcm_hw_rule_buffer_bytes_max, substream,				  SNDRV_PCM_HW_PARAM_BUFFER_BYTES, -1);	if (err < 0)		return err;	/* FIXME: remove */	if (runtime->dma_bytes) {		err = snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 0, runtime->dma_bytes);		snd_assert(err >= 0, return -EINVAL);	}	if (!(hw->rates & (SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_CONTINUOUS))) {

⌨️ 快捷键说明

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