⬢ DragonFlyBSD Kernel Audit
DF-5565 / park.c
← back to finding ↓ download raw
/*
 * park.c -- DF-5563/5564/5565 userland trigger.
 *
 * Modes (all open the device, issue one ioctl, report the result):
 *   intr    /dev/df5563 -> iicbus_request_bus(bus, dev, IIC_WAIT|IIC_INTR)
 *           (the /dev/iic0 blocking-ioctl contract, iic.c:297-299)
 *   wait    /dev/df5563 -> iicbus_request_bus(bus, dev, IIC_WAIT)
 *           (the smbus SMB_WAIT passthrough contract: ipmi_ssif.c:81,181,
 *            cyapa.c:1176,1624 -> smbus_request_bus -> iicsmb_callback ->
 *            iicbus_request_bus(parent, dev, SMB_WAIT==IIC_WAIT))
 *   nowait  /dev/df5563 -> iicbus_request_bus(bus, dev, IIC_DONTWAIT)
 *           (the iicwrite/iicread contract, iic.c:212-213/253-254)
 *   rel     /dev/df5563 -> iicbus_release_bus()
 *   iic     /dev/iic0   -> ioctl(I2CSTART) -- the real in-tree entry
 *           (iicioctl -> iicbus_request_bus(IIC_WAIT|IIC_INTR), iic.c:297)
 *
 * After a PARK ioctl returns 0 the bus is released again so tests can be
 * repeated.
 */

#include <sys/types.h>
#include <sys/ioccom.h>

#include <errno.h>
#include <fcntl.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>

/* ioctls shared with df5563_rig.c */
#define DF5563_PARK_INTR	_IOWR('d', 1, int)
#define DF5563_PARK_WAIT	_IOWR('d', 2, int)
#define DF5563_PARK_NOWAIT	_IOWR('d', 3, int)
#define DF5563_RELEASE		_IOWR('d', 4, int)

/* local copy of <bus/iicbus/iic.h> (no userland header installed) */
struct iiccmd {
	u_char slave;
	int count;
	int last;
	char *buf;
};
#define I2CSTART	_IOW('i', 1, struct iiccmd)

static void
report(const char *what, int rv)
{
	if (rv == 0)
		printf("[park %d] %s: returned 0 (OK)\n", getpid(), what);
	else
		printf("[park %d] %s: returned %d (errno=%d: %s)\n",
		    getpid(), what, rv, errno, strerror(errno));
	fflush(stdout);
}

int
main(int argc, char **argv)
{
	const char *mode = (argc > 1) ? argv[1] : "intr";
	const char *path = (argc > 2) ? argv[2] : "/dev/df5563";
	u_long cmd;
	int fd, rv, arg = 0;

	if (!strcmp(mode, "iic")) {
		struct iiccmd c;

		memset(&c, 0, sizeof(c));
		c.slave = 0x50;
		fd = open("/dev/iic0", O_RDWR);
		if (fd < 0) {
			printf("[park %d] open /dev/iic0: %s\n", getpid(),
			    strerror(errno));
			return (1);
		}
		printf("[park %d] I2CSTART on /dev/iic0 "
		    "(-> iicbus_request_bus(IIC_WAIT|IIC_INTR))...\n",
		    getpid());
		fflush(stdout);
		rv = ioctl(fd, I2CSTART, &c);
		report("I2CSTART", rv);
		return (0);
	}

	if (!strcmp(mode, "intr"))
		cmd = DF5563_PARK_INTR;
	else if (!strcmp(mode, "wait"))
		cmd = DF5563_PARK_WAIT;
	else if (!strcmp(mode, "nowait"))
		cmd = DF5563_PARK_NOWAIT;
	else if (!strcmp(mode, "rel"))
		cmd = DF5563_RELEASE;
	else {
		fprintf(stderr, "usage: park [intr|wait|nowait|rel|iic]\n");
		return (2);
	}

	fd = open(path, O_RDWR);
	if (fd < 0) {
		printf("[park %d] open %s: %s\n", getpid(), path,
		    strerror(errno));
		return (1);
	}

	printf("[park %d] ioctl 0x%lx on %s...\n", getpid(),
	    (unsigned long)cmd, path);
	fflush(stdout);
	rv = ioctl(fd, cmd, &arg);
	report("ioctl", rv);

	/* if we acquired the bus, give it back so tests can re-run */
	if (rv == 0 && cmd != DF5563_RELEASE) {
		rv = ioctl(fd, DF5563_RELEASE, &arg);
		report("release", rv);
	}
	return (0);
}