#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <linux/ppdev.h>

#define CLOCK_BIT	0x01
#define LATCH_BIT	0x02
#define	DATA_BIT	0x04

/*
 * gcc -o steckdose steckdose.c
 *
 * Use like:
 *
 * ./steckdose /dev/ppdev0 0 1 0 0 0 1 0 1
 *
 * - Use device /dev/ppdev0 (or /dev/parport0, depending on your
 *   Distribution; usually this is major=99, minor=0)
 * - Have 8 switches (one full shift register) being in states
 *   0, 1, 0, 0, 0, 1, 0, 1
 */

int
set_state (int fd, int state)
{
	int	ret;

	ret = ioctl (fd, PPWDATA, &state);
	if (ret != 0) {
		perror ("ioctl (PPWDATA)");
		close (fd);
		exit (EXIT_FAILURE);
	}

	return 0;
}

int
main (int argc, char *argv[])
{
	int	fd;
	int	active;
	int	state = 0;
	int	i;
	int	ret;

	fd = open (argv[1], O_WRONLY);
	if (fd < 0) {
		perror ("open");
		exit (EXIT_FAILURE);
	}

	ret = ioctl (fd, PPCLAIM);
	if (ret != 0) {
		perror ("ioctl (PPCLAIM)");
		close (fd);
		exit (EXIT_FAILURE);
	}

#if 0
	ret = ioctl (fd, PPEXCL);
	if (ret != 0) {
		perror ("ioctl (PPEXCL)");
		close (fd);
		exit (EXIT_FAILURE);
	}
#endif

	for (i = 2; i < argc; i++) {
		/* Get data to line */
		active = atoi (argv[i]);
		state = active? DATA_BIT: 0;
		set_state (fd, state);

		/* Strobe clock */
		state = state | CLOCK_BIT;
		set_state (fd, state);
		state = active? DATA_BIT: 0;
		set_state (fd, state);
	}

	/* Strobe latch */
	set_state (fd, LATCH_BIT);
	set_state (fd, 0);

	ret = ioctl (fd, PPRELEASE);
	if (ret != 0) {
		perror ("ioctl (PPRELEASE)");
		close (fd);
		exit (EXIT_FAILURE);
	}

	close (fd);

	return EXIT_SUCCESS;
}

