shithub: riscv

Download patch

ref: 022856f94e7a0298660139e294752d5d2646e604
parent: d9af840ca248f27e6b9d2a135e537c41b3578d52
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Thu Apr 2 14:35:43 EDT 2015

sgi: keyboard, mouse and cursor for indy

--- a/sys/src/9/sgi/dat.h
+++ b/sys/src/9/sgi/dat.h
@@ -67,6 +67,7 @@
 	ulong	pipeqsize;	/* size in bytes of pipe queues */
 	int	nuart;		/* number of uart devices */
 	int	monitor;
+	int	keyboard;
 };
 
 /*
--- /dev/null
+++ b/sys/src/9/sgi/devkbd.c
@@ -1,0 +1,339 @@
+/*
+ * keyboard input
+ */
+#include	"u.h"
+#include	"../port/lib.h"
+#include	"mem.h"
+#include	"dat.h"
+#include	"fns.h"
+#include	"io.h"
+#include	"../port/error.h"
+
+enum {
+	Data=		0x40+3,		/* data port */
+	Cmd=		0x44+3,		/* command port (write) */
+	Status=		0x44+3,		/* status port (read) */
+	 Inready=	0x01,		/*  input character ready */
+	 Outbusy=	0x02,		/*  output busy */
+	 Sysflag=	0x04,		/*  system flag */
+	 Cmddata=	0x08,		/*  cmd==0, data==1 */
+	 Inhibit=	0x10,		/*  keyboard/mouse inhibited */
+	 Minready=	0x20,		/*  mouse character ready */
+	 Rtimeout=	0x40,		/*  general timeout */
+	 Parity=	0x80,
+};
+
+enum
+{
+	/* controller command byte */
+	Cscs1=		(1<<6),		/* scan code set 1 */
+	Cauxdis=	(1<<5),		/* mouse disable */
+	Ckbddis=	(1<<4),		/* kbd disable */
+	Csf=		(1<<2),		/* system flag */
+	Cauxint=	(1<<1),		/* mouse interrupt enable */
+	Ckbdint=	(1<<0),		/* kbd interrupt enable */
+};
+
+enum {
+	Qdir,
+	Qscancode,
+	Qleds,
+};
+
+static Dirtab kbdtab[] = {
+	".",		{Qdir, 0, QTDIR},	0,	0555,
+	"scancode",	{Qscancode, 0},		0,	0440,
+	"leds",		{Qleds, 0},		0,	0220,
+};
+
+static Lock i8042lock;
+static uchar ccc, dummy;
+
+static struct {
+	Ref ref;
+	Queue *q;
+	uchar *io;
+} kbd;
+
+
+#define	inb(r)		(dummy=kbd.io[r])
+#define	outb(r,b)	(kbd.io[r]=b)
+
+/*
+ *  wait for output no longer busy
+ */
+static int
+outready(void)
+{
+	int tries;
+
+	for(tries = 0; (inb(Status) & Outbusy); tries++){
+		if(tries > 500)
+			return -1;
+		delay(2);
+	}
+	return 0;
+}
+
+/*
+ *  wait for input
+ */
+static int
+inready(void)
+{
+	int tries;
+
+	for(tries = 0; !(inb(Status) & Inready); tries++){
+		if(tries > 500)
+			return -1;
+		delay(2);
+	}
+	return 0;
+}
+
+/*
+ * set keyboard's leds for lock states (scroll, numeric, caps).
+ *
+ * at least one keyboard (from Qtronics) also sets its numeric-lock
+ * behaviour to match the led state, though it has no numeric keypad,
+ * and some BIOSes bring the system up with numeric-lock set and no
+ * setting to change that.  this combination steals the keys for these
+ * characters and makes it impossible to generate them: uiolkjm&*().
+ * thus we'd like to be able to force the numeric-lock led (and behaviour) off.
+ */
+static void
+setleds(int leds)
+{
+	static int old = -1;
+
+	if(!conf.keyboard || leds == old)
+		return;
+	leds &= 7;
+	ilock(&i8042lock);
+	for(;;){
+		if(outready() < 0)
+			break;
+		outb(Data, 0xed);		/* `reset keyboard lock states' */
+		if(outready() < 0)
+			break;
+		outb(Data, leds);
+		if(outready() < 0)
+			break;
+		old = leds;
+		break;
+	}
+	iunlock(&i8042lock);
+}
+
+/*
+ *  keyboard interrupt
+ */
+static void
+i8042intr(Ureg*, void*)
+{
+	extern void sgimouseputc(int);
+
+	int s, c;
+	uchar b;
+
+	/*
+	 *  get status
+	 */
+	ilock(&i8042lock);
+	s = inb(Status);
+	if(!(s&Inready)){
+		iunlock(&i8042lock);
+		return;
+	}
+
+	/*
+	 *  get the character
+	 */
+	c = inb(Data);
+	iunlock(&i8042lock);
+
+	b = c & 0xff;
+
+	/*
+	 *  if it's the aux port...
+	 */
+	if(s & Minready){
+		sgimouseputc(b);
+		return;
+	}
+
+	qproduce(kbd.q, &b, 1);
+}
+
+static void
+pollintr(void)
+{
+	i8042intr(nil, nil);
+}
+
+static Chan *
+kbdattach(char *spec)
+{
+	return devattach(L'b', spec);
+}
+
+static Walkqid*
+kbdwalk(Chan *c, Chan *nc, char **name, int nname)
+{
+	return devwalk(c, nc, name, nname, kbdtab, nelem(kbdtab), devgen);
+}
+
+static int
+kbdstat(Chan *c, uchar *dp, int n)
+{
+	return devstat(c, dp, n, kbdtab, nelem(kbdtab), devgen);
+}
+
+static Chan*
+kbdopen(Chan *c, int omode)
+{
+	if(!iseve())
+		error(Eperm);
+	if(c->qid.path == Qscancode){
+		if(waserror()){
+			decref(&kbd.ref);
+			nexterror();
+		}
+		if(incref(&kbd.ref) != 1)
+			error(Einuse);
+		c = devopen(c, omode, kbdtab, nelem(kbdtab), devgen);
+		poperror();
+		return c;
+	}
+	return devopen(c, omode, kbdtab, nelem(kbdtab), devgen);
+}
+
+static void
+kbdclose(Chan *c)
+{
+	if((c->flag & COPEN) && c->qid.path == Qscancode)
+		decref(&kbd.ref);
+}
+
+static Block*
+kbdbread(Chan *c, long n, ulong off)
+{
+	if(c->qid.path == Qscancode)
+		return qbread(kbd.q, n);
+	else
+		return devbread(c, n, off);
+}
+
+static long
+kbdread(Chan *c, void *a, long n, vlong)
+{
+	if(c->qid.path == Qscancode)
+		return qread(kbd.q, a, n);
+	if(c->qid.path == Qdir)
+		return devdirread(c, a, n, kbdtab, nelem(kbdtab), devgen);
+
+	error(Egreg);
+	return 0;
+}
+
+static long
+kbdwrite(Chan *c, void *a, long n, vlong)
+{
+	char tmp[8+1], *p;
+
+	if(c->qid.path != Qleds)
+		error(Egreg);
+
+	p = tmp + n;
+	if(n >= sizeof(tmp))
+		p = tmp + sizeof(tmp)-1;
+	memmove(tmp, a, p - tmp);
+	*p = 0;
+
+	setleds(atoi(tmp));
+
+	return n;
+}
+
+
+static char *initfailed = "i8042: kbdinit failed\n";
+
+static int
+outbyte(int port, int c)
+{
+	outb(port, c);
+	if(outready() < 0) {
+		print(initfailed);
+		return -1;
+	}
+	return 0;
+}
+
+static void
+kbdinit(void)
+{
+	int c, try;
+
+	kbd.io = IO(uchar, HPC3_KBDMS);
+	kbd.q = qopen(1024, Qcoalesce, 0, 0);
+	if(kbd.q == nil)
+		panic("kbdinit: qopen");
+	qnoblock(kbd.q, 1);
+
+	/* wait for a quiescent controller */
+	try = 1000;
+	while(try-- > 0 && (c = inb(Status)) & (Outbusy | Inready)) {
+		if(c & Inready)
+			inb(Data);
+		delay(1);
+	}
+	if (try <= 0) {
+		print(initfailed);
+		return;
+	}
+
+	/* get current controller command byte */
+	outb(Cmd, 0x20);
+	if(inready() < 0){
+		print("i8042: kbdinit can't read ccc\n");
+		ccc = 0;
+	} else
+		ccc = inb(Data);
+
+	/* enable kbd xfers and interrupts */
+	ccc &= ~Ckbddis;
+	ccc |= Csf | Ckbdint | Cscs1;
+	if(outready() < 0) {
+		print(initfailed);
+		return;
+	}
+	/* disable mouse */
+	if (outbyte(Cmd, 0x60) < 0 || outbyte(Data, ccc) < 0){
+		print("i8042: kbdinit mouse disable failed\n");
+		return;
+	}
+
+	conf.keyboard = 1;
+	addclock0link(pollintr, 5);
+}
+
+Dev kbddevtab = {
+	L'b',
+	"kbd",
+
+	devreset,
+	kbdinit,
+	devshutdown,
+	kbdattach,
+	kbdwalk,
+	kbdstat,
+	kbdopen,
+	devcreate,
+	kbdclose,
+	kbdread,
+	kbdbread,
+	kbdwrite,
+	devbwrite,
+	devremove,
+	devwstat,
+};
--- a/sys/src/9/sgi/indy
+++ b/sys/src/9/sgi/indy
@@ -18,6 +18,7 @@
 #	sd
 	draw screen
 	mouse
