mirror of
				https://github.com/alsa-project/alsa-lib.git
				synced 2025-10-29 05:40:25 -04:00 
			
		
		
		
	Fix infinite parse of recursive definitions
Fixed the infinite parse (and eventually segfault) of recursive definitions. Also fixed the parse of a string slave PCM of direct plugins.
This commit is contained in:
		
							parent
							
								
									bf174b7046
								
							
						
					
					
						commit
						eccc92a34d
					
				
					 29 changed files with 127 additions and 36 deletions
				
			
		|  | @ -249,4 +249,9 @@ void *snd_dlobj_cache_lookup(const char *name); | |||
| int snd_dlobj_cache_add(const char *name, void *dlobj, void *open_func); | ||||
| void snd_dlobj_cache_cleanup(void); | ||||
| 
 | ||||
| /* for recursive checks */ | ||||
| void snd_config_set_hop(snd_config_t *conf, int hop); | ||||
| int snd_config_check_hop(snd_config_t *conf); | ||||
| #define SND_CONF_MAX_HOPS	64 | ||||
| 
 | ||||
| #endif | ||||
|  |  | |||
							
								
								
									
										19
									
								
								src/conf.c
									
										
									
									
									
								
							
							
						
						
									
										19
									
								
								src/conf.c
									
										
									
									
									
								
							|  | @ -440,6 +440,7 @@ struct _snd_config { | |||
| 	} u; | ||||
| 	struct list_head list; | ||||
| 	snd_config_t *father; | ||||
| 	int hop; | ||||
| }; | ||||
| 
 | ||||
