/* Copyright (c) 2014 The Chromium OS Authors. All rights reserved. * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #include #include #include "cras_types.h" #include "buffer_share.h" static inline struct id_offset *find_unused(const struct buffer_share *mix) { unsigned int i; for (i = 0; i < mix->id_sz; i++) { if (!mix->wr_idx[i].used) return &mix->wr_idx[i]; } return NULL; } static inline struct id_offset *find_id(const struct buffer_share *mix, unsigned int id) { unsigned int i; for (i = 0; i < mix->id_sz; i++) { if (mix->wr_idx[i].used && id == mix->wr_idx[i].id) return &mix->wr_idx[i]; } return NULL; } static void alloc_more_ids(struct buffer_share *mix) { unsigned int new_size = mix->id_sz * 2; unsigned int i; mix->wr_idx = (struct id_offset *)realloc( mix->wr_idx, sizeof(mix->wr_idx[0]) * new_size); for (i = mix->id_sz; i < new_size; i++) mix->wr_idx[i].used = 0; mix->id_sz = new_size; } struct buffer_share *buffer_share_create(unsigned int buf_sz) { struct buffer_share *mix; mix = (struct buffer_share *)calloc(1, sizeof(*mix)); mix->id_sz = INITIAL_ID_SIZE; mix->wr_idx = (struct id_offset *)calloc(mix->id_sz, sizeof(mix->wr_idx[0])); mix->buf_sz = buf_sz; return mix; } void buffer_share_destroy(struct buffer_share *mix) { if (!mix) return; free(mix->wr_idx); free(mix); } int buffer_share_add_id(struct buffer_share *mix, unsigned int id, void *data) { struct id_offset *o; o = find_id(mix, id); if (o) return -EEXIST; o = find_unused(mix); if (!o) alloc_more_ids(mix); o = find_unused(mix); o->used = 1; o->id = id; o->offset = 0; o->data = data; return 0; } int buffer_share_rm_id(struct buffer_share *mix, unsigned int id) { struct id_offset *o; o = find_id(mix, id); if (!o) return -ENOENT; o->used = 0; o->data = NULL; return 0; } int buffer_share_offset_update(struct buffer_share *mix, unsigned int id, unsigned int delta) { unsigned int i; for (i = 0; i < mix->id_sz; i++) { if (id != mix->wr_idx[i].id) continue; mix->wr_idx[i].offset += delta; break; } return 0; } unsigned int buffer_share_get_new_write_point(struct buffer_share *mix) { unsigned int min_written = mix->buf_sz + 1; unsigned int i; for (i = 0; i < mix->id_sz; i++) { struct id_offset *o = &mix->wr_idx[i]; if (!o->used) continue; min_written = MIN(min_written, o->offset); } for (i = 0; i < mix->id_sz; i++) { struct id_offset *o = &mix->wr_idx[i]; o->offset -= min_written; } if (min_written > mix->buf_sz) return 0; return min_written; } static struct id_offset *get_id_offset(const struct buffer_share *mix, unsigned int id) { unsigned int i; struct id_offset *o; for (i = 0; i < mix->id_sz; i++) { o = &mix->wr_idx[i]; if (o->used && o->id == id) return o; } return NULL; } unsigned int buffer_share_id_offset(const struct buffer_share *mix, unsigned int id) { struct id_offset *o = get_id_offset(mix, id); return o ? o->offset : 0; } void *buffer_share_get_data(const struct buffer_share *mix, unsigned int id) { struct id_offset *o = get_id_offset(mix, id); return o ? o->data : NULL; }