static int binary_file_parse(snd_ctl_elem_value_t *dst, snd_ctl_elem_info_t *info, const char *filepath) { int err = 0; int fd; struct stat st; size_t sz; ssize_t sz_read; char *res; snd_ctl_elem_type_t type; unsigned int idx, count; type = snd_ctl_elem_info_get_type(info); if (type != SND_CTL_ELEM_TYPE_BYTES) { uc_error("only support byte type!"); err = -EINVAL; return err; } fd = open(filepath, O_RDONLY); if (fd < 0) { err = -errno; return err; } if (stat(filepath, &st) == -1) { err = -errno; goto __fail; } sz = st.st_size; count = snd_ctl_elem_info_get_count(info); if (sz != count || sz > sizeof(dst->value.bytes)) { uc_error("invalid parameter size %d!", sz); err = -EINVAL; goto __fail; } res = malloc(sz); if (res == NULL) { err = -ENOMEM; goto __fail; } sz_read = read(fd, res, sz); if (sz_read < 0 || (size_t)sz_read != sz) { err = -errno; goto __fail_read; } for (idx = 0; idx < sz; idx++) snd_ctl_elem_value_set_byte(dst, idx, *(res + idx)); __fail_read: free(res); __fail: close(fd); return err; }
static int read_tlv_file(unsigned int **res, const char *filepath) { int err = 0; int fd; struct stat st; size_t sz; ssize_t sz_read; struct snd_ctl_tlv *tlv; fd = open(filepath, O_RDONLY); if (fd < 0) { err = -errno; return err; } if (fstat(fd, &st) == -1) { err = -errno; goto __fail; } sz = st.st_size; if (sz > 16 * 1024 * 1024 || sz < 8 || sz % 4) { uc_error("File size should be less than 16 MB " "and multiple of 4"); err = -EINVAL; goto __fail; } *res = malloc(sz); if (res == NULL) { err = -ENOMEM; goto __fail; } sz_read = read(fd, *res, sz); if (sz_read < 0 || (size_t)sz_read != sz) { err = -EIO; free(*res); *res = NULL; } /* Check if the tlv file specifies valid size. */ tlv = (struct snd_ctl_tlv *)(*res); if (tlv->length + 2 * sizeof(unsigned int) != sz) { uc_error("Invalid tlv size: %d", tlv->length); err = -EINVAL; free(*res); *res = NULL; } __fail: close(fd); return err; }
/* * Parse safe ID */ int parse_is_name_safe(char *name) { if (strchr(name, '.')) { uc_error("char '.' now allowed in '%s'", name); return 0; } return 1; }
static int execute_cset(snd_ctl_t *ctl, const char *cset) { const char *pos; int err; snd_ctl_elem_id_t *id; snd_ctl_elem_value_t *value; snd_ctl_elem_info_t *info; snd_ctl_elem_id_malloc(&id); snd_ctl_elem_value_malloc(&value); snd_ctl_elem_info_malloc(&info); err = __snd_ctl_ascii_elem_id_parse(id, cset, &pos); if (err < 0) goto __fail; while (*pos && isspace(*pos)) pos++; if (!*pos) { uc_error("undefined value for cset >%s<", cset); err = -EINVAL; goto __fail; } snd_ctl_elem_value_set_id(value, id); snd_ctl_elem_info_set_id(info, id); err = snd_ctl_elem_read(ctl, value); if (err < 0) goto __fail; err = snd_ctl_elem_info(ctl, info); if (err < 0) goto __fail; err = snd_ctl_ascii_value_parse(ctl, value, info, pos); if (err < 0) goto __fail; err = snd_ctl_elem_write(ctl, value); if (err < 0) goto __fail; err = 0; __fail: if (id != NULL) free(id); if (value != NULL) free(value); if (info != NULL) free(info); return err; }
/* * Parse transition */ static int parse_transition(snd_use_case_mgr_t *uc_mgr, struct list_head *tlist, snd_config_t *cfg) { struct transition_sequence *tseq; const char *id; snd_config_iterator_t i, next; snd_config_t *n; int err; if (snd_config_get_id(cfg, &id) < 0) return -EINVAL; if (snd_config_get_type(cfg) != SND_CONFIG_TYPE_COMPOUND) { uc_error("compound type expected for %s", id); return -EINVAL; } snd_config_for_each(i, next, cfg) { n = snd_config_iterator_entry(i); if (snd_config_get_id(n, &id) < 0) return -EINVAL; tseq = calloc(1, sizeof(*tseq)); if (tseq == NULL) return -ENOMEM; INIT_LIST_HEAD(&tseq->transition_list); tseq->name = strdup(id); if (tseq->name == NULL) { free(tseq); return -ENOMEM; } err = parse_sequence(uc_mgr, &tseq->transition_list, n); if (err < 0) { uc_mgr_free_transition_element(tseq); return err; } list_add(&tseq->list, tlist); }
/** * \brief Execute the sequence * \param uc_mgr Use case manager * \param seq Sequence * \return zero on success, otherwise a negative error code */ static int execute_sequence(snd_use_case_mgr_t *uc_mgr, struct list_head *seq, struct list_head *value_list1, struct list_head *value_list2, struct list_head *value_list3) { struct list_head *pos; struct sequence_element *s; char *cdev = NULL; snd_ctl_t *ctl = NULL; int err = 0; list_for_each(pos, seq) { s = list_entry(pos, struct sequence_element, list); switch (s->type) { case SEQUENCE_ELEMENT_TYPE_CDEV: cdev = strdup(s->data.cdev); if (cdev == NULL) goto __fail_nomem; break; case SEQUENCE_ELEMENT_TYPE_CSET: if (cdev == NULL) { const char *cdev1 = NULL, *cdev2 = NULL; err = get_value3(&cdev1, "PlaybackCTL", value_list1, value_list2, value_list3); if (err < 0 && err != ENOENT) { uc_error("cdev is not defined!"); return err; } err = get_value3(&cdev1, "CaptureCTL", value_list1, value_list2, value_list3); if (err < 0 && err != ENOENT) { free((char *)cdev1); uc_error("cdev is not defined!"); return err; } if (cdev1 == NULL || cdev2 == NULL || strcmp(cdev1, cdev2) == 0) { cdev = (char *)cdev1; free((char *)cdev2); } else { free((char *)cdev1); free((char *)cdev2); } } if (ctl == NULL) { err = open_ctl(uc_mgr, &ctl, cdev); if (err < 0) { uc_error("unable to open ctl device '%s'", cdev); goto __fail; } } err = execute_cset(ctl, s->data.cset); if (err < 0) { uc_error("unable to execute cset '%s'\n", s->data.cset); goto __fail; } break; case SEQUENCE_ELEMENT_TYPE_SLEEP: usleep(s->data.sleep); break; case SEQUENCE_ELEMENT_TYPE_EXEC: err = system(s->data.exec); if (err < 0) goto __fail; break; default: uc_error("unknown sequence command %i", s->type); break; } }
static int execute_cset(snd_ctl_t *ctl, const char *cset, unsigned int type) { const char *pos; int err; snd_ctl_elem_id_t *id; snd_ctl_elem_value_t *value; snd_ctl_elem_info_t *info; unsigned int *res = NULL; snd_ctl_elem_id_malloc(&id); snd_ctl_elem_value_malloc(&value); snd_ctl_elem_info_malloc(&info); err = __snd_ctl_ascii_elem_id_parse(id, cset, &pos); if (err < 0) goto __fail; while (*pos && isspace(*pos)) pos++; if (!*pos) { uc_error("undefined value for cset >%s<", cset); err = -EINVAL; goto __fail; } snd_ctl_elem_info_set_id(info, id); err = snd_ctl_elem_info(ctl, info); if (err < 0) goto __fail; if (type == SEQUENCE_ELEMENT_TYPE_CSET_TLV) { if (!snd_ctl_elem_info_is_tlv_writable(info)) { err = -EINVAL; goto __fail; } err = read_tlv_file(&res, pos); if (err < 0) goto __fail; err = snd_ctl_elem_tlv_write(ctl, id, res); if (err < 0) goto __fail; } else { snd_ctl_elem_value_set_id(value, id); err = snd_ctl_elem_read(ctl, value); if (err < 0) goto __fail; if (type == SEQUENCE_ELEMENT_TYPE_CSET_BIN_FILE) err = binary_file_parse(value, info, pos); else err = snd_ctl_ascii_value_parse(ctl, value, info, pos); if (err < 0) goto __fail; err = snd_ctl_elem_write(ctl, value); if (err < 0) goto __fail; } err = 0; __fail: if (id != NULL) free(id); if (value != NULL) free(value); if (info != NULL) free(info); if (res != NULL) free(res); return err; }