Browse Source

Plan 9 from Bell Labs 2010-10-07

David du Colombier 13 years ago
parent
commit
e1bf1ce63f

+ 20 - 9
sys/src/9/omap/archomap.c

@@ -186,7 +186,7 @@ enum {
 	Pergpio3	= 1 << 14,
 	Pergpio2	= 1 << 13,
 	Perwdt3		= 1 << 12,	/* wdt3 clock enable bit for periphs */
-	Peruart3	= 1 << 11,
+	Peruart3	= 1 << 11,	/* console uart */
 	Pergpt9		= 1 << 10,
 	Pergpt8		= 1 << 9,
 	Pergpt7		= 1 << 8,
@@ -196,6 +196,8 @@ enum {
 	Pergpt3		= 1 << 4,
 	Pergpt2		= 1 << 3,	/* gpt2 clock enable bit for periphs */
 
+	Perenable	= Pergpio6 | Pergpio5 | Perwdt3 | Pergpt2 | Peruart3,
+
 	Usbhost2	= 1 << 1,	/* 120MHz clock enable */
 	Usbhost1	= 1 << 0,	/* 48MHz clock enable */
 	Usbhost		= Usbhost1,	/* iclock enable */
@@ -558,12 +560,15 @@ configper(void)
 
 	per->clksel[0] &= ~MASK(8);	/* select 32kHz clock for GPTIMER2-9 */
 
-	per->iclken |= Pergpio6 | Pergpio5 | Perwdt3 | Pergpt2;
+	per->iclken |= Perenable;
 	coherence();
-	per->fclken |= Pergpio6 | Pergpio5 | Perwdt3 | Pergpt2;
+	per->fclken |= Perenable;
 	coherence();
-	while (per->idlest & (Pergpio6 | Pergpio5 | Perwdt3 | Pergpt2))
+	while (per->idlest & Perenable)
 		;
+
+	per->autoidle = 0;
+	coherence();
 }
 
 static void
@@ -771,7 +776,7 @@ configscreengpio(void)
 	/* no clocksel needed */
 	wkup->fclken |= B(3);			/* turn gpioclock on */
 	wkup->iclken |= B(3);
-	wkup->autoidle |= B(3); 		/* gpio clock set it on auto */
+//	wkup->autoidle |= B(3); 		/* gpio clock set it on auto */
 	coherence();
 	while (wkup->idlest & Gpioidle)
 		;
@@ -1000,10 +1005,11 @@ setmuxmode(ulong addr, int shorts, int mode)
 	int omode;
 	ushort *ptr;
 
+	mode &= Muxmode;
 	for (ptr = (ushort *)addr; shorts-- > 0; ptr++) {
 		omode = *ptr & Muxmode;
 		if (omode != mode)
-			*ptr = *ptr & ~Muxmode | mode & Muxmode;
+			*ptr = *ptr & ~Muxmode | mode;
 	}
 	coherence();
 }
@@ -1015,7 +1021,6 @@ setpadmodes(void)
 
 	/* set scm pad modes for usb; hasn't made any difference yet */
 	setmuxmode(0x48002166, 7, 5);	/* hsusb3_tll* in mode 5; is mode 4 */
-	/* 216c mode 
 	setmuxmode(0x48002180, 1, 5);	/* hsusb3_tll_clk; is mode 4 */
 	setmuxmode(0x48002184, 4, 5);	/* hsusb3_tll_data?; is mode 1 */
 	setmuxmode(0x480021a2, 12, 0);	/* hsusb0 (console) in mode 0 */
@@ -1024,13 +1029,19 @@ setpadmodes(void)
 	setmuxmode(0x480025d8, 18, 6);	/* hsusb[12]_tll*; mode 3 is */
 					/* hsusb1_data*, hsusb2* */
 
+	setmuxmode(0x480020e4, 2, 5);	/* uart3_rx_* in mode 5 */
+	setmuxmode(0x4800219a, 4, 0);	/* uart3_* in mode 0 */
+	/* uart3_* in mode 2; TODO: conflicts with hsusb0 */
+	setmuxmode(0x480021aa, 4, 2);
+	setmuxmode(0x48002240, 2, 3);	/* uart3_* in mode 3 */
+
 	/*
-	 * igep only: mode 4 of 21d2 is gpio_176 (smsc9221 ether irq).
+	 * igep/gumstix only: mode 4 of 21d2 is gpio_176 (smsc9221 ether irq).
 	 * see ether9221.c for more.
 	 */
 	*(ushort *)0x480021d2 = Inena | Ptup | Ptena | 4;
 
-	/* magic from u-boot */
+	/* magic from u-boot for flash */
 	*(ushort *)GpmcA1	= Indis | Ptup | Ptena | 0;
 	*(ushort *)GpmcA2	= Indis | Ptup | Ptena | 0;
 	*(ushort *)GpmcA3	= Indis | Ptup | Ptena | 0;

+ 16 - 14
sys/src/9/omap/beagle

@@ -1,4 +1,4 @@
-# beagle & igepv2 boards
+# beagle, igepv2, gumstix overo omap35 boards
 dev
 	root
 	cons
@@ -15,33 +15,35 @@ dev
 	sdp		thwack unthwack
 	cap
 	kprof
-	aoe
-	sd
+#	aoe
+#	sd
 	fs
 #	flash
 
 	ether		netif
 	ip		arp chandial ip ipv6 ipaux iproute netlog nullmedium pktmedium ptclbsum inferno
 
-##	draw		screen vga vgax
-##	mouse		mouse
-##	vga
-#	kbmap
-##	kbin
+	draw		screen
+	dss
+	kbmap
+	kbin
+#	mouse
 
 	uart
-	usb
+#	usb
 
 link
 	archomap
 	ethermedium
+#	flashbeagle	ecc
+#	flashigep
 	loopbackmedium
 	netdevmedium
 
 	ether9221
-# avoid tickling errata 3.1.1.183
-#	usbohci
-	usbehci
+## avoid tickling errata 3.1.1.183
+##	usbohci
+#	usbehci
 
 ip
 	tcp
@@ -57,13 +59,13 @@ misc
 	rdb
 	coproc
 	dma
-	sdaoe		sdscsi
+#	mouse
+#	sdaoe		sdscsi
 	softfpu
 	syscall
 	uarti8250
 	ucalloc
 	ucallocb
-##	vgavesa
 
 port
 	int cpuserver = 1;

+ 0 - 3
sys/src/9/omap/dat.h

@@ -1,6 +1,3 @@
-#define LASTRESORT lastresortprint	/* for ./devcons.c */
-#define CRUDEPRINT serialputs		/* for ./devcons.c */
-
 /*
  * Time.
  *

+ 1 - 1
sys/src/9/omap/devarch.c

@@ -153,7 +153,7 @@ Dev archdevtab = {
 char *
 cputype2name(char *buf, int size)
 {
-#ifdef TODO		/* identify the flavour of omap3530 SoC & cpu */
+#ifdef TODO		/* identify the flavour of SoC & cpu */
 	char *soc;
 
 	m->cputype = *(ulong *)AddrDevid;

+ 16 - 29
sys/src/9/omap/devcons.c

@@ -5,7 +5,6 @@
 #include	"fns.h"
 #include	"../port/error.h"
 #include	"pool.h"
-
 #include	<authsrv.h>
 
 void	(*consdebug)(void) = nil;
@@ -144,10 +143,6 @@ kmesgputs(char *str, int n)
 static void
 putstrn0(char *str, int n, int usewrite)
 {
-#ifdef CRUDEPRINT
-	CRUDEPRINT(str, n);
-	USED(usewrite);
-#else
 	int m;
 	char *t;
 
@@ -202,7 +197,6 @@ putstrn0(char *str, int n, int usewrite)
 			break;
 		}
 	}
-#endif
 }
 
 void
@@ -212,6 +206,7 @@ putstrn(char *str, int n)
 }
 
 int noprint;
+extern int normalprint;
 
 int
 print(char *fmt, ...)
@@ -226,7 +221,13 @@ print(char *fmt, ...)
 	va_start(arg, fmt);
 	n = vseprint(buf, buf+sizeof(buf), fmt, arg) - buf;
 	va_end(arg);
-	putstrn(buf, n);
+
+	if(!normalprint) {
+		if(0) iprint("\nprint called too early from %#lux\n",
+			getcallerpc(&fmt));
+		iprint("%.*s", n, buf);
+	} else
+		putstrn(buf, n);
 
 	return n;
 }
@@ -267,11 +268,11 @@ iprint(char *fmt, ...)
 	locked = iprintcanlock(&iprintlock);
 	if(screenputs != nil && iprintscreenputs)
 		screenputs(buf, n);
-#ifdef CRUDEPRINT
-	CRUDEPRINT(buf, n);
-#else
-	uartputs(buf, n);
-#endif
+	if(consuart == nil || consuart->phys == nil ||
+	    consuart->phys->putc == nil)
+		_uartputs(buf, n);
+	else
+		uartputs(buf, n);
 	if(locked)
 		unlock(&iprintlock);
 	splx(s);
@@ -367,7 +368,6 @@ echoscreen(char *buf, int n)
 	char ebuf[128];
 	int x;
 
-iprint("echoscreen: wrong for beagle\n");
 	p = ebuf;
 	e = ebuf + sizeof(ebuf) - 4;
 	while(n-- > 0){
@@ -390,7 +390,6 @@ iprint("echoscreen: wrong for beagle\n");
 static void
 echoserialoq(char *buf, int n)
 {
-#ifdef ECHO_WORKS
 	int x;
 	char *e, *p;
 	char ebuf[128];
@@ -415,19 +414,6 @@ echoserialoq(char *buf, int n)
 	}
 	if(p != ebuf)
 		qiwrite(serialoq, ebuf, p - ebuf);
-#else
-	/*
-	 * TODO: something is broken about the above and echoed characters
-	 * don't appear.  until we figure it out, just brute force it.
-	 */
-	while(n-- > 0){
-		if(*buf == ('u' & 037))
-			CRUDEPRINT("^U\r\n", 4);
-		else
-			CRUDEPRINT(buf, 1);
-		buf++;
-	}
-#endif
 }
 
 static void
@@ -961,9 +947,10 @@ consread(Chan *c, void *buf, long n, vlong off)
 		b = malloc(READSTR);
 		if(b == nil)
 			error(Enomem);
-		n = 0;
+		k = 0;
 		for(i = 0; devtab[i] != nil; i++)