| struct filedesc { | ||||
|  | @ -4011,6 +4012,24 @@ int snd_config_search_definition(snd_config_t *config, | |||
| 	return snd_config_expand(conf, config, args, NULL, result); | ||||
| } | ||||
| 
 | ||||
| #ifndef DOC_HIDDEN | ||||
| void snd_config_set_hop(snd_config_t *conf, int hop) | ||||
| { | ||||
| 	conf->hop = hop; | ||||
| } | ||||
| 
 | ||||
| int snd_config_check_hop(snd_config_t *conf) | ||||
| { | ||||
| 	if (conf) { | ||||
| 		if (conf->hop >= SND_CONF_MAX_HOPS) { | ||||
| 			SYSERR("Too many definition levels (looped?)\n"); | ||||
| 			return -EINVAL; | ||||
| 		} | ||||
| 		return conf->hop; | ||||
| 	} | ||||
| 	return 0; | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| #if 0 | ||||
| /* Not strictly needed, but useful to check for memory leaks */ | ||||
|  |  | |||
|  | @ -2098,7 +2098,8 @@ static int snd_pcm_open_conf(snd_pcm_t **pcmp, const char *name, | |||
| } | ||||
| 
 | ||||
| static int snd_pcm_open_noupdate(snd_pcm_t **pcmp, snd_config_t *root, | ||||
| 				 const char *name, snd_pcm_stream_t stream, int mode) | ||||
| 				 const char *name, snd_pcm_stream_t stream, | ||||
| 				 int mode, int hop) | ||||
| { | ||||
| 	int err; | ||||
| 	snd_config_t *pcm_conf; | ||||
|  | @ -2107,6 +2108,7 @@ static int snd_pcm_open_noupdate(snd_pcm_t **pcmp, snd_config_t *root, | |||
| 		SNDERR("Unknown PCM %s", name); | ||||
| 		return err; | ||||
| 	} | ||||
| 	snd_config_set_hop(pcm_conf, hop); | ||||
| 	err = snd_pcm_open_conf(pcmp, name, root, pcm_conf, stream, mode); | ||||
| 	snd_config_delete(pcm_conf); | ||||
| 	return err; | ||||
|  | @ -2128,7 +2130,7 @@ int snd_pcm_open(snd_pcm_t **pcmp, const char *name, | |||
| 	err = snd_config_update(); | ||||
| 	if (err < 0) | ||||
| 		return err; | ||||
| 	return snd_pcm_open_noupdate(pcmp, snd_config, name, stream, mode); | ||||
| 	return snd_pcm_open_noupdate(pcmp, snd_config, name, stream, mode, 0); | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  | @ -2145,7 +2147,7 @@ int snd_pcm_open_lconf(snd_pcm_t **pcmp, const char *name, | |||
| 		       snd_config_t *lconf) | ||||
| { | ||||
| 	assert(pcmp && name && lconf); | ||||
| 	return snd_pcm_open_noupdate(pcmp, lconf, name, stream, mode); | ||||
| 	return snd_pcm_open_noupdate(pcmp, lconf, name, stream, mode, 0); | ||||
| } | ||||
| 
 | ||||
| #ifndef DOC_HIDDEN | ||||
|  | @ -2187,11 +2189,16 @@ int snd_pcm_free(snd_pcm_t *pcm) | |||
| 
 | ||||
| int snd_pcm_open_slave(snd_pcm_t **pcmp, snd_config_t *root, | ||||
| 		       snd_config_t *conf, snd_pcm_stream_t stream, | ||||
| 		       int mode) | ||||
| 		       int mode, snd_config_t *parent_conf) | ||||
| { | ||||
| 	const char *str; | ||||
| 	int hop; | ||||
| 
 | ||||
| 	if ((hop = snd_config_check_hop(parent_conf)) < 0) | ||||
| 		return hop; | ||||
| 	if (snd_config_get_string(conf, &str) >= 0) | ||||
| 		return snd_pcm_open_noupdate(pcmp, root, str, stream, mode); | ||||
| 		return snd_pcm_open_noupdate(pcmp, root, str, stream, mode, | ||||
| 					     hop + 1); | ||||
| 	return snd_pcm_open_conf(pcmp, NULL, root, conf, stream, mode); | ||||
| } | ||||
| #endif | ||||
|  |  | |||
|  | @ -666,7 +666,7 @@ int _snd_pcm_adpcm_open(snd_pcm_t **pcmp, const char *name, | |||
| 		SNDERR("invalid slave format"); | ||||
| 		return -EINVAL; | ||||
| 	} | ||||
| 	err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode); | ||||
| 	err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode, conf); | ||||
| 	snd_config_delete(sconf); | ||||
| 	if (err < 0) | ||||
| 		return err; | ||||
|  |  | |||
|  | @ -538,7 +538,7 @@ int _snd_pcm_alaw_open(snd_pcm_t **pcmp, const char *name, | |||
| 		SNDERR("invalid slave format"); | ||||
| 		return -EINVAL; | ||||
| 	} | ||||
| 	err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode); | ||||
| 	err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode, conf); | ||||
| 	snd_config_delete(sconf); | ||||
| 	if (err < 0) | ||||
| 		return err; | ||||
|  |  | |||
|  | @ -109,7 +109,7 @@ int _snd_pcm_asym_open(snd_pcm_t **pcmp, const char *name ATTRIBUTE_UNUSED, | |||
| 	err = snd_pcm_slave_conf(root, slave, &sconf, 0); | ||||
| 	if (err < 0) | ||||
| 		return err; | ||||
| 	err = snd_pcm_open_slave(pcmp, root, sconf, stream, mode); | ||||
| 	err = snd_pcm_open_slave(pcmp, root, sconf, stream, mode, conf); | ||||
| 	snd_config_delete(sconf); | ||||
| 	return err; | ||||
| } | ||||
|  |  | |||
|  | @ -284,7 +284,7 @@ int _snd_pcm_copy_open(snd_pcm_t **pcmp, const char *name, | |||
| 	err = snd_pcm_slave_conf(root, slave, &sconf, 0); | ||||
| 	if (err < 0) | ||||
| 		return err; | ||||
| 	err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode); | ||||
| 	err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode, conf); | ||||
| 	snd_config_delete(sconf); | ||||
| 	if (err < 0) | ||||
| 		return err; | ||||
|  |  | |||
|  | @ -1260,11 +1260,34 @@ int snd_pcm_direct_parse_bindings(snd_pcm_direct_t *dmix, snd_config_t *cfg) | |||
| /*
 | ||||
|  * parse slave config and calculate the ipc_key offset | ||||
|  */ | ||||
| int snd_pcm_direct_get_slave_ipc_offset(snd_config_t *sconf, int direction) | ||||
| 
 | ||||
