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
find_unused(const struct buffer_share * mix)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
find_id(const struct buffer_share * mix,unsigned int id)24 static inline struct id_offset *find_id(const struct buffer_share *mix,
25 unsigned int id)
26 {
27 unsigned int i;
28
29 for (i = 0; i < mix->id_sz; i++) {
30 if (mix->wr_idx[i].used && id == mix->wr_idx[i].id)
31 return &mix->wr_idx[i];
32 }
33
34 return NULL;
35 }
36
alloc_more_ids(struct buffer_share * mix)37 static void alloc_more_ids(struct buffer_share *mix)
38 {
39 unsigned int new_size = mix->id_sz * 2;
40 unsigned int i;
41
42 mix->wr_idx = (struct id_offset *)realloc(
43 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
buffer_share_create(unsigned int buf_sz)51 struct buffer_share *buffer_share_create(unsigned int buf_sz)
52 {
53 struct buffer_share *mix;
54
55 mix = (struct buffer_share *)calloc(1, sizeof(*mix));
56 mix->id_sz = INITIAL_ID_SIZE;
57 mix->wr_idx =
58 (struct id_offset *)calloc(mix->id_sz, sizeof(mix->wr_idx[0]));
59 mix->buf_sz = buf_sz;
60
61 return mix;
62 }
63
buffer_share_destroy(struct buffer_share * mix)64 void buffer_share_destroy(struct buffer_share *mix)
65 {
66 if (!mix)
67 return;
68 free(mix->wr_idx);
69 free(mix);
70 }
71
buffer_share_add_id(struct buffer_share * mix,unsigned int id,void * data)72 int buffer_share_add_id(struct buffer_share *mix, unsigned int id, void *data)
73 {
74 struct id_offset *o;
75
76 o = find_id(mix, id);
77 if (o)
78 return -EEXIST;
79
80 o = find_unused(mix);
81 if (!o)
82 alloc_more_ids(mix);
83
84 o = find_unused(mix);
85 o->used = 1;
86 o->id = id;
87 o->offset = 0;
88 o->data = data;
89
90 return 0;
91 }
92
buffer_share_rm_id(struct buffer_share * mix,unsigned int id)93 int buffer_share_rm_id(struct buffer_share *mix, unsigned int id)
94 {
95 struct id_offset *o;
96
97 o = find_id(mix, id);
98 if (!o)
99 return -ENOENT;
100 o->used = 0;
101 o->data = NULL;
102
103 return 0;
104 }
105
buffer_share_offset_update(struct buffer_share * mix,unsigned int id,unsigned int delta)106 int buffer_share_offset_update(struct buffer_share *mix, unsigned int id,
107 unsigned int delta)
108 {
109 unsigned int i;
110
111 for (i = 0; i < mix->id_sz; i++) {
112 if (id != mix->wr_idx[i].id)
113 continue;
114
115 mix->wr_idx[i].offset += delta;
116 break;
117 }
118
119 return 0;
120 }
121
buffer_share_get_new_write_point(struct buffer_share * mix)122 unsigned int buffer_share_get_new_write_point(struct buffer_share *mix)
123 {
124 unsigned int min_written = mix->buf_sz + 1;
125 unsigned int i;
126
127 for (i = 0; i < mix->id_sz; i++) {
128 struct id_offset *o = &mix->wr_idx[i];
129
130 if (!o->used)
131 continue;
132
133 min_written = MIN(min_written, o->offset);
134 }
135 for (i = 0; i < mix->id_sz; i++) {
136 struct id_offset *o = &mix->wr_idx[i];
137 o->offset -= min_written;
138 }
139
140 if (min_written > mix->buf_sz)
141 return 0;
142
143 return min_written;
144 }
145
get_id_offset(const struct buffer_share * mix,unsigned int id)146 static struct id_offset *get_id_offset(const struct buffer_share *mix,
147 unsigned int id)
148 {
149 unsigned int i;
150 struct id_offset *o;
151
152 for (i = 0; i < mix->id_sz; i++) {
153 o = &mix->wr_idx[i];
154 if (o->used && o->id == id)
155 return o;
156 }
157 return NULL;
158 }
159
buffer_share_id_offset(const struct buffer_share * mix,unsigned int id)160 unsigned int buffer_share_id_offset(const struct buffer_share *mix,
161 unsigned int id)
162 {
163 struct id_offset *o = get_id_offset(mix, id);
164 return o ? o->offset : 0;
165 }
166
buffer_share_get_data(const struct buffer_share * mix,unsigned int id)167 void *buffer_share_get_data(const struct buffer_share *mix, unsigned int id)
168 {
169 struct id_offset *o = get_id_offset(mix, id);
170 return o ? o->data : NULL;
171 }
172