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:
Takashi Iwai 2006-01-30 14:41:51 +00:00
parent bf174b7046
commit eccc92a34d
29 changed files with 127 additions and 36 deletions

View file

@ -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); int snd_dlobj_cache_add(const char *name, void *dlobj, void *open_func);
void snd_dlobj_cache_cleanup(void); 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 #endif

View file

@ -440,6 +440,7 @@ struct _snd_config {
} u; } u;
struct list_head list; struct list_head list;
snd_config_t *father; snd_config_t *father;
int hop;
}; };
struct filedesc { struct filedesc {
@ -4011,6 +4012,24 @@ int snd_config_search_definition(snd_config_t *config,
return snd_config_expand(conf, config, args, NULL, result); 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 #if 0
/* Not strictly needed, but useful to check for memory leaks */ /* Not strictly needed, but useful to check for memory leaks */

View file

@ -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, 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; int err;
snd_config_t *pcm_conf; 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); SNDERR("Unknown PCM %s", name);
return err; return err;
} }
snd_config_set_hop(pcm_conf, hop);
err = snd_pcm_open_conf(pcmp, name, root, pcm_conf, stream, mode); err = snd_pcm_open_conf(pcmp, name, root, pcm_conf, stream, mode);
snd_config_delete(pcm_conf); snd_config_delete(pcm_conf);
return err; return err;
@ -2128,7 +2130,7 @@ int snd_pcm_open(snd_pcm_t **pcmp, const char *name,
err = snd_config_update(); err = snd_config_update();
if (err < 0) if (err < 0)
return err; 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) snd_config_t *lconf)
{ {
assert(pcmp && name && 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 #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, int snd_pcm_open_slave(snd_pcm_t **pcmp, snd_config_t *root,
snd_config_t *conf, snd_pcm_stream_t stream, snd_config_t *conf, snd_pcm_stream_t stream,
int mode) int mode, snd_config_t *parent_conf)
{ {
const char *str; const char *str;
int hop;
if ((hop = snd_config_check_hop(parent_conf)) < 0)
return hop;
if (snd_config_get_string(conf, &str) >= 0) 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); return snd_pcm_open_conf(pcmp, NULL, root, conf, stream, mode);
} }
#endif #endif

View file

@ -666,7 +666,7 @@ int _snd_pcm_adpcm_open(snd_pcm_t **pcmp, const char *name,
SNDERR("invalid slave format"); SNDERR("invalid slave format");
return -EINVAL; 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); snd_config_delete(sconf);
if (err < 0) if (err < 0)
return err; return err;

View file

@ -538,7 +538,7 @@ int _snd_pcm_alaw_open(snd_pcm_t **pcmp, const char *name,
SNDERR("invalid slave format"); SNDERR("invalid slave format");
return -EINVAL; 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); snd_config_delete(sconf);
if (err < 0) if (err < 0)
return err; return err;

View file

@ -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); err = snd_pcm_slave_conf(root, slave, &sconf, 0);
if (err < 0) if (err < 0)
return err; 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); snd_config_delete(sconf);
return err; return err;
} }

View file

@ -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); err = snd_pcm_slave_conf(root, slave, &sconf, 0);
if (err < 0) if (err < 0)
return err; 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); snd_config_delete(sconf);
if (err < 0) if (err < 0)
return err; return err;

View file

@ -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 * 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; snd_config_iterator_t i, next;
int err; int err;
long card = 0, device = 0, subdevice = 0; 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_for_each(i, next, sconf) {
snd_config_t *n = snd_config_iterator_entry(i); 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); 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) int snd_pcm_direct_parse_open_conf(snd_config_t *conf, struct snd_pcm_direct_open_conf *rec)
{ {

View file

@ -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); 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_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_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); int snd_timer_async(snd_timer_t *timer, int sig, pid_t pid);
struct timespec snd_pcm_hw_fast_tstamp(snd_pcm_t *pcm); struct timespec snd_pcm_hw_fast_tstamp(snd_pcm_t *pcm);