| static int _snd_pcm_direct_get_slave_ipc_offset(snd_config_t *root, | ||||
| 						snd_config_t *sconf, | ||||
| 						int direction, | ||||
| 						int hop) | ||||
| { | ||||
| 	snd_config_iterator_t i, next; | ||||
| 	int err; | ||||
| 	long card = 0, device = 0, subdevice = 0; | ||||
| 	const char *str; | ||||
| 
 | ||||
| 	if (snd_config_get_string(sconf, &str) >= 0) { | ||||
| 		snd_config_t *pcm_conf; | ||||
| 		if (hop > SND_CONF_MAX_HOPS) { | ||||
| 			SNDERR("Too many definition levels (looped?)"); | ||||
| 			return -EINVAL; | ||||
| 		} | ||||
| 		err = snd_config_search_definition(root, "pcm", str, &pcm_conf); | ||||
| 		if (err < 0) { | ||||
| 			SNDERR("Unknown slave PCM %s", str); | ||||
| 			return err; | ||||
| 		} | ||||
| 		err = _snd_pcm_direct_get_slave_ipc_offset(root, pcm_conf, | ||||
| 							   direction, | ||||
| 							   hop + 1); | ||||
| 		snd_config_delete(pcm_conf); | ||||
| 		return err; | ||||
| 	} | ||||
| 
 | ||||
| 	snd_config_for_each(i, next, sconf) { | ||||
| 		snd_config_t *n = snd_config_iterator_entry(i); | ||||
|  | @ -1325,6 +1348,12 @@ int snd_pcm_direct_get_slave_ipc_offset(snd_config_t *sconf, int direction) | |||
| 	return direction + (card << 1) + (device << 4) + (subdevice << 8); | ||||
| } | ||||
| 
 | ||||
| int snd_pcm_direct_get_slave_ipc_offset(snd_config_t *root, | ||||
| 					snd_config_t *sconf, | ||||
| 					int direction) | ||||
| { | ||||
| 	return _snd_pcm_direct_get_slave_ipc_offset(root, sconf, direction, 0); | ||||
| } | ||||
| 
 | ||||
| int snd_pcm_direct_parse_open_conf(snd_config_t *conf, struct snd_pcm_direct_open_conf *rec) | ||||
| { | ||||
|  |  | |||
|  | @ -186,7 +186,7 @@ int snd_pcm_direct_timer_stop(snd_pcm_direct_t *dmix); | |||
| void snd_pcm_direct_clear_timer_queue(snd_pcm_direct_t *dmix); | ||||
| int snd_pcm_direct_set_timer_params(snd_pcm_direct_t *dmix); | ||||
| int snd_pcm_direct_open_secondary_client(snd_pcm_t **spcmp, snd_pcm_direct_t *dmix, const char *client_name); | ||||
| int snd_pcm_direct_get_slave_ipc_offset(snd_config_t *sconf, int direction); | ||||
| int snd_pcm_direct_get_slave_ipc_offset(snd_config_t *root, snd_config_t *sconf, int direction); | ||||
| 
 | ||||
| int snd_timer_async(snd_timer_t *timer, int sig, pid_t pid); | ||||
| struct timespec snd_pcm_hw_fast_tstamp(snd_pcm_t *pcm); | ||||
|  |  | |||
|  | @ -847,7 +847,10 @@ int snd_pcm_dmix_open(snd_pcm_t **pcmp, const char *name, | |||
| 	dmix->sync_ptr = snd_pcm_dmix_sync_ptr; | ||||
| 
 | ||||
| 	if (first_instance) { | ||||
| 		ret = snd_pcm_open_slave(&spcm, root, sconf, stream, mode | SND_PCM_NONBLOCK); | ||||
| 		/* recursion is already checked in
 | ||||
| 		   snd_pcm_direct_get_slave_ipc_offset() */ | ||||
| 		ret = snd_pcm_open_slave(&spcm, root, sconf, stream, | ||||
| 					 mode | SND_PCM_NONBLOCK, NULL); | ||||
| 		if (ret < 0) { | ||||
| 			SNDERR("unable to open slave"); | ||||
| 			goto _err; | ||||
|  | @ -1124,7 +1127,7 @@ int _snd_pcm_dmix_open(snd_pcm_t **pcmp, const char *name, | |||
| 	params.period_size = psize; | ||||
| 	params.buffer_size = bsize; | ||||
| 
 | ||||
| 	ipc_offset = snd_pcm_direct_get_slave_ipc_offset(sconf, stream); | ||||
| 	ipc_offset = snd_pcm_direct_get_slave_ipc_offset(root, sconf, stream); | ||||
| 	if (ipc_offset < 0) { | ||||
| 		snd_config_delete(sconf); | ||||
| 		return ipc_offset; | ||||
|  |  | |||
|  | @ -672,7 +672,10 @@ int snd_pcm_dshare_open(snd_pcm_t **pcmp, const char *name, | |||
| 	dshare->sync_ptr = snd_pcm_dshare_sync_ptr; | ||||
| 
 | ||||
| 	if (first_instance) { | ||||
| 		ret = snd_pcm_open_slave(&spcm, root, sconf, stream, mode | SND_PCM_NONBLOCK); | ||||
| 		/* recursion is already checked in
 | ||||
| 		   snd_pcm_direct_get_slave_ipc_offset() */ | ||||
| 		ret = snd_pcm_open_slave(&spcm, root, sconf, stream, | ||||
| 					 mode | SND_PCM_NONBLOCK, NULL); | ||||
| 		if (ret < 0) { | ||||
| 			SNDERR("unable to open slave"); | ||||
| 			goto _err; | ||||
|  | @ -873,7 +876,7 @@ int _snd_pcm_dshare_open(snd_pcm_t **pcmp, const char *name, | |||
| 	params.period_size = psize; | ||||
| 	params.buffer_size = bsize; | ||||
| 
 | ||||
| 	ipc_offset = snd_pcm_direct_get_slave_ipc_offset(sconf, stream); | ||||
| 	ipc_offset = snd_pcm_direct_get_slave_ipc_offset(root, sconf, stream); | ||||
| 	if (ipc_offset < 0) { | ||||
| 		snd_config_delete(sconf); | ||||
| 		return ipc_offset; | ||||
|  |  | |||
|  | @ -554,7 +554,10 @@ int snd_pcm_dsnoop_open(snd_pcm_t **pcmp, const char *name, | |||
| 	dsnoop->sync_ptr = snd_pcm_dsnoop_sync_ptr; | ||||
| 
 | ||||
| 	if (first_instance) { | ||||
| 		ret = snd_pcm_open_slave(&spcm, root, sconf, stream, mode | SND_PCM_NONBLOCK); | ||||
| 		/* recursion is already checked in
 | ||||
| 		   snd_pcm_direct_get_slave_ipc_offset() */ | ||||
| 		ret = snd_pcm_open_slave(&spcm, root, sconf, stream, | ||||
| 					 mode | SND_PCM_NONBLOCK, NULL); | ||||
| 		if (ret < 0) { | ||||
| 			SNDERR("unable to open slave"); | ||||
| 			goto _err; | ||||
|  | @ -745,7 +748,7 @@ int _snd_pcm_dsnoop_open(snd_pcm_t **pcmp, const char *name, | |||
| 	params.period_size = psize; | ||||
| 	params.buffer_size = bsize; | ||||
| 
 | ||||
| 	ipc_offset = snd_pcm_direct_get_slave_ipc_offset(sconf, stream); | ||||
| 	ipc_offset = snd_pcm_direct_get_slave_ipc_offset(root, sconf, stream); | ||||
| 	if (ipc_offset < 0) { | ||||
| 		snd_config_delete(sconf); | ||||
| 		return ipc_offset; | ||||
|  |  | |||
|  | @ -622,7 +622,7 @@ int snd_pcm_extplug_create(snd_pcm_extplug_t *extplug, const char *name, | |||
| 	err = snd_pcm_slave_conf(root, slave_conf, &sconf, 0); | ||||
| 	if (err < 0) | ||||
| 		return err; | ||||
| 	err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode); | ||||
| 	err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode, NULL); | ||||
| 	snd_config_delete(sconf); | ||||
| 	if (err < 0) | ||||
| 		return err; | ||||
|  |  | |||
|  | @ -556,7 +556,7 @@ int _snd_pcm_file_open(snd_pcm_t **pcmp, const char *name, | |||
| 		SNDERR("file is not defined"); | ||||
| 		return -EINVAL; | ||||
| 	} | ||||
| 	err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode); | ||||
| 	err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode, conf); | ||||
| 	snd_config_delete(sconf); | ||||
| 	if (err < 0) | ||||
| 		return err; | ||||
|  |  | |||
|  | @ -460,7 +460,7 @@ int _snd_pcm_hooks_open(snd_pcm_t **pcmp, const char *name, | |||
| 	err = snd_pcm_slave_conf(root, slave, &sconf, 0); | ||||
| 	if (err < 0) | ||||
| 		return err; | ||||
| 	err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode); | ||||
| 	err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode, conf); | ||||
| 	snd_config_delete(sconf); | ||||
| 	if (err < 0) | ||||
| 		return err; | ||||
|  |  | |||
|  | @ -662,7 +662,7 @@ int _snd_pcm_iec958_open(snd_pcm_t **pcmp, const char *name, | |||
| 		SNDERR("invalid slave format"); | ||||
| 		return -EINVAL; | ||||
| 	} | ||||
| 	err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode); | ||||
| 	err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode, conf); | ||||
| 	snd_config_delete(sconf); | ||||
| 	if (err < 0) | ||||
| 		return err; | ||||
|  |  | |||
|  | @ -1782,7 +1782,7 @@ int _snd_pcm_ladspa_open(snd_pcm_t **pcmp, const char *name, | |||
| 	err = snd_pcm_slave_conf(root, slave, &sconf, 0); | ||||
| 	if (err < 0) | ||||
| 		return err; | ||||
| 	err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode); | ||||
| 	err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode, conf); | ||||
| 	snd_config_delete(sconf); | ||||
| 	if (err < 0) | ||||
| 		return err; | ||||
|  |  | |||
|  | @ -497,7 +497,7 @@ int _snd_pcm_lfloat_open(snd_pcm_t **pcmp, const char *name, | |||
| 		SNDERR("slave format is not linear integer or linear float"); | ||||
| 		return -EINVAL; | ||||
| 	} | ||||
| 	err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode); | ||||
| 	err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode, conf); | ||||
| 	snd_config_delete(sconf); | ||||
| 	if (err < 0) | ||||
| 		return err; | ||||
|  |  | |||
|  | @ -552,7 +552,7 @@ int _snd_pcm_linear_open(snd_pcm_t **pcmp, const char *name, | |||
| 		SNDERR("slave format is not linear"); | ||||
| 		return -EINVAL; | ||||
| 	} | ||||
| 	err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode); | ||||
| 	err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode, conf); | ||||
| 	snd_config_delete(sconf); | ||||
| 	if (err < 0) | ||||
| 		return err; | ||||
|  |  | |||
|  | @ -748,7 +748,7 @@ int snd_pcm_slave_conf(snd_config_t *root, snd_config_t *conf, | |||
| 
 | ||||
| int snd_pcm_open_slave(snd_pcm_t **pcmp, snd_config_t *root, | ||||
| 		       snd_config_t *conf, snd_pcm_stream_t stream, | ||||
| 		       int mode); | ||||
| 		       int mode, snd_config_t *parent_conf); | ||||
| int snd_pcm_conf_generic_id(const char *id); | ||||
| 
 | ||||
| int snd_pcm_hw_open_fd(snd_pcm_t **pcmp, const char *name, int fd, int mmap_emulation, int sync_ptr_ioctl); | ||||
|  |  | |||
|  | @ -779,7 +779,7 @@ int _snd_pcm_meter_open(snd_pcm_t **pcmp, const char *name, | |||
| 	err = snd_pcm_slave_conf(root, slave, &sconf, 0); | ||||
| 	if (err < 0) | ||||
| 		return err; | ||||
| 	err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode); | ||||
| 	err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode, conf); | ||||
| 	snd_config_delete(sconf); | ||||
| 	if (err < 0) | ||||
| 		return err; | ||||
|  |  | |||
|  | @ -553,7 +553,7 @@ int _snd_pcm_mulaw_open(snd_pcm_t **pcmp, const char *name, | |||
| 		SNDERR("invalid slave format"); | ||||
| 		return -EINVAL; | ||||
| 	} | ||||
| 	err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode); | ||||
| 	err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode, conf); | ||||
| 	snd_config_delete(sconf); | ||||
| 	if (err < 0) | ||||
| 		return err; | ||||
|  |  | |||
|  | @ -1103,7 +1103,9 @@ int _snd_pcm_multi_open(snd_pcm_t **pcmp, const char *name, | |||
| 	} | ||||
| 	 | ||||
| 	for (idx = 0; idx < slaves_count; ++idx) { | ||||
| 		err = snd_pcm_open_slave(&slaves_pcm[idx], root, slaves_conf[idx], stream, mode); | ||||
| 		err = snd_pcm_open_slave(&slaves_pcm[idx], root, | ||||
| 					 slaves_conf[idx], stream, mode, | ||||
| 					 conf); | ||||
| 		if (err < 0) | ||||
| 			goto _free; | ||||
| 		snd_config_delete(slaves_conf[idx]); | ||||
|  |  | |||
|  | @ -1215,7 +1215,7 @@ int _snd_pcm_plug_open(snd_pcm_t **pcmp, const char *name, | |||
| 	} | ||||
| #endif | ||||
| 	 | ||||
| 	err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode); | ||||
| 	err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode, conf); | ||||
| 	snd_config_delete(sconf); | ||||
| 	if (err < 0) | ||||
| 		return err; | ||||
|  |  | |||
|  | @ -1532,7 +1532,7 @@ int _snd_pcm_rate_open(snd_pcm_t **pcmp, const char *name, | |||
| 		SNDERR("slave format is not linear"); | ||||
| 		return -EINVAL; | ||||
| 	} | ||||
| 	err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode); | ||||
| 	err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode, conf); | ||||
| 	snd_config_delete(sconf); | ||||
| 	if (err < 0) | ||||
| 		return err; | ||||
|  |  | |||
|  | @ -1152,7 +1152,7 @@ int _snd_pcm_route_open(snd_pcm_t **pcmp, const char *name, | |||
| 		return err; | ||||
| 	} | ||||
| 
 | ||||
