mouse.c 7.0 KB

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