+	kbd
 	
 link
 	etherseeq
--- a/sys/src/9/sgi/io.h
+++ b/sys/src/9/sgi/io.h
@@ -40,10 +40,15 @@
 
 #define	LIO_0_ISR	(INT2_BASE+0x3)
 #define	LIO_0_MASK	(INT2_BASE+0x7)
+#define	LIO_1_ISR	(INT2_BASE+0xb)
+#define	LIO_1_MASK	(INT2_BASE+0xf)
+#define	LIO_2_ISR	(INT2_BASE+0x13)
+#define	LIO_2_MASK	(INT2_BASE+0x17)
 
-#define HPC3_ETHER	0x1fb80000
+#define	HPC3_ETHER	0x1fb80000
+#define	HPC3_KBDMS	0x1fbd9800
+#define	GIO_NEWPORT	0x1f0f0000	/* indy */
 
 #define	MEMCFG0		0x1fa000c4	/* mem. size config. reg. 0 (w, rw) */
 #define	MEMCFG1		0x1fa000cc	/* mem. size config. reg. 1 (w, rw) */
 
-#define GIO_NEWPORT	0x1f0f0000	/* indy */
--- a/sys/src/9/sgi/main.c
+++ b/sys/src/9/sgi/main.c
@@ -154,6 +154,13 @@
 	}
 }
 
