/* * Copyright 2020 sysmocom - s.f.m.c. GmbH * Author: Pau Espin Pedrol * * SPDX-License-Identifier: 0BSD * * Permission to use, copy, modify, and/or distribute this software for any purpose * with or without fee is hereby granted.THE SOFTWARE IS PROVIDED "AS IS" AND THE * AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR * BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE * USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include #include #include "shm.h" #define ENCDECDEBUG(...) //fprintf(stderr, __VA_ARGS__) /* Convert offsets to pointers */ struct ipc_shm_stream *ipc_shm_decode_stream(void *tall_ctx, struct ipc_shm_raw_region *root_raw, struct ipc_shm_raw_stream *stream_raw) { unsigned int i; struct ipc_shm_stream *stream; stream = talloc_zero(tall_ctx, struct ipc_shm_stream); stream = talloc_zero_size(tall_ctx, sizeof(struct ipc_shm_stream) + sizeof(struct ipc_shm_raw_smpl_buf *) * stream_raw->num_buffers); if (!stream) return NULL; stream->num_buffers = stream_raw->num_buffers; stream->buffer_size = stream_raw->buffer_size; stream->raw = stream_raw; for (i = 0; i < stream->num_buffers; i++) { ENCDECDEBUG("decode: smpl_buf %d at offset %u\n", i, stream_raw->buffer_offset[i]); stream->buffers[i] = (struct ipc_shm_raw_smpl_buf *)(((uint8_t *)root_raw) + stream_raw->buffer_offset[i]); } return stream; } struct ipc_shm_channel *ipc_shm_decode_channel(void *tall_ctx, struct ipc_shm_raw_region *root_raw, struct ipc_shm_raw_channel *chan_raw) { struct ipc_shm_channel *chan; chan = talloc_zero(tall_ctx, struct ipc_shm_channel); if (!chan) return NULL; ENCDECDEBUG("decode: streams at offset %u and %u\n", chan_raw->dl_buf_offset, chan_raw->ul_buf_offset); chan->dl_stream = ipc_shm_decode_stream( chan, root_raw, (struct ipc_shm_raw_stream *)(((uint8_t *)root_raw) + chan_raw->dl_buf_offset)); chan->ul_stream = ipc_shm_decode_stream( chan, root_raw, (struct ipc_shm_raw_stream *)(((uint8_t *)root_raw) + chan_raw->ul_buf_offset)); return chan; } struct ipc_shm_region *ipc_shm_decode_region(void *tall_ctx, struct ipc_shm_raw_region *root_raw) { unsigned int i; struct ipc_shm_region *root; root = talloc_zero_size(tall_ctx, sizeof(struct ipc_shm_region) + sizeof(struct ipc_shm_channel *) * root_raw->num_chans); if (!root) return NULL; root->num_chans = root_raw->num_chans; for (i = 0; i < root->num_chans; i++) { ENCDECDEBUG("decode: channel %d at offset %u\n", i, root_raw->chan_offset[i]); root->channels[i] = ipc_shm_decode_channel( root, root_raw, (struct ipc_shm_raw_channel *)(((uint8_t *)root_raw) + root_raw->chan_offset[i])); } return root; } unsigned int ipc_shm_encode_smpl_buf(struct ipc_shm_raw_region *root_raw, struct ipc_shm_raw_smpl_buf *smpl_buf_raw, uint32_t buffer_size) { unsigned int offset = sizeof(struct ipc_shm_raw_smpl_buf); offset = (((uintptr_t)offset + 7) & ~0x07ULL); ENCDECDEBUG("encode: smpl_buf at offset %u\n", offset); offset += buffer_size * sizeof(uint16_t) * 2; /* samples */ return offset; } unsigned int ipc_shm_encode_stream(struct ipc_shm_raw_region *root_raw, struct ipc_shm_raw_stream *stream_raw, uint32_t num_buffers, uint32_t buffer_size) { unsigned int i; ptrdiff_t start = (ptrdiff_t)stream_raw; unsigned int offset = sizeof(struct ipc_shm_raw_stream) + sizeof(uint32_t) * num_buffers; offset = (((uintptr_t)offset + 7) & ~0x07ULL); ENCDECDEBUG("encode: stream at offset %lu\n", (start - (ptrdiff_t)root_raw)); if (root_raw) { stream_raw->num_buffers = num_buffers; stream_raw->buffer_size = buffer_size; stream_raw->read_next = 0; stream_raw->write_next = 0; } for (i = 0; i < num_buffers; i++) { if (root_raw) stream_raw->buffer_offset[i] = (start + offset - (ptrdiff_t)root_raw); offset += ipc_shm_encode_smpl_buf(root_raw, (struct ipc_shm_raw_smpl_buf *)(start + offset), buffer_size); } return offset; } unsigned int ipc_shm_encode_channel(struct ipc_shm_raw_region *root_raw, struct ipc_shm_raw_channel *chan_raw, uint32_t num_buffers, uint32_t buffer_size) { uint8_t *start = (uint8_t *)chan_raw; unsigned int offset = sizeof(struct ipc_shm_raw_channel); offset = (((uintptr_t)offset + 7) & ~0x07ULL); ENCDECDEBUG("encode: channel at offset %lu\n", (start - (uint8_t *)root_raw)); if (root_raw) chan_raw->dl_buf_offset = (start + offset - (uint8_t *)root_raw); offset += ipc_shm_encode_stream(root_raw, (struct ipc_shm_raw_stream *)(start + offset), num_buffers, buffer_size); if (root_raw) chan_raw->ul_buf_offset = (start + offset - (uint8_t *)root_raw); offset += ipc_shm_encode_stream(root_raw, (struct ipc_shm_raw_stream *)(start + offset), num_buffers, buffer_size); return offset; } /* if root_raw is NULL, then do a dry run, aka only calculate final offset */ unsigned int ipc_shm_encode_region(struct ipc_shm_raw_region *root_raw, uint32_t num_chans, uint32_t num_buffers, uint32_t buffer_size) { unsigned i; uintptr_t start = (uintptr_t)root_raw; unsigned int offset = sizeof(struct ipc_shm_raw_region) + sizeof(uint32_t) * num_chans; offset = (((uintptr_t)offset + 7) & ~0x07ULL); if (root_raw) root_raw->num_chans = num_chans; for (i = 0; i < num_chans; i++) { if (root_raw) root_raw->chan_offset[i] = (start + offset - (uintptr_t)root_raw); ENCDECDEBUG("encode: channel %d chan_offset[i]=%lu\n", i, start + offset - (uintptr_t)root_raw); offset += ipc_shm_encode_channel(root_raw, (struct ipc_shm_raw_channel *)(start + offset), num_buffers, buffer_size); } //TODO: pass maximum size and verify we didn't go through return offset; }