1c72fcc34Sopenharmony_ci/* 2c72fcc34Sopenharmony_ci * Extract microphone configuration from the ACPI NHLT table 3c72fcc34Sopenharmony_ci * 4c72fcc34Sopenharmony_ci * Specification: 5c72fcc34Sopenharmony_ci * https://01.org/sites/default/files/595976_intel_sst_nhlt.pdf 6c72fcc34Sopenharmony_ci * 7c72fcc34Sopenharmony_ci * Author: Jaroslav Kysela <perex@perex.cz> 8c72fcc34Sopenharmony_ci * 9c72fcc34Sopenharmony_ci * 10c72fcc34Sopenharmony_ci * This program is free software; you can redistribute it and/or modify 11c72fcc34Sopenharmony_ci * it under the terms of the GNU General Public License as published by 12c72fcc34Sopenharmony_ci * the Free Software Foundation; either version 2 of the License, or 13c72fcc34Sopenharmony_ci * (at your option) any later version. 14c72fcc34Sopenharmony_ci * 15c72fcc34Sopenharmony_ci * This program is distributed in the hope that it will be useful, 16c72fcc34Sopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of 17c72fcc34Sopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18c72fcc34Sopenharmony_ci * GNU General Public License for more details. 19c72fcc34Sopenharmony_ci * 20c72fcc34Sopenharmony_ci * You should have received a copy of the GNU General Public License 21c72fcc34Sopenharmony_ci * along with this program; if not, write to the Free Software 22c72fcc34Sopenharmony_ci * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 23c72fcc34Sopenharmony_ci * 24c72fcc34Sopenharmony_ci */ 25c72fcc34Sopenharmony_ci 26c72fcc34Sopenharmony_ci#include "aconfig.h" 27c72fcc34Sopenharmony_ci#include <stdint.h> 28c72fcc34Sopenharmony_ci#include <stdio.h> 29c72fcc34Sopenharmony_ci#include <stdlib.h> 30c72fcc34Sopenharmony_ci#include <errno.h> 31c72fcc34Sopenharmony_ci#include <string.h> 32c72fcc34Sopenharmony_ci#include <unistd.h> 33c72fcc34Sopenharmony_ci#include <fcntl.h> 34c72fcc34Sopenharmony_ci#include <getopt.h> 35c72fcc34Sopenharmony_ci#include <sys/stat.h> 36c72fcc34Sopenharmony_ci#include <arpa/inet.h> 37c72fcc34Sopenharmony_ci 38c72fcc34Sopenharmony_ciint debug = 0; 39c72fcc34Sopenharmony_ci 40c72fcc34Sopenharmony_ci/* 41c72fcc34Sopenharmony_ci * Dump dmic parameters in json 42c72fcc34Sopenharmony_ci */ 43c72fcc34Sopenharmony_ci 44c72fcc34Sopenharmony_ci#define ACPI_HDR_SIZE (4 + 4 + 1 + 1 + 6 + 8 + 4 + 4 + 4) 45c72fcc34Sopenharmony_ci#define NHLT_EP_HDR_SIZE (4 + 1 + 1 + 2 + 2 + 2 + 4 + 1 + 1 + 1) 46c72fcc34Sopenharmony_ci#define VENDOR_MIC_CFG_SIZE (1 + 1 + 2 + 2 + 2 + 1 + 1 + 2 + 2 + 2 + 2 + 2 + 2) 47c72fcc34Sopenharmony_ci 48c72fcc34Sopenharmony_cistatic const char *microphone_type(uint8_t type) 49c72fcc34Sopenharmony_ci{ 50c72fcc34Sopenharmony_ci switch (type) { 51c72fcc34Sopenharmony_ci case 0: return "omnidirectional"; 52c72fcc34Sopenharmony_ci case 1: return "subcardoid"; 53c72fcc34Sopenharmony_ci case 2: return "cardoid"; 54c72fcc34Sopenharmony_ci case 3: return "supercardoid"; 55c72fcc34Sopenharmony_ci case 4: return "hypercardoid"; 56c72fcc34Sopenharmony_ci case 5: return "8shaped"; 57c72fcc34Sopenharmony_ci case 7: return "vendor"; 58c72fcc34Sopenharmony_ci } 59c72fcc34Sopenharmony_ci return "unknown"; 60c72fcc34Sopenharmony_ci} 61c72fcc34Sopenharmony_ci 62c72fcc34Sopenharmony_cistatic const char *microphone_location(uint8_t location) 63c72fcc34Sopenharmony_ci{ 64c72fcc34Sopenharmony_ci switch (location) { 65c72fcc34Sopenharmony_ci case 0: return "laptop-top-panel"; 66c72fcc34Sopenharmony_ci case 1: return "laptop-bottom-panel"; 67c72fcc34Sopenharmony_ci case 2: return "laptop-left-panel"; 68c72fcc34Sopenharmony_ci case 3: return "laptop-right-panel"; 69c72fcc34Sopenharmony_ci case 4: return "laptop-front-panel"; 70c72fcc34Sopenharmony_ci case 5: return "laptop-rear-panel"; 71c72fcc34Sopenharmony_ci } 72c72fcc34Sopenharmony_ci return "unknown"; 73c72fcc34Sopenharmony_ci} 74c72fcc34Sopenharmony_ci 75c72fcc34Sopenharmony_ci 76c72fcc34Sopenharmony_cistatic inline uint8_t get_u8(uint8_t *base, uint32_t off) 77c72fcc34Sopenharmony_ci{ 78c72fcc34Sopenharmony_ci return *(base + off); 79c72fcc34Sopenharmony_ci} 80c72fcc34Sopenharmony_ci 81c72fcc34Sopenharmony_cistatic inline int32_t get_s16le(uint8_t *base, uint32_t off) 82c72fcc34Sopenharmony_ci{ 83c72fcc34Sopenharmony_ci uint32_t v = *(base + off + 0) | 84c72fcc34Sopenharmony_ci (*(base + off + 1) << 8); 85c72fcc34Sopenharmony_ci if (v & 0x8000) 86c72fcc34Sopenharmony_ci return -((int32_t)0x10000 - (int32_t)v); 87c72fcc34Sopenharmony_ci return v; 88c72fcc34Sopenharmony_ci} 89c72fcc34Sopenharmony_ci 90c72fcc34Sopenharmony_cistatic inline uint32_t get_u32le(uint8_t *base, uint32_t off) 91c72fcc34Sopenharmony_ci{ 92c72fcc34Sopenharmony_ci return *(base + off + 0) | 93c72fcc34Sopenharmony_ci (*(base + off + 1) << 8) | 94c72fcc34Sopenharmony_ci (*(base + off + 2) << 16) | 95c72fcc34Sopenharmony_ci (*(base + off + 3) << 24); 96c72fcc34Sopenharmony_ci} 97c72fcc34Sopenharmony_ci 98c72fcc34Sopenharmony_cistatic int nhlt_dmic_config(FILE *out, uint8_t *dmic, uint8_t mic) 99c72fcc34Sopenharmony_ci{ 100c72fcc34Sopenharmony_ci int32_t angle_begin, angle_end; 101c72fcc34Sopenharmony_ci 102c72fcc34Sopenharmony_ci if (mic > 0) 103c72fcc34Sopenharmony_ci fprintf(out, ",\n"); 104c72fcc34Sopenharmony_ci fprintf(out, "\t\t{\n"); 105c72fcc34Sopenharmony_ci fprintf(out, "\t\t\t\"channel\":%i,\n", mic); 106c72fcc34Sopenharmony_ci fprintf(out, "\t\t\t\"type\":\"%s\",\n", microphone_type(get_u8(dmic, 0))); 107c72fcc34Sopenharmony_ci fprintf(out, "\t\t\t\"location\":\"%s\"", microphone_location(get_u8(dmic, 1))); 108c72fcc34Sopenharmony_ci if (get_s16le(dmic, 2) != 0) 109c72fcc34Sopenharmony_ci fprintf(out, ",\n\t\t\t\"speaker-distance\":%i", get_s16le(dmic, 2)); 110c72fcc34Sopenharmony_ci if (get_s16le(dmic, 4) != 0) 111c72fcc34Sopenharmony_ci fprintf(out, ",\n\t\t\t\"horizontal-offset\":%i", get_s16le(dmic, 4)); 112c72fcc34Sopenharmony_ci if (get_s16le(dmic, 6) != 0) 113c72fcc34Sopenharmony_ci fprintf(out, ",\n\t\t\t\"vertical-offset\":%i", get_s16le(dmic, 6)); 114c72fcc34Sopenharmony_ci if (get_u8(dmic, 8) != 0) 115c72fcc34Sopenharmony_ci fprintf(out, ",\n\t\t\t\"freq-low-band\":%i", get_u8(dmic, 8) * 5); 116c72fcc34Sopenharmony_ci if (get_u8(dmic, 9) != 0) 117c72fcc34Sopenharmony_ci fprintf(out, ",\n\t\t\t\"freq-high-band\":%i", get_u8(dmic, 9) * 500); 118c72fcc34Sopenharmony_ci if (get_s16le(dmic, 10) != 0) 119c72fcc34Sopenharmony_ci fprintf(out, ",\n\t\t\t\"direction-angle\":%i", get_s16le(dmic, 10)); 120c72fcc34Sopenharmony_ci if (get_s16le(dmic, 12) != 0) 121c72fcc34Sopenharmony_ci fprintf(out, ",\n\t\t\t\"elevation-angle\":%i", get_s16le(dmic, 12)); 122c72fcc34Sopenharmony_ci angle_begin = get_s16le(dmic, 14); 123c72fcc34Sopenharmony_ci angle_end = get_s16le(dmic, 16); 124c72fcc34Sopenharmony_ci if (!((angle_begin == 180 && angle_end == -180) || 125c72fcc34Sopenharmony_ci (angle_begin == -180 && angle_end == 180))) { 126c72fcc34Sopenharmony_ci fprintf(out, ",\n\t\t\t\"vertical-angle-begin\":%i,\n", angle_begin); 127c72fcc34Sopenharmony_ci fprintf(out, "\t\t\t\"vertical-angle-end\":%i", angle_end); 128c72fcc34Sopenharmony_ci } 129c72fcc34Sopenharmony_ci angle_begin = get_s16le(dmic, 18); 130c72fcc34Sopenharmony_ci angle_end = get_s16le(dmic, 20); 131c72fcc34Sopenharmony_ci if (!((angle_begin == 180 && angle_end == -180) || 132c72fcc34Sopenharmony_ci (angle_begin == -180 && angle_end == 180))) { 133c72fcc34Sopenharmony_ci fprintf(out, ",\n\t\t\t\"horizontal-angle-begin\":%i,\n", angle_begin); 134c72fcc34Sopenharmony_ci fprintf(out, "\t\t\t\"horizontal-angle-end\":%i", angle_end); 135c72fcc34Sopenharmony_ci } 136c72fcc34Sopenharmony_ci fprintf(out, "\n\t\t}"); 137c72fcc34Sopenharmony_ci return 0; 138c72fcc34Sopenharmony_ci} 139c72fcc34Sopenharmony_ci 140c72fcc34Sopenharmony_cistatic int nhlt_dmic_ep_to_json(FILE *out, uint8_t *ep, uint32_t ep_size) 141c72fcc34Sopenharmony_ci{ 142c72fcc34Sopenharmony_ci uint32_t off, specific_cfg_size; 143c72fcc34Sopenharmony_ci uint8_t config_type, array_type, mic, num_mics; 144c72fcc34Sopenharmony_ci int res; 145c72fcc34Sopenharmony_ci 146c72fcc34Sopenharmony_ci off = NHLT_EP_HDR_SIZE; 147c72fcc34Sopenharmony_ci specific_cfg_size = get_u32le(ep, off); 148c72fcc34Sopenharmony_ci if (off + specific_cfg_size > ep_size) 149c72fcc34Sopenharmony_ci goto oob; 150c72fcc34Sopenharmony_ci off += 4; 151c72fcc34Sopenharmony_ci config_type = get_u8(ep, off + 1); 152c72fcc34Sopenharmony_ci if (config_type != 1) /* mic array */ 153c72fcc34Sopenharmony_ci return 0; 154c72fcc34Sopenharmony_ci array_type = get_u8(ep, off + 2); 155c72fcc34Sopenharmony_ci if ((array_type & 0x0f) != 0x0f) { 156c72fcc34Sopenharmony_ci fprintf(stderr, "Unsupported ArrayType %02x\n", array_type & 0x0f); 157c72fcc34Sopenharmony_ci return -EINVAL; 158c72fcc34Sopenharmony_ci } 159c72fcc34Sopenharmony_ci num_mics = get_u8(ep, off + 3); 160c72fcc34Sopenharmony_ci fprintf(out, "{\n"); 161c72fcc34Sopenharmony_ci fprintf(out, "\t\"mics-data-version\":1,\n"); 162c72fcc34Sopenharmony_ci fprintf(out, "\t\"mics-data-source\":\"acpi-nhlt\""); 163c72fcc34Sopenharmony_ci for (mic = 0; mic < num_mics; mic++) { 164c72fcc34Sopenharmony_ci if (off - NHLT_EP_HDR_SIZE + VENDOR_MIC_CFG_SIZE > specific_cfg_size) { 165c72fcc34Sopenharmony_ci fprintf(out, "\n}\n"); 166c72fcc34Sopenharmony_ci goto oob; 167c72fcc34Sopenharmony_ci } 168c72fcc34Sopenharmony_ci if (mic == 0) 169c72fcc34Sopenharmony_ci fprintf(out, ",\n\t\"mics\":[\n"); 170c72fcc34Sopenharmony_ci res = nhlt_dmic_config(out, ep + off + 4, mic); 171c72fcc34Sopenharmony_ci if (res < 0) 172c72fcc34Sopenharmony_ci return res; 173c72fcc34Sopenharmony_ci off += VENDOR_MIC_CFG_SIZE; 174c72fcc34Sopenharmony_ci } 175c72fcc34Sopenharmony_ci if (num_mics > 0) 176c72fcc34Sopenharmony_ci fprintf(out, "\n\t]\n"); 177c72fcc34Sopenharmony_ci fprintf(out, "}\n"); 178c72fcc34Sopenharmony_ci return num_mics; 179c72fcc34Sopenharmony_cioob: 180c72fcc34Sopenharmony_ci fprintf(stderr, "Data (out-of-bounds) error\n"); 181c72fcc34Sopenharmony_ci return -EINVAL; 182c72fcc34Sopenharmony_ci} 183c72fcc34Sopenharmony_ci 184c72fcc34Sopenharmony_cistatic int nhlt_table_to_json(FILE *out, uint8_t *nhlt, uint32_t size) 185c72fcc34Sopenharmony_ci{ 186c72fcc34Sopenharmony_ci uint32_t _size, off, ep_size; 187c72fcc34Sopenharmony_ci uint8_t sum = 0, ep, ep_count, link_type, dmics = 0; 188c72fcc34Sopenharmony_ci int res; 189c72fcc34Sopenharmony_ci 190c72fcc34Sopenharmony_ci _size = get_u32le(nhlt, 4); 191c72fcc34Sopenharmony_ci if (_size != size) { 192c72fcc34Sopenharmony_ci fprintf(stderr, "Table size mismatch (%08x != %08x)\n", _size, (uint32_t)size); 193c72fcc34Sopenharmony_ci return -EINVAL; 194c72fcc34Sopenharmony_ci } 195c72fcc34Sopenharmony_ci for (off = 0; off < size; off++) 196c72fcc34Sopenharmony_ci sum += get_u8(nhlt, off); 197c72fcc34Sopenharmony_ci if (sum != 0) { 198c72fcc34Sopenharmony_ci fprintf(stderr, "Checksum error (%02x)\n", sum); 199c72fcc34Sopenharmony_ci return -EINVAL; 200c72fcc34Sopenharmony_ci } 201c72fcc34Sopenharmony_ci /* skip header */ 202c72fcc34Sopenharmony_ci off = ACPI_HDR_SIZE; 203c72fcc34Sopenharmony_ci ep_count = get_u8(nhlt, off++); 204c72fcc34Sopenharmony_ci for (ep = 0; ep < ep_count; ep++) { 205c72fcc34Sopenharmony_ci if (off + 17 > size) 206c72fcc34Sopenharmony_ci goto oob; 207c72fcc34Sopenharmony_ci ep_size = get_u32le(nhlt, off); 208c72fcc34Sopenharmony_ci if (off + ep_size > size) 209c72fcc34Sopenharmony_ci goto oob; 210c72fcc34Sopenharmony_ci link_type = get_u8(nhlt, off + 4); 211c72fcc34Sopenharmony_ci res = 0; 212c72fcc34Sopenharmony_ci if (link_type == 2) { /* PDM */ 213c72fcc34Sopenharmony_ci res = nhlt_dmic_ep_to_json(out, nhlt + off, ep_size); 214c72fcc34Sopenharmony_ci if (res > 0) 215c72fcc34Sopenharmony_ci dmics++; 216c72fcc34Sopenharmony_ci } 217c72fcc34Sopenharmony_ci if (res < 0) 218c72fcc34Sopenharmony_ci return res; 219c72fcc34Sopenharmony_ci off += ep_size; 220c72fcc34Sopenharmony_ci } 221c72fcc34Sopenharmony_ci if (dmics == 0) { 222c72fcc34Sopenharmony_ci fprintf(stderr, "No dmic endpoint found\n"); 223c72fcc34Sopenharmony_ci return -EINVAL; 224c72fcc34Sopenharmony_ci } 225c72fcc34Sopenharmony_ci return 0; 226c72fcc34Sopenharmony_cioob: 227c72fcc34Sopenharmony_ci fprintf(stderr, "Data (out-of-bounds) error\n"); 228c72fcc34Sopenharmony_ci return -EINVAL; 229c72fcc34Sopenharmony_ci} 230c72fcc34Sopenharmony_ci 231c72fcc34Sopenharmony_cistatic int nhlt_to_json(FILE *out, const char *nhlt_file) 232c72fcc34Sopenharmony_ci{ 233c72fcc34Sopenharmony_ci struct stat st; 234c72fcc34Sopenharmony_ci uint8_t *buf; 235c72fcc34Sopenharmony_ci int _errno, fd, res; 236c72fcc34Sopenharmony_ci size_t pos, size; 237c72fcc34Sopenharmony_ci ssize_t ret; 238c72fcc34Sopenharmony_ci 239c72fcc34Sopenharmony_ci if (stat(nhlt_file, &st)) 240c72fcc34Sopenharmony_ci return -errno; 241c72fcc34Sopenharmony_ci size = st.st_size; 242c72fcc34Sopenharmony_ci if (size < 45) 243c72fcc34Sopenharmony_ci return -EINVAL; 244c72fcc34Sopenharmony_ci buf = malloc(size); 245c72fcc34Sopenharmony_ci if (buf == NULL) 246c72fcc34Sopenharmony_ci return -ENOMEM; 247c72fcc34Sopenharmony_ci fd = open(nhlt_file, O_RDONLY); 248c72fcc34Sopenharmony_ci if (fd < 0) { 249c72fcc34Sopenharmony_ci _errno = errno; 250c72fcc34Sopenharmony_ci fprintf(stderr, "Unable to open file '%s': %s\n", nhlt_file, strerror(errno)); 251c72fcc34Sopenharmony_ci free(buf); 252c72fcc34Sopenharmony_ci return _errno; 253c72fcc34Sopenharmony_ci } 254c72fcc34Sopenharmony_ci pos = 0; 255c72fcc34Sopenharmony_ci while (pos < size) { 256c72fcc34Sopenharmony_ci ret = read(fd, buf + pos, size - pos); 257c72fcc34Sopenharmony_ci if (ret <= 0) { 258c72fcc34Sopenharmony_ci fprintf(stderr, "Short read\n"); 259c72fcc34Sopenharmony_ci close(fd); 260c72fcc34Sopenharmony_ci free(buf); 261c72fcc34Sopenharmony_ci return -EIO; 262c72fcc34Sopenharmony_ci } 263c72fcc34Sopenharmony_ci pos += ret; 264c72fcc34Sopenharmony_ci } 265c72fcc34Sopenharmony_ci close(fd); 266c72fcc34Sopenharmony_ci res = nhlt_table_to_json(out, buf, size); 267c72fcc34Sopenharmony_ci free(buf); 268c72fcc34Sopenharmony_ci return res; 269c72fcc34Sopenharmony_ci} 270c72fcc34Sopenharmony_ci 271c72fcc34Sopenharmony_ci/* 272c72fcc34Sopenharmony_ci * 273c72fcc34Sopenharmony_ci */ 274c72fcc34Sopenharmony_ci 275c72fcc34Sopenharmony_ci#define PROG "nhlt-dmic-info" 276c72fcc34Sopenharmony_ci#define PROG_VERSION "1" 277c72fcc34Sopenharmony_ci 278c72fcc34Sopenharmony_ci#define NHLT_FILE "/sys/firmware/acpi/tables/NHLT" 279c72fcc34Sopenharmony_ci 280c72fcc34Sopenharmony_ci#define TITLE 0x0100 281c72fcc34Sopenharmony_ci#define HEADER 0x0200 282c72fcc34Sopenharmony_ci#define FILEARG 0x0400 283c72fcc34Sopenharmony_ci 284c72fcc34Sopenharmony_ci#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) 285c72fcc34Sopenharmony_ci 286c72fcc34Sopenharmony_cistruct arg { 287c72fcc34Sopenharmony_ci int sarg; 288c72fcc34Sopenharmony_ci char *larg; 289c72fcc34Sopenharmony_ci char *comment; 290c72fcc34Sopenharmony_ci}; 291c72fcc34Sopenharmony_ci 292c72fcc34Sopenharmony_cistatic struct arg args[] = { 293c72fcc34Sopenharmony_ci{ TITLE, NULL, "Usage: nhtl-dmic-json <options>" }, 294c72fcc34Sopenharmony_ci{ HEADER, NULL, "global options:" }, 295c72fcc34Sopenharmony_ci{ 'h', "help", "this help" }, 296c72fcc34Sopenharmony_ci{ 'v', "version", "print version of this program" }, 297c72fcc34Sopenharmony_ci{ FILEARG | 'f', "file", "NHLT file (default " NHLT_FILE ")" }, 298c72fcc34Sopenharmony_ci{ FILEARG | 'o', "output", "output file" }, 299c72fcc34Sopenharmony_ci{ 0, NULL, NULL } 300c72fcc34Sopenharmony_ci}; 301c72fcc34Sopenharmony_ci 302c72fcc34Sopenharmony_cistatic void help(void) 303c72fcc34Sopenharmony_ci{ 304c72fcc34Sopenharmony_ci struct arg *n = args, *a; 305c72fcc34Sopenharmony_ci char *larg, sa[4], buf[32]; 306c72fcc34Sopenharmony_ci int sarg; 307c72fcc34Sopenharmony_ci 308c72fcc34Sopenharmony_ci sa[0] = '-'; 309c72fcc34Sopenharmony_ci sa[2] = ','; 310c72fcc34Sopenharmony_ci sa[3] = '\0'; 311c72fcc34Sopenharmony_ci while (n->comment) { 312c72fcc34Sopenharmony_ci a = n; 313c72fcc34Sopenharmony_ci n++; 314c72fcc34Sopenharmony_ci sarg = a->sarg; 315c72fcc34Sopenharmony_ci if (sarg & (HEADER|TITLE)) { 316c72fcc34Sopenharmony_ci printf("%s%s\n", (sarg & HEADER) != 0 ? "\n" : "", 317c72fcc34Sopenharmony_ci a->comment); 318c72fcc34Sopenharmony_ci continue; 319c72fcc34Sopenharmony_ci } 320c72fcc34Sopenharmony_ci buf[0] = '\0'; 321c72fcc34Sopenharmony_ci larg = a->larg; 322c72fcc34Sopenharmony_ci sa[1] = a->sarg; 323c72fcc34Sopenharmony_ci sprintf(buf, "%s%s%s", sa[1] ? sa : "", 324c72fcc34Sopenharmony_ci larg ? "--" : "", larg ? larg : ""); 325c72fcc34Sopenharmony_ci if (sarg & FILEARG) 326c72fcc34Sopenharmony_ci strcat(buf, " #"); 327c72fcc34Sopenharmony_ci printf(" %-15s %s\n", buf, a->comment); 328c72fcc34Sopenharmony_ci } 329c72fcc34Sopenharmony_ci} 330c72fcc34Sopenharmony_ci 331c72fcc34Sopenharmony_ciint main(int argc, char *argv[]) 332c72fcc34Sopenharmony_ci{ 333c72fcc34Sopenharmony_ci char *nhlt_file = NHLT_FILE; 334c72fcc34Sopenharmony_ci char *output_file = "-"; 335c72fcc34Sopenharmony_ci int i, j, k, res; 336c72fcc34Sopenharmony_ci struct arg *a; 337c72fcc34Sopenharmony_ci struct option *o, *long_option; 338c72fcc34Sopenharmony_ci char *short_option; 339c72fcc34Sopenharmony_ci FILE *output = NULL; 340c72fcc34Sopenharmony_ci 341c72fcc34Sopenharmony_ci long_option = calloc(ARRAY_SIZE(args), sizeof(struct option)); 342c72fcc34Sopenharmony_ci if (long_option == NULL) 343c72fcc34Sopenharmony_ci exit(EXIT_FAILURE); 344c72fcc34Sopenharmony_ci short_option = malloc(128); 345c72fcc34Sopenharmony_ci if (short_option == NULL) { 346c72fcc34Sopenharmony_ci free(long_option); 347c72fcc34Sopenharmony_ci exit(EXIT_FAILURE); 348c72fcc34Sopenharmony_ci } 349c72fcc34Sopenharmony_ci for (i = j = k = 0; i < (int)ARRAY_SIZE(args); i++) { 350c72fcc34Sopenharmony_ci a = &args[i]; 351c72fcc34Sopenharmony_ci if ((a->sarg & 0xff) == 0) 352c72fcc34Sopenharmony_ci continue; 353c72fcc34Sopenharmony_ci o = &long_option[j]; 354c72fcc34Sopenharmony_ci o->name = a->larg; 355c72fcc34Sopenharmony_ci o->has_arg = (a->sarg & FILEARG) != 0; 356c72fcc34Sopenharmony_ci o->flag = NULL; 357c72fcc34Sopenharmony_ci o->val = a->sarg & 0xff; 358c72fcc34Sopenharmony_ci j++; 359c72fcc34Sopenharmony_ci short_option[k++] = o->val; 360c72fcc34Sopenharmony_ci if (o->has_arg) 361c72fcc34Sopenharmony_ci short_option[k++] = ':'; 362c72fcc34Sopenharmony_ci } 363c72fcc34Sopenharmony_ci short_option[k] = '\0'; 364c72fcc34Sopenharmony_ci while (1) { 365c72fcc34Sopenharmony_ci int c; 366c72fcc34Sopenharmony_ci 367c72fcc34Sopenharmony_ci if ((c = getopt_long(argc, argv, short_option, long_option, 368c72fcc34Sopenharmony_ci NULL)) < 0) 369c72fcc34Sopenharmony_ci break; 370c72fcc34Sopenharmony_ci switch (c) { 371c72fcc34Sopenharmony_ci case 'h': 372c72fcc34Sopenharmony_ci help(); 373c72fcc34Sopenharmony_ci res = EXIT_SUCCESS; 374c72fcc34Sopenharmony_ci goto out; 375c72fcc34Sopenharmony_ci case 'f': 376c72fcc34Sopenharmony_ci nhlt_file = optarg; 377c72fcc34Sopenharmony_ci break; 378c72fcc34Sopenharmony_ci case 'o': 379c72fcc34Sopenharmony_ci output_file = optarg; 380c72fcc34Sopenharmony_ci break; 381c72fcc34Sopenharmony_ci case 'd': 382c72fcc34Sopenharmony_ci debug = 1; 383c72fcc34Sopenharmony_ci break; 384c72fcc34Sopenharmony_ci case 'v': 385c72fcc34Sopenharmony_ci printf(PROG " version " PROG_VERSION "\n"); 386c72fcc34Sopenharmony_ci res = EXIT_SUCCESS; 387c72fcc34Sopenharmony_ci goto out; 388c72fcc34Sopenharmony_ci case '?': // error msg already printed 389c72fcc34Sopenharmony_ci help(); 390c72fcc34Sopenharmony_ci res = EXIT_FAILURE; 391c72fcc34Sopenharmony_ci goto out; 392c72fcc34Sopenharmony_ci default: // should never happen 393c72fcc34Sopenharmony_ci fprintf(stderr, 394c72fcc34Sopenharmony_ci "Invalid option '%c' (%d) not handled??\n", c, c); 395c72fcc34Sopenharmony_ci } 396c72fcc34Sopenharmony_ci } 397c72fcc34Sopenharmony_ci free(short_option); 398c72fcc34Sopenharmony_ci short_option = NULL; 399c72fcc34Sopenharmony_ci free(long_option); 400c72fcc34Sopenharmony_ci long_option = NULL; 401c72fcc34Sopenharmony_ci 402c72fcc34Sopenharmony_ci if (strcmp(output_file, "-") == 0) { 403c72fcc34Sopenharmony_ci output = stdout; 404c72fcc34Sopenharmony_ci } else { 405c72fcc34Sopenharmony_ci output = fopen(output_file, "w+"); 406c72fcc34Sopenharmony_ci if (output == NULL) { 407c72fcc34Sopenharmony_ci fprintf(stderr, "Unable to create output file \"%s\": %s\n", 408c72fcc34Sopenharmony_ci output_file, strerror(errno)); 409c72fcc34Sopenharmony_ci res = EXIT_FAILURE; 410c72fcc34Sopenharmony_ci goto out; 411c72fcc34Sopenharmony_ci } 412c72fcc34Sopenharmony_ci } 413c72fcc34Sopenharmony_ci 414c72fcc34Sopenharmony_ci if (argc - optind > 0) 415c72fcc34Sopenharmony_ci fprintf(stderr, PROG ": Ignoring extra parameters\n"); 416c72fcc34Sopenharmony_ci 417c72fcc34Sopenharmony_ci res = 0; 418c72fcc34Sopenharmony_ci if (nhlt_to_json(output, nhlt_file)) 419c72fcc34Sopenharmony_ci res = EXIT_FAILURE; 420c72fcc34Sopenharmony_ci 421c72fcc34Sopenharmony_ciout: 422c72fcc34Sopenharmony_ci if (output) 423c72fcc34Sopenharmony_ci fclose(output); 424c72fcc34Sopenharmony_ci free(short_option); 425c72fcc34Sopenharmony_ci free(long_option); 426c72fcc34Sopenharmony_ci return res; 427c72fcc34Sopenharmony_ci} 428