mouse.c 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255
  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. shift |= mouseshifted;
  91. m = MACHP(0)->ticks;
  92. if(TK2SEC(m - lasttick) > 2)
  93. nb = 0;
  94. lasttick = m;
  95. if(nb==0 && (c&0xc8)!=0x08)
  96. if(intellimouse && (c==0x00 || c==0x01 || c==0xFF)){
  97. packetsize = 4;
  98. return;
  99. }
  100. msg[nb] = c;
  101. if(++nb == packetsize){
  102. nb = 0;
  103. if(msg[0] & 0x10)
  104. msg[1] |= 0xFF00;
  105. if(msg[0] & 0x20)
  106. msg[2] |= 0xFF00;
  107. buttons = b[(msg[0]&7) | (shift ? 8 : 0)];
  108. if(intellimouse && packetsize==4){
  109. if((msg[3]&0xc8) == 0x08){
  110. packetsize = 3;
  111. msg[0] = msg[3];
  112. nb = 1;
  113. }else{
  114. if((msg[3] >> 3) & 1)
  115. buttons |= 1<<3;
  116. else if(msg[3] & 0x7)
  117. buttons |= 1<<4;
  118. }
  119. }
  120. dx = msg[1];
  121. dy = -msg[2];
  122. mousetrack(dx, dy, buttons, TK2MS(MACHP(0)->ticks));
  123. }
  124. }
  125. /*
  126. * set up a ps2 mouse
  127. */
  128. static void
  129. ps2mouse(void)
  130. {
  131. if(mousetype == MousePS2)
  132. return;
  133. // i8042auxenable(ps2mouseputc);
  134. // i8042auxcmd(0xEA); // TODO
  135. // i8042auxcmd(0xF4);
  136. mousetype = MousePS2;
  137. packetsize = 3;
  138. mousehwaccel = 1;
  139. }
  140. /*
  141. * The PS/2 Trackpoint multiplexor on the IBM Thinkpad T23 ignores
  142. * acceleration commands. It is supposed to pass them on
  143. * to the attached device, but my Logitech mouse is simply
  144. * not behaving any differently. For such devices, we allow
  145. * the user to use "hwaccel off" to tell us to back off to
  146. * software acceleration even if we're using the PS/2 port.
  147. * (Serial mice are always software accelerated.)
  148. * For more information on the Thinkpad multiplexor, see
  149. * http://wwwcssrv.almaden.ibm.com/trackpoint/
  150. */
  151. static void
  152. setaccelerated(int x)
  153. {
  154. accelerated = x;
  155. mouseaccelerate(x);
  156. }
  157. static void
  158. setlinear(void)
  159. {
  160. accelerated = 0;
  161. mouseaccelerate(0);
  162. }
  163. static void
  164. setres(int n)
  165. {
  166. resolution = n;
  167. }
  168. static void
  169. setintellimouse(void)
  170. {
  171. intellimouse = 1;
  172. packetsize = 4;
  173. }
  174. static void
  175. resetmouse(void)
  176. {
  177. packetsize = 3;
  178. }
  179. void
  180. mousectl(Cmdbuf *cb)
  181. {
  182. Cmdtab *ct;
  183. qlock(&mousectlqlock);
  184. if(waserror()){
  185. qunlock(&mousectlqlock);
  186. nexterror();
  187. }
  188. ct = lookupcmd(cb, mousectlmsg, nelem(mousectlmsg));
  189. switch(ct->index){
  190. case CMaccelerated:
  191. setaccelerated(cb->nf == 1? 1: atoi(cb->f[1]));
  192. break;
  193. case CMintellimouse:
  194. setintellimouse();
  195. break;
  196. case CMlinear:
  197. setlinear();
  198. break;
  199. case CMps2:
  200. intellimouse = 0;
  201. break;
  202. case CMps2intellimouse:
  203. setintellimouse();
  204. break;
  205. case CMres:
  206. if(cb->nf >= 2)
  207. setres(atoi(cb->f[1]));
  208. else
  209. setres(1);
  210. break;
  211. case CMreset:
  212. resetmouse();
  213. if(accelerated)
  214. setaccelerated(accelerated);
  215. if(resolution)
  216. setres(resolution);
  217. if(intellimouse)
  218. setintellimouse();
  219. break;
  220. case CMserial:
  221. error("serial mice not supported");
  222. break;
  223. case CMhwaccel:
  224. if(strcmp(cb->f[1], "on")==0)
  225. mousehwaccel = 1;
  226. else if(strcmp(cb->f[1], "off")==0)
  227. mousehwaccel = 0;
  228. else
  229. cmderror(cb, "bad mouse control message");
  230. }
  231. qunlock(&mousectlqlock);
  232. poperror();
  233. }