-			n += snprint(b+n, READSTR-n, "#%C %s\n", devtab[i]->dc,  devtab[i]->name);
+			k += snprint(b+k, READSTR-k, "#%C %s\n",
+				devtab[i]->dc,  devtab[i]->name);
 		if(waserror()){
 			free(b);
 			nexterror();

+ 187 - 0
sys/src/9/omap/devdss.c

@@ -0,0 +1,187 @@
+/*
+ * omap35 display subsystem (dss) device interface to screen.c.
+ * implements #v/vgactl
+ */
+#include "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "io.h"
+#include "ureg.h"
+#include "../port/error.h"
+
+#define	Image	IMAGE
+#include <draw.h>
+#include <memdraw.h>
+#include <cursor.h>
+#include "screen.h"
+// #include "gamma.h"
+
+enum {
+	Qdir,
+	Qdss,
+};
+
+extern OScreen oscreen;
+extern OScreen settings[];
+extern Omap3fb *framebuf;
+
+static QLock dsslck;
+static Dirtab dsstab[] = {
+	".",		{Qdir, 0, QTDIR},	0,	0555|DMDIR,
+	"vgactl",	{Qdss, 0},		0,	0666,
+};
+
+static Chan*
+screenattach(char *spec)
+{
+	return devattach('v', spec);
+}
+
+static Walkqid*
+screenwalk(Chan *c, Chan *nc, char **name, int nname)
+{
+	return devwalk(c, nc, name, nname, dsstab, nelem(dsstab), devgen);
+}
+
+static int
+screenstat(Chan *c, uchar *dp, int n)
+{
+	return devstat(c, dp, n, dsstab, nelem(dsstab), devgen);
+}
+
+static Chan*
+screenopen(Chan *c, int omode)
+{
+	if ((ulong)c->qid.path == Qdss) {
+		qlock(&dsslck);
+		oscreen.open = 1;
+		c->mode = openmode(omode);
+		c->flag |= COPEN;
+		c->offset = 0;
+	}
+	return c;
+}
+
+static void
+screenclose(Chan *c)
+{
+	if ((c->qid.type & QTDIR) == 0 && c->flag & COPEN)
+		if (c->qid.path == Qdss) {
+			oscreen.open = 0;
+			qunlock(&dsslck);
+		}
+}
+
+static ulong
+getchans(char *p)
+{
+	if (strncmp("x24" , p, 3) == 0)
+		return RGB24;		/* can't work yet, pixels are shorts */
+	else if (strncmp("x16", p, 3) == 0)
+		return RGB16;
+	else
+		return RGB16;
+}
+
+static long
+settingswrite(OScreen *setting, char *p)
+{
+#ifdef notdef
+	if(strncmp("640x480", p, 7) == 0){
+		*setting = settings[0];
+		setting->chan = getchans(p+7);
+		return 1;
+	} else
+#endif
+	if (strncmp("800x600", p, 7) == 0) {
+		*setting = settings[0];
+		setting->chan = getchans(p + 7);
+		return 1;
+	} else if (strncmp("1024x768", p, 8) == 0) {
+		*setting = settings[1];
+		setting->chan = getchans(p + 8);
+		return 1;
+	} else if (strncmp("1280x1024", p, 9) == 0) {
+		*setting = settings[2];
+		setting->chan = getchans(p + 9);
+	}
+	return -1;
+}
+
+static long
+screenread(Chan *c, void *a, long n, vlong off)
+{
+	int len, depth;
+	char *p;
+	OScreen *scr;
+
+	switch ((ulong)c->qid.path) {
+	case Qdir:
+		return devdirread(c, a, n, dsstab, nelem(dsstab),
+			devgen);
+	case Qdss:
+		scr = &oscreen;
+		p = malloc(READSTR);
+		if(waserror()){
+			free(p);
+			nexterror();
+		}
+		if (scr->chan == RGB16)
+			depth = 16;
+		else if (scr->chan == RGB24)
+			depth = 24;
+		else
+			depth = 0;
+		len = snprint(p, READSTR, "size %dx%dx%d @ %d Hz\n"
+			"addr %#p size %ud\n", scr->wid, scr->ht, depth,
+			scr->freq, framebuf, sizeof *framebuf);
+		USED(len);
+		n = readstr(off, a, n, p);
+		poperror();
+		free(p);
+		return n;
+	default:
+		error(Egreg);
+	}
+	return 0;
+}
+
+static long
+screenwrite(Chan *c, void *a, long n, vlong off)
+{
+	switch ((ulong)c->qid.path) {
+	case Qdss:
+		if(off)
+			error(Ebadarg);
+		n = settingswrite(&oscreen, a);
+		free(framebuf);
+		screeninit();
+		return n;
+	default:
+		error(Egreg);
+	}
+	return 0;
+}
+
+Dev dssdevtab = {
+	L'v',
+	"dss",
+
+	devreset,
+	devinit,
+	devshutdown,		// TODO add a shutdown to stop dma to monitor
+	screenattach,
+	screenwalk,
+	screenstat,
+	screenopen,
+	devcreate,
+	screenclose,
+	screenread,
+	devbread,
+	screenwrite,
+	devbwrite,
+	devremove,
+	devwstat,
+};

+ 120 - 0
sys/src/9/omap/devkbin.c

@@ -0,0 +1,120 @@
+/*
+ *  keyboard scan code input from outside the kernel.
+ *  to avoid duplication of keyboard map processing for usb.
+ */
+
+#include	"u.h"
+#include	"../port/lib.h"
+#include	"mem.h"
+#include	"dat.h"
+#include	"fns.h"
+#include	"../port/error.h"
+
+extern	void kbdputsc(int, int);
+
+enum {
+	Qdir,
+	Qkbd,
+};
+
+Dirtab kbintab[] = {
+	".",	{Qdir, 0, QTDIR},	0,	0555,
+	"kbin",	{Qkbd, 0},		0,	0200,
+};
+
+Lock	kbinlck;
+int	kbinbusy;
+
+static Chan *
+kbinattach(char *spec)
+{
+	return devattach(L'Ι', spec);
+}
+
+static Walkqid*
+kbinwalk(Chan *c, Chan *nc, char **name, int nname)
+{
+	return devwalk(c, nc, name, nname, kbintab, nelem(kbintab), devgen);
+}
+
+static int
+kbinstat(Chan *c, uchar *dp, int n)
+{
+	return devstat(c, dp, n, kbintab, nelem(kbintab), devgen);
+}
+
+static Chan*
+kbinopen(Chan *c, int omode)
+{
+	if(!iseve())
+		error(Eperm);
+	if(c->qid.path == Qkbd){
+		lock(&kbinlck);
+		if(kbinbusy){
+			unlock(&kbinlck);
+			error(Einuse);
+		}
+		kbinbusy++;
+		unlock(&kbinlck);
+	}
+	return devopen(c, omode, kbintab, nelem(kbintab), devgen);
+}
+
+static void
+kbinclose(Chan *c)
+{
+	if(c->aux){
+		free(c->aux);
+		c->aux = nil;
+	}
+	if(c->qid.path == Qkbd)
+		kbinbusy = 0;
+}
+
+static long
+kbinread(Chan *c, void *a, long n, vlong )
+{
+	if(c->qid.type == QTDIR)
+		return devdirread(c, a, n, kbintab, nelem(kbintab), devgen);
+	return 0;
+}
+
+static long
+kbinwrite(Chan *c, void *a, long n, vlong)
+{
+	int i;
+	uchar *p = a;
+
+	if(c->qid.type == QTDIR)
+		error(Eisdir);
+	switch((int)c->qid.path){
+	case Qkbd:
+		for(i = 0; i < n; i++)
+			kbdputsc(*p++, 1);	/* external source */
+		break;
+	default:
+		error(Egreg);
+	}
+	return n;
+}
+
+Dev kbindevtab = {
+	L'Ι',
+	"kbin",
+
+	devreset,
+	devinit,
+	devshutdown,
+	kbinattach,
+	kbinwalk,
+	kbinstat,
+	kbinopen,
+	devcreate,
+	kbinclose,
+	kbinread,
+	devbread,
+	kbinwrite,
+	devbwrite,
+	devremove,
+	devwstat,
+};

+ 789 - 0
sys/src/9/omap/devuart.c

@@ -0,0 +1,789 @@
+#include	"u.h"
+#include	"../port/lib.h"
+#include	"mem.h"
+#include	"dat.h"
+#include	"fns.h"
+#include	"io.h"
+#include	"../port/error.h"
+
+#include	"../port/netif.h"
+
+enum
+{
+	/* soft flow control chars */
+	CTLS= 023,
+	CTLQ= 021,
+};
+
+extern Dev uartdevtab;
+extern PhysUart* physuart[];
+
+static Uart* uartlist;
+static Uart** uart;
+static int uartnuart;
+static Dirtab *uartdir;
+static int uartndir;
+static Timer *uarttimer;
+
+struct Uartalloc {
+	Lock;
+	Uart *elist;	/* list of enabled interfaces */
+} uartalloc;
+
+static void	uartclock(void);
+static void	uartflow(void*);
+
+/*
+ *  enable/disable uart and add/remove to list of enabled uarts
+ */
+//static
+Uart*
+uartenable(Uart *p)
+{
+	Uart **l;
+
+	if (up == nil)
+		return p;		/* too soon; try again later */
+//		return nil;
+
+	if(p->iq == nil){
+		if((p->iq = qopen(8*1024, 0, uartflow, p)) == nil)
+			return nil;
+	}
+	else
+		qreopen(p->iq);
+	if(p->oq == nil){
+		if((p->oq = qopen(8*1024, 0, uartkick, p)) == nil){
+			qfree(p->iq);
+			p->iq = nil;
+			return nil;
+		}
+	}
+	else
+		qreopen(p->oq);
+
+	p->ir = p->istage;
+	p->iw = p->istage;
+	p->ie = &p->istage[Stagesize];
+	p->op = p->ostage;
+	p->oe = p->ostage;
+
+	p->hup_dsr = p->hup_dcd = 0;
+	p->dsr = p->dcd = 0;
+
+	/* assume we can send */
+	p->cts = 1;
+	p->ctsbackoff = 0;
+
+if (up) {
+	if(p->bits == 0)
+		uartctl(p, "l8");
+	if(p->stop == 0)
+		uartctl(p, "s1");
+	if(p->parity == 0)
+		uartctl(p, "pn");
+	if(p->baud == 0)
+		uartctl(p, "b9600");
+	(*p->phys->enable)(p, 1);
+}
+
+	/*
+	 * use ilock because uartclock can otherwise interrupt here
+	 * and would hang on an attempt to lock uartalloc.
+	 */
+	ilock(&uartalloc);
+	for(l = &uartalloc.elist; *l; l = &(*l)->elist){
+		if(*l == p)
+			break;
+	}
+	if(*l == 0){
+		p->elist = uartalloc.elist;
+		uartalloc.elist = p;
+	}
+	p->enabled = 1;
+	iunlock(&uartalloc);
+
+	return p;
+}
+
+static void
+uartdisable(Uart *p)
+{
+	Uart **l;
+
+	(*p->phys->disable)(p);
+
+	ilock(&uartalloc);
+	for(l = &uartalloc.elist; *l; l = &(*l)->elist){
+		if(*l == p){
+			*l = p->elist;
+			break;
+		}
+	}
+	p->enabled = 0;
+	iunlock(&uartalloc);
+}
+
+void
+uartmouse(Uart* p, int (*putc)(Queue*, int), int setb1200)
+{
+	qlock(p);
+	if(p->opens++ == 0 && uartenable(p) == nil){
+		qunlock(p);
+		error(Enodev);
+	}
+	if(setb1200)
+		uartctl(p, "b1200");
+	p->putc = putc;
+	p->special = 1;
+	qunlock(p);
+}
+
+void
+uartsetmouseputc(Uart* p, int (*putc)(Queue*, int))
+{
+	qlock(p);
+	if(p->opens == 0 || p->special == 0){
+		qunlock(p);
+		error(Enodev);
+	}
+	p->putc = putc;
+	qunlock(p);
+}
+
+static void
+setlength(int i)
+{
+	Uart *p;
+
+	if(i > 0){
+		p = uart[i];
+		if(p && p->opens && p->iq)
+			uartdir[1+3*i].length = qlen(p->iq);
+	} else for(i = 0; i < uartnuart; i++){
+		p = uart[i];
+		if(p && p->opens && p->iq)
+			uartdir[1+3*i].length = qlen(p->iq);
+	}
+}
+
+/*
+ *  set up the '#t' directory
+ */
+static void
+uartreset(void)
+{
+	int i;
+	Dirtab *dp;
+	Uart *p, *tail;
+
+	tail = nil;
+	for(i = 0; physuart[i] != nil; i++){
+		if(physuart[i]->pnp == nil)
+			continue;
+		if((p = physuart[i]->pnp()) == nil)
+			continue;
+		if(uartlist != nil)
+			tail->next = p;
+		else
+			uartlist = p;
+		for(tail = p; tail->next != nil; tail = tail->next)
+			uartnuart++;
+		uartnuart++;
+	}
+
+	if(uartnuart)
+		uart = xalloc(uartnuart*sizeof(Uart*));
+
+	uartndir = 1 + 3*uartnuart;
+	uartdir = xalloc(uartndir * sizeof(Dirtab));
+	if (uart == nil || uartdir == nil)
+		panic("uartreset: no memory");
+	dp = uartdir;
+	strcpy(dp->name, ".");
+	mkqid(&dp->qid, 0, 0, QTDIR);
+	dp->length = 0;
+	dp->perm = DMDIR|0555;
+	dp++;
+	p = uartlist;
+	for(i = 0; i < uartnuart; i++){
+		/* 3 directory entries per port */
+		sprint(dp->name, "eia%d", i);
+		dp->qid.path = NETQID(i, Ndataqid);
+		dp->perm = 0660;
+		dp++;
+		sprint(dp->name, "eia%dctl", i);
+		dp->qid.path = NETQID(i, Nctlqid);
+		dp->perm = 0660;
+		dp++;
+		sprint(dp->name, "eia%dstatus", i);
+		dp->qid.path = NETQID(i, Nstatqid);
+		dp->perm = 0444;
+		dp++;
+
+		uart[i] = p;
+		p->dev = i;
+		if(p->console || p->special){
+			if(uartenable(p) != nil){
+				if(p->console && up){
+					kbdq = p->iq;
+					serialoq = p->oq;
+					p->putc = kbdcr2nl;
+				}
+				p->opens++;
+			}
+		}
+		p = p->next;
+	}
+
+	if(uartnuart){
+		/*
+		 * at 115200 baud, the 1024 char buffer takes 56 ms to process,
+		 * processing it every 22 ms should be fine.
+		 */
+		uarttimer = addclock0link(uartclock, 22);
+	}
+}
+
+
+static Chan*
+uartattach(char *spec)
+{
+	return devattach('t', spec);
+}
+
+static Walkqid*
+uartwalk(Chan *c, Chan *nc, char **name, int nname)
+{
+	return devwalk(c, nc, name, nname, uartdir, uartndir, devgen);
+}
+
+static int
+uartstat(Chan *c, uchar *dp, int n)
+{
+	if(NETTYPE(c->qid.path) == Ndataqid)
+		setlength(NETID(c->qid.path));
+	return devstat(c, dp, n, uartdir, uartndir, devgen);
+}
+
+static Chan*
+uartopen(Chan *c, int omode)
+{
+	Uart *p;
+
+	c = devopen(c, omode, uartdir, uartndir, devgen);
+
+	switch(NETTYPE(c->qid.path)){
+	case Nctlqid:
+	case Ndataqid:
+		p = uart[NETID(c->qid.path)];
+		qlock(p);
+		if(p->opens++ == 0 && uartenable(p) == nil){
+			qunlock(p);
+			c->flag &= ~COPEN;
+			error(Enodev);
+		}
+		qunlock(p);
+		break;
+	}
+
+	c->iounit = qiomaxatomic;
+	return c;
+}
+
+static int
+uartdrained(void* arg)
+{
+	Uart *p;
+
+	p = arg;
+	return qlen(p->oq) == 0 && p->op == p->oe;
+}
+
+static void
+uartdrainoutput(Uart *p)
+{
+	if(!p->enabled || up == nil)
+		return;
+
+	p->drain = 1;
+	if(waserror()){
+		p->drain = 0;
+		nexterror();
+	}
+	sleep(&p->r, uartdrained, p);
+	poperror();
+}
+
+static void
+uartclose(Chan *c)
+{
+	Uart *p;
+
+	if(c->qid.type & QTDIR)
+		return;
+	if((c->flag & COPEN) == 0)
+		return;
+	switch(NETTYPE(c->qid.path)){
+	case Ndataqid:
+	case Nctlqid:
+		p = uart[NETID(c->qid.path)];
+		qlock(p);
+		if(--(p->opens) == 0){
+			qclose(p->iq);
+			ilock(&p->rlock);
+			p->ir = p->iw = p->istage;
+			iunlock(&p->rlock);
+
+			/*
+			 */
+			qhangup(p->oq, nil);
+			if(!waserror()){
+				uartdrainoutput(p);
+				poperror();
+			}
+			qclose(p->oq);
+			uartdisable(p);
+			p->dcd = p->dsr = p->dohup = 0;
+		}
+		qunlock(p);
+		break;
+	}
+}
+
+static long
+uartread(Chan *c, void *buf, long n, vlong off)
+{
+	Uart *p;
+	ulong offset = off;
+
+	if(c->qid.type & QTDIR){
+		setlength(-1);
+		return devdirread(c, buf, n, uartdir, uartndir, devgen);
+	}
+
+	p = uart[NETID(c->qid.path)];
+	switch(NETTYPE(c->qid.path)){
+	case Ndataqid:
+		return qread(p->iq, buf, n);
+	case Nctlqid:
+		return readnum(offset, buf, n, NETID(c->qid.path), NUMSIZE);
+	case Nstatqid:
+		return (*p->phys->status)(p, buf, n, offset);
+	}
+
+	return 0;
+}
+
+int
+uartctl(Uart *p, char *cmd)
+{
+	char *f[16];
+	int i, n, nf;
+
+	nf = tokenize(cmd, f, nelem(f));
+	for(i = 0; i < nf; i++){
+		if(strncmp(f[i], "break", 5) == 0){
+			(*p->phys->dobreak)(p, 0);
+			continue;
+		}
+
+		n = atoi(f[i]+1);
+		switch(*f[i]){
+		case 'B':
+		case 'b':
+			uartdrainoutput(p);
+			if((*p->phys->baud)(p, n) < 0)
+				return -1;
+			break;
+		case 'C':
+		case 'c':
+			p->hup_dcd = n;
+			break;
+		case 'D':
+		case 'd':
+			uartdrainoutput(p);
+			(*p->phys->dtr)(p, n);
+			break;
+		case 'E':
+		case 'e':
+			p->hup_dsr = n;
+			break;
+		case 'f':
+		case 'F':
+			if(p->oq != nil)
+				qflush(p->oq);
+			break;
+		case 'H':
+		case 'h':
+			if(p->iq != nil)
+				qhangup(p->iq, 0);
+			if(p->oq != nil)
+				qhangup(p->oq, 0);
+			break;
+		case 'i':
+		case 'I':
+			uartdrainoutput(p);
+			(*p->phys->fifo)(p, n);
+			break;
+		case 'K':
+		case 'k':
+			uartdrainoutput(p);
+			(*p->phys->dobreak)(p, n);
+			break;
+		case 'L':
+		case 'l':
+			uartdrainoutput(p);
+			if((*p->phys->bits)(p, n) < 0)
+				return -1;
+			break;
+		case 'm':
+		case 'M':
+			uartdrainoutput(p);
+			(*p->phys->modemctl)(p, n);
+			break;
+		case 'n':
+		case 'N':
+			if(p->oq != nil)
+				qnoblock(p->oq, n);
+			break;
+		case 'P':
+		case 'p':
+			uartdrainoutput(p);
+			if((*p->phys->parity)(p, *(f[i]+1)) < 0)
+				return -1;
+			break;
+		case 'Q':
+		case 'q':
+			if(p->iq != nil)
+				qsetlimit(p->iq, n);
+			if(p->oq != nil)
+				qsetlimit(p->oq, n);
+			break;
+		case 'R':
+		case 'r':
+			uartdrainoutput(p);
+			(*p->phys->rts)(p, n);
+			break;
+		case 'S':
+		case 's':
+			uartdrainoutput(p);
+			if((*p->phys->stop)(p, n) < 0)
+				return -1;
+			break;
+		case 'W':
+		case 'w':
+			if(uarttimer == nil || n < 1)
+				return -1;
+			uarttimer->tns = (vlong)n * 100000LL;
+			break;
+		case 'X':
+		case 'x':
+			if(p->enabled){
+				ilock(&p->tlock);
+				p->xonoff = n;
+				iunlock(&p->tlock);
+			}
+			break;
+		}
+	}
+	return 0;
+}
+
+static long
+uartwrite(Chan *c, void *buf, long n, vlong)
+{
+	Uart *p;
+	char *cmd;
+
+	if(c->qid.type & QTDIR)
+		error(Eperm);
+
+	p = uart[NETID(c->qid.path)];
+
+	switch(NETTYPE(c->qid.path)){
+	case Ndataqid:
+		qlock(p);
+		if(waserror()){
+			qunlock(p);
+			nexterror();
+		}
+
+		n = qwrite(p->oq, buf, n);
+
+		qunlock(p);
+		poperror();
+		uartkick(p);		/* desperation */
+		break;
+	case Nctlqid:
+		cmd = malloc(n+1);
+		memmove(cmd, buf, n);
+		cmd[n] = 0;
+		qlock(p);
+		if(waserror()){
+			qunlock(p);
+			free(cmd);
+			nexterror();
+		}
+
+		/* let output drain */
+		if(uartctl(p, cmd) < 0)
+			error(Ebadarg);
+
+		qunlock(p);
+		poperror();
+		free(cmd);
+		break;
+	}
+
+	return n;
+}
+
+static int
+uartwstat(Chan *c, uchar *dp, int n)
+{
+	Dir d;
+	Dirtab *dt;
+
+	if(!iseve())
+		error(Eperm);
+	if(QTDIR & c->qid.type)
+		error(Eperm);
+	if(NETTYPE(c->qid.path) == Nstatqid)
+		error(Eperm);
+
+	dt = &uartdir[1 + 3 * NETID(c->qid.path)];
+	n = convM2D(dp, n, &d, nil);
+	if(n == 0)
+		error(Eshortstat);
+	if(d.mode != ~0UL)
+		dt[0].perm = dt[1].perm = d.mode;
+	return n;
+}
+
+void
+uartpower(int on)
+{
+	Uart *p;
+
+	for(p = uartlist; p != nil; p = p->next) {
+		if(p->phys->power)
+			(*p->phys->power)(p, on);
+	}
+}
+
+Dev uartdevtab = {
+	't',
+	"uart",
+
+	uartreset,
+	devinit,
+	devshutdown,
+	uartattach,
+	uartwalk,
+	uartstat,
+	uartopen,
+	devcreate,
+	uartclose,
+	uartread,
+	devbread,
+	uartwrite,
+	devbwrite,
+	devremove,
+	uartwstat,
+	uartpower,
+};
+
+/*
+ *  restart input if it's off
+ */
+static void
+uartflow(void *v)
+{
+	Uart *p;
+
+	p = v;
+	if(p->modem)
+		(*p->phys->rts)(p, 1);
+}
+
+/*
+ *  put some bytes into the local queue to avoid calling
+ *  qconsume for every character
+ */
+int
+uartstageoutput(Uart *p)
+{
+	int n;
+
+	n = qconsume(p->oq, p->ostage, Stagesize);
+	if(n <= 0)
+//		n = 0;			/* experiment */
+		return 0;
+	p->op = p->ostage;
+	p->oe = p->ostage + n;
+	return n;
+}
+
+/*
+ *  restart output
+ */
+void
+uartkick(void *v)
+{
+	Uart *p = v;
+
+	if(p->blocked)
+		return;
+
+	ilock(&p->tlock);
+	(*p->phys->kick)(p);
+	iunlock(&p->tlock);
+
+	if(p->drain && uartdrained(p)){
+		p->drain = 0;
+		wakeup(&p->r);
+	}
+}
+
+/*
+ * Move data from the interrupt staging area to
+ * the input Queue.
+ */
+static void
+uartstageinput(Uart *p)
+{
+	int n;
+	uchar *ir, *iw;
+
+	while(p->ir != p->iw){
+		ir = p->ir;
+		if(p->ir > p->iw){
+			iw = p->ie;
+			p->ir = p->istage;
+		}
+		else{
+			iw = p->iw;
+			p->ir = p->iw;
+		}
+		if((n = qproduce(p->iq, ir, iw - ir)) < 0){
+			p->serr++;
+			(*p->phys->rts)(p, 0);
+		}
+		else if(n == 0)
+			p->berr++;
+	}
+}
+
+/*
+ *  receive a character at interrupt time
+ */
+void
+uartrecv(Uart *p,  char ch)
+{
+	uchar *next;
+
+	/* software flow control */
+	if(p->xonoff){
+		if(ch == CTLS){
+			p->blocked = 1;
+		}else if(ch == CTLQ){
+			p->blocked = 0;
+			p->ctsbackoff = 2; /* clock gets output going again */
+		}
+	}
+
+	/* receive the character */
+	if(p->putc)
+		p->putc(p->iq, ch);
+	else if (p->iw) {		/* maybe the line isn't enabled yet */
+		ilock(&p->rlock);
+		next = p->iw + 1;
+		if(next == p->ie)
+			next = p->istage;
+		if(next == p->ir)
+			uartstageinput(p);
+		if(next != p->ir){
+			*p->iw = ch;
+			p->iw = next;
+		}
+		iunlock(&p->rlock);
+	}
+}
+
+/*
+ *  we save up input characters till clock time to reduce
+ *  per character interrupt overhead.
+ */
+static void
+uartclock(void)
+{
+	Uart *p;
+
+	ilock(&uartalloc);
+	for(p = uartalloc.elist; p; p = p->elist){
+
+		/* this hopefully amortizes cost of qproduce to many chars */
+		if(p->iw != p->ir){
+			ilock(&p->rlock);
+			uartstageinput(p);
+			iunlock(&p->rlock);
+		}
+
+		/* hang up if requested */
+		if(p->dohup){
+			qhangup(p->iq, 0);
+			qhangup(p->oq, 0);
+			p->dohup = 0;
+		}
+
+		/* this adds hysteresis to hardware/software flow control */
+		if(p->ctsbackoff){
+			ilock(&p->tlock);
+			if(p->ctsbackoff){
+				if(--(p->ctsbackoff) == 0)
+					(*p->phys->kick)(p);
+			}
+			iunlock(&p->tlock);
+		}
+	}
+	iunlock(&uartalloc);
+}
+
+/*
+ * polling console input, output
+ */
+
+Uart* consuart;
+
+int
+uartgetc(void)
+{
+	if(consuart == nil || consuart->phys->getc == nil)
+		return -1;
+	return consuart->phys->getc(consuart);
+}
+
+void
+uartputc(int c)
+{
+	if(consuart == nil || consuart->phys->putc == nil)
+		return;
+	consuart->phys->putc(consuart, c);
+}
+
+void
+uartputs(char *s, int n)
+{
+	char *e;
+
+	if(consuart == nil || consuart->phys->putc == nil)
+		return;
+
+	e = s+n;
+	for(; s<e; s++){
+		if(*s == '\n')
+			consuart->phys->putc(consuart, '\r');
+		consuart->phys->putc(consuart, *s);
+	}
+}

+ 5 - 1
sys/src/9/omap/fns.h

@@ -28,6 +28,7 @@ extern void clockshutdown(void);
 extern int clz(ulong);
 extern int cmpswap(long*, long, long);
 extern void coherence(void);
+extern void configscreengpio(void);
 extern u32int controlget(void);
 extern u32int cpctget(void);
 extern u32int cpidget(void);
@@ -53,6 +54,7 @@ extern void intrsoff(void);
 extern int isaconfig(char*, int, ISAConf*);
 extern int isdmadone(int);
 extern int ispow2(uvlong);
+extern void kbdenable(void);
 extern void l2cacheuinv(void);
 extern void l2cacheuwb(void);
 extern void l2cacheuwbinv(void);
@@ -61,6 +63,7 @@ extern int log2(ulong);
 extern void machinit(void);
 extern void mmuinvalidate(void);		/* 'mmu' or 'tlb'? */
 extern void mmuinvalidateaddr(u32int);		/* 'mmu' or 'tlb'? */
+extern void mousectl(Cmdbuf *cb);
 extern u32int pidget(void);
 extern void pidput(u32int);
 extern vlong probeaddr(uintptr);
@@ -68,6 +71,7 @@ extern void procrestore(Proc *);
 extern void procsave(Proc*);
 extern void procsetup(Proc*);
 extern void _reset(void);
+extern void screenclockson(void);
 extern void screeninit(void);
 extern void serialputs(char* s, int n);
 extern void setcachelvl(int);
@@ -93,7 +97,7 @@ extern void outb(int, int);
  */
 extern void archconfinit(void);
 extern void clockinit(void);
-extern void i8250console(void);
+extern int i8250console(void);
 extern void links(void);
 extern void mmuinit(void);
 extern void touser(uintptr);

+ 410 - 0
sys/src/9/omap/kbd.c

@@ -0,0 +1,410 @@
+/*
+ * simulated keyboard input for omap35 with no keyboard (except via uart or usb)
+ *
+ * gutted version of ps2 version from ../pc
+ */
+#include	"u.h"
+#include	"../port/lib.h"
+#include	"mem.h"
+#include	"dat.h"
+#include	"fns.h"
+#include	"io.h"
+#include	"../port/error.h"
+
+enum {
+	Spec=		0xF800,		/* Unicode private space */
+	PF=		Spec|0x20,	/* num pad function key */
+	View=		Spec|0x00,	/* view (shift window up) */
+	KF=		0xF000,		/* function key (begin Unicode private space) */
+	Shift=		Spec|0x60,
+	Break=		Spec|0x61,
+	Ctrl=		Spec|0x62,
+	Latin=		Spec|0x63,
+	Caps=		Spec|0x64,
+	Num=		Spec|0x65,
+	Middle=		Spec|0x66,
+	Altgr=		Spec|0x67,
+	Kmouse=		Spec|0x100,
+	No=		0x00,		/* peter */
+
+	Home=		KF|13,
+	Up=		KF|14,
+	Pgup=		KF|15,
+	Print=		KF|16,
+	Left=		KF|17,
+	Right=		KF|18,
+	End=		KF|24,
+	Down=		View,
+	Pgdown=		KF|19,
+	Ins=		KF|20,
+	Del=		0x7F,
+	Scroll=		KF|21,
+
+	Nscan=	128,
+
+	Int=	0,			/* kbscans indices */
+	Ext,
+	Nscans,
+};
+
+/*
+ * The codes at 0x79 and 0x7b are produced by the PFU Happy Hacking keyboard.
+ * A 'standard' keyboard doesn't produce anything above 0x58.
+ */
+Rune kbtab[Nscan] = 
+{
+[0x00]	No,	0x1b,	'1',	'2',	'3',	'4',	'5',	'6',
+[0x08]	'7',	'8',	'9',	'0',	'-',	'=',	'\b',	'\t',
+[0x10]	'q',	'w',	'e',	'r',	't',	'y',	'u',	'i',
+[0x18]	'o',	'p',	'[',	']',	'\n',	Ctrl,	'a',	's',
+[0x20]	'd',	'f',	'g',	'h',	'j',	'k',	'l',	';',
+[0x28]	'\'',	'`',	Shift,	'\\',	'z',	'x',	'c',	'v',
+[0x30]	'b',	'n',	'm',	',',	'.',	'/',	Shift,	'*',
+[0x38]	Latin,	' ',	Ctrl,	KF|1,	KF|2,	KF|3,	KF|4,	KF|5,
+[0x40]	KF|6,	KF|7,	KF|8,	KF|9,	KF|10,	Num,	Scroll,	'7',
+[0x48]	'8',	'9',	'-',	'4',	'5',	'6',	'+',	'1',
+[0x50]	'2',	'3',	'0',	'.',	No,	No,	No,	KF|11,
+[0x58]	KF|12,	No,	No,	No,	No,	No,	No,	No,
+[0x60]	No,	No,	No,	No,	No,	No,	No,	No,
+[0x68]	No,	No,	No,	No,	No,	No,	No,	No,
+[0x70]	No,	No,	No,	No,	No,	No,	No,	No,
+[0x78]	No,	View,	No,	Up,	No,	No,	No,	No,
+};
+
+Rune kbtabshift[Nscan] =
+{
+[0x00]	No,	0x1b,	'!',	'@',	'#',	'$',	'%',	'^',
+[0x08]	'&',	'*',	'(',	')',	'_',	'+',	'\b',	'\t',
+[0x10]	'Q',	'W',	'E',	'R',	'T',	'Y',	'U',	'I',
+[0x18]	'O',	'P',	'{',	'}',	'\n',	Ctrl,	'A',	'S',
+[0x20]	'D',	'F',	'G',	'H',	'J',	'K',	'L',	':',
+[0x28]	'"',	'~',	Shift,	'|',	'Z',	'X',	'C',	'V',
+[0x30]	'B',	'N',	'M',	'<',	'>',	'?',	Shift,	'*',
+[0x38]	Latin,	' ',	Ctrl,	KF|1,	KF|2,	KF|3,	KF|4,	KF|5,
+[0x40]	KF|6,	KF|7,	KF|8,	KF|9,	KF|10,	Num,	Scroll,	'7',
+[0x48]	'8',	'9',	'-',	'4',	'5',	'6',	'+',	'1',
+[0x50]	'2',	'3',	'0',	'.',	No,	No,	No,	KF|11,
+[0x58]	KF|12,	No,	No,	No,	No,	No,	No,	No,
+[0x60]	No,	No,	No,	No,	No,	No,	No,	No,
+[0x68]	No,	No,	No,	No,	No,	No,	No,	No,
+[0x70]	No,	No,	No,	No,	No,	No,	No,	No,
+[0x78]	No,	Up,	No,	Up,	No,	No,	No,	No,
+};
+
+Rune kbtabesc1[Nscan] =
+{
+[0x00]	No,	No,	No,	No,	No,	No,	No,	No,
+[0x08]	No,	No,	No,	No,	No,	No,	No,	No,
+[0x10]	No,	No,	No,	No,	No,	No,	No,	No,
+[0x18]	No,	No,	No,	No,	'\n',	Ctrl,	No,	No,
+[0x20]	No,	No,	No,	No,	No,	No,	No,	No,
+[0x28]	No,	No,	Shift,	No,	No,	No,	No,	No,
+[0x30]	No,	No,	No,	No,	No,	'/',	No,	Print,
+[0x38]	Altgr,	No,	No,	No,	No,	No,	No,	No,
+[0x40]	No,	No,	No,	No,	No,	No,	Break,	Home,
+[0x48]	Up,	Pgup,	No,	Left,	No,	Right,	No,	End,
+[0x50]	Down,	Pgdown,	Ins,	Del,	No,	No,	No,	No,
+[0x58]	No,	No,	No,	No,	No,	No,	No,	No,
+[0x60]	No,	No,	No,	No,	No,	No,	No,	No,
+[0x68]	No,	No,	No,	No,	No,	No,	No,	No,
+[0x70]	No,	No,	No,	No,	No,	No,	No,	No,
+[0x78]	No,	Up,	No,	No,	No,	No,	No,	No,
+};
+
+Rune kbtabaltgr[Nscan] =
+{
+[0x00]	No,	No,	No,	No,	No,	No,	No,	No,
+[0x08]	No,	No,	No,	No,	No,	No,	No,	No,
+[0x10]	No,	No,	No,	No,	No,	No,	No,	No,
+[0x18]	No,	No,	No,	No,	'\n',	Ctrl,	No,	No,
+[0x20]	No,	No,	No,	No,	No,	No,	No,	No,
+[0x28]	No,	No,	Shift,	No,	No,	No,	No,	No,
+[0x30]	No,	No,	No,	No,	No,	'/',	No,	Print,
+[0x38]	Altgr,	No,	No,	No,	No,	No,	No,	No,
+[0x40]	No,	No,	No,	No,	No,	No,	Break,	Home,
+[0x48]	Up,	Pgup,	No,	Left,	No,	Right,	No,	End,
+[0x50]	Down,	Pgdown,	Ins,	Del,	No,	No,	No,	No,
+[0x58]	No,	No,	No,	No,	No,	No,	No,	No,
+[0x60]	No,	No,	No,	No,	No,	No,	No,	No,
+[0x68]	No,	No,	No,	No,	No,	No,	No,	No,
+[0x70]	No,	No,	No,	No,	No,	No,	No,	No,
+[0x78]	No,	Up,	No,	No,	No,	No,	No,	No,
+};
+
+Rune kbtabctrl[Nscan] =
+{
+[0x00]	No,	'', 	'', 	'', 	'', 	'', 	'', 	'', 
+[0x08]	'', 	'', 	'', 	'', 	'
', 	'', 	'\b',	'\t',
+[0x10]	'', 	'', 	'', 	'', 	'', 	'', 	'', 	'\t',
+[0x18]	'', 	'', 	'', 	'', 	'\n',	Ctrl,	'', 	'', 
+[0x20]	'', 	'', 	'', 	'\b',	'\n',	'', 	'', 	'', 
+[0x28]	'', 	No, 	Shift,	'', 	'', 	'', 	'', 	'', 
+[0x30]	'', 	'', 	'
', 	'', 	'', 	'', 	Shift,	'\n',
+[0x38]	Latin,	No, 	Ctrl,	'', 	'', 	'', 	'', 	'', 
+[0x40]	'', 	'', 	'', 	'
', 	'', 	'', 	'', 	'', 
+[0x48]	'', 	'', 	'
', 	'', 	'', 	'', 	'', 	'', 
+[0x50]	'', 	'', 	'', 	'', 	No,	No,	No,	'', 
+[0x58]	'', 	No,	No,	No,	No,	No,	No,	No,
+[0x60]	No,	No,	No,	No,	No,	No,	No,	No,
+[0x68]	No,	No,	No,	No,	No,	No,	No,	No,
+[0x70]	No,	No,	No,	No,	No,	No,	No,	No,
+[0x78]	No,	'', 	No,	'\b',	No,	No,	No,	No,
+};
+
+int mouseshifted;
+void (*kbdmouse)(int);
+
+static int kdebug;
+
+typedef struct Kbscan Kbscan;
+struct Kbscan {
+	int	esc1;
+	int	esc2;
+	int	alt;
+	int	altgr;
+	int	caps;
+	int	ctl;
+	int	num;
+	int	shift;
+	int	collecting;
+	int	nk;
+	Rune	kc[5];
+	int	buttons;
+};
+
+Kbscan kbscans[Nscans];	/* kernel and external scan code state */
+
+/*
+ * Scan code processing
+ */
+void
+kbdputsc(int c, int external)
+{
+	int i, keyup;
+	Kbscan *kbscan;
+
+	if(external)
+		kbscan = &kbscans[Ext];
+	else
+		kbscan = &kbscans[Int];
+
+	if(kdebug)
+		print("sc %x ms %d\n", c, mouseshifted);
+	/*
+	 *  e0's is the first of a 2 character sequence, e1 the first
+	 *  of a 3 character sequence (on the safari)
+	 */
+	if(c == 0xe0){
+		kbscan->esc1 = 1;
+		return;
+	} else if(c == 0xe1){
+		kbscan->esc2 = 2;
+		return;
+	}
+
+	keyup = c & 0x80;
+	c &= 0x7f;
+	if(c > sizeof kbtab){
+		c |= keyup;
+		if(c != 0xFF)	/* these come fairly often: CAPSLOCK U Y */
+			print("unknown key %ux\n", c);
+		return;
+	}
+
+	if(kbscan->esc1){
+		c = kbtabesc1[c];
+		kbscan->esc1 = 0;
+	} else if(kbscan->esc2){
+		kbscan->esc2--;
+		return;
+	} else if(kbscan->shift)
+		c = kbtabshift[c];
+	else if(kbscan->altgr)
+		c = kbtabaltgr[c];
+	else if(kbscan->ctl)
+		c = kbtabctrl[c];
+	else
+		c = kbtab[c];
+
+	if(kbscan->caps && c<='z' && c>='a')
+		c += 'A' - 'a';
+
+	/*
+	 *  keyup only important for shifts
+	 */
+	if(keyup){
+		switch(c){
+		case Latin:
+			kbscan->alt = 0;
+			break;
+		case Shift:
+			kbscan->shift = 0;
+			mouseshifted = 0;
+			if(kdebug)
+				print("shiftclr\n");
+			break;
+		case Ctrl:
+			kbscan->ctl = 0;
+			break;
+		case Altgr:
+			kbscan->altgr = 0;
+			break;
+		case Kmouse|1:
+		case Kmouse|2:
+		case Kmouse|3:
+		case Kmouse|4:
+		case Kmouse|5:
+			kbscan->buttons &= ~(1<<(c-Kmouse-1));
+			if(kbdmouse)
+				kbdmouse(kbscan->buttons);
+			break;
+		}
+		return;
+	}
+
+	/*
+	 *  normal character
+	 */
+	if(!(c & (Spec|KF))){
+		if(kbscan->ctl)
+			if(kbscan->alt && c == Del)
+				exit(0);
+		if(!kbscan->collecting){
+			kbdputc(kbdq, c);
+			return;
+		}
+		kbscan->kc[kbscan->nk++] = c;
+		c = latin1(kbscan->kc, kbscan->nk);
+		if(c < -1)	/* need more keystrokes */
+			return;
+		if(c != -1)	/* valid sequence */
+			kbdputc(kbdq, c);
+		else	/* dump characters */
+			for(i=0; i<kbscan->nk; i++)
+				kbdputc(kbdq, kbscan->kc[i]);
+		kbscan->nk = 0;
+		kbscan->collecting = 0;
+		return;
+	} else {
+		switch(c){
+		case Caps:
+			kbscan->caps ^= 1;
+			return;
+		case Num:
+			kbscan->num ^= 1;
+			return;
+		case Shift:
+			kbscan->shift = 1;
+			if(kdebug)
+				print("shift\n");
+			mouseshifted = 1;
+			return;
+		case Latin:
+			kbscan->alt = 1;
+			/*
+			 * VMware and Qemu use Ctl-Alt as the key combination
+			 * to make the VM give up keyboard and mouse focus.
+			 * This has the unfortunate side effect that when you
+			 * come back into focus, Plan 9 thinks you want to type
+			 * a compose sequence (you just typed alt). 
+			 *
+			 * As a clumsy hack around this, we look for ctl-alt
+			 * and don't treat it as the start of a compose sequence.
+			 */
+			if(!kbscan->ctl){
+				kbscan->collecting = 1;
+				kbscan->nk = 0;
+			}
+			return;
+		case Ctrl:
+			kbscan->ctl = 1;
+			return;
+		case Altgr:
+			kbscan->altgr = 1;
+			return;
+		case Kmouse|1:
+		case Kmouse|2:
+		case Kmouse|3:
+		case Kmouse|4:
+		case Kmouse|5:
+			kbscan->buttons |= 1<<(c-Kmouse-1);
+			if(kbdmouse)
+				kbdmouse(kbscan->buttons);
+			return;
+		case KF|11:
+			print("kbd debug on, F12 turns it off\n");
+			kdebug = 1;
+			break;
+		case KF|12:
+			kdebug = 0;
+			break;
+		}
+	}
+	kbdputc(kbdq, c);
+}
+
+void
+kbdenable(void)
+{
+#ifdef notdef
+	kbdq = qopen(4*1024, 0, 0, 0);
+	if(kbdq == nil)
+		panic("kbdinit");
+	qnoblock(kbdq, 1);
+#endif
+	kbscans[Int].num = 0;
+}
+
+void
+kbdputmap(ushort m, ushort scanc, Rune r)
+{
+	if(scanc >= Nscan)
+		error(Ebadarg);
+	switch(m) {
+	default:
+		error(Ebadarg);
+	case 0:
+		kbtab[scanc] = r;
+		break;
+	case 1:
+		kbtabshift[scanc] = r;
+		break;
+	case 2:
+		kbtabesc1[scanc] = r;
+		break;
+	case 3:
+		kbtabaltgr[scanc] = r;
+		break;
+	case 4:	
+		kbtabctrl[scanc] = r;
+		break;
+	}
+}
+
+int
+kbdgetmap(uint offset, int *t, int *sc, Rune *r)
+{
+	if ((int)offset < 0)
+		error(Ebadarg);
+	*t = offset/Nscan;
+	*sc = offset%Nscan;
+	switch(*t) {
+	default:
+		return 0;
+	case 0:
+		*r = kbtab[*sc];
+		return 1;
+	case 1:
+		*r = kbtabshift[*sc];
+		return 1;
+	case 2:
+		*r = kbtabesc1[*sc];
+		return 1;
+	case 3:
+		*r = kbtabaltgr[*sc];
+		return 1;
+	case 4:
+		*r = kbtabctrl[*sc];
+		return 1;
+	}
+}

+ 17 - 8
sys/src/9/omap/main.c

@@ -112,6 +112,7 @@ writeconf(void)
 	if(n >= BOOTARGSLEN)
 		error("kernel configuration too large");
 	memmove(BOOTARGS, p, n);
+	memset(BOOTARGS + n, '\n', BOOTARGSLEN - n);
 	poperror();
 	free(p);
 }
