/* * Copyright (C) 2018 Knowles Electronics * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #define LOG_TAG "ia_dump_registers" #include #define DEBUG_DEV "/dev/debug0" #define GETOPT_HELP_CHAR (CHAR_MIN - 2) #define REG_ADDR "Register Address" #define REG_VAL "Register Value" #define SRB_REG "SRB Registers" #define ARB_REG "ARB Registers" #define REG_OUT_FILE "/data/data/reg_dump.txt" #define CIRC_OUT_FILE_CM4 "/data/data/circular_buf_cm4.bin" #define CIRC_OUT_FILE_DMX "/data/data/circular_buf_dmx.bin" #define CIRC_OUT_FILE_HMD "/data/data/circular_buf_hmd.bin" //#define ENABLE_DEBUG_PRINTS static struct option const long_options[] = { {"stdout", no_argument, NULL, 'o'}, {"regdump", no_argument, NULL, 'r'}, {"circbuf", no_argument, NULL, 'c'}, {"help", no_argument, NULL, GETOPT_HELP_CHAR}, {NULL, 0, NULL, 0} }; void usage(void) { fputs("\ USAGE -\n\ -------\n\ 1) dump_debug_info -c\n\ 2) dump_debug_info -r\n\ 3) dump_debug_info -l \n\ 4) dump_debug_info -l \n\ 5) dump_debug_info -m \n\ 6) dump_debug_info -m \n\ 7) dump_debug_info -t \n\ 8) dump_debug_info -n \n\ 9) dump_debug_info -s \n\ \n\ In the first form, it dumps the circular buffer logging for Rome, the output is\n\ dumped to the file /data/data/circular_buf_(cm4/dmx/hmd).bin\n\ In the second form, it dumps all the SRB and ARB registers, the output is\n\ dumped to the file /data/data/reg_dump.txt\n\ In the third form, it sets the log level to a particular module id\n\ In the fourth form, it gets the log level for the requested modele id\n\ In the fifth form, it sets the mode to a particular processor id\n\ In the sixth form, it gets the mode for the requested processor id\n\ In the seventh form, it gets the tunnel information for the requested tunnel id [0, 31]\n\ In the eighth form, it gets the channel information for the requested channel id [0, 31]\n\ In the ninth form, it gets the stream information for the requested stream id [0, 15]\n\ ", stdout); fputs("\ Options -\n\ ---------\n\ -c Dump the circular buffer\n\ -r Dump all SRB and ARB registers\n\ -o Dump to stdout (Works only with -r option)\n\ -l Set/Get the log level for a particular module\n\ -m Set/Get the mode for a particular processor id\n\ -t Dump the tunnel information for a particular tunnel id [0, 31]\n\ -n Dump the channel information for a particular channel id [0, 31]\n\ -s Dump the stream information for a particular stream id [0, 15]\n\ \n\ Module ids -\n\ -----------\n\ enum iaxxx_debug_module_ids {\n\ IAXXX_DBG_MODULE_ID_ASSERT_LOG = 0,\n\ IAXXX_DBG_MODULE_ID_ACCDETMGR_LOG = 1,\n\ IAXXX_DBG_MODULE_ID_BATTERYMGR_LOG = 2,\n\ IAXXX_DBG_MODULE_ID_BLUETOOTHMGR_LOG = 3,\n\ IAXXX_DBG_MODULE_ID_BUTTONMGR_LOG = 4,\n\ IAXXX_DBG_MODULE_ID_CODECMGR_LOG = 5,\n\ IAXXX_DBG_MODULE_ID_CTRLMGR_LOG = 6,\n\ IAXXX_DBG_MODULE_ID_DMAMGR_LOG = 7,\n\ IAXXX_DBG_MODULE_ID_EVTMGR_LOG = 8,\n\ IAXXX_DBG_MODULE_ID_FLASHMGR_LOG = 9,\n\ IAXXX_DBG_MODULE_ID_LEDMGR_LOG = 10,\n\ IAXXX_DBG_MODULE_ID_POWERMGR_LOG = 11,\n\ IAXXX_DBG_MODULE_ID_STREAMMGR_LOG = 12,\n\ IAXXX_DBG_MODULE_ID_SENSORMGR_LOG = 13,\n\ IAXXX_DBG_MODULE_ID_TUNNELMGR_LOG = 14,\n\ IAXXX_DBG_MODULE_ID_USBMGR_LOG = 15,\n\ IAXXX_DBG_MODULE_ID_PLUGINMGR_LOG = 16,\n\ IAXXX_DBG_MODULE_ID_PLUGINVM_LOG = 17,\n\ IAXXX_DBG_MODULE_ID_PACKAGEUTILS_LOG = 18,\n\ IAXXX_DBG_MODULE_ID_ENDPOINT_LOG = 19,\n\ IAXXX_DBG_MODULE_ID_PUTMSG_LOG = 20,\n\ IAXXX_DBG_MODULE_ID_CONTROLLER_LOG = 21,\n\ IAXXX_DBG_MODULE_ID_MIPSPROFILER_LOG = 22,\n\ IAXXX_DBG_MODULE_ID_DEBUGMONITOR_LOG = 23,\n\ IAXXX_DBG_MODULE_ID_SSPDRV_LOG = 24,\n\ IAXXX_DBG_MODULE_ID_AFDRV_LOG = 25,\n\ IAXXX_DBG_MODULE_ID_SPIDRV_LOG = 26,\n\ IAXXX_DBG_MODULE_ID_I2CDRV_LOG = 27,\n\ IAXXX_DBG_MODULE_ID_A400DRV_LOG = 28,\n\ IAXXX_DBG_MODULE_ID_ADAU1361DRV_LOG = 29,\n\ IAXXX_DBG_MODULE_ID_MAX98090DRV_LOG = 30,\n\ IAXXX_DBG_MODULE_ID_BQ27425DRV_LOG = 31,\n\ IAXXX_DBG_MODULE_ID_USBDRV_LOG = 32,\n\ IAXXX_DBG_MODULE_ID_CSR8811_LOG = 33,\n\ IAXXX_DBG_MODULE_ID_CYW20707DRV_LOG = 34,\n\ IAXXX_DBG_MODULE_ID_BUTTONDRV_LOG = 35,\n\ IAXXX_DBG_MODULE_ID_LEDDRV_LOG = 36,\n\ IAXXX_DBG_MODULE_ID_TIMERDRV_LOG = 37,\n\ IAXXX_DBG_MODULE_ID_UARTDRV_LOG = 38,\n\ IAXXX_DBG_MODULE_ID_FLASHDRV_LOG = 39,\n\ IAXXX_DBG_MODULE_ID_DMADRV_LOG = 40,\n\ IAXXX_DBG_MODULE_ID_GPIODRV_LOG = 41,\n\ IAXXX_DBG_MODULE_ID_MACDRV_LOG = 42,\n\ IAXXX_DBG_MODULE_ID_STMRDRV_LOG = 43,\n\ IAXXX_DBG_MODULE_ID_STMRPTDRV_LOG = 44,\n\ IAXXX_DBG_MODULE_ID_SLIMBUSDRV_LOG = 45,\n\ IAXXX_DBG_MODULE_ID_SSENSORDRV_LOG = 46,\n\ IAXXX_DBG_MODULE_ID_STRMDRV_LOG = 47,\n\ IAXXX_DBG_MODULE_ID_CPUSTRMDRV_LOG = 48,\n\ IAXXX_DBG_MODULE_ID_CLKTREEUTILS_LOG = 49,\n\ IAXXX_DBG_MODULE_ID_SCRIPTMGR_LOG = 50,\n\ };\n\ \n\ Log Levels -\n\ ------------\n\ enum iaxxx_fw_debug_log_level {\n\ IAXXX_DBG_LOG_LVL_OFF = 0,\n\ IAXXX_DBG_LOG_LVL_CUSTOM = 1,\n\ IAXXX_DBG_LOG_LVL_FATAL = 2,\n\ IAXXX_DBG_LOG_LVL_ERROR = 3,\n\ IAXXX_DBG_LOG_LVL_WARN = 4,\n\ IAXXX_DBG_LOG_LVL_INFO = 5,\n\ IAXXX_DBG_LOG_LVL_DEBUG = 6,\n\ IAXXX_DBG_LOG_LVL_TRACE = 7,\n\ };\n\ \n\ Modes -\n\ -------\n\ enum iaxxx_fw_debug_log_mode {\n\ IAXXX_FROM_MEMORY = 0,\n\ IAXXX_FROM_ENDPOINT = 1,\n\ };\n\ \n\ Processor ids -\n\ ---------------\n\ enum iaxxx_proc_id_e {\n\ IAXXX_NO_PROC = 0,\n\ IAXXX_BOSS_ID = 1,\n\ IAXXX_SSP_ID = 2,\n\ IAXXX_CM4_ID = 3,\n\ IAXXX_HMD_ID = 4,\n\ IAXXX_DMX_ID = 5,\n\ };\n\ ", stdout); exit(EXIT_FAILURE); } void log_lvl(int fd, int module_id, int log_level) { int err = 0; struct iaxxx_log_level_info log_level_info; log_level_info.module_id = module_id; if (log_level == -1) { // We need to get the log level for the module id log_level_info.log_level = 0; err = ioctl(fd, IAXXX_GET_DBG_LOG_LEVEL, (unsigned long) &log_level_info); if (err == -1) { ALOGE("%s: ERROR: IAXXX_GET_DBG_LOG_LEVEL failed %d(%s)", __func__, errno, strerror(errno)); return; } ALOGD("%s: Module level %d Log level %u", __func__, module_id, log_level_info.log_level); } else { // We need to set the Log level for the module id log_level_info.log_level = log_level; err = ioctl(fd, IAXXX_SET_DBG_LOG_LEVEL, (unsigned long) &log_level_info); if (err == -1) { ALOGE("%s: ERROR: IAXXX_SET_DBG_LOG_LEVEL failed %d(%s)", __func__, errno, strerror(errno)); return; } } } void pmode(int fd, int proc_id, int mode) { int err = 0; struct iaxxx_log_mode_info log_mode_info; log_mode_info.proc_id = proc_id; if (mode == -1) { // We need to get the mode for the processor id log_mode_info.mode = 0; err = ioctl(fd, IAXXX_GET_DBG_LOG_MODE, (unsigned long) &log_mode_info); if (err == -1) { ALOGE("%s: ERROR: IAXXX_GET_DBG_LOG_MODE failed %d(%s)", __func__, errno, strerror(errno)); return; } ALOGD("%s: Processor ID %d Mode %u", __func__, proc_id, log_mode_info.mode); } else { // We need to set the mode for the processor id log_mode_info.mode = mode; err = ioctl(fd, IAXXX_SET_DBG_LOG_MODE, (unsigned long) &log_mode_info); if (err == -1) { ALOGE("%s: ERROR: IAXXX_SET_DBG_LOG_MODE failed %d(%s)", __func__, errno, strerror(errno)); return; } } } void dump_all_regs(const struct iaxxx_registers_dump *info, bool use_stdout) { uint32_t addr; int i, j; FILE *out_fp = NULL; const struct iaxxx_srb_info *srb_info = &info->srb_info; const struct iaxxx_arb_info *arb_info = &info->arb_info; if (use_stdout) { out_fp = stdout; } else { out_fp = fopen(REG_OUT_FILE, "w"); if (NULL == out_fp) { ALOGE("Couldn't open the file %s for writing", REG_OUT_FILE); return; } } /* SRB */ #ifdef ENABLE_DEBUG_PRINTS ALOGD("%s", SRB_REG); ALOGD("%s\t%s", REG_ADDR, REG_VAL); #endif fprintf(out_fp, "%s\n", SRB_REG); fprintf(out_fp, "%s\t%s\n", REG_ADDR, REG_VAL); addr = srb_info->reg_start_addr; for (i = 0; i < srb_info->reg_num; ++i) { uint32_t val = srb_info->reg_vals[i]; #ifdef ENABLE_DEBUG_PRINTS ALOGD("0x%X\t\t\t0x%08X", addr, val); #endif fprintf(out_fp, "0x%X\t\t\t0x%08X\n", addr, val); addr += sizeof(uint32_t); } /* ARB */ addr = arb_info->reg_start_addr; /* Dump all the ARB start address and the size at the beginning * before dumping all the ARB information */ for (i = 0, j = 0; i < arb_info->reg_num; i += 2, j++) { uint32_t arb_phy_addr = arb_info->reg_vals[i]; uint32_t arb_sz = arb_info->reg_vals[i + 1]; #ifdef ENABLE_DEBUG_PRINTS ALOGD("0x%X\t\t\t0x%08X", addr, arb_phy_addr); ALOGD("0x%X\t\t\t0x%08X", (addr + 4), arb_sz); #endif fprintf(out_fp, "0x%X\t\t\t0x%08X\n", addr, arb_phy_addr); fprintf(out_fp, "0x%X\t\t\t0x%08X\n", (addr + sizeof(uint32_t)), arb_sz); addr += (sizeof(uint32_t) * 2); } addr = arb_info->reg_start_addr; for (i = 0, j = 0; i < arb_info->reg_num; i += 2, j++) { const struct iaxxx_arb_block *block = &arb_info->blocks[j]; uint32_t k; uint32_t temp_arb_addr; #ifdef ENABLE_DEBUG_PRINTS uint32_t arb_phy_addr = arb_info->reg_vals[i]; uint32_t arb_sz = arb_info->reg_vals[i + 1]; ALOGD("0x%X \t\t arb phy addr 0x%08X arb size 0x%08X", addr, arb_phy_addr, arb_sz); ALOGD("%s %d", ARB_REG, j); ALOGD("%s\t%s", REG_ADDR, REG_VAL); #endif addr += (sizeof(uint32_t) * 2); fprintf(out_fp, "%s %d\n", ARB_REG, j); fprintf(out_fp, "%s\t%s\n", REG_ADDR, REG_VAL); if (0 == block->reg_start_addr || 0 == block->reg_num) { ALOGD("------------- NA -------------"); fprintf(out_fp, "------------- NA -------------\n"); continue; } temp_arb_addr = block->reg_start_addr; for (k = 0; k < block->reg_num; k++) { uint32_t temp_val = block->reg_vals[k]; #ifdef ENABLE_DEBUG_PRINTS ALOGD("0x%X\t\t\t0x%08X", temp_arb_addr, temp_val); #endif fprintf(out_fp, "0x%X\t\t\t0x%08X\n", temp_arb_addr, temp_val); temp_arb_addr += sizeof(uint32_t); } } fflush(out_fp); if (!use_stdout) fclose(out_fp); } /* * Register Information - * All circular buffers start address and size is stored in ARB10 * ARB10 - physical address in SRB is 0x580001bc * Start Address location Size location * CM4 ARB10 + 0 ARB10 + 4 * HMD ARB10 + 8 ARB10 + C * DMX ARB10 + 10 ARB10 + 14 */ void dump_circ_buf(const struct iaxxx_circ_buffer_info *circ_buffer_info) { uint32_t i = 0, j = 0; const char *out_file_names[IAXXX_MAX_CIRC_BUFS] = {CIRC_OUT_FILE_CM4, CIRC_OUT_FILE_HMD, CIRC_OUT_FILE_DMX}; if (circ_buffer_info->buf_num > IAXXX_MAX_CIRC_BUFS) { ALOGE("Too large buf_num: %d", circ_buffer_info->buf_num); return; } for (i = 0, j = 0; j < circ_buffer_info->buf_num; i += 2, j++) { const struct iaxxx_circ_buffer *buf = &circ_buffer_info->bufs[j]; FILE *fp = NULL; uint32_t k = 0; // Get the physical address and size for each of the circular buffers if (0 == buf->reg_start_addr || 0 == buf->reg_num) { ALOGE("Couldn't find physical address and size"); ALOGE("phy_addr 0x%X size 0x%X", buf->reg_start_addr, buf->reg_num); continue; } fp = fopen(out_file_names[j], "wb"); if (NULL == fp) { ALOGE("Couldn't open the file for writing"); continue; } for (k = 0; k < buf->reg_num; k++) fwrite(buf->reg_vals + k, sizeof(uint32_t), 1, fp); fflush(fp); fclose(fp); } } static int dump_tunnel(int fd, int tunnel_id) { int ret; struct iaxxx_tunnel_info_dump dump = { .id = tunnel_id }; if ((ret = ioctl(fd, IAXXX_IOCTL_GET_TUNNEL_INFO_DUMP, &dump)) != 0) { ALOGE("Failed to ioctl %s IAXXX_IOCTL_GET_TUNNEL_INFO_DUMP, ret=%d", DEBUG_DEV, ret); ret = errno; return ret; } fprintf(stdout, "header.en=0x%08x\n" "header.st=0x%08x\n" "header.out_buf_size=%u\n" "header.out_buf_addr=0x%08x\n" "header.out_buf_head=%u\n" "header.out_buf_tail=%u\n" "header.out_buf_threshold=%u\n" "tunnel%u.nframe_drops=%u\n" "tunnel%u.nsent_to_host=%u\n" "tunnel%u.nsent=%u\n" "tunnel%u.nrecvd=%u\n" "tunnel%u.ctrl=%u\n" "tunnel%u.format=%u\n", dump.en, dump.st, dump.out_buf_size, dump.out_buf_addr, dump.out_buf_head, dump.out_buf_tail, dump.out_buf_threshold, dump.id, dump.nframe_drops, dump.id, dump.nsent_to_host, dump.id, dump.nsent, dump.id, dump.nrecvd, dump.id, dump.ctrl, dump.id, dump.format); return ret; } static int dump_channel(int fd, int channel_id) { int ret; struct iaxxx_channel_info_dump dump = { .id = channel_id }; if ((ret = ioctl(fd, IAXXX_IOCTL_GET_CHANNEL_INFO_DUMP, &dump)) != 0) { ALOGE("Failed to ioctl %s IAXXX_IOCTL_GET_CHANNEL_INFO_DUMP, ret=%d", DEBUG_DEV, ret); ret = errno; return ret; } fprintf(stdout, "header.st=0x%08x\n" "header.direction=%u\n" "header.gain=%u\n" "channel%u.nsent=%u\n" "channel%u.nrecvd=%u\n" "channel%u.endpoint_state=%u\n" "channel%u.intr_cnt=%u\n" "channel%u.drop_cnt=%u\n" "channel%u.gain_ctrl=%u\n" "channel%u.gain_status=%u\n" "channel%u.""%s""=%u\n", dump.st, dump.direction, dump.gain, dump.id, dump.nsent, dump.id, dump.nrecvd, dump.id, dump.endpoint_state, dump.id, dump.intr_cnt, dump.id, dump.drop_cnt, dump.id, dump.gain_ctrl, dump.id, dump.gain_status, dump.id, (dump.id >= 0 && dump.id < 16) ? "out_fmt" : "in_connect", dump.in_connect); return ret; } static int dump_stream(int fd, int stream_id) { int ret; struct iaxxx_stream_info_dump dump = { .id = stream_id }; if ((ret = ioctl(fd, IAXXX_IOCTL_GET_STREAM_INFO_DUMP, &dump)) != 0) { ALOGE("Failed to ioctl %s IAXXX_IOCTL_GET_STREAM_INFO_DUMP, ret=%d", DEBUG_DEV, ret); ret = errno; return ret; } fprintf(stdout, "header.en=0x%08x\n" "header.st=0x%08x\n" "stream%u.af_error_afs_fifo_overflow_cnt=%u\n" "stream%u.af_error_afs_fifo_underflow_cnt=%u\n" "stream%u.af_error_tus_fifo_overflow_cnt=%u\n" "stream%u.af_error_tus_fifo_underflow_cnt=%u\n" "stream%u.af_error_tus_fifo_coherency_cnt=%u\n" "stream%u.af_error_deadline_cnt=%u\n" "stream%u.af_error_phy_cnt=%u\n" "stream%u.af_error_timeout_cnt=%u\n" "stream%u.af_error_access_cnt=%u\n" "stream%u.ctrl=%u\n" "stream%u.status=%u\n" "stream%u.format=%u\n" "stream%u.port=%u\n" "stream%u.channel=%u\n" "stream%u.sync=%u\n", dump.en, dump.st, dump.id, dump.af_error_afs_fifo_overflow_cnt, dump.id, dump.af_error_afs_fifo_underflow_cnt, dump.id, dump.af_error_tus_fifo_overflow_cnt, dump.id, dump.af_error_tus_fifo_underflow_cnt, dump.id, dump.af_error_tus_fifo_coherency_cnt, dump.id, dump.af_error_deadline_cnt, dump.id, dump.af_error_phy_cnt, dump.id, dump.af_error_timeout_cnt, dump.id, dump.af_error_access_cnt, dump.id, dump.ctrl, dump.id, dump.status, dump.id, dump.format, dump.id, dump.port, dump.id, dump.channel, dump.id, dump.sync); return ret; } int main(int argc, char *argv[]) { int fd = 0, ret = 0; int c; bool dump_all_registers = false; bool dump_circ_buffer = false; bool dump_tunnel_info = false; bool dump_channel_info = false; bool dump_stream_info = false; bool log_mode = false; bool use_stdout = false; bool proc_mode = false; // Log level set will require 2 arguments while get needs one const int log_lvl_req_arg_get = 1; const int log_lvl_req_arg_set = 2; // Mode level set will required 2 arguments while set needs one const int mode_req_arg_get = 1; const int mode_req_arg_set = 2; int module_id = 0, log_level = -1; int proc_id = 0, mode = -1; int tunnel_id = -1, channel_id = -1, stream_id = -1; if (argc <= 1) { usage(); return 0; } while ((c = getopt_long(argc, argv, "rcot:n:s:l:m:", long_options, NULL)) != -1) { switch (c) { case 'r': dump_all_registers = true; break; case 'c': dump_circ_buffer = true; break; case 'o': use_stdout = true; break; case 't': dump_tunnel_info = true; tunnel_id = atoi(optarg); break; case 'n': dump_channel_info = true; channel_id = atoi(optarg); break; case 's': dump_stream_info = true; stream_id = atoi(optarg); break; case 'l': log_mode = true; // reset optind by 1 --optind; if ((optind + log_lvl_req_arg_get) != argc && (optind + log_lvl_req_arg_set) != argc) { usage(); } module_id = strtol(argv[optind], NULL, 0); if ((optind + log_lvl_req_arg_set) == argc) { // Move to the next before fetching the value optind++; log_level = strtol(argv[optind], NULL, 0); optind++; } break; case 'm': proc_mode = true; // reset optind by 1 --optind; if ((optind + mode_req_arg_get) != argc && (optind + mode_req_arg_set) != argc) { usage(); } proc_id = strtol(argv[optind], NULL, 0); if ((optind + mode_req_arg_set) == argc) { // Move to the next before fetching the value optind++; mode = strtol(argv[optind], NULL, 0); optind++; } break; default: // Do nothing break; } } fd = open(DEBUG_DEV, O_RDONLY); if (-1 == fd) { fprintf(stderr, "Failed to open %s", DEBUG_DEV); ret = errno; goto exit; } if(log_mode == true) { log_lvl(fd, module_id, log_level); } if (proc_mode == true) { pmode(fd, proc_id, mode); } if (dump_all_registers || dump_circ_buffer) { static struct iaxxx_registers_dump dump; if ((ret = ioctl(fd, IAXXX_IOCTL_GET_REGISTERS_DUMP, &dump)) != 0) { fprintf(stderr, "Failed to ioctl %s IAXXX_IOCTL_GET_REGISTERS_DUMP, ret=%d", DEBUG_DEV, ret); ret = errno; } else { if (dump_all_registers) dump_all_regs(&dump, use_stdout); if (dump_circ_buffer) dump_circ_buf(&dump.circ_buffer_info); } } if (dump_tunnel_info) { if (tunnel_id >= 0 && tunnel_id < IAXXX_TUNNEL_MAX) { ret = dump_tunnel(fd, tunnel_id); if (ret) { fprintf(stderr, "Failed to dump_tunnel(), ret=%d", ret); } } else { fprintf(stderr, "Invalid tunnel_id %d\n", tunnel_id); } } if (dump_channel_info) { if (channel_id >= 0 && channel_id < IAXXX_CHANNEL_MAX) { ret = dump_channel(fd, channel_id); if (ret) { fprintf(stderr, "Failed to dump_channel(), ret=%d", ret); } } else { fprintf(stderr, "Invalid channel_id %d\n", channel_id); } } if (dump_stream_info) { if (stream_id >= 0 && stream_id < IAXXX_STREAM_MAX) { ret = dump_stream(fd, stream_id); if (ret) { fprintf(stderr, "Failed to dump_stream(), ret=%d", ret); } } else { fprintf(stderr, "Invalid stream_id %d\n", stream_id); } } exit: if (-1 != fd) close(fd); return ret; }