17dd7cddfSDavid du Colombier #include "u.h"
27dd7cddfSDavid du Colombier #include "../port/lib.h"
37dd7cddfSDavid du Colombier #include "mem.h"
47dd7cddfSDavid du Colombier #include "dat.h"
57dd7cddfSDavid du Colombier #include "fns.h"
67dd7cddfSDavid du Colombier #include "../port/error.h"
77dd7cddfSDavid du Colombier #include "io.h"
87dd7cddfSDavid du Colombier
97dd7cddfSDavid du Colombier #define Image IMAGE
107dd7cddfSDavid du Colombier #include <draw.h>
117dd7cddfSDavid du Colombier #include <memdraw.h>
127dd7cddfSDavid du Colombier #include <cursor.h>
137dd7cddfSDavid du Colombier #include "screen.h"
147dd7cddfSDavid du Colombier
157dd7cddfSDavid du Colombier /*
167dd7cddfSDavid du Colombier * mouse types
177dd7cddfSDavid du Colombier */
187dd7cddfSDavid du Colombier enum
197dd7cddfSDavid du Colombier {
207dd7cddfSDavid du Colombier Mouseother= 0,
217dd7cddfSDavid du Colombier Mouseserial= 1,
227dd7cddfSDavid du Colombier MousePS2= 2,
237dd7cddfSDavid du Colombier };
24b7b24591SDavid du Colombier
25*8cde348aSDavid du Colombier extern int mouseshifted;
26*8cde348aSDavid du Colombier
27b7b24591SDavid du Colombier static QLock mousectlqlock;
287dd7cddfSDavid du Colombier static int mousetype;
2959cc4ca5SDavid du Colombier static int intellimouse;
3059cc4ca5SDavid du Colombier static int packetsize;
3159cc4ca5SDavid du Colombier static int resolution;
3259cc4ca5SDavid du Colombier static int accelerated;
339a747e4fSDavid du Colombier static int mousehwaccel;
34aa46331bSDavid du Colombier static char mouseport[5];
359a747e4fSDavid du Colombier
369a747e4fSDavid du Colombier enum
379a747e4fSDavid du Colombier {
389a747e4fSDavid du Colombier CMaccelerated,
399a747e4fSDavid du Colombier CMhwaccel,
409a747e4fSDavid du Colombier CMintellimouse,
419a747e4fSDavid du Colombier CMlinear,
429a747e4fSDavid du Colombier CMps2,
439a747e4fSDavid du Colombier CMps2intellimouse,
449a747e4fSDavid du Colombier CMres,
459a747e4fSDavid du Colombier CMreset,
469a747e4fSDavid du Colombier CMserial,
479a747e4fSDavid du Colombier };
489a747e4fSDavid du Colombier
499a747e4fSDavid du Colombier static Cmdtab mousectlmsg[] =
509a747e4fSDavid du Colombier {
519a747e4fSDavid du Colombier CMaccelerated, "accelerated", 0,
529a747e4fSDavid du Colombier CMhwaccel, "hwaccel", 2,
539a747e4fSDavid du Colombier CMintellimouse, "intellimouse", 1,
549a747e4fSDavid du Colombier CMlinear, "linear", 1,
559a747e4fSDavid du Colombier CMps2, "ps2", 1,
569a747e4fSDavid du Colombier CMps2intellimouse, "ps2intellimouse", 1,
579a747e4fSDavid du Colombier CMres, "res", 0,
589a747e4fSDavid du Colombier CMreset, "reset", 1,
599a747e4fSDavid du Colombier CMserial, "serial", 0,
609a747e4fSDavid du Colombier };
617dd7cddfSDavid du Colombier
627dd7cddfSDavid du Colombier /*
637dd7cddfSDavid du Colombier * ps/2 mouse message is three bytes
647dd7cddfSDavid du Colombier *
657dd7cddfSDavid du Colombier * byte 0 - 0 0 SDY SDX 1 M R L
667dd7cddfSDavid du Colombier * byte 1 - DX
677dd7cddfSDavid du Colombier * byte 2 - DY
687dd7cddfSDavid du Colombier *
6959cc4ca5SDavid du Colombier * shift & right button is the same as middle button
7059cc4ca5SDavid du Colombier *
7159cc4ca5SDavid du Colombier * Intellimouse and AccuPoint with extra buttons deliver
7259cc4ca5SDavid du Colombier * byte 3 - 00 or 01 or FF according to extra button state.
7359cc4ca5SDavid du Colombier * extra buttons are mapped in this code to buttons 4 and 5.
7459cc4ca5SDavid du Colombier * AccuPoint generates repeated events for these buttons;
7559cc4ca5SDavid du Colombier * it and Intellimouse generate 'down' events only, so
7659cc4ca5SDavid du Colombier * user-level code is required to generate button 'up' events
7759cc4ca5SDavid du Colombier * if they are needed by the application.
7859cc4ca5SDavid du Colombier * Also on laptops with AccuPoint AND external mouse, the
7959cc4ca5SDavid du Colombier * controller may deliver 3 or 4 bytes according to the type
8059cc4ca5SDavid du Colombier * of the external mouse; code must adapt.
819a747e4fSDavid du Colombier *
829a747e4fSDavid du Colombier * On the NEC Versa series (and perhaps others?) we seem to
839a747e4fSDavid du Colombier * lose a byte from the packet every once in a while, which
849a747e4fSDavid du Colombier * means we lose where we are in the instruction stream.
859a747e4fSDavid du Colombier * To resynchronize, if we get a byte more than two seconds
869a747e4fSDavid du Colombier * after the previous byte, we assume it's the first in a packet.
877dd7cddfSDavid du Colombier */
887dd7cddfSDavid du Colombier static void
ps2mouseputc(int c,int shift)897dd7cddfSDavid du Colombier ps2mouseputc(int c, int shift)
907dd7cddfSDavid du Colombier {
9159cc4ca5SDavid du Colombier static short msg[4];
927dd7cddfSDavid du Colombier static int nb;
9359cc4ca5SDavid du Colombier static uchar b[] = {0, 1, 4, 5, 2, 3, 6, 7, 0, 1, 2, 3, 2, 3, 6, 7 };
949a747e4fSDavid du Colombier static ulong lasttick;
959a747e4fSDavid du Colombier ulong m;
967dd7cddfSDavid du Colombier int buttons, dx, dy;
977dd7cddfSDavid du Colombier
987dd7cddfSDavid du Colombier /*
99*8cde348aSDavid du Colombier * non-ps2 keyboards might not set shift
100*8cde348aSDavid du Colombier * but still set mouseshifted.
101*8cde348aSDavid du Colombier */
102*8cde348aSDavid du Colombier shift |= mouseshifted;
103*8cde348aSDavid du Colombier /*
1049a747e4fSDavid du Colombier * Resynchronize in stream with timing; see comment above.
1059a747e4fSDavid du Colombier */
1069a747e4fSDavid du Colombier m = MACHP(0)->ticks;
1079a747e4fSDavid du Colombier if(TK2SEC(m - lasttick) > 2)
1089a747e4fSDavid du Colombier nb = 0;
1099a747e4fSDavid du Colombier lasttick = m;
1109a747e4fSDavid du Colombier
1119a747e4fSDavid du Colombier /*
1127dd7cddfSDavid du Colombier * check byte 0 for consistency
1137dd7cddfSDavid du Colombier */
1147dd7cddfSDavid du Colombier if(nb==0 && (c&0xc8)!=0x08)
11559cc4ca5SDavid du Colombier if(intellimouse && (c==0x00 || c==0x01 || c==0xFF)){
11659cc4ca5SDavid du Colombier /* last byte of 4-byte packet */
11759cc4ca5SDavid du Colombier packetsize = 4;
1187dd7cddfSDavid du Colombier return;
11959cc4ca5SDavid du Colombier }
1207dd7cddfSDavid du Colombier
1217dd7cddfSDavid du Colombier msg[nb] = c;
12259cc4ca5SDavid du Colombier if(++nb == packetsize){
1237dd7cddfSDavid du Colombier nb = 0;
1247dd7cddfSDavid du Colombier if(msg[0] & 0x10)
1257dd7cddfSDavid du Colombier msg[1] |= 0xFF00;
1267dd7cddfSDavid du Colombier if(msg[0] & 0x20)
1277dd7cddfSDavid du Colombier msg[2] |= 0xFF00;
1287dd7cddfSDavid du Colombier
1297dd7cddfSDavid du Colombier buttons = b[(msg[0]&7) | (shift ? 8 : 0)];
13059cc4ca5SDavid du Colombier if(intellimouse && packetsize==4){
13159cc4ca5SDavid du Colombier if((msg[3]&0xc8) == 0x08){
13259cc4ca5SDavid du Colombier /* first byte of 3-byte packet */
13359cc4ca5SDavid du Colombier packetsize = 3;
13459cc4ca5SDavid du Colombier msg[0] = msg[3];
13559cc4ca5SDavid du Colombier nb = 1;
13659cc4ca5SDavid du Colombier /* fall through to emit previous packet */
13759cc4ca5SDavid du Colombier }else{
1389847521cSDavid du Colombier /* The AccuPoint on the Toshiba 34[48]0CT
1399847521cSDavid du Colombier * encodes extra buttons as 4 and 5. They repeat
1409847521cSDavid du Colombier * and don't release, however, so user-level
1419847521cSDavid du Colombier * timing code is required. Furthermore,
1429847521cSDavid du Colombier * intellimice with 3buttons + scroll give a
1439847521cSDavid du Colombier * two's complement number in the lower 4 bits
1449847521cSDavid du Colombier * (bit 4 is sign extension) that describes
1459847521cSDavid du Colombier * the amount the scroll wheel has moved during
1469847521cSDavid du Colombier * the last sample. Here we use only the sign to
1479847521cSDavid du Colombier * decide whether the wheel is moving up or down
1489847521cSDavid du Colombier * and generate a single button 4 or 5 click
1499847521cSDavid du Colombier * accordingly.
1509847521cSDavid du Colombier */
1519847521cSDavid du Colombier if((msg[3] >> 3) & 1)
15259cc4ca5SDavid du Colombier buttons |= 1<<3;
1539847521cSDavid du Colombier else if(msg[3] & 0x7)
15459cc4ca5SDavid du Colombier buttons |= 1<<4;
15559cc4ca5SDavid du Colombier }
15659cc4ca5SDavid du Colombier }
1577dd7cddfSDavid du Colombier dx = msg[1];
1587dd7cddfSDavid du Colombier dy = -msg[2];
1599a747e4fSDavid du Colombier mousetrack(dx, dy, buttons, TK2MS(MACHP(0)->ticks));
1607dd7cddfSDavid du Colombier }
1617dd7cddfSDavid du Colombier return;
1627dd7cddfSDavid du Colombier }
1637dd7cddfSDavid du Colombier
1647dd7cddfSDavid du Colombier /*
1657dd7cddfSDavid du Colombier * set up a ps2 mouse
1667dd7cddfSDavid du Colombier */
1677dd7cddfSDavid du Colombier static void
ps2mouse(void)1687dd7cddfSDavid du Colombier ps2mouse(void)
1697dd7cddfSDavid du Colombier {
1707dd7cddfSDavid du Colombier if(mousetype == MousePS2)
1717dd7cddfSDavid du Colombier return;
1727dd7cddfSDavid du Colombier
1737dd7cddfSDavid du Colombier i8042auxenable(ps2mouseputc);
1747dd7cddfSDavid du Colombier /* make mouse streaming, enabled */
1757dd7cddfSDavid du Colombier i8042auxcmd(0xEA);
1767dd7cddfSDavid du Colombier i8042auxcmd(0xF4);
1777dd7cddfSDavid du Colombier
1787dd7cddfSDavid du Colombier mousetype = MousePS2;
17959cc4ca5SDavid du Colombier packetsize = 3;
1809a747e4fSDavid du Colombier mousehwaccel = 1;
1817dd7cddfSDavid du Colombier }
1827dd7cddfSDavid du Colombier
1839a747e4fSDavid du Colombier /*
1849a747e4fSDavid du Colombier * The PS/2 Trackpoint multiplexor on the IBM Thinkpad T23 ignores
1859a747e4fSDavid du Colombier * acceleration commands. It is supposed to pass them on
1869a747e4fSDavid du Colombier * to the attached device, but my Logitech mouse is simply
1879a747e4fSDavid du Colombier * not behaving any differently. For such devices, we allow
1889a747e4fSDavid du Colombier * the user to use "hwaccel off" to tell us to back off to
1899a747e4fSDavid du Colombier * software acceleration even if we're using the PS/2 port.
1909a747e4fSDavid du Colombier * (Serial mice are always software accelerated.)
1919a747e4fSDavid du Colombier * For more information on the Thinkpad multiplexor, see
1929a747e4fSDavid du Colombier * http://wwwcssrv.almaden.ibm.com/trackpoint/
1939a747e4fSDavid du Colombier */
1947dd7cddfSDavid du Colombier static void
setaccelerated(int x)1957dd7cddfSDavid du Colombier setaccelerated(int x)
1967dd7cddfSDavid du Colombier {
1977dd7cddfSDavid du Colombier accelerated = x;
1989a747e4fSDavid du Colombier if(mousehwaccel){
1997dd7cddfSDavid du Colombier switch(mousetype){
2007dd7cddfSDavid du Colombier case MousePS2:
2017dd7cddfSDavid du Colombier i8042auxcmd(0xE7);
2029a747e4fSDavid du Colombier return;
2037dd7cddfSDavid du Colombier }
2047dd7cddfSDavid du Colombier }
2059a747e4fSDavid du Colombier mouseaccelerate(x);
2069a747e4fSDavid du Colombier }
2077dd7cddfSDavid du Colombier
2087dd7cddfSDavid du Colombier static void
setlinear(void)2097dd7cddfSDavid du Colombier setlinear(void)
2107dd7cddfSDavid du Colombier {
2117dd7cddfSDavid du Colombier accelerated = 0;
2129a747e4fSDavid du Colombier if(mousehwaccel){
2137dd7cddfSDavid du Colombier switch(mousetype){
2147dd7cddfSDavid du Colombier case MousePS2:
2157dd7cddfSDavid du Colombier i8042auxcmd(0xE6);
2169a747e4fSDavid du Colombier return;
2177dd7cddfSDavid du Colombier }
2187dd7cddfSDavid du Colombier }
2199a747e4fSDavid du Colombier mouseaccelerate(0);
2209a747e4fSDavid du Colombier }
2217dd7cddfSDavid du Colombier
2227dd7cddfSDavid du Colombier static void
setres(int n)2237dd7cddfSDavid du Colombier setres(int n)
2247dd7cddfSDavid du Colombier {
2257dd7cddfSDavid du Colombier resolution = n;
2267dd7cddfSDavid du Colombier switch(mousetype){
2277dd7cddfSDavid du Colombier case MousePS2:
2287dd7cddfSDavid du Colombier i8042auxcmd(0xE8);
2297dd7cddfSDavid du Colombier i8042auxcmd(n);
2307dd7cddfSDavid du Colombier break;
2317dd7cddfSDavid du Colombier }
2327dd7cddfSDavid du Colombier }
2337dd7cddfSDavid du Colombier
2347dd7cddfSDavid du Colombier static void
setintellimouse(void)2357dd7cddfSDavid du Colombier setintellimouse(void)
2367dd7cddfSDavid du Colombier {
2377dd7cddfSDavid du Colombier intellimouse = 1;
23859cc4ca5SDavid du Colombier packetsize = 4;
2397dd7cddfSDavid du Colombier switch(mousetype){
2407dd7cddfSDavid du Colombier case MousePS2:
2417dd7cddfSDavid du Colombier i8042auxcmd(0xF3); /* set sample */
2427dd7cddfSDavid du Colombier i8042auxcmd(0xC8);
2437dd7cddfSDavid du Colombier i8042auxcmd(0xF3); /* set sample */
2447dd7cddfSDavid du Colombier i8042auxcmd(0x64);
2457dd7cddfSDavid du Colombier i8042auxcmd(0xF3); /* set sample */
2467dd7cddfSDavid du Colombier i8042auxcmd(0x50);
2477dd7cddfSDavid du Colombier break;
248aa46331bSDavid du Colombier case Mouseserial:
249aa46331bSDavid du Colombier i8250setmouseputc(mouseport, m5mouseputc);
250aa46331bSDavid du Colombier break;
2517dd7cddfSDavid du Colombier }
2527dd7cddfSDavid du Colombier }
2537dd7cddfSDavid du Colombier
2547dd7cddfSDavid du Colombier static void
resetmouse(void)2557dd7cddfSDavid du Colombier resetmouse(void)
2567dd7cddfSDavid du Colombier {
25759cc4ca5SDavid du Colombier packetsize = 3;
2587dd7cddfSDavid du Colombier switch(mousetype){
2597dd7cddfSDavid du Colombier case MousePS2:
2607dd7cddfSDavid du Colombier i8042auxcmd(0xF6);
2617dd7cddfSDavid du Colombier i8042auxcmd(0xEA); /* streaming */
2627dd7cddfSDavid du Colombier i8042auxcmd(0xE8); /* set resolution */
2637dd7cddfSDavid du Colombier i8042auxcmd(3);
2647dd7cddfSDavid du Colombier i8042auxcmd(0xF4); /* enabled */
2657dd7cddfSDavid du Colombier break;
2667dd7cddfSDavid du Colombier }
2677dd7cddfSDavid du Colombier }
2687dd7cddfSDavid du Colombier
2697dd7cddfSDavid du Colombier void
mousectl(Cmdbuf * cb)2709a747e4fSDavid du Colombier mousectl(Cmdbuf *cb)
2717dd7cddfSDavid du Colombier {
2729a747e4fSDavid du Colombier Cmdtab *ct;
2739a747e4fSDavid du Colombier
274b7b24591SDavid du Colombier qlock(&mousectlqlock);
275b7b24591SDavid du Colombier if(waserror()){
276b7b24591SDavid du Colombier qunlock(&mousectlqlock);
277b7b24591SDavid du Colombier nexterror();
278b7b24591SDavid du Colombier }
279b7b24591SDavid du Colombier
2809a747e4fSDavid du Colombier ct = lookupcmd(cb, mousectlmsg, nelem(mousectlmsg));
2819a747e4fSDavid du Colombier switch(ct->index){
2829a747e4fSDavid du Colombier case CMaccelerated:
2839a747e4fSDavid du Colombier setaccelerated(cb->nf == 1 ? 1 : atoi(cb->f[1]));
2847dd7cddfSDavid du Colombier break;
2859a747e4fSDavid du Colombier case CMintellimouse:
2869a747e4fSDavid du Colombier setintellimouse();
2877dd7cddfSDavid du Colombier break;
2889a747e4fSDavid du Colombier case CMlinear:
2899a747e4fSDavid du Colombier setlinear();
2907dd7cddfSDavid du Colombier break;
2919a747e4fSDavid du Colombier case CMps2:
2929847521cSDavid du Colombier intellimouse = 0;
2937dd7cddfSDavid du Colombier ps2mouse();
2949a747e4fSDavid du Colombier break;
2959a747e4fSDavid du Colombier case CMps2intellimouse:
2967dd7cddfSDavid du Colombier ps2mouse();
2977dd7cddfSDavid du Colombier setintellimouse();
2989a747e4fSDavid du Colombier break;
2999a747e4fSDavid du Colombier case CMres:
3009a747e4fSDavid du Colombier if(cb->nf >= 2)
3019a747e4fSDavid du Colombier setres(atoi(cb->f[1]));
3029a747e4fSDavid du Colombier else
3039a747e4fSDavid du Colombier setres(1);
3049a747e4fSDavid du Colombier break;
3059a747e4fSDavid du Colombier case CMreset:
3067dd7cddfSDavid du Colombier resetmouse();
3077dd7cddfSDavid du Colombier if(accelerated)
3087dd7cddfSDavid du Colombier setaccelerated(accelerated);
3097dd7cddfSDavid du Colombier if(resolution)
3107dd7cddfSDavid du Colombier setres(resolution);
3117dd7cddfSDavid du Colombier if(intellimouse)
3127dd7cddfSDavid du Colombier setintellimouse();
3139a747e4fSDavid du Colombier break;
3149a747e4fSDavid du Colombier case CMserial:
315b7b24591SDavid du Colombier if(mousetype == Mouseserial)
316b7b24591SDavid du Colombier error(Emouseset);
317b7b24591SDavid du Colombier
318aa46331bSDavid du Colombier if(cb->nf > 2){
319aa46331bSDavid du Colombier if(strcmp(cb->f[2], "M") == 0)
320b7b24591SDavid du Colombier i8250mouse(cb->f[1], m3mouseputc, 0);
321aa46331bSDavid du Colombier else if(strcmp(cb->f[2], "MI") == 0)
322aa46331bSDavid du Colombier i8250mouse(cb->f[1], m5mouseputc, 0);
323b7b24591SDavid du Colombier else
324b7b24591SDavid du Colombier i8250mouse(cb->f[1], mouseputc, cb->nf == 1);
325aa46331bSDavid du Colombier } else
326aa46331bSDavid du Colombier i8250mouse(cb->f[1], mouseputc, cb->nf == 1);
327b7b24591SDavid du Colombier
328b7b24591SDavid du Colombier mousetype = Mouseserial;
32968060204SDavid du Colombier strncpy(mouseport, cb->f[1], sizeof(mouseport)-1);
330b7b24591SDavid du Colombier packetsize = 3;
3319a747e4fSDavid du Colombier break;
3329a747e4fSDavid du Colombier case CMhwaccel:
3339a747e4fSDavid du Colombier if(strcmp(cb->f[1], "on")==0)
3349a747e4fSDavid du Colombier mousehwaccel = 1;
3359a747e4fSDavid du Colombier else if(strcmp(cb->f[1], "off")==0)
3369a747e4fSDavid du Colombier mousehwaccel = 0;
3377dd7cddfSDavid du Colombier else
3389a747e4fSDavid du Colombier cmderror(cb, "bad mouse control message");
3399a747e4fSDavid du Colombier }
340b7b24591SDavid du Colombier
341b7b24591SDavid du Colombier qunlock(&mousectlqlock);
342b7b24591SDavid du Colombier poperror();
3437dd7cddfSDavid du Colombier }
344