Index: geode.c
===================================================================
RCS file: /home/ncvs/src/sys/i386/i386/geode.c,v
retrieving revision 1.3
diff -u -r1.3 geode.c
--- geode.c	28 Feb 2004 22:33:28 -0000	1.3
+++ geode.c	20 Mar 2004 22:46:07 -0000
@@ -27,6 +27,20 @@
 #include <sys/cdefs.h>
 __FBSDID("$FreeBSD: src/sys/i386/i386/geode.c,v 1.3 2004/02/28 22:33:28 phk Exp $");
 
+#include <sys/types.h>
+#include <sys/ioccom.h>
+
+struct onew {
+	u_int		rst;
+	u_int		xmt;
+	u_int		rcv;
+	uint8_t		d[32];
+};
+
+#define ONEW	_IOWR('1', 0, struct onew)
+
+#ifdef _KERNEL
+
 #include <sys/param.h>
 #include <sys/systm.h>
 #include <sys/timetc.h>
@@ -42,6 +56,189 @@
 static unsigned	gpio;
 static unsigned	geode_counter;
 
+/******************************************************************/
+
+#include <sys/conf.h>
+
+static u_int atms, porti, porto;
+static uint8_t pd, pdh, pdl;
+
+#define onew_high()	outb(porto, pdh)
+#define onew_low()	outb(porto, pdl)
+#define onew_in()	inb(porti)
+
+static void
+onew_reset(void)
+{
+	int i;
+	u_long eflags;
+
+        eflags = read_eflags();
+        disable_intr();
+	onew_high();
+	for (i = 0; i < 480; i++)
+		onew_low();
+	onew_high();
+        write_eflags(eflags);
+	for (i = 0; i < 1000; i++)
+		onew_high();
+
+}
+
+static void
+onew_wr0(void)
+{
+	int i;
+	u_long eflags;
+
+        eflags = read_eflags();
+        disable_intr();
+	for (i = 0; i < 60; i++)
+		onew_low();
+	onew_high();
+        write_eflags(eflags);
+	for (i = 0; i < 10; i++)
+		onew_high();
+
+}
+
+static void
+onew_wr1(void)
+{
+	int i;
+	u_long eflags;
+
+        eflags = read_eflags();
+        disable_intr();
+	onew_low();
+	onew_high();
+        write_eflags(eflags);
+	for (i = 0; i < 60; i++)
+		onew_high();
+
+}
+
+static void
+onew_wr8(int i)
+{
+
+	if (i & 0x01) onew_wr1(); else onew_wr0();
+	if (i & 0x02) onew_wr1(); else onew_wr0();
+	if (i & 0x04) onew_wr1(); else onew_wr0();
+	if (i & 0x08) onew_wr1(); else onew_wr0();
+	if (i & 0x10) onew_wr1(); else onew_wr0();
+	if (i & 0x20) onew_wr1(); else onew_wr0();
+	if (i & 0x40) onew_wr1(); else onew_wr0();
+	if (i & 0x80) onew_wr1(); else onew_wr0();
+}
+
+static int
+onew_rd1(void)
+{
+	int i, x, y;
+	u_long eflags;
+
+        eflags = read_eflags();
+        disable_intr();
+	onew_low();
+	onew_high();
+	x = onew_in();
+        write_eflags(eflags);
+	for (i = 0; i < 60; i++)
+		y = onew_in();
+	do
+		y = onew_in();
+	while (!(y & 4));
+	return (x & 4 ? 1 : 0);
+}
+
+static u_int
+onew_rd8(void)
+{
+	u_int u;
+
+	u = 0;
+	u |= onew_rd1() << 0;
+	u |= onew_rd1() << 1;
+	u |= onew_rd1() << 2;
+	u |= onew_rd1() << 3;
+	u |= onew_rd1() << 4;
+	u |= onew_rd1() << 5;
+	u |= onew_rd1() << 6;
+	u |= onew_rd1() << 7;
+	return (u);
+}
+
+
+static int
+onew_ioctl(dev_t dev, u_long cmd, caddr_t data, int fflag, struct thread *td)
+{
+	struct onew *op;
+	int i;
+	uint8_t *p;
+
+	if (cmd != ONEW)
+		return (ENOIOCTL);
+
+	op = (void *)data;
+#if 0
+	printf("rst %d xmt %d rcv %d -> ", op->rst, op->xmt, op->rcv);
+	hexdump (op->d, sizeof op->d, "d:", HD_OMIT_COUNT | HD_OMIT_CHARS);
+#endif
+	if (op->rst)
+		onew_reset();
+	p = op->d;
+	for (i = 0; i < op->xmt; i++)
+		onew_wr8(*p++);
+	for (i = 0; i < op->rcv; i++)
+		*p++ = onew_rd8();
+	return (0);
+}
+
+static struct cdevsw onew_cdevsw = {
+	.d_version =	D_VERSION,
+	.d_flags =	D_NEEDGIANT,
+	.d_ioctl =	onew_ioctl,
+	.d_name =	"ONEW",
+};
+
+static void
+onew_init(void)
+{
+	int i;
+
+	outb(0x2e, 0x20);
+	i = inb(0x2f);
+	if (i != 0xe9) {
+		printf("Expected 0xe9 for superIO ID, got 0x%x\n", i);
+		return;
+	}
+
+	outb(0x2e, 0x07); outb(0x2f, 0x07);
+	outb(0x2e, 0x60); atms = inb(0x2f) << 8;
+	outb(0x2e, 0x61); atms |= inb(0x2f);
+	outb(0x2e, 0x30); i = inb(0x2f);
+	if (!(i & 1)) {
+		printf("GPIO not enabled\n");
+		return;
+	}
+	printf("ATMS %x\n", atms);
+	outb(0x2e, 0xf0); outb(0x2f, 0x12);
+	outb(0x2e, 0xf1); outb(0x2f, 0x03);
+
+	porto = atms + 4;
+	porti = atms + 5;
+	pd = inb(porti);
+	pdl = pd & ~0x4;
+	pdh = pd | 0x4;
+	
+	make_dev(&onew_cdevsw, 0,
+	    UID_ROOT, GID_WHEEL, 0600, "onew");
+
+}
+
+/*****************************************************************/
+
 #ifdef CPU_SOEKRIS
 
 #include <dev/led/led.h>
@@ -130,6 +327,8 @@
 			tc_init(&geode_timecounter);
 			EVENTHANDLER_REGISTER(watchdog_list, geode_watchdog,
 			    NULL, 0);
+
+			onew_init();
 		}
 	} else if (pci_get_devid(self) == 0x0510100b) {
 		gpio = pci_read_config(self, PCIR_BAR(0), 4);
@@ -168,3 +367,4 @@
 static devclass_t geode_devclass;
 
 DRIVER_MODULE(geode, pci, geode_driver, geode_devclass, 0, 0);
+#endif /* _KERNEL */