View file

@ -847,7 +847,10 @@ int snd_pcm_dmix_open(snd_pcm_t **pcmp, const char *name,
dmix->sync_ptr = snd_pcm_dmix_sync_ptr; dmix->sync_ptr = snd_pcm_dmix_sync_ptr;
if (first_instance) { 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) { if (ret < 0) {
SNDERR("unable to open slave"); SNDERR("unable to open slave");
goto _err; goto _err;
@ -1124,7 +1127,7 @@ int _snd_pcm_dmix_open(snd_pcm_t **pcmp, const char *name,
params.period_size = psize; params.period_size = psize;
params.buffer_size = bsize; 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) { if (ipc_offset < 0) {
snd_config_delete(sconf); snd_config_delete(sconf);
return ipc_offset; return ipc_offset;

View file

@ -672,7 +672,10 @@ int snd_pcm_dshare_open(snd_pcm_t **pcmp, const char *name,
dshare->sync_ptr = snd_pcm_dshare_sync_ptr; dshare->sync_ptr = snd_pcm_dshare_sync_ptr;
if (first_instance) { 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) { if (ret < 0) {
SNDERR("unable to open slave"); SNDERR("unable to open slave");
goto _err; goto _err;
@ -873,7 +876,7 @@ int _snd_pcm_dshare_open(snd_pcm_t **pcmp, const char *name,
params.period_size = psize; params.period_size = psize;
params.buffer_size = bsize; 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) { if (ipc_offset < 0) {
snd_config_delete(sconf); snd_config_delete(sconf);
return ipc_offset; return ipc_offset;

View file

@ -554,7 +554,10 @@ int snd_pcm_dsnoop_open(snd_pcm_t **pcmp, const char *name,
dsnoop->sync_ptr = snd_pcm_dsnoop_sync_ptr; dsnoop->sync_ptr = snd_pcm_dsnoop_sync_ptr;
if (first_instance) { 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) { if (ret < 0) {
SNDERR("unable to open slave"); SNDERR("unable to open slave");
goto _err; goto _err;
@ -745,7 +748,7 @@ int _snd_pcm_dsnoop_open(snd_pcm_t **pcmp, const char *name,
params.period_size = psize; params.period_size = psize;
params.buffer_size = bsize; 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) { if (ipc_offset < 0) {
snd_config_delete(sconf); snd_config_delete(sconf);
return ipc_offset; return ipc_offset;

View file

@ -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); err = snd_pcm_slave_conf(root, slave_conf, &sconf, 0);
if (err < 0) if (err < 0)
return err; 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); snd_config_delete(sconf);
if (err < 0) if (err < 0)
return err; return err;

View file

@ -556,7 +556,7 @@ int _snd_pcm_file_open(snd_pcm_t **pcmp, const char *name,
SNDERR("file is not defined"); SNDERR("file is not defined");
return -EINVAL; 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); snd_config_delete(sconf);
if (err < 0) if (err < 0)
return err; return err;

View file

@ -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); err = snd_pcm_slave_conf(root, slave, &sconf, 0);
if (err < 0) if (err < 0)
return err; 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); snd_config_delete(sconf);
if (err < 0) if (err < 0)
return err; return err;

View file

@ -662,7 +662,7 @@ int _snd_pcm_iec958_open(snd_pcm_t **pcmp, const char *name,
SNDERR("invalid slave format"); SNDERR("invalid slave format");
return -EINVAL; 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); snd_config_delete(sconf);
if (err < 0) if (err < 0)
return err; return err;

View file

@ -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); err = snd_pcm_slave_conf(root, slave, &sconf, 0);
if (err < 0) if (err < 0)
return err; 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); snd_config_delete(sconf);
if (err < 0) if (err < 0)
return err; return err;

View file

@ -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"); SNDERR("slave format is not linear integer or linear float");
return -EINVAL; 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); snd_config_delete(sconf);
if (err < 0) if (err < 0)
return err; return err;

View file

@ -552,7 +552,7 @@ int _snd_pcm_linear_open(snd_pcm_t **pcmp, const char *name,
SNDERR("slave format is not linear"); SNDERR("slave format is not linear");
return -EINVAL; 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); snd_config_delete(sconf);
if (err < 0) if (err < 0)
return err; return err;

View file

@ -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, int snd_pcm_open_slave(snd_pcm_t **pcmp, snd_config_t *root,
snd_config_t *conf, snd_pcm_stream_t stream, 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_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); int snd_pcm_hw_open_fd(snd_pcm_t **pcmp, const char *name, int fd, int mmap_emulation, int sync_ptr_ioctl);

View file

@ -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); err = snd_pcm_slave_conf(root, slave, &sconf, 0);
if (err < 0) if (err < 0)
return err; 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); snd_config_delete(sconf);
if (err < 0) if (err < 0)
return err; return err;

View file

@ -553,7 +553,7 @@ int _snd_pcm_mulaw_open(snd_pcm_t **pcmp, const char *name,
SNDERR("invalid slave format"); SNDERR("invalid slave format");
return -EINVAL; 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); snd_config_delete(sconf);
if (err < 0) if (err < 0)
return err; return err;

View file

@ -1103,7 +1103,9 @@ int _snd_pcm_multi_open(snd_pcm_t **pcmp, const char *name,
} }
for (idx = 0; idx < slaves_count; ++idx) { 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) if (err < 0)
goto _free; goto _free;
snd_config_delete(slaves_conf[idx]); snd_config_delete(slaves_conf[idx]);

View file

@ -1215,7 +1215,7 @@ int _snd_pcm_plug_open(snd_pcm_t **pcmp, const char *name,
} }
#endif #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); snd_config_delete(sconf);
if (err < 0) if (err < 0)
return err; return err;

View file

@ -1532,7 +1532,7 @@ int _snd_pcm_rate_open(snd_pcm_t **pcmp, const char *name,
SNDERR("slave format is not linear"); SNDERR("slave format is not linear");
return -EINVAL; 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); snd_config_delete(sconf);
if (err < 0) if (err < 0)
return err; return err;

View file

@ -1152,7 +1152,7 @@ int _snd_pcm_route_open(snd_pcm_t **pcmp, const char *name,
return err; 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); snd_config_delete(sconf);
if (err < 0) { if (err < 0) {
free(ttable); free(ttable);

View file

@ -814,7 +814,7 @@ int _snd_pcm_softvol_open(snd_pcm_t **pcmp, const char *name,
snd_config_delete(sconf); snd_config_delete(sconf);
return -EINVAL; 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); snd_config_delete(sconf);
if (err < 0) if (err < 0)
return err; return err;

View file

@ -53,6 +53,10 @@ typedef struct {
snd_seq_event_t out_event; snd_seq_event_t out_event;
int pending; int pending;
} snd_rawmidi_virtual_t; } 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 #endif
static int snd_rawmidi_virtual_close(snd_rawmidi_t *rmidi) 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) if (! slave_str)
slave_str = "default"; 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) if (err < 0)
return err; return err;

View file

@ -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, 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; int err;
snd_config_t *seq_conf; 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); SNDERR("Unknown SEQ %s", name);
return err; return err;
} }
snd_config_set_hop(seq_conf, hop);
err = snd_seq_open_conf(seqp, name, root, seq_conf, streams, mode); err = snd_seq_open_conf(seqp, name, root, seq_conf, streams, mode);
snd_config_delete(seq_conf); snd_config_delete(seq_conf);
return err; return err;
@ -971,7 +973,7 @@ int snd_seq_open(snd_seq_t **seqp, const char *name,
err = snd_config_update(); err = snd_config_update();
if (err < 0) if (err < 0)
return err; 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) int streams, int mode, snd_config_t *lconf)
{ {
assert(seqp && name && 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 * \brief Close the sequencer
* \param seq Handle returned from #snd_seq_open() * \param seq Handle returned from #snd_seq_open()