1 /* Copyright (c) 2014 The Chromium OS Authors. All rights reserved. 2 * Use of this source code is governed by a BSD-style license that can be 3 * found in the LICENSE file. 4 */ 5 6 #include <stdlib.h> 7 #include <sys/param.h> 8 9 #include "cras_types.h" 10 #include "buffer_share.h" 11 12 static inline struct id_offset *find_unused(const struct buffer_share *mix) 13 { 14 unsigned int i; 15 16 for (i = 0; i < mix->id_sz; i++) { 17 if (!mix->wr_idx[i].used) 18 return &mix->wr_idx[i]; 19 } 20 21 return NULL; 22 } 23 24 25 static inline struct id_offset *find_id(const struct buffer_share *mix, 26 unsigned int id) 27 { 28 unsigned int i; 29 30 for (i = 0; i < mix->id_sz; i++) { 31 if (mix->wr_idx[i].used && id == mix->wr_idx[i].id) 32 return &mix->wr_idx[i]; 33 } 34 35 return NULL; 36 } 37 38 static void alloc_more_ids(struct buffer_share *mix) 39 { 40 unsigned int new_size = mix->id_sz * 2; 41 unsigned int i; 42 43 mix->wr_idx = realloc(mix->wr_idx, sizeof(mix->wr_idx[0]) * new_size); 44 45 for (i = mix->id_sz; i < new_size; i++) 46 mix->wr_idx[i].used = 0; 47 48 mix->id_sz = new_size; 49 } 50 51 struct buffer_share *buffer_share_create(unsigned int buf_sz) 52 { 53 struct buffer_share *mix; 54 55 mix = calloc(1, sizeof(*mix)); 56 mix->id_sz = INITIAL_ID_SIZE; 57 mix->wr_idx = calloc(mix->id_sz, sizeof(mix->wr_idx[0])); 58 mix->buf_sz = buf_sz; 59 60 return mix; 61 } 62 63 void buffer_share_destroy(struct buffer_share *mix) 64 { 65 if (!mix) 66 return; 67 free(mix->wr_idx); 68 free(mix); 69 } 70 71 int buffer_share_add_id(struct buffer_share *mix, unsigned int id, void *data) 72 { 73 struct id_offset *o; 74 75 o = find_id(mix, id); 76 if (o) 77 return -EEXIST; 78 79 o = find_unused(mix); 80 if (!o) 81 alloc_more_ids(mix); 82 83 o = find_unused(mix); 84 o->used = 1; 85 o->id = id; 86 o->offset = 0; 87 o->data = data; 88 89 return 0; 90 } 91 92 int buffer_share_rm_id(struct buffer_share *mix, unsigned int id) 93 { 94 struct id_offset *o; 95 96 o = find_id(mix, id); 97 if (!o) 98 return -ENOENT; 99 o->used = 0; 100 o->data = NULL; 101 102 return 0; 103 } 104 105 int buffer_share_offset_update(struct buffer_share *mix, unsigned int id, 106 unsigned int delta) 107 { 108 unsigned int i; 109 110 for (i = 0; i < mix->id_sz; i++) { 111 if (id != mix->wr_idx[i].id) 112 continue; 113 114 mix->wr_idx[i].offset += delta; 115 break; 116 } 117 118 return 0; 119 } 120 121 unsigned int buffer_share_get_new_write_point(struct buffer_share *mix) 122 { 123 unsigned int min_written = mix->buf_sz + 1; 124 unsigned int i; 125 126 for (i = 0; i < mix->id_sz; i++) { 127 struct id_offset *o = &mix->wr_idx[i]; 128 129 if (!o->used) 130 continue; 131 132 min_written = MIN(min_written, o->offset); 133 } 134 for (i = 0; i < mix->id_sz; i++) { 135 struct id_offset *o = &mix->wr_idx[i]; 136 o->offset -= min_written; 137 } 138 139 if (min_written > mix->buf_sz) 140 return 0; 141 142 return min_written; 143 } 144 145 static struct id_offset *get_id_offset(const struct buffer_share *mix, 146 unsigned int id) 147 { 148 unsigned int i; 149 struct id_offset *o; 150 151 for (i = 0; i < mix->id_sz; i++) { 152 o = &mix->wr_idx[i]; 153 if (o->used && o->id == id) 154 return o; 155 } 156 return NULL; 157 } 158 159 unsigned int buffer_share_id_offset(const struct buffer_share *mix, 160 unsigned int id) 161 { 162 struct id_offset *o = get_id_offset(mix, id); 163 return o ? o->offset : 0; 164 } 165 166 void *buffer_share_get_data(const struct buffer_share *mix, 167 unsigned int id) 168 { 169 struct id_offset *o = get_id_offset(mix, id); 170 return o ? o->data : NULL; 171 } 172