1d5ac70f0Sopenharmony_ci/*
2d5ac70f0Sopenharmony_ci *  Mask inlines
3d5ac70f0Sopenharmony_ci *  Copyright (c) 2000 by Abramo Bagnara <abramo@alsa-project.org>
4d5ac70f0Sopenharmony_ci *
5d5ac70f0Sopenharmony_ci *
6d5ac70f0Sopenharmony_ci *   This library is free software; you can redistribute it and/or modify
7d5ac70f0Sopenharmony_ci *   it under the terms of the GNU Lesser General Public License as
8d5ac70f0Sopenharmony_ci *   published by the Free Software Foundation; either version 2.1 of
9d5ac70f0Sopenharmony_ci *   the License, or (at your option) any later version.
10d5ac70f0Sopenharmony_ci *
11d5ac70f0Sopenharmony_ci *   This program is distributed in the hope that it will be useful,
12d5ac70f0Sopenharmony_ci *   but WITHOUT ANY WARRANTY; without even the implied warranty of
13d5ac70f0Sopenharmony_ci *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14d5ac70f0Sopenharmony_ci *   GNU Lesser General Public License for more details.
15d5ac70f0Sopenharmony_ci *
16d5ac70f0Sopenharmony_ci *   You should have received a copy of the GNU Lesser General Public
17d5ac70f0Sopenharmony_ci *   License along with this library; if not, write to the Free Software
18d5ac70f0Sopenharmony_ci *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
19d5ac70f0Sopenharmony_ci *
20d5ac70f0Sopenharmony_ci */
21d5ac70f0Sopenharmony_ci
22d5ac70f0Sopenharmony_ci#include <strings.h>
23d5ac70f0Sopenharmony_ci#include <sys/types.h>
24d5ac70f0Sopenharmony_ci
25d5ac70f0Sopenharmony_ci#define MASK_INLINE static inline
26d5ac70f0Sopenharmony_ci
27d5ac70f0Sopenharmony_ci#define MASK_MAX SND_MASK_MAX
28d5ac70f0Sopenharmony_ci#define MASK_SIZE (MASK_MAX / 32)
29d5ac70f0Sopenharmony_ci
30d5ac70f0Sopenharmony_ci#define MASK_OFS(i)	((i) >> 5)
31d5ac70f0Sopenharmony_ci#define MASK_BIT(i)	(1U << ((i) & 31))
32d5ac70f0Sopenharmony_ci
33d5ac70f0Sopenharmony_ciMASK_INLINE unsigned int ld2(uint32_t v)
34d5ac70f0Sopenharmony_ci{
35d5ac70f0Sopenharmony_ci        unsigned r = 0;
36d5ac70f0Sopenharmony_ci
37d5ac70f0Sopenharmony_ci        if (v >= 0x10000) {
38d5ac70f0Sopenharmony_ci                v >>= 16;
39d5ac70f0Sopenharmony_ci                r += 16;
40d5ac70f0Sopenharmony_ci        }
41d5ac70f0Sopenharmony_ci        if (v >= 0x100) {
42d5ac70f0Sopenharmony_ci                v >>= 8;
43d5ac70f0Sopenharmony_ci                r += 8;
44d5ac70f0Sopenharmony_ci        }
45d5ac70f0Sopenharmony_ci        if (v >= 0x10) {
46d5ac70f0Sopenharmony_ci                v >>= 4;
47d5ac70f0Sopenharmony_ci                r += 4;
48d5ac70f0Sopenharmony_ci        }
49d5ac70f0Sopenharmony_ci        if (v >= 4) {
50d5ac70f0Sopenharmony_ci                v >>= 2;
51d5ac70f0Sopenharmony_ci                r += 2;
52d5ac70f0Sopenharmony_ci        }
53d5ac70f0Sopenharmony_ci        if (v >= 2)
54d5ac70f0Sopenharmony_ci                r++;
55d5ac70f0Sopenharmony_ci        return r;
56d5ac70f0Sopenharmony_ci}
57d5ac70f0Sopenharmony_ci
58d5ac70f0Sopenharmony_ciMASK_INLINE unsigned int hweight32(uint32_t v)
59d5ac70f0Sopenharmony_ci{
60d5ac70f0Sopenharmony_ci        v = (v & 0x55555555) + ((v >> 1) & 0x55555555);
61d5ac70f0Sopenharmony_ci        v = (v & 0x33333333) + ((v >> 2) & 0x33333333);
62d5ac70f0Sopenharmony_ci        v = (v & 0x0F0F0F0F) + ((v >> 4) & 0x0F0F0F0F);
63d5ac70f0Sopenharmony_ci        v = (v & 0x00FF00FF) + ((v >> 8) & 0x00FF00FF);
64d5ac70f0Sopenharmony_ci        return (v & 0x0000FFFF) + ((v >> 16) & 0x0000FFFF);
65d5ac70f0Sopenharmony_ci}
66d5ac70f0Sopenharmony_ci
67d5ac70f0Sopenharmony_ciMASK_INLINE size_t snd_mask_sizeof(void)
68d5ac70f0Sopenharmony_ci{
69d5ac70f0Sopenharmony_ci	return sizeof(snd_mask_t);
70d5ac70f0Sopenharmony_ci}
71d5ac70f0Sopenharmony_ci
72d5ac70f0Sopenharmony_ciMASK_INLINE void snd_mask_none(snd_mask_t *mask)
73d5ac70f0Sopenharmony_ci{
74d5ac70f0Sopenharmony_ci	memset(mask, 0, sizeof(*mask));
75d5ac70f0Sopenharmony_ci}
76d5ac70f0Sopenharmony_ci
77d5ac70f0Sopenharmony_ciMASK_INLINE void snd_mask_any(snd_mask_t *mask)
78d5ac70f0Sopenharmony_ci{
79d5ac70f0Sopenharmony_ci	memset(mask, 0xff, MASK_SIZE * sizeof(uint32_t));
80d5ac70f0Sopenharmony_ci}
81d5ac70f0Sopenharmony_ci
82d5ac70f0Sopenharmony_ciMASK_INLINE int snd_mask_empty(const snd_mask_t *mask)
83d5ac70f0Sopenharmony_ci{
84d5ac70f0Sopenharmony_ci	int i;
85d5ac70f0Sopenharmony_ci	for (i = 0; i < MASK_SIZE; i++)
86d5ac70f0Sopenharmony_ci		if (mask->bits[i])
87d5ac70f0Sopenharmony_ci			return 0;
88d5ac70f0Sopenharmony_ci	return 1;
89d5ac70f0Sopenharmony_ci}
90d5ac70f0Sopenharmony_ci
91d5ac70f0Sopenharmony_ciMASK_INLINE int snd_mask_full(const snd_mask_t *mask)
92d5ac70f0Sopenharmony_ci{
93d5ac70f0Sopenharmony_ci	int i;
94d5ac70f0Sopenharmony_ci	for (i = 0; i < MASK_SIZE; i++)
95d5ac70f0Sopenharmony_ci		if (mask->bits[i] != 0xffffffff)
96d5ac70f0Sopenharmony_ci			return 0;
97d5ac70f0Sopenharmony_ci	return 1;
98d5ac70f0Sopenharmony_ci}
99d5ac70f0Sopenharmony_ci
100d5ac70f0Sopenharmony_ciMASK_INLINE unsigned int snd_mask_count(const snd_mask_t *mask)
101d5ac70f0Sopenharmony_ci{
102d5ac70f0Sopenharmony_ci	int i, w = 0;
103d5ac70f0Sopenharmony_ci	for (i = 0; i < MASK_SIZE; i++)
104d5ac70f0Sopenharmony_ci		w += hweight32(mask->bits[i]);
105d5ac70f0Sopenharmony_ci	return w;
106d5ac70f0Sopenharmony_ci}
107d5ac70f0Sopenharmony_ci
108d5ac70f0Sopenharmony_ciMASK_INLINE unsigned int snd_mask_min(const snd_mask_t *mask)
109d5ac70f0Sopenharmony_ci{
110d5ac70f0Sopenharmony_ci	int i;
111d5ac70f0Sopenharmony_ci	assert(!snd_mask_empty(mask));
112d5ac70f0Sopenharmony_ci	for (i = 0; i < MASK_SIZE; i++) {
113d5ac70f0Sopenharmony_ci		if (mask->bits[i])
114d5ac70f0Sopenharmony_ci			return ffs(mask->bits[i]) - 1 + (i << 5);
115d5ac70f0Sopenharmony_ci	}
116d5ac70f0Sopenharmony_ci	return 0;
117d5ac70f0Sopenharmony_ci}
118d5ac70f0Sopenharmony_ci
119d5ac70f0Sopenharmony_ciMASK_INLINE unsigned int snd_mask_max(const snd_mask_t *mask)
120d5ac70f0Sopenharmony_ci{
121d5ac70f0Sopenharmony_ci	int i;
122d5ac70f0Sopenharmony_ci	assert(!snd_mask_empty(mask));
123d5ac70f0Sopenharmony_ci	for (i = MASK_SIZE - 1; i >= 0; i--) {
124d5ac70f0Sopenharmony_ci		if (mask->bits[i])
125d5ac70f0Sopenharmony_ci			return ld2(mask->bits[i]) + (i << 5);
126d5ac70f0Sopenharmony_ci	}
127d5ac70f0Sopenharmony_ci	return 0;
128d5ac70f0Sopenharmony_ci}
129d5ac70f0Sopenharmony_ci
130d5ac70f0Sopenharmony_ciMASK_INLINE void snd_mask_set(snd_mask_t *mask, unsigned int val)
131d5ac70f0Sopenharmony_ci{
132d5ac70f0Sopenharmony_ci	assert(val <= SND_MASK_MAX);
133d5ac70f0Sopenharmony_ci	mask->bits[MASK_OFS(val)] |= MASK_BIT(val);
134d5ac70f0Sopenharmony_ci}
135d5ac70f0Sopenharmony_ci
136d5ac70f0Sopenharmony_ciMASK_INLINE void snd_mask_reset(snd_mask_t *mask, unsigned int val)
137d5ac70f0Sopenharmony_ci{
138d5ac70f0Sopenharmony_ci	assert(val <= SND_MASK_MAX);
139d5ac70f0Sopenharmony_ci	mask->bits[MASK_OFS(val)] &= ~MASK_BIT(val);
140d5ac70f0Sopenharmony_ci}
141d5ac70f0Sopenharmony_ci
142d5ac70f0Sopenharmony_ciMASK_INLINE void snd_mask_set_range(snd_mask_t *mask, unsigned int from, unsigned int to)
143d5ac70f0Sopenharmony_ci{
144d5ac70f0Sopenharmony_ci	unsigned int i;
145d5ac70f0Sopenharmony_ci	assert(to <= SND_MASK_MAX && from <= to);
146d5ac70f0Sopenharmony_ci	for (i = from; i <= to; i++)
147d5ac70f0Sopenharmony_ci		mask->bits[MASK_OFS(i)] |= MASK_BIT(i);
148d5ac70f0Sopenharmony_ci}
149d5ac70f0Sopenharmony_ci
150d5ac70f0Sopenharmony_ciMASK_INLINE void snd_mask_reset_range(snd_mask_t *mask, unsigned int from, unsigned int to)
151d5ac70f0Sopenharmony_ci{
152d5ac70f0Sopenharmony_ci	unsigned int i;
153d5ac70f0Sopenharmony_ci	assert(to <= SND_MASK_MAX && from <= to);
154d5ac70f0Sopenharmony_ci	for (i = from; i <= to; i++)
155d5ac70f0Sopenharmony_ci		mask->bits[MASK_OFS(i)] &= ~MASK_BIT(i);
156d5ac70f0Sopenharmony_ci}
157d5ac70f0Sopenharmony_ci
158d5ac70f0Sopenharmony_ciMASK_INLINE void snd_mask_leave(snd_mask_t *mask, unsigned int val)
159d5ac70f0Sopenharmony_ci{
160d5ac70f0Sopenharmony_ci	unsigned int v;
161d5ac70f0Sopenharmony_ci	assert(val <= SND_MASK_MAX);
162d5ac70f0Sopenharmony_ci	v = mask->bits[MASK_OFS(val)] & MASK_BIT(val);
163d5ac70f0Sopenharmony_ci	snd_mask_none(mask);
164d5ac70f0Sopenharmony_ci	mask->bits[MASK_OFS(val)] = v;
165d5ac70f0Sopenharmony_ci}
166d5ac70f0Sopenharmony_ci
167d5ac70f0Sopenharmony_ciMASK_INLINE void snd_mask_intersect(snd_mask_t *mask, const snd_mask_t *v)
168d5ac70f0Sopenharmony_ci{
169d5ac70f0Sopenharmony_ci	int i;
170d5ac70f0Sopenharmony_ci	for (i = 0; i < MASK_SIZE; i++)
171d5ac70f0Sopenharmony_ci		mask->bits[i] &= v->bits[i];
172d5ac70f0Sopenharmony_ci}
173d5ac70f0Sopenharmony_ci
174d5ac70f0Sopenharmony_ciMASK_INLINE void snd_mask_union(snd_mask_t *mask, const snd_mask_t *v)
175d5ac70f0Sopenharmony_ci{
176d5ac70f0Sopenharmony_ci	int i;
177d5ac70f0Sopenharmony_ci	for (i = 0; i < MASK_SIZE; i++)
178d5ac70f0Sopenharmony_ci		mask->bits[i] |= v->bits[i];
179d5ac70f0Sopenharmony_ci}
180d5ac70f0Sopenharmony_ci
181d5ac70f0Sopenharmony_ciMASK_INLINE int snd_mask_eq(const snd_mask_t *mask, const snd_mask_t *v)
182d5ac70f0Sopenharmony_ci{
183d5ac70f0Sopenharmony_ci	return ! memcmp(mask, v, MASK_SIZE * 4);
184d5ac70f0Sopenharmony_ci}
185d5ac70f0Sopenharmony_ci
186d5ac70f0Sopenharmony_ciMASK_INLINE void snd_mask_copy(snd_mask_t *mask, const snd_mask_t *v)
187d5ac70f0Sopenharmony_ci{
188d5ac70f0Sopenharmony_ci	*mask = *v;
189d5ac70f0Sopenharmony_ci}
190d5ac70f0Sopenharmony_ci
191d5ac70f0Sopenharmony_ciMASK_INLINE int snd_mask_test(const snd_mask_t *mask, unsigned int val)
192d5ac70f0Sopenharmony_ci{
193d5ac70f0Sopenharmony_ci	assert(val <= SND_MASK_MAX);
194d5ac70f0Sopenharmony_ci	return mask->bits[MASK_OFS(val)] & MASK_BIT(val);
195d5ac70f0Sopenharmony_ci}
196d5ac70f0Sopenharmony_ci
197d5ac70f0Sopenharmony_ciMASK_INLINE int snd_mask_single(const snd_mask_t *mask)
198d5ac70f0Sopenharmony_ci{
199d5ac70f0Sopenharmony_ci	int i, c = 0;
200d5ac70f0Sopenharmony_ci	assert(!snd_mask_empty(mask));
201d5ac70f0Sopenharmony_ci	for (i = 0; i < MASK_SIZE; i++) {
202d5ac70f0Sopenharmony_ci		if (! mask->bits[i])
203d5ac70f0Sopenharmony_ci			continue;
204d5ac70f0Sopenharmony_ci		if (mask->bits[i] & (mask->bits[i] - 1))
205d5ac70f0Sopenharmony_ci			return 0;
206d5ac70f0Sopenharmony_ci		if (c)
207d5ac70f0Sopenharmony_ci			return 0;
208d5ac70f0Sopenharmony_ci		c++;
209d5ac70f0Sopenharmony_ci	}
210d5ac70f0Sopenharmony_ci	return 1;
211d5ac70f0Sopenharmony_ci}
212d5ac70f0Sopenharmony_ci
213d5ac70f0Sopenharmony_ciMASK_INLINE int snd_mask_refine(snd_mask_t *mask, const snd_mask_t *v)
214d5ac70f0Sopenharmony_ci{
215d5ac70f0Sopenharmony_ci	snd_mask_t old;
216d5ac70f0Sopenharmony_ci	if (snd_mask_empty(mask))
217d5ac70f0Sopenharmony_ci		return -ENOENT;
218d5ac70f0Sopenharmony_ci	snd_mask_copy(&old, mask);
219d5ac70f0Sopenharmony_ci	snd_mask_intersect(mask, v);
220d5ac70f0Sopenharmony_ci	if (snd_mask_empty(mask))
221d5ac70f0Sopenharmony_ci		return -EINVAL;
222d5ac70f0Sopenharmony_ci	return !snd_mask_eq(mask, &old);
223d5ac70f0Sopenharmony_ci}
224d5ac70f0Sopenharmony_ci
225d5ac70f0Sopenharmony_ciMASK_INLINE int snd_mask_refine_first(snd_mask_t *mask)
226d5ac70f0Sopenharmony_ci{
227d5ac70f0Sopenharmony_ci	if (snd_mask_empty(mask))
228d5ac70f0Sopenharmony_ci		return -ENOENT;
229d5ac70f0Sopenharmony_ci	if (snd_mask_single(mask))
230d5ac70f0Sopenharmony_ci		return 0;
231d5ac70f0Sopenharmony_ci	snd_mask_leave(mask, snd_mask_min(mask));
232d5ac70f0Sopenharmony_ci	return 1;
233d5ac70f0Sopenharmony_ci}
234d5ac70f0Sopenharmony_ci
235d5ac70f0Sopenharmony_ciMASK_INLINE int snd_mask_refine_last(snd_mask_t *mask)
236d5ac70f0Sopenharmony_ci{
237d5ac70f0Sopenharmony_ci	if (snd_mask_empty(mask))
238d5ac70f0Sopenharmony_ci		return -ENOENT;
239d5ac70f0Sopenharmony_ci	if (snd_mask_single(mask))
240d5ac70f0Sopenharmony_ci		return 0;
241d5ac70f0Sopenharmony_ci	snd_mask_leave(mask, snd_mask_max(mask));
242d5ac70f0Sopenharmony_ci	return 1;
243d5ac70f0Sopenharmony_ci}
244d5ac70f0Sopenharmony_ci
245d5ac70f0Sopenharmony_ciMASK_INLINE int snd_mask_refine_min(snd_mask_t *mask, unsigned int val)
246d5ac70f0Sopenharmony_ci{
247d5ac70f0Sopenharmony_ci	if (snd_mask_empty(mask))
248d5ac70f0Sopenharmony_ci		return -ENOENT;
249d5ac70f0Sopenharmony_ci	if (snd_mask_min(mask) >= val)
250d5ac70f0Sopenharmony_ci		return 0;
251d5ac70f0Sopenharmony_ci	snd_mask_reset_range(mask, 0, val - 1);
252d5ac70f0Sopenharmony_ci	if (snd_mask_empty(mask))
253d5ac70f0Sopenharmony_ci		return -EINVAL;
254d5ac70f0Sopenharmony_ci	return 1;
255d5ac70f0Sopenharmony_ci}
256d5ac70f0Sopenharmony_ci
257d5ac70f0Sopenharmony_ciMASK_INLINE int snd_mask_refine_max(snd_mask_t *mask, unsigned int val)
258d5ac70f0Sopenharmony_ci{
259d5ac70f0Sopenharmony_ci	if (snd_mask_empty(mask))
260d5ac70f0Sopenharmony_ci		return -ENOENT;
261d5ac70f0Sopenharmony_ci	if (snd_mask_max(mask) <= val)
262d5ac70f0Sopenharmony_ci		return 0;
263d5ac70f0Sopenharmony_ci	snd_mask_reset_range(mask, val + 1, SND_MASK_MAX);
264d5ac70f0Sopenharmony_ci	if (snd_mask_empty(mask))
265d5ac70f0Sopenharmony_ci		return -EINVAL;
266d5ac70f0Sopenharmony_ci	return 1;
267d5ac70f0Sopenharmony_ci}
268d5ac70f0Sopenharmony_ci
269d5ac70f0Sopenharmony_ciMASK_INLINE int snd_mask_refine_set(snd_mask_t *mask, unsigned int val)
270d5ac70f0Sopenharmony_ci{
271d5ac70f0Sopenharmony_ci	int changed;
272d5ac70f0Sopenharmony_ci	if (snd_mask_empty(mask))
273d5ac70f0Sopenharmony_ci		return -ENOENT;
274d5ac70f0Sopenharmony_ci	changed = !snd_mask_single(mask);
275d5ac70f0Sopenharmony_ci	snd_mask_leave(mask, val);
276d5ac70f0Sopenharmony_ci	if (snd_mask_empty(mask))
277d5ac70f0Sopenharmony_ci		return -EINVAL;
278d5ac70f0Sopenharmony_ci	return changed;
279d5ac70f0Sopenharmony_ci}
280d5ac70f0Sopenharmony_ci
281d5ac70f0Sopenharmony_ciMASK_INLINE int snd_mask_value(const snd_mask_t *mask)
282d5ac70f0Sopenharmony_ci{
283d5ac70f0Sopenharmony_ci	assert(!snd_mask_empty(mask));
284d5ac70f0Sopenharmony_ci	return snd_mask_min(mask);
285d5ac70f0Sopenharmony_ci}
286d5ac70f0Sopenharmony_ci
287d5ac70f0Sopenharmony_ciMASK_INLINE int snd_mask_always_eq(const snd_mask_t *m1, const snd_mask_t *m2)
288d5ac70f0Sopenharmony_ci{
289d5ac70f0Sopenharmony_ci	return snd_mask_single(m1) && snd_mask_single(m2) &&
290d5ac70f0Sopenharmony_ci		snd_mask_value(m1) == snd_mask_value(m2);
291d5ac70f0Sopenharmony_ci}
292d5ac70f0Sopenharmony_ci
293d5ac70f0Sopenharmony_ciMASK_INLINE int snd_mask_never_eq(const snd_mask_t *m1, const snd_mask_t *m2)
294d5ac70f0Sopenharmony_ci{
295d5ac70f0Sopenharmony_ci	int i;
296d5ac70f0Sopenharmony_ci	for (i = 0; i < MASK_SIZE; i++)
297d5ac70f0Sopenharmony_ci		if (m1->bits[i] & m2->bits[i])
298d5ac70f0Sopenharmony_ci			return 0;
299d5ac70f0Sopenharmony_ci	return 1;
300d5ac70f0Sopenharmony_ci}
301