diff --git a/src/ucm/parser.c b/src/ucm/parser.c index f61201a6..798bf48e 100644 --- a/src/ucm/parser.c +++ b/src/ucm/parser.c @@ -56,6 +56,9 @@ static const char * const component_dir[] = { NULL, /* terminator */ }; +static int filename_filter(const struct dirent *dirent); +static int is_component_directory(const char *dir); + static int parse_sequence(snd_use_case_mgr_t *uc_mgr, struct list_head *base, snd_config_t *cfg); @@ -1329,6 +1332,66 @@ static int parse_master_file(snd_use_case_mgr_t *uc_mgr, snd_config_t *cfg) return 0; } +/* find the card in the local machine and store the card long name */ +static int get_card_long_name(snd_use_case_mgr_t *mgr) +{ + const char *card_name = mgr->card_name; + snd_ctl_t *handle; + int card, err; + snd_ctl_card_info_t *info; + const char *_name, *_long_name; + + snd_ctl_card_info_alloca(&info); + + card = -1; + if (snd_card_next(&card) < 0 || card < 0) { + uc_error("no soundcards found..."); + return -1; + } + + while (card >= 0) { + char name[32]; + + sprintf(name, "hw:%d", card); + err = snd_ctl_open(&handle, name, 0); + if (err < 0) { + uc_error("control open (%i): %s", card, + snd_strerror(err)); + goto next_card; + } + + err = snd_ctl_card_info(handle, info); + if (err < 0) { + uc_error("control hardware info (%i): %s", card, + snd_strerror(err)); + snd_ctl_close(handle); + goto next_card; + } + + /* Find the local card by comparing the given name with the + * card short name and long name. The given card name may be + * either a short name or long name, because users may open + * the card by either of the two names. + */ + _name = snd_ctl_card_info_get_name(info); + _long_name = snd_ctl_card_info_get_longname(info); + if (!strcmp(card_name, _name) + || !strcmp(card_name, _long_name)) { + strcpy(mgr->card_long_name, _long_name); + snd_ctl_close(handle); + return 0; + } + + snd_ctl_close(handle); +next_card: + if (snd_card_next(&card) < 0) { + uc_error("snd_card_next"); + break; + } + } + + return -1; +} static int load_master_config(const char *card_name, snd_config_t **cfg) { char filename[MAX_FILE]; @@ -1356,15 +1419,43 @@ static int load_master_config(const char *card_name, snd_config_t **cfg) return 0; } -/* load master use case file for sound card */ +/* load master use case file for sound card + * + * The same ASoC machine driver can be shared by many different devices. + * For user space to differentiate them and get the best device-specific + * configuration, ASoC machine drivers may use the DMI info + * (vendor-product-version-board) as the card long name. And user space can + * define configuration files like longnamei/longname.conf for a specific device. + * + * This function will try to find the card in the local machine and get its + * long name, then load the file longname/longname.conf to get the best + * device-specific configuration. If the card is not found in the local + * machine or the device-specific file is not available, fall back to load + * the default configuration file name/name.conf. + */ int uc_mgr_import_master_config(snd_use_case_mgr_t *uc_mgr) { snd_config_t *cfg; int err; - err = load_master_config(uc_mgr->card_name, &cfg); - if (err < 0) - return err; + err = get_card_long_name(uc_mgr); + if (err == 0) /* load file that maches the card long name */ + err = load_master_config(uc_mgr->card_long_name, &cfg); + + if (err == 0) { + /* got device-specific file that matches the card long name */ + strcpy(uc_mgr->conf_file_name, uc_mgr->card_long_name); + } else { + /* Fall back to the file that maches the given card name, + * either short name or long name (users may open a card by + * its name or long name). + */ + err = load_master_config(uc_mgr->card_name, &cfg); + if (err < 0) + return err; + strcpy(uc_mgr->conf_file_name, uc_mgr->card_name); + } + err = parse_master_file(uc_mgr, cfg); snd_config_delete(cfg); if (err < 0) diff --git a/src/ucm/ucm_local.h b/src/ucm/ucm_local.h index e41aafa4..299a5b96 100644 --- a/src/ucm/ucm_local.h +++ b/src/ucm/ucm_local.h @@ -191,6 +191,8 @@ struct use_case_verb { */ struct snd_use_case_mgr { char *card_name; + char card_long_name[MAX_CARD_LONG_NAME]; + char conf_file_name[MAX_CARD_LONG_NAME]; char *comment; /* use case verb, devices and modifier configs parsed from files */