/* * Copyright (c) 2019 Actions Semiconductor Co., Ltd * * SPDX-License-Identifier: Apache-2.0 */ /** * @file clone stream interface */ #define SYS_LOG_DOMAIN "clonestream" #include #include #include #include #include #include #include static bool validate_stream_state(io_stream_t handle, uint8_t state) { return handle->state == state; } static int clone_stream_init(io_stream_t handle, void *param) { struct clone_stream_info *info = param; int i; if (!validate_stream_state(info->origin, STATE_INIT)) { SYS_LOG_ERR("state not init\n"); return -EINVAL; } for (i = 0; i < ARRAY_SIZE(info->clones); i++) { if (!info->clones[i]) break; if (!validate_stream_state(info->clones[i], STATE_OPEN)) { SYS_LOG_ERR("state not open\n", i); return -EINVAL; } if (!(info->clones[i]->mode & MODE_OUT)) { SYS_LOG_ERR("stream clone[%d] not writable\n", i); return -EINVAL; } } handle->data = mem_malloc(sizeof(*info)); if (!handle->data) { SYS_LOG_ERR("malloc data\n", i); return -ENOMEM; } memcpy(handle->data, info, sizeof(*info)); return 0; } static int clone_stream_open(io_stream_t handle, stream_mode mode) { struct clone_stream_info *info = handle->data; int res; SYS_LOG_DBG(" call\n"); res = stream_open(info->origin, mode); if (res) return res; handle->write_finished = 0; return 0; } static int clone_stream_read(io_stream_t handle, unsigned char *buf,int num) { struct clone_stream_info *info = handle->data; int len, i; len = stream_read(info->origin, buf, num); if (len <= 0) return len; /* clone read data */ if (handle->mode & info->clone_mode) { for (i = 0; i < ARRAY_SIZE(info->clones); i++) { if (!info->clones[i]) break; info->clones[i]->ops->write(info->clones[i], buf, len); } } return len; } static int clone_stream_write(io_stream_t handle, unsigned char *buf,int num) { struct clone_stream_info *info = handle->data; int len, i; len = stream_write(info->origin, buf, num); if (len <= 0) return len; /* clone write data */ if (handle->mode & info->clone_mode) { for (i = 0; i < ARRAY_SIZE(info->clones); i++) { if (!info->clones[i]) break; info->clones[i]->ops->write(info->clones[i], buf, len); } } return len; } static int clone_stream_seek(io_stream_t handle, int offset, seek_dir origin) { /* FIXME: seek ops will make clone stream data disordered */ return -ENOSYS; } static int clone_stream_tell(io_stream_t handle) { struct clone_stream_info *info = handle->data; return stream_tell(info->origin); } static int clone_stream_get_length(io_stream_t handle) { struct clone_stream_info *info = handle->data; return stream_get_length(info->origin); } static int clone_stream_get_space(io_stream_t handle) { struct clone_stream_info *info = handle->data; return stream_get_space(info->origin); } static int clone_stream_flush(io_stream_t handle) { struct clone_stream_info *info = handle->data; int res, i; res = stream_flush(info->origin); for (i = 0; i < ARRAY_SIZE(info->clones); i++) { if (!info->clones[i]) break; if (info->clones[i]->ops->flush) info->clones[i]->ops->flush(info->clones[i]); } return res; } static int clone_stream_close(io_stream_t handle) { struct clone_stream_info *info = handle->data; int i; /* notify write finished */ for (i = 0; i < ARRAY_SIZE(info->clones); i++) { if (!info->clones[i]) break; info->clones[i]->ops->write(info->clones[i], NULL, 0); } return stream_close(info->origin); } static int clone_stream_destroy(io_stream_t handle) { struct clone_stream_info *info = handle->data; int res; res = stream_destroy(info->origin); mem_free(info); return res; } const stream_ops_t clone_stream_ops = { .init = clone_stream_init, .open = clone_stream_open, .read = clone_stream_read, .seek = clone_stream_seek, .tell = clone_stream_tell, .get_length = clone_stream_get_length, .get_space = clone_stream_get_space, .write = clone_stream_write, .flush = clone_stream_flush, .close = clone_stream_close, .destroy = clone_stream_destroy, }; io_stream_t clone_stream_create(struct clone_stream_info *info) { return stream_create(&clone_stream_ops, info); }