| 	err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode); | ||||
| 	err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode, conf); | ||||
| 	snd_config_delete(sconf); | ||||
| 	if (err < 0) { | ||||
| 		free(ttable); | ||||
|  |  | |||
|  | @ -814,7 +814,7 @@ int _snd_pcm_softvol_open(snd_pcm_t **pcmp, const char *name, | |||
| 		snd_config_delete(sconf); | ||||
| 		return -EINVAL; | ||||
| 	} | ||||
| 	err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode); | ||||
| 	err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode, conf); | ||||
| 	snd_config_delete(sconf); | ||||
| 	if (err < 0) | ||||
| 		return err; | ||||
|  |  | |||
|  | @ -53,6 +53,10 @@ typedef struct { | |||
| 	snd_seq_event_t out_event; | ||||
| 	int pending; | ||||
| } snd_rawmidi_virtual_t; | ||||
| 
 | ||||
| int _snd_seq_open_lconf(snd_seq_t **seqp, const char *name,  | ||||
| 			int streams, int mode, snd_config_t *lconf, | ||||
| 			snd_config_t *parent_conf); | ||||
| #endif | ||||
| 
 | ||||
| static int snd_rawmidi_virtual_close(snd_rawmidi_t *rmidi) | ||||
|  | @ -439,7 +443,8 @@ int _snd_rawmidi_virtual_open(snd_rawmidi_t **inputp, snd_rawmidi_t **outputp, | |||
| 
 | ||||
| 	if (! slave_str) | ||||
| 		slave_str = "default"; | ||||
| 	err = snd_seq_open_lconf(&seq_handle, slave_str, streams, seq_mode, root); | ||||
| 	err = _snd_seq_open_lconf(&seq_handle, slave_str, streams, seq_mode, | ||||
| 				  root, conf); | ||||
| 	if (err < 0) | ||||
| 		return err; | ||||
| 
 | ||||
|  |  | |||
|  | @ -919,7 +919,8 @@ static int snd_seq_open_conf(snd_seq_t **seqp, const char *name, | |||
| } | ||||
| 
 | ||||
| static int snd_seq_open_noupdate(snd_seq_t **seqp, snd_config_t *root, | ||||
| 				 const char *name, int streams, int mode) | ||||
| 				 const char *name, int streams, int mode, | ||||
| 				 int hop) | ||||
| { | ||||
| 	int err; | ||||
| 	snd_config_t *seq_conf; | ||||
|  | @ -928,6 +929,7 @@ static int snd_seq_open_noupdate(snd_seq_t **seqp, snd_config_t *root, | |||
| 		SNDERR("Unknown SEQ %s", name); | ||||
| 		return err; | ||||
| 	} | ||||
| 	snd_config_set_hop(seq_conf, hop); | ||||
| 	err = snd_seq_open_conf(seqp, name, root, seq_conf, streams, mode); | ||||
| 	snd_config_delete(seq_conf); | ||||
| 	return err; | ||||
|  | @ -971,7 +973,7 @@ int snd_seq_open(snd_seq_t **seqp, const char *name, | |||
| 	err = snd_config_update(); | ||||
| 	if (err < 0) | ||||
| 		return err; | ||||
| 	return snd_seq_open_noupdate(seqp, snd_config, name, streams, mode); | ||||
| 	return snd_seq_open_noupdate(seqp, snd_config, name, streams, mode, 0); | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  | @ -993,9 +995,22 @@ int snd_seq_open_lconf(snd_seq_t **seqp, const char *name, | |||
| 		       int streams, int mode, snd_config_t *lconf) | ||||
| { | ||||
| 	assert(seqp && name && lconf); | ||||
| 	return snd_seq_open_noupdate(seqp, lconf, name, streams, mode); | ||||
| 	return snd_seq_open_noupdate(seqp, lconf, name, streams, mode, 0); | ||||
| } | ||||
| 
 | ||||
| #ifndef DOC_HIDDEN | ||||
| int _snd_seq_open_lconf(snd_seq_t **seqp, const char *name,  | ||||
| 			int streams, int mode, snd_config_t *lconf, | ||||
| 			snd_config_t *parent_conf) | ||||
| { | ||||
| 	int hop; | ||||
| 	assert(seqp && name && lconf); | ||||
| 	if ((hop = snd_config_check_hop(parent_conf)) < 0) | ||||
| 		return hop; | ||||
| 	return snd_seq_open_noupdate(seqp, lconf, name, streams, mode, hop + 1); | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| /**
 | ||||
|  * \brief Close the sequencer | ||||
|  * \param seq Handle returned from #snd_seq_open() | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Takashi Iwai
						Takashi Iwai