@@ -225,9 +226,9 @@ wave('l');
 
 	confinit();
 	/* xinit prints (if it can), so finish up the banner here. */
-	delay(10);
+	delay(500);
 	iprint("l Labs\n\n");
-	delay(10);
+	delay(500);
 	xinit();
 
 	/*
@@ -247,15 +248,14 @@ wave('l');
 
 	archconfinit();
 
-	archreset();			/* configures clock signals */
+	archreset();			/* configure clock signals */
 	clockinit();			/* start clocks */
 	timersinit();
 	watchdoginit();
 
+	delay(250);			/* let uart catch up */
 	printinit();
-	i8250console();
-//	uartconsole(CONSOLE, "");		/* was "b115200" */
-//	normalprint = 1;
+	kbdenable();
 
 	cpuidprint();
 //	chkmissing();
@@ -265,7 +265,11 @@ wave('l');
 
 	dmainit();
 	links();
-	chandevreset();
+	conf.monitor = 1;
+	screeninit();
+	chandevreset();			/* most devices are discovered here */
+
+//	i8250console();			/* too early; see init0 */
 
 	pageinit();
 	swapinit();
@@ -436,7 +440,12 @@ init0(void)
 
 	dmatest();		/* needs `up' set, so can't do it earlier */
 	chandevinit();
