sgi: keyboard, mouse and cursor for indy

This commit is contained in:
cinap_lenrek 2015-04-02 18:35:43 +02:00
parent d9af840ca2
commit 022856f94e
7 changed files with 468 additions and 11 deletions

View file

@ -67,6 +67,7 @@ struct Conf
ulong pipeqsize; /* size in bytes of pipe queues */
int nuart; /* number of uart devices */
int monitor;
int keyboard;
};
/*

339
sys/src/9/sgi/devkbd.c Normal file
View file

@ -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,
};

View file

@ -18,6 +18,7 @@ dev
# sd
draw screen
mouse
kbd
link
etherseeq

View file

@ -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 */

View file

@ -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);

View file

@ -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));
}
}

View file

@ -56,7 +56,6 @@ arcsproc(void*)
while(waserror())
;
for(;;){
//sched();
tsleep(&up->sleep, return0, nil, 50);
c = arcsgetc();
if(c < 0)