Home | History | Annotate | Download | only in hal
      1 /*
      2  * Copyright (C) 2014 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15 */
     16 
     17 #define LOG_TAG "platform_info"
     18 #define LOG_NDDEBUG 0
     19 
     20 #include <errno.h>
     21 #include <stdio.h>
     22 #include <expat.h>
     23 #include <cutils/log.h>
     24 #include <audio_hw.h>
     25 #include "platform_api.h"
     26 #include <platform.h>
     27 #include <math.h>
     28 
     29 typedef enum {
     30     ROOT,
     31     ACDB,
     32     PCM_ID,
     33     BACKEND_NAME,
     34     CONFIG_PARAMS,
     35     OPERATOR_SPECIFIC,
     36     GAIN_LEVEL_MAPPING,
     37     APP_TYPE,
     38 } section_t;
     39 
     40 typedef void (* section_process_fn)(const XML_Char **attr);
     41 
     42 static void process_acdb_id(const XML_Char **attr);
     43 static void process_pcm_id(const XML_Char **attr);
     44 static void process_backend_name(const XML_Char **attr);
     45 static void process_config_params(const XML_Char **attr);
     46 static void process_root(const XML_Char **attr);
     47 static void process_operator_specific(const XML_Char **attr);
     48 static void process_gain_db_to_level_map(const XML_Char **attr);
     49 static void process_app_type(const XML_Char **attr);
     50 
     51 static section_process_fn section_table[] = {
     52     [ROOT] = process_root,
     53     [ACDB] = process_acdb_id,
     54     [PCM_ID] = process_pcm_id,
     55     [BACKEND_NAME] = process_backend_name,
     56     [CONFIG_PARAMS] = process_config_params,
     57     [OPERATOR_SPECIFIC] = process_operator_specific,
     58     [GAIN_LEVEL_MAPPING] = process_gain_db_to_level_map,
     59     [APP_TYPE] = process_app_type,
     60 };
     61 
     62 static set_parameters_fn set_parameters = &platform_set_parameters;
     63 
     64 static section_t section;
     65 
     66 struct platform_info {
     67     bool              do_full_parse;
     68     void             *platform;
     69     struct str_parms *kvpairs;
     70 };
     71 
     72 static struct platform_info my_data = {true, NULL, NULL};
     73 
     74 /*
     75  * <audio_platform_info>
     76  * <acdb_ids>
     77  * <device name="???" acdb_id="???"/>
     78  * ...
     79  * ...
     80  * </acdb_ids>
     81  * <backend_names>
     82  * <device name="???" backend="???"/>
     83  * ...
     84  * ...
     85  * </backend_names>
     86  * <pcm_ids>
     87  * <usecase name="???" type="in/out" id="???"/>
     88  * ...
     89  * ...
     90  * </pcm_ids>
     91  * <config_params>
     92  *      <param key="snd_card_name" value="msm8994-tomtom-mtp-snd-card"/>
     93  *      <param key="operator_info" value="tmus;aa;bb;cc"/>
     94  *      <param key="operator_info" value="sprint;xx;yy;zz"/>
     95  *      ...
     96  *      ...
     97  * </config_params>
     98  *
     99  * <operator_specific>
    100  *      <device name="???" operator="???" mixer_path="???" acdb_id="???"/>
    101  *      ...
    102  *      ...
    103  * </operator_specific>
    104  *
    105  * </audio_platform_info>
    106  */
    107 
    108 static void process_root(const XML_Char **attr __unused)
    109 {
    110 }
    111 
    112 /* mapping from usecase to pcm dev id */
    113 static void process_pcm_id(const XML_Char **attr)
    114 {
    115     int index;
    116 
    117     if (strcmp(attr[0], "name") != 0) {
    118         ALOGE("%s: 'name' not found, no pcm_id set!", __func__);
    119         goto done;
    120     }
    121 
    122     index = platform_get_usecase_index((char *)attr[1]);
    123     if (index < 0) {
    124         ALOGE("%s: usecase %s in %s not found!",
    125               __func__, attr[1], PLATFORM_INFO_XML_PATH);
    126         goto done;
    127     }
    128 
    129     if (strcmp(attr[2], "type") != 0) {
    130         ALOGE("%s: usecase type not mentioned", __func__);
    131         goto done;
    132     }
    133 
    134     int type = -1;
    135 
    136     if (!strcasecmp((char *)attr[3], "in")) {
    137         type = 1;
    138     } else if (!strcasecmp((char *)attr[3], "out")) {
    139         type = 0;
    140     } else {
    141         ALOGE("%s: type must be IN or OUT", __func__);
    142         goto done;
    143     }
    144 
    145     if (strcmp(attr[4], "id") != 0) {
    146         ALOGE("%s: usecase id not mentioned", __func__);
    147         goto done;
    148     }
    149 
    150     int id = atoi((char *)attr[5]);
    151 
    152     if (platform_set_usecase_pcm_id(index, type, id) < 0) {
    153         ALOGE("%s: usecase %s in %s, type %d id %d was not set!",
    154               __func__, attr[1], PLATFORM_INFO_XML_PATH, type, id);
    155         goto done;
    156     }
    157 
    158 done:
    159     return;
    160 }
    161 
    162 /* backend to be used for a device */
    163 static void process_backend_name(const XML_Char **attr)
    164 {
    165     int index;
    166     char *hw_interface = NULL;
    167 
    168     if (strcmp(attr[0], "name") != 0) {
    169         ALOGE("%s: 'name' not found, no ACDB ID set!", __func__);
    170         goto done;
    171     }
    172 
    173     index = platform_get_snd_device_index((char *)attr[1]);
    174     if (index < 0) {
    175         ALOGE("%s: Device %s in %s not found, no ACDB ID set!",
    176               __func__, attr[1], PLATFORM_INFO_XML_PATH);
    177         goto done;
    178     }
    179 
    180     if (strcmp(attr[2], "backend") != 0) {
    181         ALOGE("%s: Device %s in %s has no backed set!",
    182               __func__, attr[1], PLATFORM_INFO_XML_PATH);
    183         goto done;
    184     }
    185 
    186     if (attr[4] != NULL) {
    187         if (strcmp(attr[4], "interface") != 0) {
    188             hw_interface = NULL;
    189         } else {
    190             hw_interface = (char *)attr[5];
    191         }
    192     }
    193 
    194     if (platform_set_snd_device_backend(index, attr[3], hw_interface) < 0) {
    195         ALOGE("%s: Device %s in %s, backend %s was not set!",
    196               __func__, attr[1], PLATFORM_INFO_XML_PATH, attr[3]);
    197         goto done;
    198     }
    199 
    200 done:
    201     return;
    202 }
    203 
    204 static void process_gain_db_to_level_map(const XML_Char **attr)
    205 {
    206     struct amp_db_and_gain_table tbl_entry;
    207 
    208     if ((strcmp(attr[0], "db") != 0) ||
    209         (strcmp(attr[2], "level") != 0)) {
    210         ALOGE("%s: invalid attribute passed  %s %sexpected amp db level",
    211                __func__, attr[0], attr[2]);
    212         goto done;
    213     }
    214 
    215     tbl_entry.db = atof(attr[1]);
    216     tbl_entry.amp = exp(tbl_entry.db * 0.115129f);
    217     tbl_entry.level = atoi(attr[3]);
    218 
    219     //custome level should be > 0. Level 0 is fixed for default
    220     CHECK(tbl_entry.level > 0);
    221 
    222     ALOGV("%s: amp [%f]  db [%f] level [%d]", __func__,
    223            tbl_entry.amp, tbl_entry.db, tbl_entry.level);
    224     platform_add_gain_level_mapping(&tbl_entry);
    225 
    226 done:
    227     return;
    228 }
    229 
    230 static void process_acdb_id(const XML_Char **attr)
    231 {
    232     int index;
    233 
    234     if (strcmp(attr[0], "name") != 0) {
    235         ALOGE("%s: 'name' not found, no ACDB ID set!", __func__);
    236         goto done;
    237     }
    238 
    239     index = platform_get_snd_device_index((char *)attr[1]);
    240     if (index < 0) {
    241         ALOGE("%s: Device %s in %s not found, no ACDB ID set!",
    242               __func__, attr[1], PLATFORM_INFO_XML_PATH);
    243         goto done;
    244     }
    245 
    246     if (strcmp(attr[2], "acdb_id") != 0) {
    247         ALOGE("%s: Device %s in %s has no acdb_id, no ACDB ID set!",
    248               __func__, attr[1], PLATFORM_INFO_XML_PATH);
    249         goto done;
    250     }
    251 
    252     if (platform_set_snd_device_acdb_id(index, atoi((char *)attr[3])) < 0) {
    253         ALOGE("%s: Device %s in %s, ACDB ID %d was not set!",
    254               __func__, attr[1], PLATFORM_INFO_XML_PATH, atoi((char *)attr[3]));
    255         goto done;
    256     }
    257 
    258 done:
    259     return;
    260 }
    261 
    262 
    263 static void process_operator_specific(const XML_Char **attr)
    264 {
    265     snd_device_t snd_device = SND_DEVICE_NONE;
    266 
    267     if (strcmp(attr[0], "name") != 0) {
    268         ALOGE("%s: 'name' not found", __func__);
    269         goto done;
    270     }
    271 
    272     snd_device = platform_get_snd_device_index((char *)attr[1]);
    273     if (snd_device < 0) {
    274         ALOGE("%s: Device %s in %s not found, no ACDB ID set!",
    275               __func__, (char *)attr[3], PLATFORM_INFO_XML_PATH);
    276         goto done;
    277     }
    278 
    279     if (strcmp(attr[2], "operator") != 0) {
    280         ALOGE("%s: 'operator' not found", __func__);
    281         goto done;
    282     }
    283 
    284     if (strcmp(attr[4], "mixer_path") != 0) {
    285         ALOGE("%s: 'mixer_path' not found", __func__);
    286         goto done;
    287     }
    288 
    289     if (strcmp(attr[6], "acdb_id") != 0) {
    290         ALOGE("%s: 'acdb_id' not found", __func__);
    291         goto done;
    292     }
    293 
    294     platform_add_operator_specific_device(snd_device, (char *)attr[3], (char *)attr[5], atoi((char *)attr[7]));
    295 
    296 done:
    297     return;
    298 }
    299 
    300 /* platform specific configuration key-value pairs */
    301 static void process_config_params(const XML_Char **attr)
    302 {
    303     if (strcmp(attr[0], "key") != 0) {
    304         ALOGE("%s: 'key' not found", __func__);
    305         goto done;
    306     }
    307 
    308     if (strcmp(attr[2], "value") != 0) {
    309         ALOGE("%s: 'value' not found", __func__);
    310         goto done;
    311     }
    312 
    313     str_parms_add_str(my_data.kvpairs, (char*)attr[1], (char*)attr[3]);
    314     set_parameters(my_data.platform, my_data.kvpairs);
    315 done:
    316     return;
    317 }
    318 
    319 static void process_app_type(const XML_Char **attr)
    320 {
    321     if (strcmp(attr[0], "uc_type")) {
    322         ALOGE("%s: uc_type not found", __func__);
    323         goto done;
    324     }
    325 
    326     if (strcmp(attr[2], "mode")) {
    327         ALOGE("%s: mode not found", __func__);
    328         goto done;
    329     }
    330 
    331     if (strcmp(attr[4], "bit_width")) {
    332         ALOGE("%s: bit_width not found", __func__);
    333         goto done;
    334     }
    335 
    336     if (strcmp(attr[6], "id")) {
    337         ALOGE("%s: id not found", __func__);
    338         goto done;
    339     }
    340 
    341     if (strcmp(attr[8], "max_rate")) {
    342         ALOGE("%s: max rate not found", __func__);
    343         goto done;
    344     }
    345 
    346     platform_add_app_type(attr[1], attr[3], atoi(attr[5]), atoi(attr[7]),
    347                           atoi(attr[9]));
    348 done:
    349     return;
    350 }
    351 
    352 static void start_tag(void *userdata __unused, const XML_Char *tag_name,
    353                       const XML_Char **attr)
    354 {
    355     const XML_Char              *attr_name = NULL;
    356     const XML_Char              *attr_value = NULL;
    357     unsigned int                i;
    358 
    359 
    360     if (my_data.do_full_parse) {
    361         if (strcmp(tag_name, "acdb_ids") == 0) {
    362             section = ACDB;
    363         } else if (strcmp(tag_name, "pcm_ids") == 0) {
    364             section = PCM_ID;
    365         } else if (strcmp(tag_name, "backend_names") == 0) {
    366             section = BACKEND_NAME;
    367         } else if (strcmp(tag_name, "config_params") == 0) {
    368             section = CONFIG_PARAMS;
    369         } else if (strcmp(tag_name, "operator_specific") == 0) {
    370             section = OPERATOR_SPECIFIC;
    371         } else if (strcmp(tag_name, "gain_db_to_level_mapping") == 0) {
    372             section = GAIN_LEVEL_MAPPING;
    373         } else if (strcmp(tag_name, "app_types") == 0) {
    374             section = APP_TYPE;
    375         } else if (strcmp(tag_name, "device") == 0) {
    376             if ((section != ACDB) && (section != BACKEND_NAME) && (section != OPERATOR_SPECIFIC)) {
    377                 ALOGE("device tag only supported for acdb/backend names");
    378                 return;
    379             }
    380 
    381             /* call into process function for the current section */
    382             section_process_fn fn = section_table[section];
    383             fn(attr);
    384         } else if (strcmp(tag_name, "usecase") == 0) {
    385             if (section != PCM_ID) {
    386                 ALOGE("usecase tag only supported with PCM_ID section");
    387                 return;
    388             }
    389 
    390             section_process_fn fn = section_table[PCM_ID];
    391             fn(attr);
    392         } else if (strcmp(tag_name, "param") == 0) {
    393             if (section != CONFIG_PARAMS) {
    394                 ALOGE("param tag only supported with CONFIG_PARAMS section");
    395                 return;
    396             }
    397 
    398             section_process_fn fn = section_table[section];
    399             fn(attr);
    400         } else if (strcmp(tag_name, "gain_level_map") == 0) {
    401             if (section != GAIN_LEVEL_MAPPING) {
    402                 ALOGE("usecase tag only supported with GAIN_LEVEL_MAPPING section");
    403                 return;
    404             }
    405 
    406             section_process_fn fn = section_table[GAIN_LEVEL_MAPPING];
    407             fn(attr);
    408         } else if (!strcmp(tag_name, "app")) {
    409             if (section != APP_TYPE) {
    410                 ALOGE("app tag only valid in section APP_TYPE");
    411                 return;
    412             }
    413 
    414             section_process_fn fn = section_table[APP_TYPE];
    415             fn(attr);
    416         }
    417     } else {
    418         if(strcmp(tag_name, "config_params") == 0) {
    419             section = CONFIG_PARAMS;
    420         } else if (strcmp(tag_name, "param") == 0) {
    421             if (section != CONFIG_PARAMS) {
    422                 ALOGE("param tag only supported with CONFIG_PARAMS section");
    423                 return;
    424             }
    425 
    426             section_process_fn fn = section_table[section];
    427             fn(attr);
    428         }
    429     }
    430 
    431     return;
    432 }
    433 
    434 static void end_tag(void *userdata __unused, const XML_Char *tag_name)
    435 {
    436     if (strcmp(tag_name, "acdb_ids") == 0) {
    437         section = ROOT;
    438     } else if (strcmp(tag_name, "pcm_ids") == 0) {
    439         section = ROOT;
    440     } else if (strcmp(tag_name, "backend_names") == 0) {
    441         section = ROOT;
    442     } else if (strcmp(tag_name, "config_params") == 0) {
    443         section = ROOT;
    444     } else if (strcmp(tag_name, "operator_specific") == 0) {
    445         section = ROOT;
    446     } else if (strcmp(tag_name, "gain_db_to_level_mapping") == 0) {
    447         section = ROOT;
    448     } else if (strcmp(tag_name, "app_types") == 0) {
    449         section = ROOT;
    450     }
    451 }
    452 
    453 int snd_card_info_init(const char *filename, void *platform, set_parameters_fn fn)
    454 {
    455     set_parameters = fn;
    456     my_data.do_full_parse = false;
    457     return platform_info_init(filename, platform);
    458 }
    459 
    460 int platform_info_init(const char *filename, void *platform)
    461 {
    462     XML_Parser      parser;
    463     FILE            *file;
    464     int             ret = 0;
    465     int             bytes_read;
    466     void            *buf;
    467     static const uint32_t kBufSize = 1024;
    468     char   platform_info_file_name[MIXER_PATH_MAX_LENGTH]= {0};
    469     section = ROOT;
    470 
    471     if (filename == NULL) {
    472         strlcpy(platform_info_file_name, PLATFORM_INFO_XML_PATH, MIXER_PATH_MAX_LENGTH);
    473     } else {
    474         strlcpy(platform_info_file_name, filename, MIXER_PATH_MAX_LENGTH);
    475     }
    476 
    477     ALOGV("%s: platform info file name is %s", __func__, platform_info_file_name);
    478 
    479     file = fopen(platform_info_file_name, "r");
    480 
    481     if (!file) {
    482         ALOGD("%s: Failed to open %s, using defaults.",
    483             __func__, platform_info_file_name);
    484         ret = -ENODEV;
    485         goto done;
    486     }
    487 
    488     parser = XML_ParserCreate(NULL);
    489     if (!parser) {
    490         ALOGE("%s: Failed to create XML parser!", __func__);
    491         ret = -ENODEV;
    492         goto err_close_file;
    493     }
    494 
    495     my_data.platform = platform;
    496     my_data.kvpairs = str_parms_create();
    497 
    498     XML_SetElementHandler(parser, start_tag, end_tag);
    499 
    500     while (1) {
    501         buf = XML_GetBuffer(parser, kBufSize);
    502         if (buf == NULL) {
    503             ALOGE("%s: XML_GetBuffer failed", __func__);
    504             ret = -ENOMEM;
    505             goto err_free_parser;
    506         }
    507 
    508         bytes_read = fread(buf, 1, kBufSize, file);
    509         if (bytes_read < 0) {
    510             ALOGE("%s: fread failed, bytes read = %d", __func__, bytes_read);
    511              ret = bytes_read;
    512             goto err_free_parser;
    513         }
    514 
    515         if (XML_ParseBuffer(parser, bytes_read,
    516                             bytes_read == 0) == XML_STATUS_ERROR) {
    517             ALOGE("%s: XML_ParseBuffer failed, for %s",
    518                 __func__, platform_info_file_name);
    519             ret = -EINVAL;
    520             goto err_free_parser;
    521         }
    522 
    523         if (bytes_read == 0)
    524             break;
    525     }
    526 
    527     set_parameters = &platform_set_parameters;
    528     my_data.do_full_parse = true;
    529 
    530 err_free_parser:
    531     XML_ParserFree(parser);
    532 err_close_file:
    533     fclose(file);
    534 done:
    535     return ret;
    536 }
    537