-	i8250console();		/* again */
+	i8250console();		/* might be redundant, but harmless */
+	if(kbdq == nil)
+		panic("init0: nil kbdq");
+	if(serialoq == nil)
+		panic("init0: nil serialoq");
+	normalprint = 0;	/* always use iprint, print to uart is broken */
 
 	if(!waserror()){
 		snprint(buf, sizeof(buf), "%s %s", "ARM", conffile);

+ 7 - 6
sys/src/9/omap/mkfile

@@ -50,6 +50,7 @@ OBJ=\
 	fpi.$O\
 	fpiarm.$O\
 	fpimem.$O\
+	kbd.$O\
 	main.$O\
 	mmu.$O\
 	random.$O\
@@ -89,7 +90,7 @@ $OBJ: $HFILES
 install:V: /$objtype/$p$CONF
 
 /$objtype/$p$CONF:D: $p$CONF s$p$CONF
-	cp -x $p$CONF s$p$CONF /$objtype &
+	{ cp -x $p$CONF s$p$CONF /$objtype } &
 	wait
 	touch $target
 
@@ -103,14 +104,14 @@ arch.$O clock.$O fpiarm.$O main.$O mmu.$O screen.$O sdscsi.$O syscall.$O \
 	trap.$O: /$objtype/include/ureg.h
 
 archomap.$O devether.$0 ether9221.$O: etherif.h ../port/netif.h
-archomap.$O devflash.$O flashomap.$O: ../port/flashif.h
-ecc.$O flashomap.$O: ../port/nandecc.h
+archomap.$O devflash.$O flashbeagle.$O flashigep.$O: ../port/flashif.h
+ecc.$O flashbeagle.$O flashigep.$O: ../port/nandecc.h io.h
 fpi.$O fpiarm.$O fpimem.$O: fpi.h
 l.$O lexception.$O lproc.$O mmu.$O: arm.s arm.h mem.h
 l.$O rebootcode.$O: cache.v7.s
-main.$O:	errstr.h init.h reboot.h
-mouse.$O:	screen.h
-devusb.$O:	usb.h
+main.$O: errstr.h init.h reboot.h
+devmouse.$O mouse.$O screen.$O: screen.h
+devusb.$O: usb.h
 usbehci.$O usbohci.$O usbuhci.$O: usb.h usbehci.h uncached.h
 
 init.h:D:	../port/initcode.c init9.s

+ 255 - 0
sys/src/9/omap/mouse.c

@@ -0,0 +1,255 @@
+#include "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "../port/error.h"
+#include "io.h"
+
+#define	Image	IMAGE
+#include <draw.h>
+#include <memdraw.h>
+#include <cursor.h>
+#include "screen.h"
+
+/*
+ *  mouse types
+ */
+enum
+{
+	Mouseother=	0,
+	Mouseserial=	1,
+	MousePS2=	2,
+};
+
+extern int mouseshifted;
+
+static QLock mousectlqlock;
+static int mousetype;
+static int intellimouse;
+static int packetsize;
+static int resolution;
+static int accelerated;
+static int mousehwaccel;
+static char mouseport[5];
+
+enum
+{
+	CMaccelerated,
+	CMhwaccel,
+	CMintellimouse,
+	CMlinear,
+	CMps2,
+	CMps2intellimouse,
+	CMres,
+	CMreset,
+	CMserial,
+};
+
+static Cmdtab mousectlmsg[] =
+{
+	CMaccelerated,		"accelerated",		0,
+	CMhwaccel,		"hwaccel",		2,
+	CMintellimouse,		"intellimouse",		1,
+	CMlinear,		"linear",		1,
+	CMps2,			"ps2",			1,
+	CMps2intellimouse,	"ps2intellimouse",	1,
+	CMres,			"res",			0,
+	CMreset,		"reset",		1,
+	CMserial,		"serial",		0,
+};
+
+/*
+ *  ps/2 mouse message is three bytes
+ *
+ *	byte 0 -	0 0 SDY SDX 1 M R L
+ *	byte 1 -	DX
+ *	byte 2 -	DY
+ *
+ *  shift & right button is the same as middle button
+ *
+ * Intellimouse and AccuPoint with extra buttons deliver
+ *	byte 3 -	00 or 01 or FF according to extra button state.
+ * extra buttons are mapped in this code to buttons 4 and 5.
+ * AccuPoint generates repeated events for these buttons;
+*  it and Intellimouse generate 'down' events only, so
+ * user-level code is required to generate button 'up' events
+ * if they are needed by the application.
+ * Also on laptops with AccuPoint AND external mouse, the
+ * controller may deliver 3 or 4 bytes according to the type
+ * of the external mouse; code must adapt.
+ *
+ * On the NEC Versa series (and perhaps others?) we seem to
+ * lose a byte from the packet every once in a while, which
+ * means we lose where we are in the instruction stream.
+ * To resynchronize, if we get a byte more than two seconds
+ * after the previous byte, we assume it's the first in a packet.
+ */
+static void
+ps2mouseputc(int c, int shift)
+{
+	static short msg[4];
+	static int nb;
+	static uchar b[] = {0, 1, 4, 5, 2, 3, 6, 7, 0, 1, 2, 3, 2, 3, 6, 7 };
+	static ulong lasttick;
+	ulong m;
+	int buttons, dx, dy;
+
+	shift |= mouseshifted;
+	m = MACHP(0)->ticks;
+	if(TK2SEC(m - lasttick) > 2)
+		nb = 0;
+	lasttick = m;
+	if(nb==0 && (c&0xc8)!=0x08)
+		if(intellimouse && (c==0x00 || c==0x01 || c==0xFF)){
+			packetsize = 4;
+			return;
+		}
+
+	msg[nb] = c;
+	if(++nb == packetsize){
+		nb = 0;
+		if(msg[0] & 0x10)
+			msg[1] |= 0xFF00;
+		if(msg[0] & 0x20)
+			msg[2] |= 0xFF00;
+
+		buttons = b[(msg[0]&7) | (shift ? 8 : 0)];
+		if(intellimouse && packetsize==4){
+			if((msg[3]&0xc8) == 0x08){
+				packetsize = 3;
+				msg[0] = msg[3];
+				nb = 1;
+			}else{
+				if((msg[3] >> 3) & 1)
+					buttons |= 1<<3;
+				else if(msg[3] & 0x7)
+					buttons |= 1<<4;
+			}
+		}
+		dx = msg[1];
+		dy = -msg[2];
+		mousetrack(dx, dy, buttons, TK2MS(MACHP(0)->ticks));
+	}
+}
+
+/*
+ *  set up a ps2 mouse
+ */
+static void
+ps2mouse(void)
+{
+	if(mousetype == MousePS2)
+		return;
+
+//	i8042auxenable(ps2mouseputc);
+//	i8042auxcmd(0xEA);	// TODO
+//	i8042auxcmd(0xF4);
+
+	mousetype = MousePS2;
+	packetsize = 3;
+	mousehwaccel = 1;
+}
+
+/*
+ * The PS/2 Trackpoint multiplexor on the IBM Thinkpad T23 ignores
+ * acceleration commands.  It is supposed to pass them on
+ * to the attached device, but my Logitech mouse is simply
+ * not behaving any differently.  For such devices, we allow
+ * the user to use "hwaccel off" to tell us to back off to
+ * software acceleration even if we're using the PS/2 port.
+ * (Serial mice are always software accelerated.)
+ * For more information on the Thinkpad multiplexor, see
+ * http://wwwcssrv.almaden.ibm.com/trackpoint/
+ */
+static void
+setaccelerated(int x)
+{
+	accelerated = x;
+	mouseaccelerate(x);
+}
+
+static void
+setlinear(void)
+{
+	accelerated = 0;
+	mouseaccelerate(0);
+}
+
+static void
+setres(int n)
+{
+	resolution = n;
+}
+
+static void
+setintellimouse(void)
+{
+	intellimouse = 1;
+	packetsize = 4;
+}
+
+static void
+resetmouse(void)
+{
+	packetsize = 3;
+}
+
+void
+mousectl(Cmdbuf *cb)
+{
+	Cmdtab *ct;
+
+	qlock(&mousectlqlock);
+	if(waserror()){
+		qunlock(&mousectlqlock);
+		nexterror();
+	}
+
+	ct = lookupcmd(cb, mousectlmsg, nelem(mousectlmsg));
+	switch(ct->index){
+	case CMaccelerated:
+		setaccelerated(cb->nf == 1? 1: atoi(cb->f[1]));
+		break;
+	case CMintellimouse:
+		setintellimouse();
+		break;
+	case CMlinear:
+		setlinear();
+		break;
+	case CMps2:
+		intellimouse = 0;
+		break;
+	case CMps2intellimouse:
+		setintellimouse();
+		break;
+	case CMres:
+		if(cb->nf >= 2)
+			setres(atoi(cb->f[1]));
+		else
+			setres(1);
+		break;
+	case CMreset:
+		resetmouse();
+		if(accelerated)
+			setaccelerated(accelerated);
+		if(resolution)
+			setres(resolution);
+		if(intellimouse)
+			setintellimouse();
+		break;
+	case CMserial:
+		error("serial mice not supported");
+		break;
+	case CMhwaccel:
+		if(strcmp(cb->f[1], "on")==0)
+			mousehwaccel = 1;
+		else if(strcmp(cb->f[1], "off")==0)
+			mousehwaccel = 0;
+		else
+			cmderror(cb, "bad mouse control message");
+	}
+
+	qunlock(&mousectlqlock);
+	poperror();
+}

+ 611 - 0
sys/src/9/omap/screen.c

@@ -0,0 +1,611 @@
+/*
+ * ti omap35 display subsystem (dss)
+ *
+ * can handle 2ⁿ bits per pixel for 0 < n ≤ 4, and 12 and 24 bits.
+ * can handle	1024×768 at 60 Hz with pixel clock of 63.5 MHz
+ *		1280×800 at 59.91 Hz with pixel clock of 71 MHz
+ *		1400×1050 lcd at 50 MHz with pixel clock of 75 MHz
+ * has 256 24-bit entries in RGB palette
+ */
+#include "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "io.h"
+#include "ureg.h"
+#include "../port/error.h"
+
+#define	Image	IMAGE
+#include <draw.h>
+#include <memdraw.h>
+#include <cursor.h>
+#include "screen.h"
+// #include "gamma.h"
+
+#define MINX 8
+
+enum {
+	Tabstop	= 4,		/* should be 8 */
+	/*
+	 * screen settings for Wid and Ht, should a bit more dynamic?
+	 * http://www.epanorama.net/faq/vga2rgb/calc.html
+	 * used to calculate settings.
+	 */
+
+//	Hbp     = (248-1) << 20,
+//	Hfp     = (48-1) << 8,
+//	Hsw     = 112-1,
+
+//	Vbp     = 38 << 20,
+//	Vfp     = 1 << 8,
+//	Vsw     = 3,
+
+	Tft	= 0x60,
+
+//	Pcd	= HOWMANY(432000, pixelclock),	/* a bit too magic */
+
+	Loadmode = 2 << 1,
+	Fifosize = 0x400,
+
+	/* dispc sysconfig */
+	Midlemode	= 2 << 12,
+	Sidlemode	= 2 << 3,
+	EnableWakeup	= 1 << 2,
+	Autoidle	= 1 << 0,
+
+	/* dispc pool_freq  */
+	Ipc		= 1 << 14,
+	Ihs		= 1 << 13,
+	Ivs		= 1 << 12,
+	Acb		= 0x28,
+
+	/* gfx attribs */
+	Burstsize	= 2 << 6,
+	Format		= 6 << 1,
+	Gfxenable	= 1 << 0,
+
+	/* dispc control */
+	Gpout1		= 1 << 16,
+	Gpout0		= 1 << 15,
+	Tftdata		= 3 << 8,
+	Digital		= 1 << 6,
+	Lcd		= 1 << 5,
+	Stntft		= 1 << 3,
+	Digitalen	= 1 << 1,
+//	Lcden		= 1 << 0,	/* unused */
+};
+
+enum {					/* settings indices */
+	Res800x600,
+	Res1024x768,
+	Res1280x1024,
+};
+
+typedef struct Dispcregs Dispc;
+typedef struct Dssregs Dss;
+typedef struct Ioregs Ioregs;
+
+struct Ioregs {				/* common registers, 68 (0x44) bytes */
+	ulong 	rev;
+	uchar	_pad0[0x10-0x4];
+	ulong	sysconf;
+	ulong	sysstat;
+	ulong	irqstat1;
+
+	/* Dispc only regs */
+	ulong	irqen1;
+	ulong	wkupen;
+	ulong	_pad1;
+	ulong	irqsts2;
+	ulong	irqen2;
+	ulong	_pad2[4];
+
+	ulong	ctrl;
+};
+
+struct Dssregs {			/* display subsys at 0x48050000 */
+	Ioregs;
+	ulong	sdicrtl;
+	ulong	pllcrtl;
+	uchar	_pad3[0x5c-0x4c];
+	ulong	sdistat;
+};
+
+struct Dispcregs {			/* display ctlr at 0x48050400 */
+	Ioregs;
+	ulong	config;
+	ulong	_pad3;
+	ulong 	defaultcolor[2];
+	ulong	transcolor[2];
+	ulong	linestat;
+	ulong	linenum;
+	ulong	timing_h;
+	ulong	timing_v;
+	ulong	pol_req;
+	ulong	divisor;
+	ulong	alpha;
+	ulong	digsize;
+	ulong	lcdsize;
+
+	ulong	base[2];	/* should allocate both to avoid dithering */
+	ulong	pos;
+	ulong	size;
+	ulong	_pad4[4];
+	ulong	attrib;
+	ulong	fifothr;
+	ulong	fifosize;
+	ulong	rowinc;
+	ulong	pixelinc;
+	ulong	winskip;
+	ulong	palette;		/* gfx_table_ba */
+	uchar	_pad5[0x5d4 - 0x4bc];
+
+	ulong	datacycle[3];
+	uchar	_pad5[0x620 - 0x5e0];
+
+	ulong	cprcoefr;
+	ulong	cprcoefg;
+	ulong	cprcoefb;
+	ulong	preload;
+};
+
+int	drawdebug;
+Point	ZP = {0, 0};
+Cursor	arrow = {
+	{ -1, -1 },
+	{ 0xFF, 0xFF, 0x80, 0x01, 0x80, 0x02, 0x80, 0x0C,
+	  0x80, 0x10, 0x80, 0x10, 0x80, 0x08, 0x80, 0x04,
+	  0x80, 0x02, 0x80, 0x01, 0x80, 0x02, 0x8C, 0x04,
+	  0x92, 0x08, 0x91, 0x10, 0xA0, 0xA0, 0xC0, 0x40,
+	},
+	{ 0x00, 0x00, 0x7F, 0xFE, 0x7F, 0xFC, 0x7F, 0xF0,
+	  0x7F, 0xE0, 0x7F, 0xE0, 0x7F, 0xF0, 0x7F, 0xF8,
+	  0x7F, 0xFC, 0x7F, 0xFE, 0x7F, 0xFC, 0x73, 0xF8,
+	  0x61, 0xF0, 0x60, 0xE0, 0x40, 0x40, 0x00, 0x00,
+	},
+};
+
+static struct {
+	Point	pos;
+	int	bwid;
+} out;
+
+OScreen oscreen;
+OScreen settings[] = {
+	0,  800,  600, 60, RGB16,  40000,  87<<20, 39<<8, 127, 23<<20, 1<<8, 4,
+	0, 1024,  768, 60, RGB16,  65000, 159<<20, 23<<8, 135, 29<<20, 3<<8, 6,
+	0, 1280, 1024, 60, RGB16, 108000, 247<<20, 47<<8, 111, 38<<20, 1<<8, 3,
+};
+struct Omap3fb *framebuf;
+Memimage *gscreen;
+
+static Memdata xgdata;
+
+static Memimage xgscreen =
+{
+	{ 0, 0, Wid, Ht },	/* r */
+	{ 0, 0, Wid, Ht },	/* clipr */
+	Depth,			/* depth */
+	3,			/* nchan */
+	RGB16,			/* chan */
+	nil,			/* cmap */
+	&xgdata,		/* data */
+	0,			/* zero */
+	Wid*(Depth/BI2BY)/BY2WD, /* width in words of a single scan line */
+	0,			/* layer */
+	0,			/* flags */
+};
+
+static Memimage *conscol;
+static Memimage *back;
+
+static Memsubfont *memdefont;
+
+static Lock screenlock;
+
+static Point	curpos;
+static int	h, w;
+static int	landscape = 0;	/* screen orientation, default is 0: portrait */
+static ushort	*vscreen;	/* virtual screen */
+static Rectangle window;
+
+static Dispc *dispc = (Dispc *)PHYSDISPC;
+static Dss *dss	= (Dss *)PHYSDSS;
+
+static	void	omapscreenputs(char *s, int n);
+static	ulong	rep(ulong, int);
+static	void	screenputc(char *buf);
+static	void	screenwin(void);
+
+static void
+lcdoff(void)
+{
+	dispc->ctrl &= ~1;		/* disable the lcd */
+	coherence();
+
+	dispc->irqstat1 |= 1;		/* set framedone */
+	coherence();
+
+	/* the lcd never comes ready, so don't bother with this */
+#ifdef notdef
+	/* spin until the frame is complete, but not forever */
+	for(cnt = 50; !(dispc->irqstat1 & 1) && cnt-- > 0; )
+		delay(10);
+	if(cnt <= 0)
+		iprint("screen: lcd never came ready!\n");
+#endif
+	delay(20);			/* worst case for 1 frame, 50Hz */
+}
+
+static void
+dssstart(void)
+{
+	/* should reset the dss system */
+	dss->sysconf |= 1;
+}
+
+static void
+configdispc(void)
+{
+	dss->ctrl &= 0x78;		/* choose dss clock */
+	dispc->sysconf = Midlemode | Sidlemode | EnableWakeup | Autoidle;
+	dispc->config = Loadmode;
+	coherence();
+
+	/* pll */
+	dispc->defaultcolor[0] = 0;	/* set background color to black? */
+	dispc->defaultcolor[1] = 0;
+	dispc->transcolor[0] = 0;	/* set transparency to full */
+	dispc->transcolor[1] = 0;
+
+	dispc->timing_h = oscreen.hbp | oscreen.hfp | oscreen.hsw;
+	dispc->timing_v = oscreen.vbp | oscreen.vfp | oscreen.vsw;
+
+	dispc->pol_req = Ipc | Ihs | Ivs | Acb;
+	dispc->divisor = 1 << 16 | HOWMANY(432000, oscreen.pixelclock);
+
+	dispc->lcdsize = (oscreen.ht - 1) << 16 | (oscreen.wid - 1);
+	coherence();
+
+	dispc->base[0] = PADDR(framebuf->pixel);
+	dispc->base[1] = PADDR(framebuf->pixel);
+
+	dispc->pos = 0;			/* place screen in the left corner */
+	/* use the whole screen */
+	dispc->size = (oscreen.ht - 1) << 16 | (oscreen.wid - 1);
+
+	/* what mode does plan 9 use for fb? */
+	dispc->attrib = Burstsize | Format | Gfxenable;
+
+	dispc->preload = Tft;
+	dispc->fifosize = Fifosize;
+	/* 1008 is max for our Burstsize */
+	dispc->fifothr = (Fifosize - 1) << 16 | (1008 - 1);
+
+	/* 1 byte is one pixel (not true, we use 2 bytes per pixel) */
+	dispc->rowinc = 1;
+	dispc->pixelinc = 1;
+	dispc->winskip = 0;		/* don't skip anything */
+	coherence();
+
+	// dispc->palette = PADDR(framebuf->palette);
+}
+
+static void
+lcdon(int enable)
+{
+	dispc->ctrl = Gpout1 | Gpout0 | Tftdata | Digital | Lcd | Stntft |
+		Digitalen | enable;
+	coherence();
+	delay(10);
+}
+
+static void
+lcdinit(void)
+{
+	configscreengpio();
+	screenclockson();
+
+	lcdoff();
+	dssstart();
+	configdispc();
+}
+
+/* Paint the image data with blue pixels */
+void
+screentest(void)
+{
+	int h = Ht, w = Wid, i, k;
+
+	for (i = 0; i < h; i++)
+		for (k = 0; k < w; k++)
+			framebuf->pixel[i*w + k] = 0x1f;
+//	memset(framebuf->pixel, ~0, sizeof framebuf->pixel);	/* white */
+}
+
+void
+screenpower(int on)
+{
+	blankscreen(on == 0);
+}
+
+int
+cursoron(int)
+{
+	return 0;
+}
+
+void
+cursoroff(int)
+{
+}
+
+void
+setcursor(Cursor* curs)
+{
+//	VGAscr *scr;
+
+	USED(curs);
+//	scr = &vgascreen[0];
+//	cursorload(scr, curs);
+}
+
+void
+screeninit(void)
+{
+	iprint("screeninit...");
+	oscreen = settings[Res1280x1024];
+	/* mode is 16*32 = 512 */
+	framebuf = xspanalloc(sizeof *framebuf, 16*32, 0);
+
+	lcdinit();
+	lcdon(1);
+
+	screentest();
+
+	xgdata.ref = 1;
+	xgdata.bdata = (uchar *)framebuf->pixel;
+
+	gscreen = &xgscreen;
+	gscreen->r = Rect(0, 0, Wid, Ht);
+	gscreen->clipr = gscreen->r;
+	/* width, in words, of a single scan line */
+	gscreen->width = Wid*(Depth/BI2BY)/BY2WD;
+	flushmemscreen(gscreen->r);
+
+	iprint("on: blue for a few seconds...");
+	delay(2*1000);
+	iprint("\n");
+
+	memimageinit();
+	memdefont = getmemdefont();
+
+	out.pos.x = MINX;
+	out.pos.y = 0;
+	out.bwid = memdefont->info[' '].width;
+	blanktime = 3;				/* minutes */
+
+	screenwin();
+	screenputs = omapscreenputs;
+	iprint("screen: frame buffer at %#p\n", framebuf);
+}
+
+/* flushmemscreen should change buffer? */
+void
+flushmemscreen(Rectangle r)
+{
+	ulong start, end;
+
+	if (r.min.x < 0)
+		r.min.x = 0;
+	if (r.max.x > Wid)
+		r.max.x = Wid;
+	if (r.min.y < 0)
+		r.min.y = 0;
+	if (r.max.y > Ht)
+		r.max.y = Ht;
+	if (rectclip(&r, gscreen->r) == 0)
+		return;
+	start = (ulong)&framebuf->pixel[r.min.y*Wid + r.min.x];
+	end   = (ulong)&framebuf->pixel[(r.max.y - 1)*Wid + r.max.x -1];
+	cachedwbse((ulong *)start, end - start);
+}
+
+/*
+ * export screen to devdraw
+ */
+uchar*
+attachscreen(Rectangle *r, ulong *chan, int *d, int *width, int *softscreen)
+{
+	*r = gscreen->r;
+	*d = gscreen->depth;
+	*chan = gscreen->chan;
+	*width = gscreen->width;
+	*softscreen = (landscape == 0);
+	return (uchar *)gscreen->data->bdata;
+}
+
+void
+getcolor(ulong p, ulong *pr, ulong *pg, ulong *pb)
+{
+	USED(p, pr, pg, pb);
+}
+
+int
+setcolor(ulong p, ulong r, ulong g, ulong b)
+{
+	USED(p, r, g, b);
+	return 0;
+}
+
+void
+blankscreen(int blank)
+{
+	if (blank)
+		lcdon(0);
+	else {
+		lcdinit();
+		lcdon(1);
+	}
+}
+
+static void
+omapscreenputs(char *s, int n)
+{
+	int i;
+	Rune r;
+	char buf[4];
+
+	if (!islo()) {
+		/* don't deadlock trying to print in interrupt */
+		if (!canlock(&screenlock))
+			return;			/* discard s */
+	} else
+		lock(&screenlock);
+
+	while (n > 0) {
+		i = chartorune(&r, s);
+		if (i == 0) {
+			s++;
+			--n;
+			continue;
+		}
+		memmove(buf, s, i);
+		buf[i] = 0;
+		n -= i;
+		s += i;
+		screenputc(buf);
+	}
+	unlock(&screenlock);
+}
+
+static void
+screenwin(void)
+{
+	char *greet;
+	Memimage *orange;
+	Point p, q;
+	Rectangle r;
+
+	memsetchan(gscreen, RGB16);
+
+	back = memwhite;
+	conscol = memblack;
+
+	orange = allocmemimage(Rect(0, 0, 1, 1), RGB16);
+	orange->flags |= Frepl;
+	orange->clipr = gscreen->r;
+	orange->data->bdata[0] = 0x40;		/* magic: colour? */
+	orange->data->bdata[1] = 0xfd;		/* magic: colour? */
+
+	w = memdefont->info[' '].width;
+	h = memdefont->height;
+
+	r = insetrect(gscreen->r, 4);
+
+	memimagedraw(gscreen, r, memblack, ZP, memopaque, ZP, S);
+	window = insetrect(r, 4);
+	memimagedraw(gscreen, window, memwhite, ZP, memopaque, ZP, S);
+
+	memimagedraw(gscreen, Rect(window.min.x, window.min.y,
+		window.max.x, window.min.y + h + 5 + 6), orange, ZP, nil, ZP, S);
+	freememimage(orange);
+	window = insetrect(window, 5);
+
+	greet = " Plan 9 Console ";
+	p = addpt(window.min, Pt(10, 0));
+	q = memsubfontwidth(memdefont, greet);
+	memimagestring(gscreen, p, conscol, ZP, memdefont, greet);
+	flushmemscreen(r);
+	window.min.y += h + 6;
+	curpos = window.min;
+	window.max.y = window.min.y + ((window.max.y - window.min.y) / h) * h;
+}
+
+static void
+scroll(void)
+{
+	int o;
+	Point p;
+	Rectangle r;
+
+	/* move window contents up 8 text lines */
+	o = 8 * h;
+	r = Rpt(window.min, Pt(window.max.x, window.max.y - o));
+	p = Pt(window.min.x, window.min.y + o);
+	memimagedraw(gscreen, r, gscreen, p, nil, p, S);
+	flushmemscreen(r);
+
+	/* clear the bottom 8 text lines */
+	r = Rpt(Pt(window.min.x, window.max.y - o), window.max);
+	memimagedraw(gscreen, r, back, ZP, nil, ZP, S);
+	flushmemscreen(r);
+
+	curpos.y -= o;
+}
+
+static void
+screenputc(char *buf)
+{
+	int w;
+	uint pos;
+	Point p;
+	Rectangle r;
+	static int *xp;
+	static int xbuf[256];
+
+	if (xp < xbuf || xp >= &xbuf[sizeof(xbuf)])
+		xp = xbuf;
+
+	switch (buf[0]) {
+	case '\n':
+		if (curpos.y + h >= window.max.y)
+			scroll();
+		curpos.y += h;
+		screenputc("\r");
+		break;
+	case '\r':
+		xp = xbuf;
+		curpos.x = window.min.x;
+		break;
+	case '\t':
+		p = memsubfontwidth(memdefont, " ");
+		w = p.x;
+		if (curpos.x >= window.max.x - Tabstop * w)
+			screenputc("\n");
+
+		pos = (curpos.x - window.min.x) / w;
+		pos = Tabstop - pos % Tabstop;
+		*xp++ = curpos.x;
+		r = Rect(curpos.x, curpos.y, curpos.x + pos * w, curpos.y + h);
+		memimagedraw(gscreen, r, back, back->r.min, nil, back->r.min, S);
+		flushmemscreen(r);
+		curpos.x += pos * w;
+		break;
+	case '\b':
+		if (xp <= xbuf)
+			break;
+		xp--;
+		r = Rect(*xp, curpos.y, curpos.x, curpos.y + h);
+		memimagedraw(gscreen, r, back, back->r.min, nil, back->r.min, S);
+		flushmemscreen(r);
+		curpos.x = *xp;
+		break;
+	case '\0':
+		break;
+	default:
+		p = memsubfontwidth(memdefont, buf);
+		w = p.x;
+
+		if (curpos.x >= window.max.x - w)
+			screenputc("\n");
+
+		*xp++ = curpos.x;
+		r = Rect(curpos.x, curpos.y, curpos.x + w, curpos.y + h);
+		memimagedraw(gscreen, r, back, back->r.min, nil, back->r.min, S);
+		memimagestring(gscreen, curpos, conscol, ZP, memdefont, buf);
+		flushmemscreen(r);
+		curpos.x += w;
+	}
+}

+ 106 - 0
sys/src/9/omap/screen.h

@@ -0,0 +1,106 @@
+typedef struct Cursor Cursor;
+typedef struct Cursorinfo	Cursorinfo;
+typedef struct Scr	Scr;
+
+struct Cursorinfo
+{
+	Cursor;
+	Lock;
+};
+
+extern Cursor	arrow;
+extern ulong	blanktime;
+extern Cursorinfo cursor;
+
+extern void	cursoroff(int);
+extern int	cursoron(int);
+extern void	mouseaccelerate(int);
+extern void	mouseresize(void);
+extern void	mousetrack(int, int, int, int);
+extern void	setcursor(Cursor* curs);
+
+extern uchar*	attachscreen(Rectangle*, ulong*, int*, int*, int*);
+extern void	blankscreen(int);
+extern void	flushmemscreen(Rectangle);
+
+#define ishwimage(i)	0
+
+/* for communication between devdss.c and screen.c */
+
+enum {					/* maxima */
+	Wid		= 1280,
+	Ht		= 1024,
+	Depth		= 16,		/* bits per pixel */
+
+	Pcolours	= 256,		/* Palette */
+	Pred		= 0,
+	Pgreen		= 1,
+	Pblue		= 2,
+
+	Pblack		= 0x00,
+	Pwhite		= 0xFF,
+};
+
+typedef struct OScreen OScreen;
+typedef struct Omap3fb Omap3fb;
+
+struct OScreen {
+	int	open;
+	uint	wid;
+	uint	ht;
+	uint	freq;
+	uint	chan;
+
+//	Lock;
+//	Cursor;
+
+	/* shouldn't be needed? */
+	uint	pixelclock;
+	uint	hbp;
+	uint	hfp;
+	uint	hsw;
+
+	uint	vbp;
+	uint	vfp;
+	uint	vsw;
+};
+
+struct Omap3fb {		/* frame buffer for 24-bit active color */
+//	short	palette[256];
+	/* pixel data, even; base type's width must match Depth */
+	ushort	pixel[Wid*Ht];
+};
+
+struct Scr {
+	Lock	devlock;
+//	VGAdev*	dev;
+//	Pcidev*	pci;
+
+//	VGAcur*	cur;
+	ulong	storage;
+	Cursor;
+
+	int	useflush;
+
+	ulong	paddr;		/* frame buffer */
+	void*	vaddr;
+	int	apsize;
+
+	ulong	io;			/* device specific registers */
+	ulong	*mmio;
+	
+	ulong	colormap[Pcolours][3];
+	int	palettedepth;
+
+	Memimage* gscreen;
+	Memdata* gscreendata;
+	Memsubfont* memdefont;
+
+	int	(*fill)(Scr*, Rectangle, ulong);
+	int	(*scroll)(Scr*, Rectangle, Rectangle);
+	void	(*blank)(Scr*, int);
+
+	ulong	id;	/* internal identifier for driver use */
+	int	isblank;
+	int	overlayinit;
+};

+ 99 - 57
sys/src/9/omap/uarti8250.c

@@ -1,17 +1,19 @@
+/*
+ * omap35 8250-like UART
+ *
+ * we ignore the first 2 uarts on the omap35 (see below) and use the
+ * third one but call it 0.
+ *
+ * TODO: uart output other than from iprint never appears.
+ *	are we not getting tx interrupts?
+ */
+
 #include "u.h"
 #include "../port/lib.h"
 #include "mem.h"
 #include "dat.h"
 #include "fns.h"
 
-/*
- * we ignore the first 2 uarts on the omap3530 (see below) and use the
- * third one but call it 0.
- */
-
-/*
- * 8250 UART and compatibles.
- */
 enum {					/* registers */
 	Rbr		= 0,		/* Receiver Buffer (RO) */
 	Thr		= 0,		/* Transmitter Holding (WO) */
@@ -23,7 +25,8 @@ enum {					/* registers */
 	Lsr		= 5,		/* Line Status */
 	Msr		= 6,		/* Modem Status */
 	Scr		= 7,		/* Scratch Pad */
-	Usr		= 31,		/* Uart Status Register */
+	Mdr		= 8,		/* Mode Def'n (omap rw) */
+//	Usr		= 31,		/* Uart Status Register; missing in omap? */
 	Dll		= 0,		/* Divisor Latch LSB */
 	Dlm		= 1,		/* Divisor Latch MSB */
 };
@@ -54,6 +57,7 @@ enum {					/* Fcr */
 	FIFOena		= 0x01,		/* FIFO enable */
 	FIFOrclr	= 0x02,		/* clear Rx FIFO */
 	FIFOtclr	= 0x04,		/* clear Tx FIFO */
+//	FIFOdma		= 0x08,
 	FIFO1		= 0x00,		/* Rx FIFO trigger level 1 byte */
 	FIFO4		= 0x40,		/*	4 bytes */
 	FIFO8		= 0x80,		/*	8 bytes */
@@ -78,7 +82,7 @@ enum {					/* Mcr */
 	Dtr		= 0x01,		/* Data Terminal Ready */
 	Rts		= 0x02,		/* Ready To Send */
 	Out1		= 0x04,		/* no longer in use */
-	Ie		= 0x08,		/* IRQ Enable */
+//	Ie		= 0x08,		/* IRQ Enable (cd_sts_ch on omap) */
 	Dm		= 0x10,		/* Diagnostic Mode loopback */
 };
 
@@ -89,7 +93,7 @@ enum {					/* Lsr */
 	Fe		= 0x08,		/* Framing Error */
 	Bi		= 0x10,		/* Break Interrupt */
 	Thre		= 0x20,		/* Thr Empty */
-	Temt		= 0x40,		/* Tramsmitter Empty */
+	Temt		= 0x40,		/* Transmitter Empty */
 	FIFOerr		= 0x80,		/* error in receiver FIFO */
 };
 
@@ -101,9 +105,15 @@ enum {					/* Msr */
 	Cts		= 0x10,		/* Clear To Send */
 	Dsr		= 0x20,		/* Data Set Ready */
 	Ri		= 0x40,		/* Ring Indicator */
-	Dcd		= 0x80,		/* Data Set Ready */
+	Dcd		= 0x80,		/* Carrier Detect */
+};
+
+enum {					/* Mdr */
+	Modemask	= 7,
+	Modeuart	= 0,
 };
 
+
 typedef struct Ctlr {
 	u32int*	io;
 	int	irq;
@@ -111,7 +121,7 @@ typedef struct Ctlr {
 	int	iena;
 	int	poll;
 
-	uchar	sticky[8];
+	uchar	sticky[Scr+1];
 
 	Lock;
 	int	hasfifo;
@@ -123,10 +133,11 @@ extern PhysUart i8250physuart;
 extern int normalprint;
 
 static Ctlr i8250ctlr[] = {
-{	.io	= (u32int*)PHYSCONS,
+{	.io	= (u32int*)PHYSCONS,		/* UART3 in TI terminology */
 	.irq	= 74,
 	.tbdf	= -1,
 	.poll	= 0, },
+
 /* these exist, but I don't think they're connected to anything external */
 //{	.io	= (u32int*)PHYSUART0,
 //	.irq	= 72,
@@ -163,9 +174,9 @@ static Uart i8250uart[] = {
 //	.next	= &i8250uart[2], },
 };
 
-#define csr8r(c, r)	((c)->io[(r)])
-#define csr8w(c, r, v)	((c)->io[(r)] = (c)->sticky[(r)]|(v))
-#define csr8o(c, r, v)	((c)->io[(r)] = (v))
+#define csr8r(c, r)	((c)->io[r])
+#define csr8w(c, r, v)	((c)->io[r] = (c)->sticky[r] | (v), coherence())
+#define csr8o(c, r, v)	((c)->io[r] = (v), coherence())
 
 static long
 i8250status(Uart* uart, void* buf, long n, long offset)
@@ -275,7 +286,6 @@ i8250dtr(Uart* uart, int on)
 	else
 		ctlr->sticky[Mcr] &= ~Dtr;
 	csr8w(ctlr, Mcr, 0);
-	coherence();
 }
 
 static void
@@ -292,7 +302,6 @@ i8250rts(Uart* uart, int on)
 	else
 		ctlr->sticky[Mcr] &= ~Rts;
 	csr8w(ctlr, Mcr, 0);
-	coherence();
 }
 
 static void
@@ -304,13 +313,13 @@ i8250modemctl(Uart* uart, int on)
 	ilock(&uart->tlock);
 	if(on){
 		ctlr->sticky[Ier] |= Ems;
-		csr8w(ctlr, Ier, ctlr->sticky[Ier]);
+		csr8w(ctlr, Ier, 0);
 		uart->modem = 1;
 		uart->cts = csr8r(ctlr, Msr) & Cts;
 	}
 	else{
 		ctlr->sticky[Ier] &= ~Ems;
-		csr8w(ctlr, Ier, ctlr->sticky[Ier]);
+		csr8w(ctlr, Ier, 0);
 		uart->modem = 0;
 		uart->cts = 1;
 	}
@@ -343,7 +352,6 @@ i8250parity(Uart* uart, int parity)
 	}
 	ctlr->sticky[Lcr] = lcr;
 	csr8w(ctlr, Lcr, 0);
-	coherence();
 
 	uart->parity = parity;
 
@@ -370,7 +378,6 @@ i8250stop(Uart* uart, int stop)
 	}
 	ctlr->sticky[Lcr] = lcr;
 	csr8w(ctlr, Lcr, 0);
-	coherence();
 
 	uart->stop = stop;
 
@@ -404,7 +411,6 @@ i8250bits(Uart* uart, int bits)
 	}
 	ctlr->sticky[Lcr] = lcr;
 	csr8w(ctlr, Lcr, 0);
-	coherence();
 
 	uart->bits = bits;
 
@@ -418,6 +424,7 @@ i8250baud(Uart* uart, int baud)
 	ulong bgc;
 	Ctlr *ctlr;
 	extern int i8250freq;	/* In the config file */
+
 	/*
 	 * Set the Baud rate by calculating and setting the Baud rate
 	 * Generator Constant. This will work with fairly non-standard
@@ -430,16 +437,12 @@ i8250baud(Uart* uart, int baud)
 	ctlr = uart->regs;
 	while(csr8r(ctlr, Usr) & Busy)
 		delay(1);
-	csr8w(ctlr, Lcr, Dlab);
+	csr8w(ctlr, Lcr, Dlab);		/* begin kludge */
 	csr8o(ctlr, Dlm, bgc>>8);
 	csr8o(ctlr, Dll, bgc);
 	csr8w(ctlr, Lcr, 0);
-	coherence();
-
-	uart->baud = baud;
-#else
-	USED(uart, baud);
 #endif
+	uart->baud = baud;
 	return 0;
 }
 
@@ -448,6 +451,8 @@ i8250break(Uart* uart, int ms)
 {
 	Ctlr *ctlr;
 
+	if (up == nil)
+		panic("i8250break: nil up");
 	/*
 	 * Send a break.
 	 */
@@ -456,10 +461,15 @@ i8250break(Uart* uart, int ms)
 
 	ctlr = uart->regs;
 	csr8w(ctlr, Lcr, Brk);
-	coherence();
 	tsleep(&up->sleep, return0, 0, ms);
 	csr8w(ctlr, Lcr, 0);
-	coherence();
+}
+
+static void
+emptyoutstage(Uart *uart, int n)
+{
+	_uartputs((char *)uart->op, n);
+	uart->op = uart->oe = uart->ostage;
 }
 
 static void
@@ -471,12 +481,19 @@ i8250kick(Uart* uart)
 	if(/* uart->cts == 0 || */ uart->blocked)
 		return;
 
+	if(!normalprint) {
+		if (uart->op < uart->oe)
+			emptyoutstage(uart, uart->oe - uart->op);
+		while ((i = uartstageoutput(uart)) > 0)
+			emptyoutstage(uart, i);
+		return;
+	}
+
 	/* nothing more to send? then disable xmit intr */
 	ctlr = uart->regs;
 	if (uart->op >= uart->oe && csr8r(ctlr, Lsr) & Temt) {
 		ctlr->sticky[Ier] &= ~Ethre;
-		csr8w(ctlr, Ier, ctlr->sticky[Ier]);
-		coherence();
+		csr8w(ctlr, Ier, 0);
 		return;
 	}
 
@@ -491,14 +508,18 @@ i8250kick(Uart* uart)
 			break;
 		if(uart->op >= uart->oe && uartstageoutput(uart) == 0)
 			break;
-		csr8o(ctlr, Thr, *(uart->op++));
-		coherence();
+		csr8o(ctlr, Thr, *uart->op++);		/* start tx */
 		ctlr->sticky[Ier] |= Ethre;
-		csr8w(ctlr, Ier, ctlr->sticky[Ier]);
-		coherence();
+		csr8w(ctlr, Ier, 0);			/* intr when done */
 	}
 }
 
