#include "u.h"#include "../port/lib.h"#include "mem.h"#include "dat.h"#include "fns.h"#include "io.h"#include "../port/error.h" /* * TODO * - shift key should modify right button with non-serial mice * + intellimouse implementation * - acceleration for all mouse types * + spurious interrupt 7 after probing for ps2 mouse for the first time...? * - test with ms busmouse * - test with logitech serial mouse */ /* * mouse types */enum{ Mouseother, Mouseserial, MousePS2, Mousebus, Mouseintelli, Mousemsbus,}; static int mousetype;static int mouseswap;static int mouseport; /* port for serial mice, irq for bus mice */static int mousesubtype;static int accelerated;static QLock mouselock; static int msbusmousedetect(void);static int busmousedetect(void);static void mousectl(char *buf);static void mouseprobe(char *buf, int len);static void mousestatus(char *buf, int len); enum{ Qdir, Qmousectl, Qmouseprobe,}; staticDirtab mousetab[]={ "mousectl", {Qmousectl, 0}, 0, 0600, "mouseprobe", {Qmouseprobe, 0}, 0, 0400,}; static Chan*mouseattach(char* spec){ return devattach('m', spec);} static intmousewalk(Chan* c, char* name){ return devwalk(c, name, mousetab, nelem(mousetab), devgen);} static voidmousestat(Chan* c, char* db){ devstat(c, db, mousetab, nelem(mousetab), devgen);} static Chan*mouseopen(Chan* c, int omode){ return devopen(c, omode, mousetab, nelem(mousetab), devgen);} static voidmouseclose(Chan* c){ USED(c);} static longmouseread(Chan* c, void* a, long n, vlong offset){ char buf[64]; USED(offset); switch(c->qid.path & ~CHDIR){ case Qdir: return devdirread(c, a, n, mousetab, nelem(mousetab), devgen); case Qmousectl: qlock(&mouselock); mousestatus(buf, sizeof(buf)); qunlock(&mouselock); n = readstr(offset, a, n, buf); break; case Qmouseprobe: if (mousetype) error(Emouseset); mouseprobe(buf, sizeof(buf)); n = readstr(offset, a, n, buf); break; default: n=0; break; } return n;} static longmousewrite(Chan* c, void *a, long n, vlong){ char buf[64]; if ((c->qid.path & ~CHDIR) != Qmousectl) error(Ebadusefd); if (n >= sizeof(buf)) n = sizeof(buf) - 1; strncpy(buf, a, n); buf[n] = 0; qlock(&mouselock); if (waserror()) { qunlock(&mouselock); nexterror(); } mousectl(buf); poperror(); qunlock(&mouselock); return n;} static voidtrack(int b, int dx, int dy){ static uchar map[8] = {0,4,2,6,1,5,3,7}; if (mouseswap) b = map[b&7]; mousetrack(b, dx, dy);} static voidsetintellimouse(void){ i8042auxcmd(0xF3); /* set sample */ i8042auxcmd(0xC8); i8042auxcmd(0xF3); /* set sample */ i8042auxcmd(0x64); i8042auxcmd(0xF3); /* set sample */ i8042auxcmd(0x50);} /* * check for an Intellimouse. * this is only used when we know there's an 8042 aux device */static intintellimousedetect(void){ int id; setintellimouse(); /* check whether the mouse is now in extended mode */ id = i8042auxcmdval(0xf2); /* identify device */ if (id != 3) { /* * set back to standard sample rate (100 per sec) */ i8042auxcmd(0xf3); i8042auxcmd(0x64); return 0; } return 1;} static voidmouseprobe(char *buf, int len){ USED(len); /* * bus mice are easiest, so probe them first */ if (busmousedetect()) sprint(buf, "bus\n"); else if (msbusmousedetect()) sprint(buf, "msbus\n"); else if (i8042auxdetect()) { if (intellimousedetect()) sprint(buf, "ps2intellimouse\n"); else sprint(buf, "ps2\n"); } else *buf = 0;} static voidmousestatus(char *buf, int len){ char *s; USED(len); s = buf; switch (mousetype) { case Mouseserial: if (mousesubtype) s += sprint(s, "serial %d %c\n", mouseport, mousesubtype); else s += sprint(s, "serial %d\n", mouseport); break; case MousePS2: s += sprint(s, "ps2\n"); break; case Mousebus: s += sprint(s, "bus %d\n", mouseport); break; case Mouseintelli: s += sprint(s, "intelli\n"); break; case Mousemsbus: s += sprint(s, "msbus %d\n", mouseport); break; default: case Mouseother: s += sprint(s, "unknown\n"); break; } if (accelerated) s += sprint(s, "accelerated\n"); if (mouseswap) sprint(s, "swap\n");} /* * Logitech 5 byte packed binary mouse format, 8 bit bytes * * shift & right button is the same as middle button (for 2 button mice) */static intlogitechmouseputc(Queue *q, int c){ static short msg[5]; static int nb; static uchar b[] = {0, 4, 2, 6, 1, 5, 3, 7, 0, 2, 2, 6, 1, 5, 3, 7}; int dx, dy, newbuttons; int mouseshifted; USED(q); if((c&0xF0) == 0x80) nb=0; msg[nb] = c; if(c & 0x80) msg[nb] |= ~0xFF; /* sign extend */ if(++nb == 5){ mouseshifted = 0; /* XXX should be from keyboard shift key */ newbuttons = b[((msg[0]&7)^7) | (mouseshifted ? 8 : 0)]; dx = msg[1]+msg[3]; dy = -(msg[2]+msg[4]); track(newbuttons, dx, dy); nb = 0; } return 0;} /* * microsoft 3 button, 7 bit bytes * * byte 0 - 1 L R Y7 Y6 X7 X6 * byte 1 - 0 X5 X4 X3 X2 X1 X0 * byte 2 - 0 Y5 Y4 Y3 Y2 Y1 Y0 * byte 3 - 0 M x x x x x (optional) * * shift & right button is the same as middle button (for 2 button mice) */static intm3mouseputc(Queue*, int c){ static uchar msg[3]; static int nb; static int middle; static uchar b[] = { 0, 4, 1, 5, 0, 2, 1, 5 }; short x; int dx, dy, buttons; /* * check bit 6 for consistency */ if(nb==0){ if((c&0x40) == 0){ /* an extra byte gets sent for the middle button */ if(c & 0x1c) return 0; middle = (c&0x20) ? 2 : 0; buttons = (mouse.b & ~2) | middle; track(buttons, 0, 0); return 0; } } msg[nb] = c&0x3f; if(++nb == 3){ nb = 0; buttons = middle | b[(msg[0]>>4)&3]; x = (msg[0]&0x3)<<14; dx = (x>>8) | msg[1]; x = (msg[0]&0xc)<<12; dy = (x>>8) | msg[2]; track(buttons, dx, dy); } return 0;} static voidserialmouse(int port, char *type, int setspeed){ int (*putc)(Queue *, int) = 0; char pn[KNAMELEN]; if(mousetype) error(Emouseset); if(port >= 2 || port < 0) error(Ebadarg); if (type == 0) putc = logitechmouseputc; else if (*type == 'M') putc = m3mouseputc; else error(Ebadarg); snprint(pn, sizeof(pn), "%d", port); i8250mouse(pn, putc, setspeed); mousetype = Mouseserial; mouseport = port; mousesubtype = (type && *type == 'M') ? 'M' : 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 & left button is the same as middle button */static voidps2mouseputc(int c, int shift){ static short msg[3]; static int nb; static uchar b[] = {0, 1, 4, 5, 2, 3, 6, 7, 0, 1, 2, 5, 2, 3, 6, 7 }; int buttons, dx, dy; /* * check byte 0 for consistency */ if(nb==0 && (c&0xc8)!=0x08) return; msg[nb] = c; if(++nb == 3){ nb = 0; if(msg[0] & 0x10) msg[1] |= 0xFF00; if(msg[0] & 0x20) msg[2] |= 0xFF00; buttons = b[(msg[0]&7) | (shift ? 8 : 0)]; dx = msg[1]; dy = -msg[2]; track(buttons, dx, dy); } return;} /* * set up a ps2 mouse */static voidps2mouse(void){ if(mousetype) error(Emouseset); i8042auxenable(ps2mouseputc); /* make mouse streaming, enabled */ i8042auxcmd(0xEA); i8042auxcmd(0xF4); mousetype = MousePS2;} /* logitech bus mouse ports and commands */enum { /* ports */ BMdatap = 0x23c, BMsigp = 0x23d, BMctlp = 0x23e, BMintrp = 0x23e, BMconfigp = 0x23f, /* commands */ BMintron = 0x0, BMintroff = 0x10, BMrxlo = 0x80, BMrxhi = 0xa0, BMrylo = 0xc0, BMryhi = 0xe0, BMconfig = 0x91, BMdefault = 0x90, BMsigval = 0xa5}; static voidbusmouseintr(Ureg *, void *){ char dx, dy; uchar b; static uchar oldb; static Lock intrlock; ilock(&intrlock); outb(BMintrp, BMintroff); outb(BMctlp, BMrxlo); dx = inb(BMdatap) & 0xf; outb(BMctlp, BMrxhi); dx |= (inb(BMdatap) & 0xf) << 4; outb(BMctlp, BMrylo); dy = inb(BMdatap) & 0xf; outb(BMctlp, BMryhi); b = inb(BMdatap); dy |= (b & 0xf) << 4; b = ~(b >> 5) & 7; if (dx || dy || b != oldb) { oldb = b; track((b>>2)|(b&0x02)|((b&0x01)<<2), dx, dy); } iunlock(&intrlock); outb(BMintrp, BMintron);} static intbusmousedetect(void){ outb(BMconfigp, BMconfig); outb(BMsigp, BMsigval); delay(2); if (inb(BMsigp) != BMsigval) return 0; outb(BMconfigp, BMdefault); return 1;} /* * set up a logitech bus mouse */static voidbusmouse(int irq){ if (mousetype) error(Emouseset); if (!busmousedetect()) error(Enodev); intrenable(irq >= 0 ? irq+VectorPIC : VectorBUSMOUSE, busmouseintr, 0, BUSUNKNOWN); outb(BMintrp, BMintron); mousetype = Mousebus; mouseport = irq >= 0 ? irq : VectorBUSMOUSE-VectorPIC;} /* microsoft bus mouse ports and commands */enum { MBMdatap= 0x23d, MBMsigp= 0x23e, MBMctlp= 0x23c, MBMconfigp= 0x23f, MBMintron= 0x11, MBMintroff= 0x10, MBMrbuttons= 0x00, MBMrx= 0x01, MBMry= 0x02, MBMstart= 0x80, MBMcmd= 0x07,}; static voidmsbusmouseintr(Ureg *, void *){ char dx, dy; uchar b; static uchar oldb; static Lock intrlock; ilock(&intrlock); outb(MBMctlp, MBMcmd); outb(MBMdatap, inb(MBMdatap)|0x20);Lines 1–500 of 672. Load more
#include "u.h" #include "../port/lib.h" #include "mem.h" #include "dat.h" #include "fns.h" #include "io.h" #include "../port/error.h" /* * TODO * - shift key should modify right button with non-serial mice * + intellimouse implementation * - acceleration for all mouse types * + spurious interrupt 7 after probing for ps2 mouse for the first time...? * - test with ms busmouse * - test with logitech serial mouse */ /* * mouse types */ enum { Mouseother, Mouseserial, MousePS2, Mousebus, Mouseintelli, Mousemsbus, }; static int mousetype; static int mouseswap; static int mouseport; /* port for serial mice, irq for bus mice */ static int mousesubtype; static int accelerated; static QLock mouselock; static int msbusmousedetect(void); static int busmousedetect(void); static void mousectl(char *buf); static void mouseprobe(char *buf, int len); static void mousestatus(char *buf, int len); enum{ Qdir, Qmousectl, Qmouseprobe, }; static Dirtab mousetab[]={ "mousectl", {Qmousectl, 0}, 0, 0600, "mouseprobe", {Qmouseprobe, 0}, 0, 0400, }; static Chan* mouseattach(char* spec) { return devattach('m', spec); } static int mousewalk(Chan* c, char* name) { return devwalk(c, name, mousetab, nelem(mousetab), devgen); } static void mousestat(Chan* c, char* db) { devstat(c, db, mousetab, nelem(mousetab), devgen); } static Chan* mouseopen(Chan* c, int omode) { return devopen(c, omode, mousetab, nelem(mousetab), devgen); } static void mouseclose(Chan* c) { USED(c); } static long mouseread(Chan* c, void* a, long n, vlong offset) { char buf[64]; USED(offset); switch(c->qid.path & ~CHDIR){ case Qdir: return devdirread(c, a, n, mousetab, nelem(mousetab), devgen); case Qmousectl: qlock(&mouselock); mousestatus(buf, sizeof(buf)); qunlock(&mouselock); n = readstr(offset, a, n, buf); break; case Qmouseprobe: if (mousetype) error(Emouseset); mouseprobe(buf, sizeof(buf)); n = readstr(offset, a, n, buf); break; default: n=0; break; } return n; } static long mousewrite(Chan* c, void *a, long n, vlong) { char buf[64]; if ((c->qid.path & ~CHDIR) != Qmousectl) error(Ebadusefd); if (n >= sizeof(buf)) n = sizeof(buf) - 1; strncpy(buf, a, n); buf[n] = 0; qlock(&mouselock); if (waserror()) { qunlock(&mouselock); nexterror(); } mousectl(buf); poperror(); qunlock(&mouselock); return n; } static void track(int b, int dx, int dy) { static uchar map[8] = {0,4,2,6,1,5,3,7}; if (mouseswap) b = map[b&7]; mousetrack(b, dx, dy); } static void setintellimouse(void) { i8042auxcmd(0xF3); /* set sample */ i8042auxcmd(0xC8); i8042auxcmd(0xF3); /* set sample */ i8042auxcmd(0x64); i8042auxcmd(0xF3); /* set sample */ i8042auxcmd(0x50); } /* * check for an Intellimouse. * this is only used when we know there's an 8042 aux device */ static int intellimousedetect(void) { int id; setintellimouse(); /* check whether the mouse is now in extended mode */ id = i8042auxcmdval(0xf2); /* identify device */ if (id != 3) { /* * set back to standard sample rate (100 per sec) */ i8042auxcmd(0xf3); i8042auxcmd(0x64); return 0; } return 1; } static void mouseprobe(char *buf, int len) { USED(len); /* * bus mice are easiest, so probe them first */ if (busmousedetect()) sprint(buf, "bus\n"); else if (msbusmousedetect()) sprint(buf, "msbus\n"); else if (i8042auxdetect()) { if (intellimousedetect()) sprint(buf, "ps2intellimouse\n"); else sprint(buf, "ps2\n"); } else *buf = 0; } static void mousestatus(char *buf, int len) { char *s; USED(len); s = buf; switch (mousetype) { case Mouseserial: if (mousesubtype) s += sprint(s, "serial %d %c\n", mouseport, mousesubtype); else s += sprint(s, "serial %d\n", mouseport); break; case MousePS2: s += sprint(s, "ps2\n"); break; case Mousebus: s += sprint(s, "bus %d\n", mouseport); break; case Mouseintelli: s += sprint(s, "intelli\n"); break; case Mousemsbus: s += sprint(s, "msbus %d\n", mouseport); break; default: case Mouseother: s += sprint(s, "unknown\n"); break; } if (accelerated) s += sprint(s, "accelerated\n"); if (mouseswap) sprint(s, "swap\n"); } /* * Logitech 5 byte packed binary mouse format, 8 bit bytes * * shift & right button is the same as middle button (for 2 button mice) */ static int logitechmouseputc(Queue *q, int c) { static short msg[5]; static int nb; static uchar b[] = {0, 4, 2, 6, 1, 5, 3, 7, 0, 2, 2, 6, 1, 5, 3, 7}; int dx, dy, newbuttons; int mouseshifted; USED(q); if((c&0xF0) == 0x80) nb=0; msg[nb] = c; if(c & 0x80) msg[nb] |= ~0xFF; /* sign extend */ if(++nb == 5){ mouseshifted = 0; /* XXX should be from keyboard shift key */ newbuttons = b[((msg[0]&7)^7) | (mouseshifted ? 8 : 0)]; dx = msg[1]+msg[3]; dy = -(msg[2]+msg[4]); track(newbuttons, dx, dy); nb = 0; } return 0; } /* * microsoft 3 button, 7 bit bytes * * byte 0 - 1 L R Y7 Y6 X7 X6 * byte 1 - 0 X5 X4 X3 X2 X1 X0 * byte 2 - 0 Y5 Y4 Y3 Y2 Y1 Y0 * byte 3 - 0 M x x x x x (optional) * * shift & right button is the same as middle button (for 2 button mice) */ static int m3mouseputc(Queue*, int c) { static uchar msg[3]; static int nb; static int middle; static uchar b[] = { 0, 4, 1, 5, 0, 2, 1, 5 }; short x; int dx, dy, buttons; /* * check bit 6 for consistency */ if(nb==0){ if((c&0x40) == 0){ /* an extra byte gets sent for the middle button */ if(c & 0x1c) return 0; middle = (c&0x20) ? 2 : 0; buttons = (mouse.b & ~2) | middle; track(buttons, 0, 0); return 0; } } msg[nb] = c&0x3f; if(++nb == 3){ nb = 0; buttons = middle | b[(msg[0]>>4)&3]; x = (msg[0]&0x3)<<14; dx = (x>>8) | msg[1]; x = (msg[0]&0xc)<<12; dy = (x>>8) | msg[2]; track(buttons, dx, dy); } return 0; } static void serialmouse(int port, char *type, int setspeed) { int (*putc)(Queue *, int) = 0; char pn[KNAMELEN]; if(mousetype) error(Emouseset); if(port >= 2 || port < 0) error(Ebadarg); if (type == 0) putc = logitechmouseputc; else if (*type == 'M') putc = m3mouseputc; else error(Ebadarg); snprint(pn, sizeof(pn), "%d", port); i8250mouse(pn, putc, setspeed); mousetype = Mouseserial; mouseport = port; mousesubtype = (type && *type == 'M') ? 'M' : 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 & left button is the same as middle button */ static void ps2mouseputc(int c, int shift) { static short msg[3]; static int nb; static uchar b[] = {0, 1, 4, 5, 2, 3, 6, 7, 0, 1, 2, 5, 2, 3, 6, 7 }; int buttons, dx, dy; /* * check byte 0 for consistency */ if(nb==0 && (c&0xc8)!=0x08) return; msg[nb] = c; if(++nb == 3){ nb = 0; if(msg[0] & 0x10) msg[1] |= 0xFF00; if(msg[0] & 0x20) msg[2] |= 0xFF00; buttons = b[(msg[0]&7) | (shift ? 8 : 0)]; dx = msg[1]; dy = -msg[2]; track(buttons, dx, dy); } return; } /* * set up a ps2 mouse */ static void ps2mouse(void) { if(mousetype) error(Emouseset); i8042auxenable(ps2mouseputc); /* make mouse streaming, enabled */ i8042auxcmd(0xEA); i8042auxcmd(0xF4); mousetype = MousePS2; } /* logitech bus mouse ports and commands */ enum { /* ports */ BMdatap = 0x23c, BMsigp = 0x23d, BMctlp = 0x23e, BMintrp = 0x23e, BMconfigp = 0x23f, /* commands */ BMintron = 0x0, BMintroff = 0x10, BMrxlo = 0x80, BMrxhi = 0xa0, BMrylo = 0xc0, BMryhi = 0xe0, BMconfig = 0x91, BMdefault = 0x90, BMsigval = 0xa5 }; static void busmouseintr(Ureg *, void *) { char dx, dy; uchar b; static uchar oldb; static Lock intrlock; ilock(&intrlock); outb(BMintrp, BMintroff); outb(BMctlp, BMrxlo); dx = inb(BMdatap) & 0xf; outb(BMctlp, BMrxhi); dx |= (inb(BMdatap) & 0xf) << 4; outb(BMctlp, BMrylo); dy = inb(BMdatap) & 0xf; outb(BMctlp, BMryhi); b = inb(BMdatap); dy |= (b & 0xf) << 4; b = ~(b >> 5) & 7; if (dx || dy || b != oldb) { oldb = b; track((b>>2)|(b&0x02)|((b&0x01)<<2), dx, dy); } iunlock(&intrlock); outb(BMintrp, BMintron); } static int busmousedetect(void) { outb(BMconfigp, BMconfig); outb(BMsigp, BMsigval); delay(2); if (inb(BMsigp) != BMsigval) return 0; outb(BMconfigp, BMdefault); return 1; } /* * set up a logitech bus mouse */ static void busmouse(int irq) { if (mousetype) error(Emouseset); if (!busmousedetect()) error(Enodev); intrenable(irq >= 0 ? irq+VectorPIC : VectorBUSMOUSE, busmouseintr, 0, BUSUNKNOWN); outb(BMintrp, BMintron); mousetype = Mousebus; mouseport = irq >= 0 ? irq : VectorBUSMOUSE-VectorPIC; } /* microsoft bus mouse ports and commands */ enum { MBMdatap= 0x23d, MBMsigp= 0x23e, MBMctlp= 0x23c, MBMconfigp= 0x23f, MBMintron= 0x11, MBMintroff= 0x10, MBMrbuttons= 0x00, MBMrx= 0x01, MBMry= 0x02, MBMstart= 0x80, MBMcmd= 0x07, }; static void msbusmouseintr(Ureg *, void *) { char dx, dy; uchar b; static uchar oldb; static Lock intrlock; ilock(&intrlock); outb(MBMctlp, MBMcmd); outb(MBMdatap, inb(MBMdatap)|0x20);