diff options
-rw-r--r-- | sys/src/9/sgi/dat.h | 1 | ||||
-rw-r--r-- | sys/src/9/sgi/devkbd.c | 339 | ||||
-rw-r--r-- | sys/src/9/sgi/indy | 1 | ||||
-rw-r--r-- | sys/src/9/sgi/io.h | 9 | ||||
-rw-r--r-- | sys/src/9/sgi/main.c | 17 | ||||
-rw-r--r-- | sys/src/9/sgi/screen.c | 111 | ||||
-rw-r--r-- | sys/src/9/sgi/uartarcs.c | 1 |
7 files changed, 468 insertions, 11 deletions
diff --git a/sys/src/9/sgi/dat.h b/sys/src/9/sgi/dat.h index 49cb2f8d9..b0e47a6cb 100644 --- a/sys/src/9/sgi/dat.h +++ b/sys/src/9/sgi/dat.h @@ -67,6 +67,7 @@ struct Conf ulong pipeqsize; /* size in bytes of pipe queues */ int nuart; /* number of uart devices */ int monitor; + int keyboard; }; /* diff --git a/sys/src/9/sgi/devkbd.c b/sys/src/9/sgi/devkbd.c new file mode 100644 index 000000000..01e52d399 --- /dev/null +++ b/sys/src/9/sgi/devkbd.c @@ -0,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, +}; diff --git a/sys/src/9/sgi/indy b/sys/src/9/sgi/indy index 817133b62..e36162253 100644 --- a/sys/src/9/sgi/indy +++ b/sys/src/9/sgi/indy @@ -18,6 +18,7 @@ dev # sd draw screen mouse + kbd link etherseeq diff --git a/sys/src/9/sgi/io.h b/sys/src/9/sgi/io.h index 54331e3c7..4a86c4277 100644 --- a/sys/src/9/sgi/io.h +++ b/sys/src/9/sgi/io.h @@ -40,10 +40,15 @@ enum { #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 */ diff --git a/sys/src/9/sgi/main.c b/sys/src/9/sgi/main.c index d58763a2b..086ab4fb2 100644 --- a/sys/src/9/sgi/main.c +++ b/sys/src/9/sgi/main.c @@ -154,6 +154,13 @@ meminit(void) } } +static int +havegfx(void) +{ + char *s = getconf("ConsoleOut"); + return s != nil && strstr(s, "video()") != nil; +} + void main(void) { @@ -173,7 +180,10 @@ main(void) timersinit(); fmtinit(); - screeninit(); + if(havegfx()){ + conf.monitor = 1; + screeninit(); + } ckpagemask(PGSZ, BY2PG); tlbinit(); @@ -252,8 +262,6 @@ init0(void) 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 @@ init0(void) } /* process input for arcs console */ - kproc("arcs", arcsproc, 0); + if(!conf.keyboard) + kproc("arcs", arcsproc, 0); kproc("alarm", alarmkproc, 0); touser(sp); diff --git a/sys/src/9/sgi/screen.c b/sys/src/9/sgi/screen.c index f8567869e..1c059a0f5 100644 --- a/sys/src/9/sgi/screen.c +++ b/sys/src/9/sgi/screen.c @@ -446,20 +446,90 @@ Cursor arrow = { 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 @@ setmode(void) 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 @@ screeninit(void) 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* @@ -566,3 +637,35 @@ 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)); + } +} diff --git a/sys/src/9/sgi/uartarcs.c b/sys/src/9/sgi/uartarcs.c index 128aa6a32..461b5e5e7 100644 --- a/sys/src/9/sgi/uartarcs.c +++ b/sys/src/9/sgi/uartarcs.c @@ -56,7 +56,6 @@ arcsproc(void*) while(waserror()) ; for(;;){ - //sched(); tsleep(&up->sleep, return0, nil, 50); c = arcsgetc(); if(c < 0) |