FreeBSD/Linux Kernel Cross Reference
sys/pc/mouse.c
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
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 /*
99 * non-ps2 keyboards might not set shift
100 * but still set mouseshifted.
101 */
102 shift |= mouseshifted;
103 /*
104 * Resynchronize in stream with timing; see comment above.
105 */
106 m = MACHP(0)->ticks;
107 if(TK2SEC(m - lasttick) > 2)
108 nb = 0;
109 lasttick = m;
110
111 /*
112 * check byte 0 for consistency
113 */
114 if(nb==0 && (c&0xc8)!=0x08)
115 if(intellimouse && (c==0x00 || c==0x01 || c==0xFF)){
116 /* last byte of 4-byte packet */
117 packetsize = 4;
118 return;
119 }
120
121 msg[nb] = c;
122 if(++nb == packetsize){
123 nb = 0;
124 if(msg[0] & 0x10)
125 msg[1] |= 0xFF00;
126 if(msg[0] & 0x20)
127 msg[2] |= 0xFF00;
128
129 buttons = b[(msg[0]&7) | (shift ? 8 : 0)];
130 if(intellimouse && packetsize==4){
131 if((msg[3]&0xc8) == 0x08){
132 /* first byte of 3-byte packet */
133 packetsize = 3;
134 msg[0] = msg[3];
135 nb = 1;
136 /* fall through to emit previous packet */
137 }else{
138 /* The AccuPoint on the Toshiba 34[48]0CT
139 * encodes extra buttons as 4 and 5. They repeat
140 * and don't release, however, so user-level
141 * timing code is required. Furthermore,
142 * intellimice with 3buttons + scroll give a
143 * two's complement number in the lower 4 bits
144 * (bit 4 is sign extension) that describes
145 * the amount the scroll wheel has moved during
146 * the last sample. Here we use only the sign to
147 * decide whether the wheel is moving up or down
148 * and generate a single button 4 or 5 click
149 * accordingly.
150 */
151 if((msg[3] >> 3) & 1)
152 buttons |= 1<<3;
153 else if(msg[3] & 0x7)
154 buttons |= 1<<4;
155 }
156 }
157 dx = msg[1];
158 dy = -msg[2];
159 mousetrack(dx, dy, buttons, TK2MS(MACHP(0)->ticks));
160 }
161 return;
162 }
163
164 /*
165 * set up a ps2 mouse
166 */
167 static void
168 ps2mouse(void)
169 {
170 if(mousetype == MousePS2)
171 return;
172
173 i8042auxenable(ps2mouseputc);
174 /* make mouse streaming, enabled */
175 i8042auxcmd(0xEA);
176 i8042auxcmd(0xF4);
177
178 mousetype = MousePS2;
179 packetsize = 3;
180 mousehwaccel = 1;
181 }
182
183 /*
184 * The PS/2 Trackpoint multiplexor on the IBM Thinkpad T23 ignores
185 * acceleration commands. It is supposed to pass them on
186 * to the attached device, but my Logitech mouse is simply
187 * not behaving any differently. For such devices, we allow
188 * the user to use "hwaccel off" to tell us to back off to
189 * software acceleration even if we're using the PS/2 port.
190 * (Serial mice are always software accelerated.)
191 * For more information on the Thinkpad multiplexor, see
192 * http://wwwcssrv.almaden.ibm.com/trackpoint/
193 */
194 static void
195 setaccelerated(int x)
196 {
197 accelerated = x;
198 if(mousehwaccel){
199 switch(mousetype){
200 case MousePS2:
201 i8042auxcmd(0xE7);
202 return;
203 }
204 }
205 mouseaccelerate(x);
206 }
207
208 static void
209 setlinear(void)
210 {
211 accelerated = 0;
212 if(mousehwaccel){
213 switch(mousetype){
214 case MousePS2:
215 i8042auxcmd(0xE6);
216 return;
217 }
218 }
219 mouseaccelerate(0);
220 }
221
222 static void
223 setres(int n)
224 {
225 resolution = n;
226 switch(mousetype){
227 case MousePS2:
228 i8042auxcmd(0xE8);
229 i8042auxcmd(n);
230 break;
231 }
232 }
233
234 static void
235 setintellimouse(void)
236 {
237 intellimouse = 1;
238 packetsize = 4;
239 switch(mousetype){
240 case MousePS2:
241 i8042auxcmd(0xF3); /* set sample */
242 i8042auxcmd(0xC8);
243 i8042auxcmd(0xF3); /* set sample */
244 i8042auxcmd(0x64);
245 i8042auxcmd(0xF3); /* set sample */
246 i8042auxcmd(0x50);
247 break;
248 case Mouseserial:
249 i8250setmouseputc(mouseport, m5mouseputc);
250 break;
251 }
252 }
253
254 static void
255 resetmouse(void)
256 {
257 packetsize = 3;
258 switch(mousetype){
259 case MousePS2:
260 i8042auxcmd(0xF6);
261 i8042auxcmd(0xEA); /* streaming */
262 i8042auxcmd(0xE8); /* set resolution */
263 i8042auxcmd(3);
264 i8042auxcmd(0xF4); /* enabled */
265 break;
266 }
267 }
268
269 void
270 mousectl(Cmdbuf *cb)
271 {
272 Cmdtab *ct;
273
274 qlock(&mousectlqlock);
275 if(waserror()){
276 qunlock(&mousectlqlock);
277 nexterror();
278 }
279
280 ct = lookupcmd(cb, mousectlmsg, nelem(mousectlmsg));
281 switch(ct->index){
282 case CMaccelerated:
283 setaccelerated(cb->nf == 1 ? 1 : atoi(cb->f[1]));
284 break;
285 case CMintellimouse:
286 setintellimouse();
287 break;
288 case CMlinear:
289 setlinear();
290 break;
291 case CMps2:
292 intellimouse = 0;
293 ps2mouse();
294 break;
295 case CMps2intellimouse:
296 ps2mouse();
297 setintellimouse();
298 break;
299 case CMres:
300 if(cb->nf >= 2)
301 setres(atoi(cb->f[1]));
302 else
303 setres(1);
304 break;
305 case CMreset:
306 resetmouse();
307 if(accelerated)
308 setaccelerated(accelerated);
309 if(resolution)
310 setres(resolution);
311 if(intellimouse)
312 setintellimouse();
313 break;
314 case CMserial:
315 if(mousetype == Mouseserial)
316 error(Emouseset);
317
318 if(cb->nf > 2){
319 if(strcmp(cb->f[2], "M") == 0)
320 i8250mouse(cb->f[1], m3mouseputc, 0);
321 else if(strcmp(cb->f[2], "MI") == 0)
322 i8250mouse(cb->f[1], m5mouseputc, 0);
323 else
324 i8250mouse(cb->f[1], mouseputc, cb->nf == 1);
325 } else
326 i8250mouse(cb->f[1], mouseputc, cb->nf == 1);
327
328 mousetype = Mouseserial;
329 strncpy(mouseport, cb->f[1], sizeof(mouseport)-1);
330 packetsize = 3;
331 break;
332 case CMhwaccel:
333 if(strcmp(cb->f[1], "on")==0)
334 mousehwaccel = 1;
335 else if(strcmp(cb->f[1], "off")==0)
336 mousehwaccel = 0;
337 else
338 cmderror(cb, "bad mouse control message");
339 }
340
341 qunlock(&mousectlqlock);
342 poperror();
343 }
Cache object: 1a23d251b1330db1571fbf1a6d1b71b3
|