1*93631029SDavid du Colombier #include "u.h"
2*93631029SDavid du Colombier #include "../port/lib.h"
3*93631029SDavid du Colombier #include "mem.h"
4*93631029SDavid du Colombier #include "dat.h"
5*93631029SDavid du Colombier #include "fns.h"
6*93631029SDavid du Colombier #include "../port/error.h"
7*93631029SDavid du Colombier #include "io.h"
8*93631029SDavid du Colombier
9*93631029SDavid du Colombier #define Image IMAGE
10*93631029SDavid du Colombier #include <draw.h>
11*93631029SDavid du Colombier #include <memdraw.h>
12*93631029SDavid du Colombier #include <cursor.h>
13*93631029SDavid du Colombier #include "screen.h"
14*93631029SDavid du Colombier
15*93631029SDavid du Colombier /*
16*93631029SDavid du Colombier * mouse types
17*93631029SDavid du Colombier */
18*93631029SDavid du Colombier enum
19*93631029SDavid du Colombier {
20*93631029SDavid du Colombier Mouseother= 0,
21*93631029SDavid du Colombier Mouseserial= 1,
22*93631029SDavid du Colombier MousePS2= 2,
23*93631029SDavid du Colombier };
24*93631029SDavid du Colombier
25*93631029SDavid du Colombier extern int mouseshifted;
26*93631029SDavid du Colombier
27*93631029SDavid du Colombier static QLock mousectlqlock;
28*93631029SDavid du Colombier static int mousetype;
29*93631029SDavid du Colombier static int intellimouse;
30*93631029SDavid du Colombier static int packetsize;
31*93631029SDavid du Colombier static int resolution;
32*93631029SDavid du Colombier static int accelerated;
33*93631029SDavid du Colombier static int mousehwaccel;
34*93631029SDavid du Colombier static char mouseport[5];
35*93631029SDavid du Colombier
36*93631029SDavid du Colombier enum
37*93631029SDavid du Colombier {
38*93631029SDavid du Colombier CMaccelerated,
39*93631029SDavid du Colombier CMhwaccel,
40*93631029SDavid du Colombier CMintellimouse,
41*93631029SDavid du Colombier CMlinear,
42*93631029SDavid du Colombier CMps2,
43*93631029SDavid du Colombier CMps2intellimouse,
44*93631029SDavid du Colombier CMres,
45*93631029SDavid du Colombier CMreset,
46*93631029SDavid du Colombier CMserial,
47*93631029SDavid du Colombier };
48*93631029SDavid du Colombier
49*93631029SDavid du Colombier static Cmdtab mousectlmsg[] =
50*93631029SDavid du Colombier {
51*93631029SDavid du Colombier CMaccelerated, "accelerated", 0,
52*93631029SDavid du Colombier CMhwaccel, "hwaccel", 2,
53*93631029SDavid du Colombier CMintellimouse, "intellimouse", 1,
54*93631029SDavid du Colombier CMlinear, "linear", 1,
55*93631029SDavid du Colombier CMps2, "ps2", 1,
56*93631029SDavid du Colombier CMps2intellimouse, "ps2intellimouse", 1,
57*93631029SDavid du Colombier CMres, "res", 0,
58*93631029SDavid du Colombier CMreset, "reset", 1,
59*93631029SDavid du Colombier CMserial, "serial", 0,
60*93631029SDavid du Colombier };
61*93631029SDavid du Colombier
62*93631029SDavid du Colombier /*
63*93631029SDavid du Colombier * ps/2 mouse message is three bytes
64*93631029SDavid du Colombier *
65*93631029SDavid du Colombier * byte 0 - 0 0 SDY SDX 1 M R L
66*93631029SDavid du Colombier * byte 1 - DX
67*93631029SDavid du Colombier * byte 2 - DY
68*93631029SDavid du Colombier *
69*93631029SDavid du Colombier * shift & right button is the same as middle button
70*93631029SDavid du Colombier *
71*93631029SDavid du Colombier * Intellimouse and AccuPoint with extra buttons deliver
72*93631029SDavid du Colombier * byte 3 - 00 or 01 or FF according to extra button state.
73*93631029SDavid du Colombier * extra buttons are mapped in this code to buttons 4 and 5.
74*93631029SDavid du Colombier * AccuPoint generates repeated events for these buttons;
75*93631029SDavid du Colombier * it and Intellimouse generate 'down' events only, so
76*93631029SDavid du Colombier * user-level code is required to generate button 'up' events
77*93631029SDavid du Colombier * if they are needed by the application.
78*93631029SDavid du Colombier * Also on laptops with AccuPoint AND external mouse, the
79*93631029SDavid du Colombier * controller may deliver 3 or 4 bytes according to the type
80*93631029SDavid du Colombier * of the external mouse; code must adapt.
81*93631029SDavid du Colombier *
82*93631029SDavid du Colombier * On the NEC Versa series (and perhaps others?) we seem to
83*93631029SDavid du Colombier * lose a byte from the packet every once in a while, which
84*93631029SDavid du Colombier * means we lose where we are in the instruction stream.
85*93631029SDavid du Colombier * To resynchronize, if we get a byte more than two seconds
86*93631029SDavid du Colombier * after the previous byte, we assume it's the first in a packet.
87*93631029SDavid du Colombier */
88*93631029SDavid du Colombier static void
ps2mouseputc(int c,int shift)89*93631029SDavid du Colombier ps2mouseputc(int c, int shift)
90*93631029SDavid du Colombier {
91*93631029SDavid du Colombier static short msg[4];
92*93631029SDavid du Colombier static int nb;
93*93631029SDavid du Colombier static uchar b[] = {0, 1, 4, 5, 2, 3, 6, 7, 0, 1, 2, 3, 2, 3, 6, 7 };
94*93631029SDavid du Colombier static ulong lasttick;
95*93631029SDavid du Colombier ulong m;
96*93631029SDavid du Colombier int buttons, dx, dy;
97*93631029SDavid du Colombier
98*93631029SDavid du Colombier shift |= mouseshifted;
99*93631029SDavid du Colombier m = MACHP(0)->ticks;
100*93631029SDavid du Colombier if(TK2SEC(m - lasttick) > 2)
101*93631029SDavid du Colombier nb = 0;
102*93631029SDavid du Colombier lasttick = m;
103*93631029SDavid du Colombier if(nb==0 && (c&0xc8)!=0x08)
104*93631029SDavid du Colombier if(intellimouse && (c==0x00 || c==0x01 || c==0xFF)){
105*93631029SDavid du Colombier packetsize = 4;
106*93631029SDavid du Colombier return;
107*93631029SDavid du Colombier }
108*93631029SDavid du Colombier
109*93631029SDavid du Colombier msg[nb] = c;
110*93631029SDavid du Colombier if(++nb == packetsize){
111*93631029SDavid du Colombier nb = 0;
112*93631029SDavid du Colombier if(msg[0] & 0x10)
113*93631029SDavid du Colombier msg[1] |= 0xFF00;
114*93631029SDavid du Colombier if(msg[0] & 0x20)
115*93631029SDavid du Colombier msg[2] |= 0xFF00;
116*93631029SDavid du Colombier
117*93631029SDavid du Colombier buttons = b[(msg[0]&7) | (shift ? 8 : 0)];
118*93631029SDavid du Colombier if(intellimouse && packetsize==4){
119*93631029SDavid du Colombier if((msg[3]&0xc8) == 0x08){
120*93631029SDavid du Colombier packetsize = 3;
121*93631029SDavid du Colombier msg[0] = msg[3];
122*93631029SDavid du Colombier nb = 1;
123*93631029SDavid du Colombier }else{
124*93631029SDavid du Colombier if((msg[3] >> 3) & 1)
125*93631029SDavid du Colombier buttons |= 1<<3;
126*93631029SDavid du Colombier else if(msg[3] & 0x7)
127*93631029SDavid du Colombier buttons |= 1<<4;
128*93631029SDavid du Colombier }
129*93631029SDavid du Colombier }
130*93631029SDavid du Colombier dx = msg[1];
131*93631029SDavid du Colombier dy = -msg[2];
132*93631029SDavid du Colombier mousetrack(dx, dy, buttons, TK2MS(MACHP(0)->ticks));
133*93631029SDavid du Colombier }
134*93631029SDavid du Colombier }
135*93631029SDavid du Colombier
136*93631029SDavid du Colombier /*
137*93631029SDavid du Colombier * set up a ps2 mouse
138*93631029SDavid du Colombier */
139*93631029SDavid du Colombier static void
ps2mouse(void)140*93631029SDavid du Colombier ps2mouse(void)
141*93631029SDavid du Colombier {
142*93631029SDavid du Colombier if(mousetype == MousePS2)
143*93631029SDavid du Colombier return;
144*93631029SDavid du Colombier
145*93631029SDavid du Colombier // i8042auxenable(ps2mouseputc);
146*93631029SDavid du Colombier // i8042auxcmd(0xEA); // TODO
147*93631029SDavid du Colombier // i8042auxcmd(0xF4);
148*93631029SDavid du Colombier
149*93631029SDavid du Colombier mousetype = MousePS2;
150*93631029SDavid du Colombier packetsize = 3;
151*93631029SDavid du Colombier mousehwaccel = 1;
152*93631029SDavid du Colombier }
153*93631029SDavid du Colombier
154*93631029SDavid du Colombier /*
155*93631029SDavid du Colombier * The PS/2 Trackpoint multiplexor on the IBM Thinkpad T23 ignores
156*93631029SDavid du Colombier * acceleration commands. It is supposed to pass them on
157*93631029SDavid du Colombier * to the attached device, but my Logitech mouse is simply
158*93631029SDavid du Colombier * not behaving any differently. For such devices, we allow
159*93631029SDavid du Colombier * the user to use "hwaccel off" to tell us to back off to
160*93631029SDavid du Colombier * software acceleration even if we're using the PS/2 port.
161*93631029SDavid du Colombier * (Serial mice are always software accelerated.)
162*93631029SDavid du Colombier * For more information on the Thinkpad multiplexor, see
163*93631029SDavid du Colombier * http://wwwcssrv.almaden.ibm.com/trackpoint/
164*93631029SDavid du Colombier */
165*93631029SDavid du Colombier static void
setaccelerated(int x)166*93631029SDavid du Colombier setaccelerated(int x)
167*93631029SDavid du Colombier {
168*93631029SDavid du Colombier accelerated = x;
169*93631029SDavid du Colombier mouseaccelerate(x);
170*93631029SDavid du Colombier }
171*93631029SDavid du Colombier
172*93631029SDavid du Colombier static void
setlinear(void)173*93631029SDavid du Colombier setlinear(void)
174*93631029SDavid du Colombier {
175*93631029SDavid du Colombier accelerated = 0;
176*93631029SDavid du Colombier mouseaccelerate(0);
177*93631029SDavid du Colombier }
178*93631029SDavid du Colombier
179*93631029SDavid du Colombier static void
setres(int n)180*93631029SDavid du Colombier setres(int n)
181*93631029SDavid du Colombier {
182*93631029SDavid du Colombier resolution = n;
183*93631029SDavid du Colombier }
184*93631029SDavid du Colombier
185*93631029SDavid du Colombier static void
setintellimouse(void)186*93631029SDavid du Colombier setintellimouse(void)
187*93631029SDavid du Colombier {
188*93631029SDavid du Colombier intellimouse = 1;
189*93631029SDavid du Colombier packetsize = 4;
190*93631029SDavid du Colombier }
191*93631029SDavid du Colombier
192*93631029SDavid du Colombier static void
resetmouse(void)193*93631029SDavid du Colombier resetmouse(void)
194*93631029SDavid du Colombier {
195*93631029SDavid du Colombier packetsize = 3;
196*93631029SDavid du Colombier }
197*93631029SDavid du Colombier
198*93631029SDavid du Colombier void
mousectl(Cmdbuf * cb)199*93631029SDavid du Colombier mousectl(Cmdbuf *cb)
200*93631029SDavid du Colombier {
201*93631029SDavid du Colombier Cmdtab *ct;
202*93631029SDavid du Colombier
203*93631029SDavid du Colombier qlock(&mousectlqlock);
204*93631029SDavid du Colombier if(waserror()){
205*93631029SDavid du Colombier qunlock(&mousectlqlock);
206*93631029SDavid du Colombier nexterror();
207*93631029SDavid du Colombier }
208*93631029SDavid du Colombier
209*93631029SDavid du Colombier ct = lookupcmd(cb, mousectlmsg, nelem(mousectlmsg));
210*93631029SDavid du Colombier switch(ct->index){
211*93631029SDavid du Colombier case CMaccelerated:
212*93631029SDavid du Colombier setaccelerated(cb->nf == 1? 1: atoi(cb->f[1]));
213*93631029SDavid du Colombier break;
214*93631029SDavid du Colombier case CMintellimouse:
215*93631029SDavid du Colombier setintellimouse();
216*93631029SDavid du Colombier break;
217*93631029SDavid du Colombier case CMlinear:
218*93631029SDavid du Colombier setlinear();
219*93631029SDavid du Colombier break;
220*93631029SDavid du Colombier case CMps2:
221*93631029SDavid du Colombier intellimouse = 0;
222*93631029SDavid du Colombier break;
223*93631029SDavid du Colombier case CMps2intellimouse:
224*93631029SDavid du Colombier setintellimouse();
225*93631029SDavid du Colombier break;
226*93631029SDavid du Colombier case CMres:
227*93631029SDavid du Colombier if(cb->nf >= 2)
228*93631029SDavid du Colombier setres(atoi(cb->f[1]));
229*93631029SDavid du Colombier else
230*93631029SDavid du Colombier setres(1);
231*93631029SDavid du Colombier break;
232*93631029SDavid du Colombier case CMreset:
233*93631029SDavid du Colombier resetmouse();
234*93631029SDavid du Colombier if(accelerated)
235*93631029SDavid du Colombier setaccelerated(accelerated);
236*93631029SDavid du Colombier if(resolution)
237*93631029SDavid du Colombier setres(resolution);
238*93631029SDavid du Colombier if(intellimouse)
239*93631029SDavid du Colombier setintellimouse();
240*93631029SDavid du Colombier break;
241*93631029SDavid du Colombier case CMserial:
242*93631029SDavid du Colombier error("serial mice not supported");
243*93631029SDavid du Colombier break;
244*93631029SDavid du Colombier case CMhwaccel:
245*93631029SDavid du Colombier if(strcmp(cb->f[1], "on")==0)
246*93631029SDavid du Colombier mousehwaccel = 1;
247*93631029SDavid du Colombier else if(strcmp(cb->f[1], "off")==0)
248*93631029SDavid du Colombier mousehwaccel = 0;
249*93631029SDavid du Colombier else
250*93631029SDavid du Colombier cmderror(cb, "bad mouse control message");
251*93631029SDavid du Colombier }
252*93631029SDavid du Colombier
253*93631029SDavid du Colombier qunlock(&mousectlqlock);
254*93631029SDavid du Colombier poperror();
255*93631029SDavid du Colombier }
256