PS2MouseDevice.cpp 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. #include "PS2MouseDevice.h"
  2. #include "IO.h"
  3. #define IRQ_MOUSE 1
  4. #define I8042_BUFFER 0x60
  5. #define I8042_STATUS 0x64
  6. #define I8042_ACK 0xFA
  7. #define I8042_BUFFER_FULL 0x01
  8. #define I8042_WHICH_BUFFER 0x20
  9. #define I8042_MOUSE_BUFFER 0x20
  10. #define I8042_KEYBOARD_BUFFER 0x00
  11. //#define PS2MOUSE_DEBUG
  12. static PS2MouseDevice* s_the;
  13. PS2MouseDevice::PS2MouseDevice()
  14. : IRQHandler(12)
  15. , CharacterDevice(10, 1)
  16. {
  17. s_the = this;
  18. initialize();
  19. }
  20. PS2MouseDevice::~PS2MouseDevice()
  21. {
  22. }
  23. PS2MouseDevice& PS2MouseDevice::the()
  24. {
  25. return *s_the;
  26. }
  27. void PS2MouseDevice::handle_irq()
  28. {
  29. for (;;) {
  30. byte status = IO::in8(I8042_STATUS);
  31. if (!(((status & I8042_WHICH_BUFFER) == I8042_MOUSE_BUFFER) && (status & I8042_BUFFER_FULL)))
  32. return;
  33. byte data = IO::in8(I8042_BUFFER);
  34. m_data[m_data_state] = data;
  35. switch (m_data_state) {
  36. case 0:
  37. if (!(data & 0x08)) {
  38. dbgprintf("PS2Mouse: Stream out of sync.\n");
  39. break;
  40. }
  41. ++m_data_state;
  42. break;
  43. case 1:
  44. ++m_data_state;
  45. break;
  46. case 2:
  47. m_data_state = 0;
  48. #ifdef PS2MOUSE_DEBUG
  49. dbgprintf("PS2Mouse: %d, %d %s %s (buffered: %u)\n",
  50. m_data[1],
  51. m_data[2],
  52. (m_data[0] & 1) ? "Left" : "",
  53. (m_data[0] & 2) ? "Right" : "",
  54. m_queue.size()
  55. );
  56. #endif
  57. parse_data_packet();
  58. break;
  59. }
  60. }
  61. }
  62. void PS2MouseDevice::parse_data_packet()
  63. {
  64. int x = m_data[1];
  65. int y = m_data[2];
  66. bool x_overflow = m_data[0] & 0x40;
  67. bool y_overflow = m_data[0] & 0x80;
  68. bool x_sign = m_data[0] & 0x10;
  69. bool y_sign = m_data[0] & 0x20;
  70. if (x && x_sign)
  71. x -= 0x100;
  72. if (y && y_sign)
  73. y -= 0x100;
  74. if (x_overflow || y_overflow) {
  75. x = 0;
  76. y = 0;
  77. }
  78. MousePacket packet;
  79. packet.dx = x;
  80. packet.dy = y;
  81. packet.buttons = m_data[0] & 0x07;
  82. m_queue.enqueue(packet);
  83. }
  84. void PS2MouseDevice::wait_then_write(byte port, byte data)
  85. {
  86. prepare_for_output();
  87. IO::out8(port, data);
  88. }
  89. byte PS2MouseDevice::wait_then_read(byte port)
  90. {
  91. prepare_for_input();
  92. return IO::in8(port);
  93. }
  94. void PS2MouseDevice::initialize()
  95. {
  96. // Enable PS aux port
  97. wait_then_write(0x64, 0xa8);
  98. // Enable interrupts
  99. wait_then_write(0x64, 0x20);
  100. // Enable the PS/2 mouse IRQ (12).
  101. // NOTE: The keyboard uses IRQ 1 (and is enabled by bit 0 in this register).
  102. byte status = wait_then_read(0x60) | 2;
  103. wait_then_write(0x64, 0x60);
  104. wait_then_write(0x60, status);
  105. // Set default settings.
  106. mouse_write(0xf6);
  107. byte ack1 = mouse_read();
  108. ASSERT(ack1 == 0xfa);
  109. // Enable.
  110. mouse_write(0xf4);
  111. byte ack2 = mouse_read();
  112. ASSERT(ack2 == 0xfa);
  113. enable_irq();
  114. }
  115. void PS2MouseDevice::prepare_for_input()
  116. {
  117. for (;;) {
  118. if (IO::in8(0x64) & 1)
  119. return;
  120. }
  121. }
  122. void PS2MouseDevice::prepare_for_output()
  123. {
  124. for (;;) {
  125. if (!(IO::in8(0x64) & 2))
  126. return;
  127. }
  128. }
  129. void PS2MouseDevice::mouse_write(byte data)
  130. {
  131. prepare_for_output();
  132. IO::out8(0x64, 0xd4);
  133. prepare_for_output();
  134. IO::out8(0x60, data);
  135. }
  136. byte PS2MouseDevice::mouse_read()
  137. {
  138. prepare_for_input();
  139. return IO::in8(0x60);
  140. }
  141. bool PS2MouseDevice::can_read(FileDescriptor&) const
  142. {
  143. return !m_queue.is_empty();
  144. }
  145. ssize_t PS2MouseDevice::read(FileDescriptor&, byte* buffer, ssize_t size)
  146. {
  147. ssize_t nread = 0;
  148. while (nread < size) {
  149. if (m_queue.is_empty())
  150. break;
  151. // Don't return partial data frames.
  152. if ((size - nread) < (ssize_t)sizeof(MousePacket))
  153. break;
  154. auto packet = m_queue.dequeue();
  155. memcpy(buffer, &packet, sizeof(MousePacket));
  156. nread += sizeof(MousePacket);
  157. }
  158. return nread;
  159. }
  160. ssize_t PS2MouseDevice::write(FileDescriptor&, const byte*, ssize_t)
  161. {
  162. return 0;
  163. }