mirror of
				https://github.com/alsa-project/alsa-lib.git
				synced 2025-11-03 09:01:52 -05:00 
			
		
		
		
	ucm: add _identifiers list
Signed-off-by: Jaroslav Kysela <perex@perex.cz>
This commit is contained in:
		
							parent
							
								
									9baf64da2f
								
							
						
					
					
						commit
						ebdd2b6cdb
					
				
					 2 changed files with 208 additions and 61 deletions
				
			
		| 
						 | 
					@ -206,6 +206,7 @@ int snd_use_case_free_list(const char *list[], int items);
 | 
				
			||||||
 *   - _enadevs			- get list of enabled devices
 | 
					 *   - _enadevs			- get list of enabled devices
 | 
				
			||||||
 *   - _enamods			- get list of enabled modifiers
 | 
					 *   - _enamods			- get list of enabled modifiers
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 | 
					 *   - _identifiers/{modifier}|{device}[/{verb}]     - list of value identifiers
 | 
				
			||||||
 *   - _supporteddevs/{modifier}|{device}[/{verb}]   - list of supported devices
 | 
					 *   - _supporteddevs/{modifier}|{device}[/{verb}]   - list of supported devices
 | 
				
			||||||
 *   - _conflictingdevs/{modifier}|{device}[/{verb}] - list of conflicting devices
 | 
					 *   - _conflictingdevs/{modifier}|{device}[/{verb}] - list of conflicting devices
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										228
									
								
								src/ucm/main.c
									
										
									
									
									
								
							
							
						
						
									
										228
									
								
								src/ucm/main.c
									
										
									
									
									
								
							| 
						 | 
					@ -1072,7 +1072,6 @@ int snd_use_case_mgr_reset(snd_use_case_mgr_t *uc_mgr)
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * \brief Get list of verbs in pair verbname+comment
 | 
					 * \brief Get list of verbs in pair verbname+comment
 | 
				
			||||||
 * \param list Returned list
 | 
					 * \param list Returned list
 | 
				
			||||||
 * \param verbname For verb (NULL = current)
 | 
					 | 
				
			||||||
 * \return Number of list entries if success, otherwise a negative error code
 | 
					 * \return Number of list entries if success, otherwise a negative error code
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
static int get_verb_list(snd_use_case_mgr_t *uc_mgr, const char **list[])
 | 
					static int get_verb_list(snd_use_case_mgr_t *uc_mgr, const char **list[])
 | 
				
			||||||
