Plan 9 from Bell Labs’s /usr/web/sources/contrib/dho/zt550x/devzt550x.c

Copyright © 2021 Plan 9 Foundation.
Distributed under the MIT License.
Download the Plan 9 distribution.


/*
 * Ziatech 550x (5503) watchdog driver
 */

#include "u.h"
#include "../port/lib.h"
#include "mem.h"
#include "dat.h"
#include "fns.h"
#include "../port/error.h"

enum {
	Qdir,
	Qwatchdog,
};

static Dirtab zt550x_dirtab[] = {
	".",			{ Qdir, 0, QTDIR},	0,	0555,
	"watchdog",	{ Qwatchdog, 0},	0,	0600,
};

/* Useful I/O ports */

enum {
	IOP_Watchdog = 0x79,
	IOP_KBReset = 0x64, /* Keyboard controller reset */
};

/* Useful bitmasks for the Watchdog */

enum {
	Watchdog_Enabled = 0x20,

	Watchdog_250ms_Timeout = 0x00,
	Watchdog_500ms_Timeout = 0x01,
	Watchdog_1s_Timeout = 0x02,
	Watchdog_8s_Timeout = 0x03,
	Watchdog_32s_Timeout = 0x04,
	Watchdog_64s_Timeout = 0x05,
	Watchdog_128s_Timeout = 0x06,
	Watchdog_256s_Timeout = 0x07,
	Watchdog_Timeout_Mask = 0x07,
	Watchdog_Invalid_Timeout = -1,

	ZT550x_Reset_Code = 0xfe,
};

static Timer *watchdog_timer;

struct resolution {
	ulong timeout;
	ulong resolution;
};

static const char *zt550x_reg2str(ulong);
static struct resolution zt550x_res2res(char *);

void
watchdog_strobe(void)
{
		inb(IOP_Watchdog);
}

static void
zt550x_reset(void)
{
	/* To reset this board, we need to actually force a reset in
	 * hardware. I don't know how bad this is. To force this reset
	 * we can out 0xFEh to 0x64.
	 */
	outb(IOP_KBReset, ZT550x_Reset_Code);
}

static Chan *
zt550x_attach(char *spec)
{
	return  devattach('Z', spec);
}

static Walkqid *
zt550x_walk(Chan *c, Chan *nc, char **name, int nname)
{
	return devwalk(c, nc, name, nname, zt550x_dirtab, nelem(zt550x_dirtab), devgen);
}

static int
zt550x_stat(Chan *c, uchar *dp, int n)
{
	return devstat(c, dp, n, zt550x_dirtab, nelem(zt550x_dirtab), devgen);
}

static Chan *
zt550x_open(Chan *c, int mode)
{
	return devopen(c, mode, zt550x_dirtab, nelem(zt550x_dirtab), devgen);
}

static void
zt550x_close(Chan *c)
{
	USED(c);
}

static long
zt550x_read(Chan *c, void *a, long n, vlong off)
{
	ulong ioreg;

	switch((ulong)c->qid.path) {
	case Qdir:
		return devdirread(c, a, n, zt550x_dirtab, nelem(zt550x_dirtab), devgen);
	case Qwatchdog:
		ioreg = inb(IOP_Watchdog);
		if (ioreg & Watchdog_Enabled)
			return readstr(off, a, n, zt550x_reg2str(ioreg));
		else
			return readstr(off, a, n, "disabled");
	default:
		n = 0;
		break;
	}

	return n;
}

static long
zt550x_write(Chan *c, void *a, long n, vlong off)
{
	ulong ioreg;
	struct resolution res;
	char buffer[128];

	USED(off);

	if (n >= sizeof(buffer)) 
		n = sizeof(buffer);

	strncpy(buffer, a, n - 1);
	buffer[n] = 0;

	switch((ulong)c->qid.path) {
	case Qwatchdog:
		ioreg = inb(IOP_Watchdog);
		if (strncmp(buffer, "enable resolution", 17) == 0) {
			res = zt550x_res2res(buffer + 17);
			if (res.resolution == Watchdog_Invalid_Timeout)
				error (Ebadarg);
			if (!(ioreg & Watchdog_Enabled)) {
				watchdog_timer = addclock0link(watchdog_strobe, res.resolution);
				ioreg &= ~Watchdog_Timeout_Mask;
				ioreg|=  Watchdog_Enabled + res.timeout;
				outb(IOP_Watchdog, ioreg);
			}
		} else if (strncmp(buffer, "disable", 7) == 0) {
			if (ioreg & Watchdog_Enabled) {
				ioreg &= ~Watchdog_Enabled;
				outb(IOP_Watchdog, ioreg);
				timerdel(watchdog_timer);
			}
		}
	default:
		error(Ebadusefd);
	}

	return n;
}


static struct resolution
zt550x_res2res(char *buffer)
{
	struct resolution r;

	if (strncmp(buffer, "250ms", 5) == 0) {
		r.timeout = Watchdog_250ms_Timeout;
		r.resolution = 250;
	} else if (strncmp(buffer, "500ms", 5) == 0) {
		r.timeout = Watchdog_500ms_Timeout;
		r.resolution = 500;
	} else if (strncmp(buffer, "1s", 2) == 0) {
		r.timeout = Watchdog_1s_Timeout;
		r.resolution = 1000;
	} else if (strncmp(buffer, "8s", 2) == 0) {
		r.timeout = Watchdog_8s_Timeout;
		r.resolution = 8000;
	} else if (strncmp(buffer, "32s", 3) == 0) {
		r.timeout = Watchdog_32s_Timeout;
		r.resolution = 32000;
	} else if (strncmp(buffer, "64s", 3) == 0) {
		r.timeout = Watchdog_64s_Timeout;
		r.resolution = 64000;
	} else if (strncmp(buffer, "128s", 4) == 0) {
		r.timeout = Watchdog_128s_Timeout;
		r.resolution = 128000;
	} else if (strncmp(buffer, "256s", 4) == 0) {
		r.timeout = Watchdog_256s_Timeout;
		r.resolution = 256000;
	} else
		r.timeout = r.resolution = Watchdog_Invalid_Timeout;

	return r;
}

static const char *
zt550x_reg2str(ulong ioreg)
{
	ioreg &= ~Watchdog_Timeout_Mask;

	switch(ioreg) {
	case Watchdog_250ms_Timeout:
		return "enabled; resolution 250ms";
	case Watchdog_500ms_Timeout:
		return "enabled; resolution 500ms";
	case Watchdog_1s_Timeout:
		return "enabled; resolution 1s";
	case Watchdog_8s_Timeout:
		return "enabled; resolution 8s";
	case Watchdog_32s_Timeout:
		return "enabled; resolution 32s";
	case Watchdog_64s_Timeout:
		return "enabled; resolution 64s";
	case Watchdog_128s_Timeout:
		return "enabled; resolution 128s";
	case Watchdog_256s_Timeout:
		return "enabled; resolution 256s";
	}
}

Dev zt550xdevtab = {
	'Z',
	"zt550x",

	zt550x_reset,
	devinit,
	devshutdown,
	zt550x_attach,
	zt550x_walk,
	zt550x_stat,
	zt550x_open,
	devcreate,
	zt550x_close,
	zt550x_read,
	devbread,
	zt550x_write,
	devbwrite,
	devremove,
	devwstat,
};

Bell Labs OSI certified Powered by Plan 9

(Return to Plan 9 Home Page)

Copyright © 2021 Plan 9 Foundation. All Rights Reserved.
Comments to webmaster@9p.io.