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 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 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 166 setaccelerated(int x) 167 { 168 accelerated = x; 169 mouseaccelerate(x); 170 } 171 172 static void 173 setlinear(void) 174 { 175 accelerated = 0; 176 mouseaccelerate(0); 177 } 178 179 static void 180 setres(int n) 181 { 182 resolution = n; 183 } 184 185 static void 186 setintellimouse(void) 187 { 188 intellimouse = 1; 189 packetsize = 4; 190 } 191 192 static void 193 resetmouse(void) 194 { 195 packetsize = 3; 196 } 197 198 void 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