| 
						 | 
					@ -1181,7 +1180,6 @@ static int get_supcon_device_list(snd_use_case_mgr_t *uc_mgr,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return -ENOENT;
 | 
						return -ENOENT;
 | 
				
			||||||
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
| 
						 | 
					@ -1211,42 +1209,202 @@ static int get_conflicting_device_list(snd_use_case_mgr_t *uc_mgr,
 | 
				
			||||||
#ifndef DOC_HIDDEN
 | 
					#ifndef DOC_HIDDEN
 | 
				
			||||||
struct myvalue {
 | 
					struct myvalue {
 | 
				
			||||||
	struct list_head list;
 | 
						struct list_head list;
 | 
				
			||||||
        char *value;
 | 
						const char *text;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * \brief Convert myvalue list string list
 | 
				
			||||||
 | 
					 * \param list myvalue list
 | 
				
			||||||
 | 
					 * \param res string list
 | 
				
			||||||
 | 
					 * \retval Number of list entries if success, otherwise a negativer error code
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static int myvalue_to_str_list(struct list_head *list, char ***res)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct list_head *pos;
 | 
				
			||||||
 | 
						struct myvalue *value;
 | 
				
			||||||
 | 
						char **p;
 | 
				
			||||||
 | 
						int cnt;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						cnt = alloc_str_list(list, 1, res);
 | 
				
			||||||
 | 
						if (cnt < 0)
 | 
				
			||||||
 | 
							return cnt;
 | 
				
			||||||
 | 
						p = *res;
 | 
				
			||||||
 | 
						list_for_each(pos, list) {
 | 
				
			||||||
 | 
							value = list_entry(pos, struct myvalue, list);
 | 
				
			||||||
 | 
							*p = strdup(value->text);
 | 
				
			||||||
 | 
							if (*p == NULL) {
 | 
				
			||||||
 | 
								snd_use_case_free_list((const char **)p, cnt);
 | 
				
			||||||
 | 
								return -ENOMEM;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							p++;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return cnt;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * \brief Free myvalue list
 | 
				
			||||||
 | 
					 * \param list myvalue list
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static void myvalue_list_free(struct list_head *list)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct list_head *pos, *npos;
 | 
				
			||||||
 | 
						struct myvalue *value;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						list_for_each_safe(pos, npos, list) {
 | 
				
			||||||
 | 
							value = list_entry(pos, struct myvalue, list);
 | 
				
			||||||
 | 
							list_del(&value->list);
 | 
				
			||||||
 | 
							free(value);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * \brief Merge one value to the myvalue list
 | 
				
			||||||
 | 
					 * \param list The list with values
 | 
				
			||||||
 | 
					 * \param value The value to be merged (without duplicates)
 | 
				
			||||||
 | 
					 * \return 1 if dup, 0 if success, otherwise a negative error code
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static int merge_value(struct list_head *list, const char *text)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct list_head *pos;
 | 
				
			||||||
 | 
						struct myvalue *value;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						list_for_each(pos, list) {
 | 
				
			||||||
 | 
							value = list_entry(pos, struct myvalue, list);
 | 
				
			||||||
 | 
							if (strcmp(value->text, text) == 0)
 | 
				
			||||||
 | 
								return 1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						value = malloc(sizeof(*value));
 | 
				
			||||||
 | 
						if (value == NULL)
 | 
				
			||||||
 | 
							return -ENOMEM;
 | 
				
			||||||
 | 
						value->text = text;
 | 
				
			||||||
 | 
						list_add_tail(&value->list, list);
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * \brief Find all values for given identifier
 | 
				
			||||||
 | 
					 * \param list Returned list
 | 
				
			||||||
 | 
					 * \param source Source list with ucm_value structures
 | 
				
			||||||
 | 
					 * \return Zero if success, otherwise a negative error code
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static int add_identifiers(struct list_head *list,
 | 
				
			||||||
 | 
								   struct list_head *source)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct ucm_value *v;
 | 
				
			||||||
 | 
						struct list_head *pos;
 | 
				
			||||||
 | 
						int err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						list_for_each(pos, source) {
 | 
				
			||||||
 | 
							v = list_entry(pos, struct ucm_value, list);
 | 
				
			||||||
 | 
							err = merge_value(list, v->name);
 | 
				
			||||||
 | 
							if (err < 0)
 | 
				
			||||||
 | 
								return err;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * \brief Find all values for given identifier
 | 
				
			||||||
 | 
					 * \param list Returned list
 | 
				
			||||||
 | 
					 * \param identifier Identifier
 | 
				
			||||||
 | 
					 * \param source Source list with ucm_value structures
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
static int add_values(struct list_head *list,
 | 
					static int add_values(struct list_head *list,
 | 
				
			||||||
                      const char *identifier,
 | 
					                      const char *identifier,
 | 
				
			||||||
                      struct list_head *source)
 | 
					                      struct list_head *source)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct ucm_value *v;
 | 
						struct ucm_value *v;
 | 
				
			||||||
        struct myvalue *val;
 | 
						struct list_head *pos;
 | 
				
			||||||
        struct list_head *pos, *pos1;
 | 
						int err;
 | 
				
			||||||
        int match;
 | 
					 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
	list_for_each(pos, source) {
 | 
						list_for_each(pos, source) {
 | 
				
			||||||
		v = list_entry(pos, struct ucm_value, list);
 | 
							v = list_entry(pos, struct ucm_value, list);
 | 
				
			||||||
		if (check_identifier(identifier, v->name)) {
 | 
							if (check_identifier(identifier, v->name)) {
 | 
				
			||||||
                        match = 0;
 | 
								err = merge_value(list, v->data);
 | 
				
			||||||
                        list_for_each(pos1, list) {
 | 
								if (err < 0)
 | 
				
			||||||
                                val = list_entry(pos1, struct myvalue, list);
 | 
									return err;
 | 
				
			||||||
                                if (strcmp(val->value, v->data) == 0) {
 | 
					 | 
				
			||||||
                                        match = 1;
 | 
					 | 
				
			||||||
                                        break;
 | 
					 | 
				
			||||||
                                }
 | 
					 | 
				
			||||||
                        }
 | 
					 | 
				
			||||||
                        if (!match) {
 | 
					 | 
				
			||||||
                                val = malloc(sizeof(struct myvalue));
 | 
					 | 
				
			||||||
                                if (val == NULL)
 | 
					 | 
				
			||||||
                                        return -ENOMEM;
 | 
					 | 
				
			||||||
				val->value = v->data;
 | 
					 | 
				
			||||||
                                list_add_tail(&val->list, list);
 | 
					 | 
				
			||||||
                        }
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * \brief compare two identifiers
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static int identifier_cmp(const void *_a, const void *_b)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						const char * const *a = _a;
 | 
				
			||||||
 | 
						const char * const *b = _b;
 | 
				
			||||||
 | 
						return strcmp(*a, *b);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * \brief Get list of available identifiers
 | 
				
			||||||
 | 
					 * \param list Returned list
 | 
				
			||||||
 | 
					 * \param name Name of verb or modifier to query
 | 
				
			||||||
 | 
					 * \return Number of list entries if success, otherwise a negative error code
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static int get_identifiers_list(snd_use_case_mgr_t *uc_mgr,
 | 
				
			||||||
 | 
									const char **list[], char *name)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct use_case_verb *verb;
 | 
				
			||||||
 | 
						struct use_case_modifier *modifier;
 | 
				
			||||||
 | 
						struct use_case_device *device;
 | 
				
			||||||
 | 
						struct list_head mylist;
 | 
				
			||||||
 | 
						struct list_head *value_list;
 | 
				
			||||||
 | 
						char *str, **res;
 | 
				
			||||||
 | 
						int err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!name)
 | 
				
			||||||
 | 
							return -ENOENT;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						str = strchr(name, '/');
 | 
				
			||||||
 | 
						if (str) {
 | 
				
			||||||
 | 
							*str = '\0';
 | 
				
			||||||
 | 
							verb = find_verb(uc_mgr, str + 1);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						else {
 | 
				
			||||||
 | 
							verb = uc_mgr->active_verb;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (!verb)
 | 
				
			||||||
 | 
							return -ENOENT;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						value_list = NULL;
 | 
				
			||||||
 | 
						modifier = find_modifier(uc_mgr, verb, name, 0);
 | 
				
			||||||
 | 
						if (modifier) {
 | 
				
			||||||
 | 
							value_list = &modifier->value_list;
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							device = find_device(uc_mgr, verb, name, 0);
 | 
				
			||||||
 | 
							if (device)
 | 
				
			||||||
 | 
								value_list = &device->value_list;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (value_list == NULL)
 | 
				
			||||||
 | 
							return -ENOENT;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						INIT_LIST_HEAD(&mylist);
 | 
				
			||||||
 | 
						err = add_identifiers(&mylist, &uc_mgr->value_list);
 | 
				
			||||||
 | 
						if (err < 0)
 | 
				
			||||||
 | 
							goto __fail;
 | 
				
			||||||
 | 
						err = add_identifiers(&mylist, &verb->value_list);
 | 
				
			||||||
 | 
						if (err < 0)
 | 
				
			||||||
 | 
							goto __fail;
 | 
				
			||||||
 | 
						err = add_identifiers(&mylist, value_list);
 | 
				
			||||||
 | 
						if (err < 0)
 | 
				
			||||||
 | 
							goto __fail;
 | 
				
			||||||
 | 
						err = myvalue_to_str_list(&mylist, &res);
 | 
				
			||||||
 | 
						if (err > 0)
 | 
				
			||||||
 | 
							*list = (const char **)res;
 | 
				
			||||||
 | 
						else if (err == 0)
 | 
				
			||||||
 | 
							*list = NULL;
 | 
				
			||||||
 | 
					__fail:
 | 
				
			||||||
 | 
						myvalue_list_free(&mylist);
 | 
				
			||||||
 | 
						if (err <= 0)
 | 
				
			||||||
 | 
							return err;
 | 
				
			||||||
 | 
						qsort(*list, err, sizeof(char *), identifier_cmp);
 | 
				
			||||||
 | 
						return err;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * \brief Get list of values
 | 
					 * \brief Get list of values
 | 
				
			||||||
 * \param list Returned list
 | 
					 * \param list Returned list
 | 
				
			||||||
| 
						 | 
					@ -1258,8 +1416,7 @@ static int get_value_list(snd_use_case_mgr_t *uc_mgr,
 | 
				
			||||||
                          const char **list[],
 | 
					                          const char **list[],
 | 
				
			||||||
                          char *verbname)
 | 
					                          char *verbname)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
        struct list_head mylist, *pos, *npos;
 | 
						struct list_head mylist, *pos;
 | 
				
			||||||
        struct myvalue *val;
 | 
					 | 
				
			||||||
        struct use_case_verb *verb;
 | 
					        struct use_case_verb *verb;
 | 
				
			||||||
        struct use_case_device *dev;
 | 
					        struct use_case_device *dev;
 | 
				
			||||||
        struct use_case_modifier *mod;
 | 
					        struct use_case_modifier *mod;
 | 
				
			||||||
| 
						 | 
					@ -1292,26 +1449,13 @@ static int get_value_list(snd_use_case_mgr_t *uc_mgr,
 | 
				
			||||||
                if (err < 0)
 | 
					                if (err < 0)
 | 
				
			||||||
                        goto __fail;
 | 
					                        goto __fail;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        err = alloc_str_list(&mylist, 1, &res);
 | 
						err = myvalue_to_str_list(&mylist, &res);
 | 
				
			||||||
        if (err >= 0) {
 | 
						if (err > 0)
 | 
				
			||||||
	        *list = (const char **)res;
 | 
						        *list = (const char **)res;
 | 
				
			||||||
                list_for_each(pos, &mylist) {
 | 
						else if (err == 0)
 | 
				
			||||||
                        val = list_entry(pos, struct myvalue, list);
 | 
							*list = NULL;
 | 
				
			||||||
                        *res = strdup(val->value);
 | 
					 | 
				
			||||||
                        if (*res == NULL) {
 | 
					 | 
				
			||||||
                                snd_use_case_free_list((const char **)res, err);
 | 
					 | 
				
			||||||
                                err = -ENOMEM;
 | 
					 | 
				
			||||||
                                goto __fail;
 | 
					 | 
				
			||||||
                        }
 | 
					 | 
				
			||||||
                        res++;
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
      __fail:
 | 
					      __fail:
 | 
				
			||||||
        list_for_each_safe(pos, npos, &mylist) {
 | 
						myvalue_list_free(&mylist);
 | 
				
			||||||
                val = list_entry(pos, struct myvalue, list);
 | 
					 | 
				
			||||||
                list_del(&val->list);
 | 
					 | 
				
			||||||
                free(val);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        return err;
 | 
					        return err;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1385,6 +1529,8 @@ int snd_use_case_get_list(snd_use_case_mgr_t *uc_mgr,
 | 
				
			||||||
			err = get_device_list(uc_mgr, list, str);
 | 
								err = get_device_list(uc_mgr, list, str);
 | 
				
			||||||
                else if (check_identifier(identifier, "_modifiers"))
 | 
					                else if (check_identifier(identifier, "_modifiers"))
 | 
				
			||||||
			err = get_modifier_list(uc_mgr, list, str);
 | 
								err = get_modifier_list(uc_mgr, list, str);
 | 
				
			||||||
 | 
							else if (check_identifier(identifier, "_identifiers"))
 | 
				
			||||||
 | 
								err = get_identifiers_list(uc_mgr, list, str);
 | 
				
			||||||
		else if (check_identifier(identifier, "_supporteddevs"))
 | 
							else if (check_identifier(identifier, "_supporteddevs"))
 | 
				
			||||||
			err = get_supported_device_list(uc_mgr, list, str);
 | 
								err = get_supported_device_list(uc_mgr, list, str);
 | 
				
			||||||
		else if (check_identifier(identifier, "_conflictingdevs"))
 | 
							else if (check_identifier(identifier, "_conflictingdevs"))
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue