blob: 5d106f0563932e30d1496676f425703d95998719 [file] [log] [blame]
/* 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 <stdlib.h>
#include <sys/param.h>
#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;
}