mouse.c 6.2 KB

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