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 
     28 #define PLATFORM_INFO_XML_PATH      "/system/etc/audio_platform_info.xml"
     29 
     30 typedef enum {
     31     ROOT,
     32     ACDB,
     33     PCM_ID,
     34     BACKEND_NAME,
     35     CONFIG_PARAMS,
     36 } section_t;
     37 
     38 typedef void (* section_process_fn)(const XML_Char **attr);
     39 
     40 static void process_acdb_id(const XML_Char **attr);
     41 static void process_pcm_id(const XML_Char **attr);
     42 static void process_backend_name(const XML_Char **attr);
     43 static void process_config_params(const XML_Char **attr);
     44 static void process_root(const XML_Char **attr);
     45 
     46 static section_process_fn section_table[] = {
     47     [ROOT] = process_root,
     48     [ACDB] = process_acdb_id,
     49     [PCM_ID] = process_pcm_id,
     50     [BACKEND_NAME] = process_backend_name,
     51     [CONFIG_PARAMS] = process_config_params,
     52 };
     53 
     54 static section_t section;
     55 
     56 struct platform_info {
     57     void             *platform;
     58     struct str_parms *kvpairs;
     59 };
     60 
     61 static struct platform_info my_data;
     62 
     63 /*
     64  * <audio_platform_info>
     65  * <acdb_ids>
     66  * <device name="???" acdb_id="???"/>
     67  * ...
     68  * ...
     69  * </acdb_ids>
     70  * <backend_names>
     71  * <device name="???" backend="???"/>
     72  * ...
     73  * ...
     74  * </backend_names>
     75  * <pcm_ids>
     76  * <usecase name="???" type="in/out" id="???"/>
     77  * ...
     78  * ...
     79  * </pcm_ids>
     80  * <config_params>
     81  *      <param key="snd_card_name" value="msm8994-tomtom-mtp-snd-card"/>
     82  *      ...
     83  *      ...
     84  * </config_params>
     85  *
     86  * </audio_platform_info>
     87  */
     88 
     89 static void process_root(const XML_Char **attr __unused)
     90 {
     91 }
     92 
     93 /* mapping from usecase to pcm dev id */
     94 static void process_pcm_id(const XML_Char **attr)
     95 {
     96     int index;
     97 
     98     if (strcmp(attr[0], "name") != 0) {
     99         ALOGE("%s: 'name' not found, no pcm_id set!", __func__);
    100         goto done;
    101     }
    102 
    103     index = platform_get_usecase_index((char *)attr[1]);
    104     if (index < 0) {
    105         ALOGE("%s: usecase %s in %s not found!",
    106               __func__, attr[1], PLATFORM_INFO_XML_PATH);
    107         goto done;
    108     }
    109 
    110     if (strcmp(attr[2], "type") != 0) {
    111         ALOGE("%s: usecase type not mentioned", __func__);
    112         goto done;
    113     }
    114 
    115     int type = -1;
    116 
    117     if (!strcasecmp((char *)attr[3], "in")) {
    118         type = 1;
    119     } else if (!strcasecmp((char *)attr[3], "out")) {
    120         type = 0;
    121     } else {
    122         ALOGE("%s: type must be IN or OUT", __func__);
    123         goto done;
    124     }
    125 
    126     if (strcmp(attr[4], "id") != 0) {
    127         ALOGE("%s: usecase id not mentioned", __func__);
    128         goto done;
    129     }
    130 
    131     int id = atoi((char *)attr[5]);
    132 
    133     if (platform_set_usecase_pcm_id(index, type, id) < 0) {
    134         ALOGE("%s: usecase %s in %s, type %d id %d was not set!",
    135               __func__, attr[1], PLATFORM_INFO_XML_PATH, type, id);
    136         goto done;
    137     }
    138 
    139 done:
    140     return;
    141 }
    142 
    143 /* backend to be used for a device */
    144 static void process_backend_name(const XML_Char **attr)
    145 {
    146     int index;
    147     char *hw_interface = NULL;
    148 
    149     if (strcmp(attr[0], "name") != 0) {
    150         ALOGE("%s: 'name' not found, no ACDB ID set!", __func__);
    151         goto done;
    152     }
    153 
    154     index = platform_get_snd_device_index((char *)attr[1]);
    155     if (index < 0) {
    156         ALOGE("%s: Device %s in %s not found, no ACDB ID set!",
    157               __func__, attr[1], PLATFORM_INFO_XML_PATH);
    158         goto done;
    159     }
    160 
    161     if (strcmp(attr[2], "backend") != 0) {
    162         ALOGE("%s: Device %s in %s has no backed set!",
    163               __func__, attr[1], PLATFORM_INFO_XML_PATH);
    164         goto done;
    165     }
    166 
    167     if (attr[4] != NULL) {
    168         if (strcmp(attr[4], "interface") != 0) {
    169             hw_interface = NULL;
    170         } else {
    171             hw_interface = (char *)attr[5];
    172         }
    173     }
    174 
    175     if (platform_set_snd_device_backend(index, attr[3], hw_interface) < 0) {
    176         ALOGE("%s: Device %s in %s, backend %s was not set!",
    177               __func__, attr[1], PLATFORM_INFO_XML_PATH, attr[3]);
    178         goto done;
    179     }
    180 
    181 done:
    182     return;
    183 }
    184 
    185 static void process_acdb_id(const XML_Char **attr)
    186 {
    187     int index;
    188 
    189     if (strcmp(attr[0], "name") != 0) {
    190         ALOGE("%s: 'name' not found, no ACDB ID set!", __func__);
    191         goto done;
    192     }
    193 
    194     index = platform_get_snd_device_index((char *)attr[1]);
    195     if (index < 0) {
    196         ALOGE("%s: Device %s in %s not found, no ACDB ID set!",
    197               __func__, attr[1], PLATFORM_INFO_XML_PATH);
    198         goto done;
    199     }
    200 
    201     if (strcmp(attr[2], "acdb_id") != 0) {
    202         ALOGE("%s: Device %s in %s has no acdb_id, no ACDB ID set!",
    203               __func__, attr[1], PLATFORM_INFO_XML_PATH);
    204         goto done;
    205     }
    206 
    207     if (platform_set_snd_device_acdb_id(index, atoi((char *)attr[3])) < 0) {
    208         ALOGE("%s: Device %s in %s, ACDB ID %d was not set!",
    209               __func__, attr[1], PLATFORM_INFO_XML_PATH, atoi((char *)attr[3]));
    210         goto done;
    211     }
    212 
    213 done:
    214     return;
    215 }
    216 
    217 /* platform specific configuration key-value pairs */
    218 static void process_config_params(const XML_Char **attr)
    219 {
    220     if (strcmp(attr[0], "key") != 0) {
    221         ALOGE("%s: 'key' not found", __func__);
    222         goto done;
    223     }
    224 
    225     if (strcmp(attr[2], "value") != 0) {
    226         ALOGE("%s: 'value' not found", __func__);
    227         goto done;
    228     }
    229 
    230     str_parms_add_str(my_data.kvpairs, (char*)attr[1], (char*)attr[3]);
    231 done:
    232     return;
    233 }
    234 
    235 static void start_tag(void *userdata __unused, const XML_Char *tag_name,
    236                       const XML_Char **attr)
    237 {
    238     const XML_Char              *attr_name = NULL;
    239     const XML_Char              *attr_value = NULL;
    240     unsigned int                i;
    241 
    242     if (strcmp(tag_name, "acdb_ids") == 0) {
    243         section = ACDB;
    244     } else if (strcmp(tag_name, "pcm_ids") == 0) {
    245         section = PCM_ID;
    246     } else if (strcmp(tag_name, "backend_names") == 0) {
    247         section = BACKEND_NAME;
    248     } else if (strcmp(tag_name, "config_params") == 0) {
    249         section = CONFIG_PARAMS;
    250     } else if (strcmp(tag_name, "device") == 0) {
    251         if ((section != ACDB) && (section != BACKEND_NAME)) {
    252             ALOGE("device tag only supported for acdb/backend names");
    253             return;
    254         }
    255 
    256         /* call into process function for the current section */
    257         section_process_fn fn = section_table[section];
    258         fn(attr);
    259     } else if (strcmp(tag_name, "usecase") == 0) {
    260         if (section != PCM_ID) {
    261             ALOGE("usecase tag only supported with PCM_ID section");
    262             return;
    263         }
    264 
    265         section_process_fn fn = section_table[PCM_ID];
    266         fn(attr);
    267     } else if (strcmp(tag_name, "param") == 0) {
    268         if (section != CONFIG_PARAMS) {
    269             ALOGE("param tag only supported with CONFIG_PARAMS section");
    270             return;
    271         }
    272 
    273         section_process_fn fn = section_table[section];
    274         fn(attr);
    275     }
    276 
    277     return;
    278 }
    279 
    280 static void end_tag(void *userdata __unused, const XML_Char *tag_name)
    281 {
    282     if (strcmp(tag_name, "acdb_ids") == 0) {
    283         section = ROOT;
    284     } else if (strcmp(tag_name, "pcm_ids") == 0) {
    285         section = ROOT;
    286     } else if (strcmp(tag_name, "backend_names") == 0) {
    287         section = ROOT;
    288     } else if (strcmp(tag_name, "config_params") == 0) {
    289         section = ROOT;
    290         platform_set_parameters(my_data.platform, my_data.kvpairs);
    291     }
    292 }
    293 
    294 int platform_info_init(void *platform)
    295 {
    296     XML_Parser      parser;
    297     FILE            *file;
    298     int             ret = 0;
    299     int             bytes_read;
    300     void            *buf;
    301     static const uint32_t kBufSize = 1024;
    302 
    303     section = ROOT;
    304 
    305     file = fopen(PLATFORM_INFO_XML_PATH, "r");
    306     if (!file) {
    307         ALOGD("%s: Failed to open %s, using defaults.",
    308             __func__, PLATFORM_INFO_XML_PATH);
    309         ret = -ENODEV;
    310         goto done;
    311     }
    312 
    313     parser = XML_ParserCreate(NULL);
    314     if (!parser) {
    315         ALOGE("%s: Failed to create XML parser!", __func__);
    316         ret = -ENODEV;
    317         goto err_close_file;
    318     }
    319 
    320     my_data.platform = platform;
    321     my_data.kvpairs = str_parms_create();
    322 
    323     XML_SetElementHandler(parser, start_tag, end_tag);
    324 
    325     while (1) {
    326         buf = XML_GetBuffer(parser, kBufSize);
    327         if (buf == NULL) {
    328             ALOGE("%s: XML_GetBuffer failed", __func__);
    329             ret = -ENOMEM;
    330             goto err_free_parser;
    331         }
    332 
    333         bytes_read = fread(buf, 1, kBufSize, file);
    334         if (bytes_read < 0) {
    335             ALOGE("%s: fread failed, bytes read = %d", __func__, bytes_read);
    336              ret = bytes_read;
    337             goto err_free_parser;
    338         }
    339 
    340         if (XML_ParseBuffer(parser, bytes_read,
    341                             bytes_read == 0) == XML_STATUS_ERROR) {
    342             ALOGE("%s: XML_ParseBuffer failed, for %s",
    343                 __func__, PLATFORM_INFO_XML_PATH);
    344             ret = -EINVAL;
    345             goto err_free_parser;
    346         }
    347 
    348         if (bytes_read == 0)
    349             break;
    350     }
    351 
    352 err_free_parser:
    353     XML_ParserFree(parser);
    354 err_close_file:
    355     fclose(file);
    356 done:
    357     return ret;
    358 }
    359