/*
 * dfctl.c -- userland driver for /dev/df5632 (DF-5632..5635 evidence).
 */
#include <sys/types.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <err.h>
#include <unistd.h>

#define DF5632_IOCTL_MAGIC	'D'
struct df5632_req {
	int32_t		arg;
	int32_t		rc;
	int64_t		v0, v1, v2, v3;
};
#define DF5632_STAT		_IOWR(DF5632_IOCTL_MAGIC, 1, struct df5632_req)
#define DF5632_CYCLE		_IOWR(DF5632_IOCTL_MAGIC, 2, struct df5632_req)
#define DF5632_ADDCHILD		_IOWR(DF5632_IOCTL_MAGIC, 3, struct df5632_req)
#define DF5632_IVAR_RT		_IOWR(DF5632_IOCTL_MAGIC, 4, struct df5632_req)
#define DF5632_FAILCHILD	_IOWR(DF5632_IOCTL_MAGIC, 5, struct df5632_req)
#define DF5632_DETACH_BUS	_IOWR(DF5632_IOCTL_MAGIC, 6, struct df5632_req)
#define DF5632_REQBUS		_IOWR(DF5632_IOCTL_MAGIC, 7, struct df5632_req)

int
main(int argc, char **argv)
{
	struct df5632_req r;
	unsigned long cmd;
	int fd;

	if (argc < 2) {
		fprintf(stderr,
		    "usage: dfctl stat|cycle N|addchild|ivar|failchild"
		    "|detach_bus|reqbus\n");
		return (2);
	}
	memset(&r, 0, sizeof(r));

	if (!strcmp(argv[1], "stat"))		cmd = DF5632_STAT;
	else if (!strcmp(argv[1], "cycle"))	cmd = DF5632_CYCLE;
	else if (!strcmp(argv[1], "addchild"))	cmd = DF5632_ADDCHILD;
	else if (!strcmp(argv[1], "ivar"))	cmd = DF5632_IVAR_RT;
	else if (!strcmp(argv[1], "failchild"))	cmd = DF5632_FAILCHILD;
	else if (!strcmp(argv[1], "detach_bus"))	cmd = DF5632_DETACH_BUS;
	else if (!strcmp(argv[1], "reqbus"))	cmd = DF5632_REQBUS;
	else errx(2, "unknown op %s", argv[1]);

	if (cmd == DF5632_CYCLE)
		r.arg = (argc > 2) ? (int32_t)strtol(argv[2], NULL, 0) : 1;

	fd = open("/dev/df5632", O_RDWR);
	if (fd < 0)
		err(1, "open /dev/df5632 (is the rig loaded?)");
	if (ioctl(fd, cmd, &r) < 0)
		err(1, "ioctl");
	printf("dfctl %s: kernel rc=%d v0=0x%llx v1=0x%llx v2=0x%llx\n",
	    argv[1], r.rc, (unsigned long long)r.v0,
	    (unsigned long long)r.v1, (unsigned long long)r.v2);
	return (0);
}
