1#if 0
2//#if defined(__i386__) || defined(__x86_64__)
3#define LOCK_PREFIX "lock ; "
4#define ARCH_ADD(p,a)					\
5	__asm__ __volatile__(LOCK_PREFIX "addl %1,%0"	\
6			     :"=m" (*p)			\
7			     :"ir" (a), "m" (*p))
8struct __xchg_dummy { unsigned long a[100]; };
9#define __xg(x) ((struct __xchg_dummy *)(x))
10static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old,
11				      unsigned long new, int size)
12{
13	unsigned long prev;
14	switch (size) {
15	case 1:
16		__asm__ __volatile__(LOCK_PREFIX "cmpxchgb %b1,%2"
17				     : "=a"(prev)
18				     : "q"(new), "m"(*__xg(ptr)), "0"(old)
19				     : "memory");
20		return prev;
21	case 2:
22		__asm__ __volatile__(LOCK_PREFIX "cmpxchgw %w1,%2"
23				     : "=a"(prev)
24				     : "q"(new), "m"(*__xg(ptr)), "0"(old)
25				     : "memory");
26		return prev;
27	case 4:
28		__asm__ __volatile__(LOCK_PREFIX "cmpxchgl %1,%2"
29				     : "=a"(prev)
30				     : "q"(new), "m"(*__xg(ptr)), "0"(old)
31				     : "memory");
32		return prev;
33	}
34	return old;
35}
36
37#define ARCH_CMPXCHG(ptr,o,n)\
38	((__typeof__(*(ptr)))__cmpxchg((ptr),(unsigned long)(o),\
39					(unsigned long)(n),sizeof(*(ptr))))
40#define IS_CONCURRENT	1	/* check race */
41#endif
42
43#ifndef ARCH_ADD
44#define ARCH_ADD(p,a) (*(p) += (a))
45#define ARCH_CMPXCHG(p,a,b) (*(p)) /* fake */
46#define NO_CONCURRENT_ACCESS	/* use semaphore to avoid race */
47#define IS_CONCURRENT	0	/* no race check */
48#endif
49
50#if IS_CONCURRENT
51static void mix_areas_16(unsigned int size,
52			 volatile signed short *dst, signed short *src,
53			 volatile signed int *sum, size_t dst_step,
54			 size_t src_step, size_t sum_step)
55{
56	register signed int sample, old_sample;
57
58	for (;;) {
59		sample = *src;
60		old_sample = *sum;
61		if (ARCH_CMPXCHG(dst, 0, 1) == 0)
62			sample -= old_sample;
63		ARCH_ADD(sum, sample);
64		do {
65			old_sample = *sum;
66			if (old_sample > 0x7fff)
67				sample = 0x7fff;
68			else if (old_sample < -0x8000)
69				sample = -0x8000;
70			else
71				sample = old_sample;
72			*dst = sample;
73		} while (IS_CONCURRENT && *sum != old_sample);
74		if (!--size)
75			return;
76		src = (signed short *) ((char *)src + src_step);
77		dst = (signed short *) ((char *)dst + dst_step);
78		sum = (signed int *)   ((char *)sum + sum_step);
79	}
80}
81
82static void mix_areas_32(unsigned int size,
83			 volatile signed int *dst, signed int *src,
84			 volatile signed int *sum, size_t dst_step,
85			 size_t src_step, size_t sum_step)
86{
87	register signed int sample, old_sample;
88
89	for (;;) {
90		sample = *src >> 8;
91		old_sample = *sum;
92		if (ARCH_CMPXCHG(dst, 0, 1) == 0)
93			sample -= old_sample;
94		ARCH_ADD(sum, sample);
95		do {
96			old_sample = *sum;
97			if (old_sample > 0x7fffff)
98				sample = 0x7fffffff;
99			else if (old_sample < -0x800000)
100				sample = -0x80000000;
101			else
102				sample = old_sample * 256;
103			*dst = sample;
104		} while (IS_CONCURRENT && *sum != old_sample);
105		if (!--size)
106			return;
107		src = (signed int *) ((char *)src + src_step);
108		dst = (signed int *) ((char *)dst + dst_step);
109		sum = (signed int *) ((char *)sum + sum_step);
110	}
111}
112
113static void mix_select_callbacks(snd_pcm_direct_t *dmix)
114{
115	dmix->u.dmix.mix_areas_16 = mix_areas_16;
116	dmix->u.dmix.mix_areas_32 = mix_areas_32;
117}
118
119#else
120
121/* non-concurrent version, supporting both endians */
122#define generic_dmix_supported_format \
123	((1ULL << SND_PCM_FORMAT_S16_LE) | (1ULL << SND_PCM_FORMAT_S32_LE) |\
124	 (1ULL << SND_PCM_FORMAT_S16_BE) | (1ULL << SND_PCM_FORMAT_S32_BE) |\
125	 (1ULL << SND_PCM_FORMAT_S24_LE) | (1ULL << SND_PCM_FORMAT_S24_3LE) | \
126	 (1ULL << SND_PCM_FORMAT_U8))
127
128#include <byteswap.h>
129
130static void generic_mix_areas_16_native(unsigned int size,
131					volatile signed short *dst,
132					signed short *src,
133					volatile signed int *sum,
134					size_t dst_step,
135					size_t src_step,
136					size_t sum_step)
137{
138	register signed int sample;
139
140	for (;;) {
141		sample = *src;
142		if (! *dst) {
143			*sum = sample;
144			*dst = *src;
145		} else {
146			sample += *sum;
147			*sum = sample;
148			if (sample > 0x7fff)
149				sample = 0x7fff;
150			else if (sample < -0x8000)
151				sample = -0x8000;
152			*dst = sample;
153		}
154		if (!--size)
155			return;
156		src = (signed short *) ((char *)src + src_step);
157		dst = (signed short *) ((char *)dst + dst_step);
158		sum = (signed int *)   ((char *)sum + sum_step);
159	}
160}
161
162static void generic_remix_areas_16_native(unsigned int size,
163					  volatile signed short *dst,
164					  signed short *src,
165					  volatile signed int *sum,
166					  size_t dst_step,
167					  size_t src_step,
168					  size_t sum_step)
169{
170	register signed int sample;
171
172	for (;;) {
173		sample = *src;
174		if (! *dst) {
175			*sum = -sample;
176			*dst = -sample;
177		} else {
178			*sum = sample = *sum - sample;
179			if (sample > 0x7fff)
180				sample = 0x7fff;
181			else if (sample < -0x8000)
182				sample = -0x8000;
183			*dst = sample;
184		}
185		if (!--size)
186			return;
187		src = (signed short *) ((char *)src + src_step);
188		dst = (signed short *) ((char *)dst + dst_step);
189		sum = (signed int *)   ((char *)sum + sum_step);
190	}
191}
192
193static void generic_mix_areas_32_native(unsigned int size,
194					volatile signed int *dst,
195					signed int *src,
196					volatile signed int *sum,
197					size_t dst_step,
198					size_t src_step,
199					size_t sum_step)
200{
201	register signed int sample;
202
203	for (;;) {
204		sample = *src >> 8;
205		if (! *dst) {
206			*sum = sample;
207			*dst = *src;
208		} else {
209			sample += *sum;
210			*sum = sample;
211			if (sample > 0x7fffff)
212				sample = 0x7fffffff;
213			else if (sample < -0x800000)
214				sample = -0x80000000;
215			else
216				sample *= 256;
217			*dst = sample;
218		}
219		if (!--size)
220			return;
221		src = (signed int *) ((char *)src + src_step);
222		dst = (signed int *) ((char *)dst + dst_step);
223		sum = (signed int *) ((char *)sum + sum_step);
224	}
225}
226
227static void generic_remix_areas_32_native(unsigned int size,
228					  volatile signed int *dst,
229					  signed int *src,
230					  volatile signed int *sum,
231					  size_t dst_step,
232					  size_t src_step,
233					  size_t sum_step)
234{
235	register signed int sample;
236
237	for (;;) {
238		sample = *src >> 8;
239		if (! *dst) {
240			*sum = -sample;
241			*dst = -*src;
242		} else {
243			*sum = sample = *sum - sample;
244			if (sample > 0x7fffff)
245				sample = 0x7fffffff;
246			else if (sample < -0x800000)
247				sample = -0x80000000;
248			else
249				sample *= 256;
250			*dst = sample;
251		}
252		if (!--size)
253			return;
254		src = (signed int *) ((char *)src + src_step);
255		dst = (signed int *) ((char *)dst + dst_step);
256		sum = (signed int *) ((char *)sum + sum_step);
257	}
258}
259
260static void generic_mix_areas_16_swap(unsigned int size,
261				      volatile signed short *dst,
262				      signed short *src,
263				      volatile signed int *sum,
264				      size_t dst_step,
265				      size_t src_step,
266				      size_t sum_step)
267{
268	register signed int sample;
269
270	for (;;) {
271		sample = (signed short) bswap_16(*src);
272		if (! *dst) {
273			*sum = sample;
274			*dst = *src;
275		} else {
276			sample += *sum;
277			*sum = sample;
278			if (sample > 0x7fff)
279				sample = 0x7fff;
280			else if (sample < -0x8000)
281				sample = -0x8000;
282			*dst = (signed short) bswap_16((signed short) sample);
283		}
284		if (!--size)
285			return;
286		src = (signed short *) ((char *)src + src_step);
287		dst = (signed short *) ((char *)dst + dst_step);
288		sum = (signed int *)   ((char *)sum + sum_step);
289	}
290}
291
292static void generic_remix_areas_16_swap(unsigned int size,
293				        volatile signed short *dst,
294				        signed short *src,
295				        volatile signed int *sum,
296				        size_t dst_step,
297				        size_t src_step,
298				        size_t sum_step)
299{
300	register signed int sample;
301
302	for (;;) {
303		sample = (signed short) bswap_16(*src);
304		if (! *dst) {
305			*sum = -sample;
306			*dst = (signed short) bswap_16((signed short) -sample);
307		} else {
308			*sum = sample = *sum - sample;
309			if (sample > 0x7fff)
310				sample = 0x7fff;
311			else if (sample < -0x8000)
312				sample = -0x8000;
313			*dst = (signed short) bswap_16((signed short) sample);
314		}
315		if (!--size)
316			return;
317		src = (signed short *) ((char *)src + src_step);
318		dst = (signed short *) ((char *)dst + dst_step);
319		sum = (signed int *)   ((char *)sum + sum_step);
320	}
321}
322
323static void generic_mix_areas_32_swap(unsigned int size,
324				      volatile signed int *dst,
325				      signed int *src,
326				      volatile signed int *sum,
327				      size_t dst_step,
328				      size_t src_step,
329				      size_t sum_step)
330{
331	register signed int sample;
332
333	for (;;) {
334		sample = bswap_32(*src) >> 8;
335		if (! *dst) {
336			*sum = sample;
337			*dst = *src;
338		} else {
339			sample += *sum;
340			*sum = sample;
341			if (sample > 0x7fffff)
342				sample = 0x7fffffff;
343			else if (sample < -0x800000)
344				sample = -0x80000000;
345			else
346				sample *= 256;
347			*dst = bswap_32(sample);
348		}
349		if (!--size)
350			return;
351		src = (signed int *) ((char *)src + src_step);
352		dst = (signed int *) ((char *)dst + dst_step);
353		sum = (signed int *) ((char *)sum + sum_step);
354	}
355}
356
357static void generic_remix_areas_32_swap(unsigned int size,
358				        volatile signed int *dst,
359				        signed int *src,
360				        volatile signed int *sum,
361				        size_t dst_step,
362				        size_t src_step,
363				        size_t sum_step)
364{
365	register signed int sample;
366
367	for (;;) {
368		sample = bswap_32(*src) >> 8;
369		if (! *dst) {
370			*sum = -sample;
371			*dst = bswap_32(-sample);
372		} else {
373			*sum = sample = *sum - sample;
374			if (sample > 0x7fffff)
375				sample = 0x7fffffff;
376			else if (sample < -0x800000)
377				sample = -0x80000000;
378			else
379				sample *= 256;
380			*dst = bswap_32(sample);
381		}
382		if (!--size)
383			return;
384		src = (signed int *) ((char *)src + src_step);
385		dst = (signed int *) ((char *)dst + dst_step);
386		sum = (signed int *) ((char *)sum + sum_step);
387	}
388}
389
390/* always little endian */
391static void generic_mix_areas_24(unsigned int size,
392				 volatile unsigned char *dst,
393				 unsigned char *src,
394				 volatile signed int *sum,
395				 size_t dst_step,
396				 size_t src_step,
397				 size_t sum_step)
398{
399	register signed int sample;
400
401	for (;;) {
402		sample = src[0] | (src[1] << 8) | (((signed char *)src)[2] << 16);
403		if (!(dst[0] | dst[1] | dst[2])) {
404			*sum = sample;
405		} else {
406			sample += *sum;
407			*sum = sample;
408			if (sample > 0x7fffff)
409				sample = 0x7fffff;
410			else if (sample < -0x800000)
411				sample = -0x800000;
412		}
413		dst[0] = sample;
414		dst[1] = sample >> 8;
415		dst[2] = sample >> 16;
416		if (!--size)
417			return;
418		dst += dst_step;
419		src += src_step;
420		sum = (signed int *) ((char *)sum + sum_step);
421	}
422}
423
424static void generic_remix_areas_24(unsigned int size,
425				   volatile unsigned char *dst,
426				   unsigned char *src,
427				   volatile signed int *sum,
428				   size_t dst_step,
429				   size_t src_step,
430				   size_t sum_step)
431{
432	register signed int sample;
433
434	for (;;) {
435		sample = src[0] | (src[1] << 8) | (((signed char *)src)[2] << 16);
436		if (!(dst[0] | dst[1] | dst[2])) {
437			sample = -sample;
438			*sum = sample;
439		} else {
440			*sum = sample = *sum - sample;
441			if (sample > 0x7fffff)
442				sample = 0x7fffff;
443			else if (sample < -0x800000)
444				sample = -0x800000;
445		}
446		dst[0] = sample;
447		dst[1] = sample >> 8;
448		dst[2] = sample >> 16;
449		if (!--size)
450			return;
451		dst += dst_step;
452		src += src_step;
453		sum = (signed int *) ((char *)sum + sum_step);
454	}
455}
456
457static void generic_mix_areas_u8(unsigned int size,
458				 volatile unsigned char *dst,
459				 unsigned char *src,
460				 volatile signed int *sum,
461				 size_t dst_step,
462				 size_t src_step,
463				 size_t sum_step)
464{
465	for (;;) {
466		register int sample = *src - 0x80;
467		if (*dst == 0x80) {
468			*sum = sample;
469		} else {
470			sample += *sum;
471			*sum = sample;
472			if (sample > 0x7f)
473				sample = 0x7f;
474			else if (sample < -0x80)
475				sample = -0x80;
476		}
477		*dst = sample + 0x80;
478		if (!--size)
479			return;
480		dst += dst_step;
481		src += src_step;
482		sum = (signed int *) ((char *)sum + sum_step);
483	}
484}
485
486static void generic_remix_areas_u8(unsigned int size,
487				   volatile unsigned char *dst,
488				   unsigned char *src,
489				   volatile signed int *sum,
490				   size_t dst_step,
491				   size_t src_step,
492				   size_t sum_step)
493{
494	for (;;) {
495		register int sample = *src - 0x80;
496		if (*dst == 0x80) {
497			sample = -sample;
498			*sum = sample;
499		} else {
500			*sum = sample = *sum - sample;
501			if (sample > 0x7f)
502				sample = 0x7f;
503			else if (sample < -0x80)
504				sample = -0x80;
505		}
506		*dst = sample + 0x80;
507		if (!--size)
508			return;
509		dst += dst_step;
510		src += src_step;
511		sum = (signed int *) ((char *)sum + sum_step);
512	}
513}
514
515
516static void generic_mix_select_callbacks(snd_pcm_direct_t *dmix)
517{
518	if (snd_pcm_format_cpu_endian(dmix->shmptr->s.format)) {
519		dmix->u.dmix.mix_areas_16 = generic_mix_areas_16_native;
520		dmix->u.dmix.mix_areas_32 = generic_mix_areas_32_native;
521		dmix->u.dmix.remix_areas_16 = generic_remix_areas_16_native;
522		dmix->u.dmix.remix_areas_32 = generic_remix_areas_32_native;
523	} else {
524		dmix->u.dmix.mix_areas_16 = generic_mix_areas_16_swap;
525		dmix->u.dmix.mix_areas_32 = generic_mix_areas_32_swap;
526		dmix->u.dmix.remix_areas_16 = generic_remix_areas_16_swap;
527		dmix->u.dmix.remix_areas_32 = generic_remix_areas_32_swap;
528	}
529	dmix->u.dmix.mix_areas_24 = generic_mix_areas_24;
530	dmix->u.dmix.mix_areas_u8 = generic_mix_areas_u8;
531	dmix->u.dmix.remix_areas_24 = generic_remix_areas_24;
532	dmix->u.dmix.remix_areas_u8 = generic_remix_areas_u8;
533}
534
535#endif
536