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