sgi: keyboard, mouse and cursor for indy
This commit is contained in:
parent
d9af840ca2
commit
022856f94e
7 changed files with 468 additions and 11 deletions
|
@ -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
339
sys/src/9/sgi/devkbd.c
Normal 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,
|
||||
};
|
|
@ -18,6 +18,7 @@ dev
|
|||
# sd
|
||||
draw screen
|
||||
mouse
|
||||
kbd
|
||||
|
||||
link
|
||||
etherseeq
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -56,7 +56,6 @@ arcsproc(void*)
|
|||
while(waserror())
|
||||
;
|
||||
for(;;){
|
||||
//sched();
|
||||
tsleep(&up->sleep, return0, nil, 50);
|
||||
c = arcsgetc();
|
||||
if(c < 0)
|
||||
|
|
Loading…
Reference in a new issue