mouse.c 6.5 KB

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