ps2mouse.c 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250
  1. /* vim: tabstop=4 shiftwidth=4 noexpandtab
  2. * This file is part of ToaruOS and is released under the terms
  3. * of the NCSA / University of Illinois License - see LICENSE.md
  4. * Copyright (C) 2014-2018 K. Lange
  5. *
  6. * Mouse driver
  7. *
  8. */
  9. #include <kernel/system.h>
  10. #include <kernel/logging.h>
  11. #include <kernel/pipe.h>
  12. #include <kernel/module.h>
  13. #include <kernel/mouse.h>
  14. #include <kernel/args.h>
  15. static uint8_t mouse_cycle = 0;
  16. static uint8_t mouse_byte[4];
  17. #define PACKETS_IN_PIPE 1024
  18. #define DISCARD_POINT 32
  19. #define MOUSE_IRQ 12
  20. #define MOUSE_PORT 0x60
  21. #define MOUSE_STATUS 0x64
  22. #define MOUSE_ABIT 0x02
  23. #define MOUSE_BBIT 0x01
  24. #define MOUSE_WRITE 0xD4
  25. #define MOUSE_F_BIT 0x20
  26. #define MOUSE_V_BIT 0x08
  27. #define MOUSE_DEFAULT 0
  28. #define MOUSE_SCROLLWHEEL 1
  29. #define MOUSE_BUTTONS 2
  30. static int8_t mouse_mode = MOUSE_DEFAULT;
  31. static fs_node_t * mouse_pipe;
  32. void (*ps2_mouse_alternate)(void) = NULL;
  33. static void mouse_wait(uint8_t a_type) {
  34. uint32_t timeout = 100000;
  35. if (!a_type) {
  36. while (--timeout) {
  37. if ((inportb(MOUSE_STATUS) & MOUSE_BBIT) == 1) {
  38. return;
  39. }
  40. }
  41. debug_print(INFO, "mouse timeout");
  42. return;
  43. } else {
  44. while (--timeout) {
  45. if (!((inportb(MOUSE_STATUS) & MOUSE_ABIT))) {
  46. return;
  47. }
  48. }
  49. debug_print(INFO, "mouse timeout");
  50. return;
  51. }
  52. }
  53. static void mouse_write(uint8_t write) {
  54. mouse_wait(1);
  55. outportb(MOUSE_STATUS, MOUSE_WRITE);
  56. mouse_wait(1);
  57. outportb(MOUSE_PORT, write);
  58. }
  59. static uint8_t mouse_read(void) {
  60. mouse_wait(0);
  61. char t = inportb(MOUSE_PORT);
  62. return t;
  63. }
  64. static int mouse_handler(struct regs *r) {
  65. uint8_t status = inportb(MOUSE_STATUS);
  66. while ((status & MOUSE_BBIT) && (status & MOUSE_F_BIT)) {
  67. if (ps2_mouse_alternate) {
  68. ps2_mouse_alternate();
  69. break;
  70. }
  71. int8_t mouse_in = inportb(MOUSE_PORT);
  72. switch (mouse_cycle) {
  73. case 0:
  74. mouse_byte[0] = mouse_in;
  75. if (!(mouse_in & MOUSE_V_BIT)) break;
  76. ++mouse_cycle;
  77. break;
  78. case 1:
  79. mouse_byte[1] = mouse_in;
  80. ++mouse_cycle;
  81. break;
  82. case 2:
  83. mouse_byte[2] = mouse_in;
  84. if (mouse_mode == MOUSE_SCROLLWHEEL || mouse_mode == MOUSE_BUTTONS) {
  85. ++mouse_cycle;
  86. break;
  87. }
  88. goto finish_packet;
  89. case 3:
  90. mouse_byte[3] = mouse_in;
  91. goto finish_packet;
  92. }
  93. goto read_next;
  94. finish_packet:
  95. mouse_cycle = 0;
  96. /* We now have a full mouse packet ready to use */
  97. mouse_device_packet_t packet;
  98. packet.magic = MOUSE_MAGIC;
  99. int x = mouse_byte[1];
  100. int y = mouse_byte[2];
  101. if (x && mouse_byte[0] & (1 << 4)) {
  102. /* Sign bit */
  103. x = x - 0x100;
  104. }
  105. if (y && mouse_byte[0] & (1 << 5)) {
  106. /* Sign bit */
  107. y = y - 0x100;
  108. }
  109. if (mouse_byte[0] & (1 << 6) || mouse_byte[0] & (1 << 7)) {
  110. /* Overflow */
  111. x = 0;
  112. y = 0;
  113. }
  114. packet.x_difference = x;
  115. packet.y_difference = y;
  116. packet.buttons = 0;
  117. if (mouse_byte[0] & 0x01) {
  118. packet.buttons |= LEFT_CLICK;
  119. }
  120. if (mouse_byte[0] & 0x02) {
  121. packet.buttons |= RIGHT_CLICK;
  122. }
  123. if (mouse_byte[0] & 0x04) {
  124. packet.buttons |= MIDDLE_CLICK;
  125. }
  126. if (mouse_mode == MOUSE_SCROLLWHEEL && mouse_byte[3]) {
  127. if ((int8_t)mouse_byte[3] > 0) {
  128. packet.buttons |= MOUSE_SCROLL_DOWN;
  129. } else if ((int8_t)mouse_byte[3] < 0) {
  130. packet.buttons |= MOUSE_SCROLL_UP;
  131. }
  132. }
  133. mouse_device_packet_t bitbucket;
  134. while (pipe_size(mouse_pipe) > (int)(DISCARD_POINT * sizeof(packet))) {
  135. read_fs(mouse_pipe, 0, sizeof(packet), (uint8_t *)&bitbucket);
  136. }
  137. write_fs(mouse_pipe, 0, sizeof(packet), (uint8_t *)&packet);
  138. read_next:
  139. break;
  140. }
  141. irq_ack(MOUSE_IRQ);
  142. return 1;
  143. }
  144. static int ioctl_mouse(fs_node_t * node, int request, void * argp) {
  145. if (request == 1) {
  146. mouse_cycle = 0;
  147. return 0;
  148. }
  149. return -1;
  150. }
  151. static int mouse_install(void) {
  152. debug_print(NOTICE, "Initializing PS/2 mouse interface");
  153. uint8_t status, result;
  154. IRQ_OFF;
  155. while ((inportb(0x64) & 1)) {
  156. inportb(0x60);
  157. }
  158. mouse_pipe = make_pipe(sizeof(mouse_device_packet_t) * PACKETS_IN_PIPE);
  159. mouse_wait(1);
  160. outportb(MOUSE_STATUS, 0xA8);
  161. mouse_read();
  162. mouse_wait(1);
  163. outportb(MOUSE_STATUS, 0x20);
  164. mouse_wait(0);
  165. status = inportb(0x60) | 3;
  166. mouse_wait(1);
  167. outportb(MOUSE_STATUS, 0x60);
  168. mouse_wait(1);
  169. outportb(MOUSE_PORT, status);
  170. mouse_write(0xF6);
  171. mouse_read();
  172. mouse_write(0xF4);
  173. mouse_read();
  174. /* Try to enable scroll wheel (but not buttons) */
  175. if (!args_present("nomousescroll")) {
  176. mouse_write(0xF2);
  177. mouse_read();
  178. result = mouse_read();
  179. mouse_write(0xF3);
  180. mouse_read();
  181. mouse_write(200);
  182. mouse_read();
  183. mouse_write(0xF3);
  184. mouse_read();
  185. mouse_write(100);
  186. mouse_read();
  187. mouse_write(0xF3);
  188. mouse_read();
  189. mouse_write(80);
  190. mouse_read();
  191. mouse_write(0xF2);
  192. mouse_read();
  193. result = mouse_read();
  194. if (result == 3) {
  195. mouse_mode = MOUSE_SCROLLWHEEL;
  196. }
  197. }
  198. /* keyboard scancode set */
  199. mouse_wait(1);
  200. outportb(MOUSE_PORT, 0xF0);
  201. mouse_wait(1);
  202. outportb(MOUSE_PORT, 0x02);
  203. mouse_wait(1);
  204. mouse_read();
  205. irq_install_handler(MOUSE_IRQ, mouse_handler, "ps2 mouse");
  206. IRQ_RES;
  207. uint8_t tmp = inportb(0x61);
  208. outportb(0x61, tmp | 0x80);
  209. outportb(0x61, tmp & 0x7F);
  210. inportb(MOUSE_PORT);
  211. while ((inportb(0x64) & 1)) {
  212. inportb(0x60);
  213. }
  214. mouse_pipe->flags = FS_CHARDEVICE;
  215. mouse_pipe->ioctl = ioctl_mouse;
  216. vfs_mount("/dev/mouse", mouse_pipe);
  217. return 0;
  218. }
  219. static int mouse_uninstall(void) {
  220. /* TODO */
  221. return 0;
  222. }
  223. MODULE_DEF(ps2mouse, mouse_install, mouse_uninstall);