+static int
+havegfx(void)
+{
+	char *s = getconf("ConsoleOut");
+	return s != nil && strstr(s, "video()") != nil;
+}
+
 void
 main(void)
 {
@@ -173,7 +180,10 @@
 	timersinit();
 	fmtinit();
 
-	screeninit();
+	if(havegfx()){
+		conf.monitor = 1;
+		screeninit();
+	}
 
 	ckpagemask(PGSZ, BY2PG);
 	tlbinit();
@@ -252,8 +262,6 @@
 			ksetenv("service", "terminal", 0);
 
 		ksetenv("bootargs", "tcp", 0);
-
-		/* make kbdfs attach to /dev/eia0 arcs console */ 
 		ksetenv("console", "0", 0);
 
 		/* no usb */
@@ -264,7 +272,8 @@
 	}
 
 	/* process input for arcs console */
-	kproc("arcs", arcsproc, 0);
+	if(!conf.keyboard)
+		kproc("arcs", arcsproc, 0);
 
 	kproc("alarm", alarmkproc, 0);
 	touser(sp);
--- a/sys/src/9/sgi/screen.c
+++ b/sys/src/9/sgi/screen.c
@@ -446,21 +446,91 @@
 
 Memimage *gscreen;
 
+static void 
+vc2set(uchar r, ushort val)
+{
+	regs->dcbmode = NPORT_DMODE_AVC2 | VC2_REGADDR_INDEX |
+		NPORT_DMODE_W3 | NPORT_DMODE_ECINC | VC2_PROTOCOL;
+	regs->dcbdata0 = r << 24 | val << 8;
+}
+
+static ushort
+vc2get(uchar r)
+{
+	regs->dcbmode = NPORT_DMODE_AVC2 | VC2_REGADDR_INDEX |
+		NPORT_DMODE_W1 | NPORT_DMODE_ECINC | VC2_PROTOCOL;
+	regs->dcbdata0 = r << 24;
+	regs->dcbmode = NPORT_DMODE_AVC2 | VC2_REGADDR_IREG |
+		NPORT_DMODE_W2 | NPORT_DMODE_ECINC | VC2_PROTOCOL;
+	return regs->dcbdata0 >> 16;
+}
+
+static Point curoff;
+
 void
 cursoron(void)
 {
+	Point xy;
+	int s;
+
+	xy = addpt(mousexy(), curoff);
+
+	s = splhi();
+	vc2set(VC2_IREG_CURSX, xy.x);
+	vc2set(VC2_IREG_CURSY, xy.y);
+	vc2set(VC2_IREG_CONTROL, vc2get(VC2_IREG_CONTROL) | VC2_CTRL_ECDISP);
+	splx(s);
 }
 
 void
 cursoroff(void)
 {
+	int s;
+
+	s = splhi();
+	vc2set(VC2_IREG_CONTROL, vc2get(VC2_IREG_CONTROL) & ~VC2_CTRL_ECDISP);
+	splx(s);
 }
 
 void
