/* round 2: clone-alias open, open/close churn + hammer, heavier */
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <pthread.h>
#include <sys/ioctl.h>
#include <sys/soundcard.h>

#define MIXER_WRITE_J(j) (0x80044d00u | (j))
#define MIXER_READ_J(j)  (0xc0044d00u | (j))

static volatile int stop;

static void *
churn(void *arg)
{
	int i, fd;
	(void)arg;
	for (i = 0; i < 3000 && !stop; i++) {
		fd = open("/dev/mixer0", O_RDWR);
		if (fd >= 0) {
			int v = 0x5050;
			ioctl(fd, MIXER_WRITE_J(SOUND_MIXER_VOLUME), &v);
			close(fd);
		}
		fd = open("/dev/mixer", O_RDWR);	/* clone alias */
		if (fd >= 0) {
			int v = 0;
			ioctl(fd, MIXER_READ_J(0xfe), &v);
			close(fd);
		}
	}
	return (NULL);
}

static void *
hammer(void *arg)
{
	long id = (long)arg;
	int i, v, fd = open("/dev/mixer0", O_RDWR);
	(void)arg;
	if (fd < 0) { perror("hammer open"); return (NULL); }
	for (i = 0; i < 200000 && !stop; i++) {
		v = (i & 0x7f) | (((i * 13) & 0x7f) << 8);
		ioctl(fd, MIXER_WRITE_J(4 + (i % 21)), &v);
		v = i;
		ioctl(fd, MIXER_WRITE_J(0xff), &v);
		v = 0;
		ioctl(fd, MIXER_READ_J(0xfd), &v);
	}
	close(fd);
	if (id == 0) printf("hammer %ld done\n", id);
	return (NULL);
}

int
main(void)
{
	pthread_t ch[2], h[4];
	long i;

	printf("clone-alias open: ");
	fflush(stdout);
	int fd = open("/dev/mixer", O_RDWR);
	printf("%s (errno=%d)\n", fd >= 0 ? "OK" : "FAIL", errno);
	if (fd >= 0) {
		int v = 0;
		printf("alias DEVMASK read rc=%d v=0x%x\n",
		    ioctl(fd, MIXER_READ_J(0xfe), &v), v);
		close(fd);
	}
	for (i = 0; i < 2; i++)
		pthread_create(&ch[i], NULL, churn, NULL);
	for (i = 0; i < 4; i++)
		pthread_create(&h[i], NULL, hammer, (void *)i);
	for (i = 0; i < 4; i++)
		pthread_join(h[i], NULL);
	stop = 1;
	for (i = 0; i < 2; i++)
		pthread_join(ch[i], NULL);
	printf("ROUND2 COMPLETE alive: %s\n",
	    system("echo yes") == 0 ? "yes" : "NO");
	return (0);
}
