]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/pc/mouse.c
sdide: never timeout or retry scsi commands from the controller driver
[plan9front.git] / sys / src / 9 / 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 static QLock mousectlqlock;
26 static int mousetype;
27 static int intellimouse;
28 static int packetsize;
29 static int resolution;
30 static int accelerated;
31 static int mousehwaccel;
32 static char mouseport[5];
33
34 enum
35 {
36         CMaccelerated,
37         CMhwaccel,
38         CMintellimouse,
39         CMlinear,
40         CMps2,
41         CMps2intellimouse,
42         CMres,
43         CMreset,
44         CMserial,
45 };
46
47 static Cmdtab mousectlmsg[] =
48 {
49         CMaccelerated,          "accelerated",          0,
50         CMhwaccel,              "hwaccel",              2,
51         CMintellimouse,         "intellimouse",         1,
52         CMlinear,               "linear",               1,
53         CMps2,                  "ps2",                  1,
54         CMps2intellimouse,      "ps2intellimouse",      1,
55         CMres,                  "res",                  0,
56         CMreset,                "reset",                1,
57         CMserial,               "serial",               0,
58 };
59
60 /*
61  *  ps/2 mouse message is three bytes
62  *
63  *      byte 0 -        0 0 SDY SDX 1 M R L
64  *      byte 1 -        DX
65  *      byte 2 -        DY
66  *
67  *  shift & right button is the same as middle button
68  *
69  * Intellimouse and AccuPoint with extra buttons deliver
70  *      byte 3 -        00 or 01 or FF according to extra button state.
71  * extra buttons are mapped in this code to buttons 4 and 5.
72  * AccuPoint generates repeated events for these buttons;
73 *  it and Intellimouse generate 'down' events only, so
74  * user-level code is required to generate button 'up' events
75  * if they are needed by the application.
76  * Also on laptops with AccuPoint AND external mouse, the
77  * controller may deliver 3 or 4 bytes according to the type
78  * of the external mouse; code must adapt.
79  *
80  * On the NEC Versa series (and perhaps others?) we seem to
81  * lose a byte from the packet every once in a while, which
82  * means we lose where we are in the instruction stream.
83  * To resynchronize, if we get a byte more than two seconds
84  * after the previous byte, we assume it's the first in a packet.
85  */
86 static void
87 ps2mouseputc(int c, int shift)
88 {
89         static short msg[4];
90         static int nb;
91         static uchar b[] = {0, 1, 4, 5, 2, 3, 6, 7, 0, 1, 2, 3, 2, 3, 6, 7 };
92         static ulong lasttick;
93         ulong m;
94         int buttons, dx, dy;
95
96         /*
97          * Resynchronize in stream with timing; see comment above.
98          */
99         m = MACHP(0)->ticks;
100         if(TK2SEC(m - lasttick) > 2)
101                 nb = 0;
102         lasttick = m;
103
104         /* 
105          *  check byte 0 for consistency
106          */
107         if(nb==0 && (c&0xc8)!=0x08){
108                 if(intellimouse && (c==0x00 || c==0x01 || c==0xFF)){
109                         /* last byte of 4-byte packet */
110                         packetsize = 4;
111                 }
112                 return;
113         }
114
115         msg[nb] = c;
116         if(++nb == packetsize){
117                 nb = 0;
118                 if(msg[0] & 0x10)
119                         msg[1] |= 0xFF00;
120                 if(msg[0] & 0x20)
121                         msg[2] |= 0xFF00;
122
123                 buttons = b[(msg[0]&7) | (shift ? 8 : 0)];
124                 if(intellimouse && packetsize==4){
125                         if((msg[3]&0xc8) == 0x08){
126                                 /* first byte of 3-byte packet */
127                                 packetsize = 3;
128                                 msg[0] = msg[3];
129                                 nb = 1;
130                                 /* fall through to emit previous packet */
131                         }else{
132                                 /* The AccuPoint on the Toshiba 34[48]0CT
133                                  * encodes extra buttons as 4 and 5. They repeat
134                                  * and don't release, however, so user-level
135                                  * timing code is required. Furthermore,
136                                  * intellimice with 3buttons + scroll give a
137                                  * two's complement number in the lower 4 bits
138                                  * (bit 4 is sign extension) that describes
139                                  * the amount the scroll wheel has moved during
140                                  * the last sample. Here we use only the sign to
141                                  * decide whether the wheel is moving up or down
142                                  * and generate a single button 4 or 5 click
143                                  * accordingly.
144                                  */
145                                 if((msg[3] >> 3) & 1) 
146                                         buttons |= 1<<3;
147                                 else if(msg[3] & 0x7) 
148                                         buttons |= 1<<4;
149                         }
150                 }
151                 dx = msg[1];
152                 dy = -msg[2];
153                 mousetrack(dx, dy, buttons, TK2MS(MACHP(0)->ticks));
154         }
155         return;
156 }
157
158 /*
159  *  set up a ps2 mouse
160  */
161 static void
162 ps2mouse(void)
163 {
164         if(mousetype == MousePS2)
165                 return;
166
167         i8042auxenable(ps2mouseputc);
168         i8042auxcmd(0xEA);      /* set stream mode */
169
170         mousetype = MousePS2;
171         packetsize = 3;
172         mousehwaccel = 0;
173 }
174
175 /*
176  * The PS/2 Trackpoint multiplexor on the IBM Thinkpad T23 ignores
177  * acceleration commands.  It is supposed to pass them on
178  * to the attached device, but my Logitech mouse is simply
179  * not behaving any differently.  For such devices, we allow
180  * the user to use "hwaccel off" to tell us to back off to
181  * software acceleration even if we're using the PS/2 port.
182  * (Serial mice are always software accelerated.)
183  * For more information on the Thinkpad multiplexor, see
184  * http://wwwcssrv.almaden.ibm.com/trackpoint/
185  */
186 static void
187 setaccelerated(int x)
188 {
189         accelerated = x;
190         if(mousehwaccel){
191                 switch(mousetype){
192                 case MousePS2:
193                         i8042auxcmd(0xE7);
194                         return;
195                 }
196         }
197         mouseaccelerate(x);
198 }
199
200 static void
201 setlinear(void)
202 {
203         accelerated = 0;
204         if(mousehwaccel){
205                 switch(mousetype){
206                 case MousePS2:
207                         i8042auxcmd(0xE6);
208                         return;
209                 }
210         }
211         mouseaccelerate(0);
212 }
213
214 static void
215 setres(int n)
216 {
217         resolution = n;
218         switch(mousetype){
219         case MousePS2:
220                 i8042auxcmd(0xE8);
221                 i8042auxcmd(n);
222                 break;
223         }
224 }
225
226 static void
227 setintellimouse(void)
228 {
229         intellimouse = 1;
230         packetsize = 4;
231         switch(mousetype){
232         case MousePS2:
233                 i8042auxcmd(0xF3);      /* set sample */
234                 i8042auxcmd(0xC8);
235                 i8042auxcmd(0xF3);      /* set sample */
236                 i8042auxcmd(0x64);
237                 i8042auxcmd(0xF3);      /* set sample */
238                 i8042auxcmd(0x50);
239                 break;
240         case Mouseserial:
241                 uartsetmouseputc(mouseport, m5mouseputc);
242                 break;
243         }
244 }
245
246 static void
247 resetmouse(void)
248 {
249         packetsize = 3;
250         switch(mousetype){
251         case MousePS2:
252                 i8042auxcmd(0xF6);
253                 i8042auxcmd(0xEA);      /* streaming */
254                 i8042auxcmd(0xE8);      /* set resolution */
255                 i8042auxcmd(3);
256                 break;
257         }
258 }
259
260 static void
261 setstream(int on)
262 {
263         int i;
264
265         switch(mousetype){
266         case MousePS2:
267                 /*
268                  * disabling streaming can fail when
269                  * a packet is currently transmitted.
270                  */
271                 for(i=0; i<4; i++){
272                         if(i8042auxcmd(on ? 0xF4 : 0xF5) != -1)
273                                 break;
274                         delay(50);
275                 }
276                 break;
277         }
278 }
279
280 void
281 mousectl(Cmdbuf *cb)
282 {
283         Cmdtab *ct;
284
285         qlock(&mousectlqlock);
286         if(waserror()){
287                 qunlock(&mousectlqlock);
288                 nexterror();
289         }
290
291         ct = lookupcmd(cb, mousectlmsg, nelem(mousectlmsg));
292         switch(ct->index){
293         case CMaccelerated:
294                 setstream(0);
295                 setaccelerated(cb->nf == 1 ? 1 : atoi(cb->f[1]));
296                 setstream(1);
297                 break;
298         case CMintellimouse:
299                 setstream(0);
300                 setintellimouse();
301                 setstream(1);
302                 break;
303         case CMlinear:
304                 setstream(0);
305                 setlinear();
306                 setstream(1);
307                 break;
308         case CMps2:
309                 intellimouse = 0;
310                 ps2mouse();
311                 setstream(1);
312                 break;
313         case CMps2intellimouse:
314                 ps2mouse();
315                 setintellimouse();
316                 setstream(1);
317                 break;
318         case CMres:
319                 setstream(0);
320                 if(cb->nf >= 2)
321                         setres(atoi(cb->f[1]));
322                 else
323                         setres(1);
324                 setstream(1);
325                 break;
326         case CMreset:
327                 resetmouse();
328                 if(accelerated)
329                         setaccelerated(accelerated);
330                 if(resolution)
331                         setres(resolution);
332                 if(intellimouse)
333                         setintellimouse();
334                 setstream(1);
335                 break;
336         case CMserial:
337                 if(mousetype == Mouseserial)
338                         error(Emouseset);
339
340                 if(cb->nf > 2){
341                         if(strcmp(cb->f[2], "M") == 0)
342                                 uartmouse(cb->f[1], m3mouseputc, 0);
343                         else if(strcmp(cb->f[2], "MI") == 0)
344                                 uartmouse(cb->f[1], m5mouseputc, 0);
345                         else
346                                 uartmouse(cb->f[1], mouseputc, cb->nf == 1);
347                 } else
348                         uartmouse(cb->f[1], mouseputc, cb->nf == 1);
349
350                 mousetype = Mouseserial;
351                 strncpy(mouseport, cb->f[1], sizeof(mouseport)-1);
352                 mouseport[sizeof(mouseport)-1] = 0;
353                 packetsize = 3;
354                 break;
355         case CMhwaccel:
356                 if(strcmp(cb->f[1], "on")==0)
357                         mousehwaccel = 1;
358                 else if(strcmp(cb->f[1], "off")==0)
359                         mousehwaccel = 0;
360                 else
361                         cmderror(cb, "bad mouse control message");
362         }
363
364         qunlock(&mousectlqlock);
365         poperror();
366 }