-setcursor(Cursor*)
+setcursor(Cursor *curs)
 {
-}
+	static uchar mem[(2*32*32)/8];
+	uchar *set, *clr;
+	int i, s;
 
+	memset(mem, 0, sizeof(mem));
+
+	/*
+	 * convert to two 32x32 bitmaps
+	 */
+	set = mem;
+	clr = mem + (32*32)/8;
+	for(i=0;i<32;i++) {
+		*set++ = curs->set[i];
+		*clr++ = curs->clr[i];
+		if(i & 1){
+			set += 2;
+			clr += 2;
+		}
+	}
+	curoff = addpt(Pt(30,30), curs->offset);
+
+	/*
+	 * upload two bytes at a time
+	 */
+	s = splhi();
+	vc2set(VC2_IREG_RADDR, vc2get(VC2_IREG_CENTRY));
+	regs->dcbmode = NPORT_DMODE_AVC2 | VC2_REGADDR_RAM |
+		NPORT_DMODE_W2 | VC2_PROTOCOL;
+	for(i = 0; i < sizeof(mem); i += 2){
+		while(regs->stat & NPORT_STAT_BBUSY)
+			;
+		regs->dcbdata0 = *(ushort*)(&mem[i]) << 16;
+	}
+	splx(s);
+}	
+
 static void
 setmode(void)
 {
@@ -486,6 +556,8 @@
 	regs->drawmode1 = DM1_RGBPLANES | 
 		NPORT_DMODE1_CCLT | NPORT_DMODE1_CCEQ | NPORT_DMODE1_CCGT | NPORT_DMODE1_LOSRC |
 		NPORT_DMODE1_DD24 | NPORT_DMODE1_RGBMD | NPORT_DMODE1_HD32 | NPORT_DMODE1_RWPCKD;
+
+	setcursor(&arrow);
 }
 
 void
@@ -526,13 +598,12 @@
 	enum {
 		RGBX32 = CHAN4(CRed, 8, CGreen, 8, CBlue, 8, CIgnore, 8),
 	};
-
-	conf.monitor = 1;
 	memimageinit();
 	gscreen = allocmemimage(Rect(0,0,1280,1024), RGBX32);
 	if(gscreen == nil)
 		panic("screeninit: gscreen == nil");
 	memfillcolor(gscreen, 0xFFFFFFFF);
+	mouseaccelerate(3);
 }
 
 uchar*
@@ -565,4 +636,36 @@
 void
 mousectl(Cmdbuf *)
 {
+}
+
+/*
+ * sgi mouse protocol
+ *	byte 0 -	Y0 X0 Y7 X7  F  M  R  L
+ *	byte 1 -	X7 X6 X5 X4 X3 X2 X1 X0
+ *	byte 2 -	Y7 Y6 Y5 Y4 Y3 Y2 Y1 Y0
+ */
+void
+sgimouseputc(int c)
+{
+	static uchar msg[3];
+	static int nb;
+	int dx, dy, newbuttons;
+	static uchar b[] = { 0, 1, 4, 5, 2, 3, 6, 7 };
+	static ulong lasttick;
+	ulong m;
+
+	/* Resynchronize in stream with timing. */
+	m = MACHP(0)->ticks;
+	if(TK2SEC(m - lasttick) > 2)
+		nb = 0;
+	lasttick = m;
+
+	msg[nb] = c;
+	if(++nb == 3){
+		nb = 0;
+		newbuttons = b[msg[0]&7];
+		dx = (char)msg[1];
+		dy = -(char)msg[2];
+		mousetrack(dx, dy, newbuttons, TK2MS(MACHP(0)->ticks));
+	}
 }
--- a/sys/src/9/sgi/uartarcs.c
+++ b/sys/src/9/sgi/uartarcs.c
@@ -56,7 +56,6 @@
 	while(waserror())
 		;
 	for(;;){
-		//sched();
 		tsleep(&up->sleep, return0, nil, 50);
 		c = arcsgetc();
 		if(c < 0)