+void
+serialkick(void)
+{
+	uartkick(&i8250uart[CONSOLE]);
+}
+
 static void
 i8250interrupt(Ureg*, void* arg)
 {
@@ -581,8 +602,7 @@ i8250disable(Uart* uart)
 
 	ctlr = uart->regs;
 	ctlr->sticky[Ier] = 0;
-	csr8w(ctlr, Ier, ctlr->sticky[Ier]);
-	coherence();
+	csr8w(ctlr, Ier, 0);
 
 	if(ctlr->iena != 0){
 		if(irqdisable(ctlr->irq, i8250interrupt, uart, uart->name) == 0)
@@ -593,10 +613,21 @@ i8250disable(Uart* uart)
 static void
 i8250enable(Uart* uart, int ie)
 {
+	int mode;
 	Ctlr *ctlr;
 
+	if (up == nil)
+		return;				/* too soon */
+
 	ctlr = uart->regs;
 
+	/* omap only: set uart/irda/cir mode to uart */
+	mode = csr8r(ctlr, Mdr);
+	csr8o(ctlr, Mdr, (mode & ~Modemask) | Modeuart);
+
+	ctlr->sticky[Lcr] = Wls8;		/* no parity */
+	csr8w(ctlr, Lcr, 0);
+
 	/*
 	 * Check if there is a FIFO.
 	 * Changing the FIFOena bit in Fcr flushes data
@@ -619,7 +650,6 @@ i8250enable(Uart* uart, int ie)
 		if(csr8r(ctlr, Iir) & Ifena)
 			ctlr->hasfifo = 1;
 		csr8w(ctlr, Fcr, 0);
-		coherence();
 		ctlr->checkfifo = 1;
 	}
 	iunlock(ctlr);
@@ -635,16 +665,17 @@ i8250enable(Uart* uart, int ie)
 			irqenable(ctlr->irq, i8250interrupt, uart, uart->name);
 			ctlr->iena = 1;
 		}
-		ctlr->sticky[Ier] = Ethre|Erda;
-		ctlr->sticky[Mcr] |= Ie;
+//		ctlr->sticky[Ier] = Ethre|Erda;		/* tx intr broken */
+		ctlr->sticky[Ier] = Erda;
+//		ctlr->sticky[Mcr] |= Ie;		/* not on omap */
+		ctlr->sticky[Mcr] = 0;
 	}
 	else{
 		ctlr->sticky[Ier] = 0;
 		ctlr->sticky[Mcr] = 0;
 	}
-	csr8w(ctlr, Ier, ctlr->sticky[Ier]);
-	csr8w(ctlr, Mcr, ctlr->sticky[Mcr]);
-	coherence();
+	csr8w(ctlr, Ier, 0);
+	csr8w(ctlr, Mcr, 0);
 
 	(*uart->phys->dtr)(uart, 1);
 	(*uart->phys->rts)(uart, 1);
@@ -684,7 +715,7 @@ i8250putc(Uart* uart, int c)
 	int i;
 	Ctlr *ctlr;
 
-	if (!normalprint) {	/* too early; use brute force */
+	if (!normalprint) {		/* too early; use brute force */
 		int s = splhi();
 
 		while (!(((ulong *)PHYSCONS)[Lsr] & Thre))
@@ -698,8 +729,7 @@ i8250putc(Uart* uart, int c)
 	ctlr = uart->regs;
 	for(i = 0; !(csr8r(ctlr, Lsr) & Thre) && i < 128; i++)
 		delay(1);
-	csr8o(ctlr, Thr, c);
-	coherence();
+	csr8o(ctlr, Thr, (uchar)c);
 	for(i = 0; !(csr8r(ctlr, Lsr) & Thre) && i < 128; i++)
 		delay(1);
 }
@@ -716,6 +746,7 @@ serialputs(char* s, int n)
 	_uartputs(s, n);
 }
 
+#ifdef notdef
 static void
 i8250poll(Uart* uart)
 {
@@ -736,6 +767,7 @@ i8250poll(Uart* uart)
 		return;
 	i8250interrupt(nil, uart);
 }
+#endif
 
 PhysUart i8250physuart = {
 	.name		= "i8250",
@@ -755,7 +787,7 @@ PhysUart i8250physuart = {
 	.fifo		= i8250fifo,
 	.getc		= i8250getc,
 	.putc		= i8250putc,
-//	.poll		= i8250poll,
+//	.poll		= i8250poll,		/* only in 9k, not 9 */
 };
 
 static void
@@ -765,24 +797,34 @@ i8250dumpregs(Ctlr* ctlr)
 	int _uartprint(char*, ...);
 
 	csr8w(ctlr, Lcr, Dlab);
-	coherence();
 	dlm = csr8r(ctlr, Dlm);
 	dll = csr8r(ctlr, Dll);
 	csr8w(ctlr, Lcr, 0);
-	coherence();
 
 	_uartprint("dlm %#ux dll %#ux\n", dlm, dll);
 }
 
-void
+Uart*	uartenable(Uart *p);
+
+/* must call this from a process's context */
+int
 i8250console(void)
 {
 	Uart *uart = &i8250uart[CONSOLE];
 
-//	(*uart->phys->enable)(uart, 0);
-//	uartctl(uart, "b115200 l8 pn s1 i1");
-//	uart->console = 1;
-	consuart = uart;
+	if (up == nil)
+		return -1;			/* too early */
+
+	if(uartenable(uart) != nil /* && uart->console */){
+iprint("i8250console: enabling console uart\n");
+		kbdq = uart->iq;
+		serialoq = uart->oq;
+		uart->putc = kbdcr2nl;
+		uart->opens++;
+		consuart = uart;
+	}
+	uartctl(uart, "b115200 l8 pn r1 s1 i1");
+	return 0;
 }
 
 void

+ 18 - 13
sys/src/9/omap/words

@@ -46,20 +46,19 @@ l4 interconnect firewalls seem to be sane at boot time
 ___
 The state of the Beagleboard/IGEPv2 (TI OMAP35 SoC, Cortex-A8) port.
 
-Plan 9 runs on the IGEPv2 board.
+Plan 9 runs on the IGEPv2 and Gumstix Overo boards.
 
 On the Beagleboard, Plan 9 is not yet usable but it gets as far as
 trying to access the USB ethernet (since the Beagleboard has no
 built-in ethernet and must use USB ethernet).
 
-IGEP Ethernet
+IGEP & Gumstix Ethernet
 
-The igep's smsc9221 ethernet consumes a lot of system time.  The
-design decision to use fifos rather than buffer rings and to not
-incorporate dma into the ethernet controller is probably responsible.
-With only a single core, running the 9221 consumes a lot of the
-available CPU time.  It's probably worth trying to use the system dma
-controller again.
+The smsc9221 ethernet consumes a lot of system time.  The design
+decision to use fifos rather than buffer rings and to not incorporate
+dma into the ethernet controller is probably responsible.  With only a
+single core, running the 9221 consumes a lot of the available CPU
+time.  It's probably worth trying to use the system dma controller again.
 
 USB
 
@@ -93,8 +92,15 @@ than 5c/5l currently generate.  New 5c or 5l is in the works.
 
 Video
 
-The video controller may be documented and source is available for a
-Linux driver.
+The display subsystem for omap3 (dss) is divided into 3 parts, called lcd,
+video and dsi (ignoring the various accelerators).  The system only
+supports the lcd via dvi interface so far because it's the only one we
+have been able to test.  1280x1024x16 is the default resolution, this
+might be changed.  Writing to /dev/dssctl (e.g., echo 1024x768x16
+>/dev/dssctl) changes the resolution.  Currently the system does not
+use the rfbi since it seems like an unnecessary optimisation at this
+point.  Per Odlund wrote the first draft of the video driver for a
+Google Summer of Code project.
 ___
 
 The code is fairly heavy-handed with the use of barrier instructions
@@ -112,9 +118,8 @@ There are a few rough edges:
 timers are complex, but one could eventually do better (or just let
 timesync compensate).
 
-- Serial console printing is rudimentary.  I tried repeatedly to hook
-into devuart, but failed.  "g 'CRUDEPRINT|LASTRESORT' ." should find
-the workarounds.
+- Serial console printing is rudimentary and polled.  It looks like
+we're not getting uart transmit interrupts or something similar.
 
 - User processes are limited to 512MB (mainly by the IGEPv2 Ethernet
 being at 0x2c000000), which isn't a problem since Beagleboards only

+ 2 - 2
sys/src/9/port/xalloc.c

@@ -93,7 +93,7 @@ xspanalloc(ulong size, int align, ulong span)
 	ulong a, v, t;
 	a = (ulong)xalloc(size+align+span);
 	if(a == 0)
-		panic("xspanalloc: %lud %d %lux\n", size, align, span);
+		panic("xspanalloc: %lud %d %lux", size, align, span);
 
 	if(span > 2) {
 		v = (a + span) & ~(span-1);
@@ -189,7 +189,7 @@ xmerge(void *vp, void *vq)
 			print("\n");
 			wd++;
 		}
-		panic("xmerge(%#p, %#p) bad magic %#lux, %#lux\n",
+		panic("xmerge(%#p, %#p) bad magic %#lux, %#lux",
 			vp, vq, p->magix, q->magix);
 	}
 	if((uchar*)p+p->size == (uchar*)q) {