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