I8042Controller.cpp 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266
  1. /*
  2. * Copyright (c) 2020, the SerenityOS developers.
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include <Kernel/Devices/HID/I8042Controller.h>
  7. #include <Kernel/Devices/HID/PS2KeyboardDevice.h>
  8. #include <Kernel/Devices/HID/PS2MouseDevice.h>
  9. #include <Kernel/Devices/HID/VMWareMouseDevice.h>
  10. #include <Kernel/IO.h>
  11. #include <Kernel/Sections.h>
  12. namespace Kernel {
  13. UNMAP_AFTER_INIT NonnullRefPtr<I8042Controller> I8042Controller::initialize()
  14. {
  15. return adopt_ref(*new I8042Controller());
  16. }
  17. RefPtr<MouseDevice> I8042Controller::mouse() const
  18. {
  19. return m_mouse_device;
  20. }
  21. RefPtr<KeyboardDevice> I8042Controller::keyboard() const
  22. {
  23. return m_keyboard_device;
  24. }
  25. UNMAP_AFTER_INIT I8042Controller::I8042Controller()
  26. {
  27. }
  28. UNMAP_AFTER_INIT void I8042Controller::detect_devices()
  29. {
  30. u8 configuration;
  31. {
  32. SpinlockLocker lock(m_lock);
  33. // Disable devices
  34. do_wait_then_write(I8042_STATUS, 0xad);
  35. do_wait_then_write(I8042_STATUS, 0xa7); // ignored if it doesn't exist
  36. // Drain buffers
  37. do_drain();
  38. do_wait_then_write(I8042_STATUS, 0x20);
  39. configuration = do_wait_then_read(I8042_BUFFER);
  40. do_wait_then_write(I8042_STATUS, 0x60);
  41. configuration &= ~3; // Disable IRQs for all
  42. do_wait_then_write(I8042_BUFFER, configuration);
  43. m_is_dual_channel = (configuration & (1 << 5)) != 0;
  44. dbgln("I8042: {} channel controller",
  45. m_is_dual_channel ? "Dual" : "Single");
  46. // Perform controller self-test
  47. do_wait_then_write(I8042_STATUS, 0xaa);
  48. if (do_wait_then_read(I8042_BUFFER) == 0x55) {
  49. // Restore configuration in case the controller reset
  50. do_wait_then_write(I8042_STATUS, 0x60);
  51. do_wait_then_write(I8042_BUFFER, configuration);
  52. } else {
  53. dbgln("I8042: Controller self test failed");
  54. }
  55. // Test ports and enable them if available
  56. do_wait_then_write(I8042_STATUS, 0xab); // test
  57. m_first_port_available = (do_wait_then_read(I8042_BUFFER) == 0);
  58. if (m_first_port_available) {
  59. do_wait_then_write(I8042_STATUS, 0xae); //enable
  60. configuration |= 1;
  61. configuration &= ~(1 << 4);
  62. } else {
  63. dbgln("I8042: Keyboard port not available");
  64. }
  65. if (m_is_dual_channel) {
  66. do_wait_then_write(I8042_STATUS, 0xa9); // test
  67. m_second_port_available = (do_wait_then_read(I8042_BUFFER) == 0);
  68. if (m_second_port_available) {
  69. do_wait_then_write(I8042_STATUS, 0xa8); // enable
  70. configuration |= 2;
  71. configuration &= ~(1 << 5);
  72. } else {
  73. dbgln("I8042: Mouse port not available");
  74. }
  75. }
  76. // Enable IRQs for the ports that are usable
  77. if (m_first_port_available || m_second_port_available) {
  78. configuration &= ~0x30; // renable clocks
  79. do_wait_then_write(I8042_STATUS, 0x60);
  80. do_wait_then_write(I8042_BUFFER, configuration);
  81. }
  82. }
  83. // Try to detect and initialize the devices
  84. if (m_first_port_available) {
  85. m_keyboard_device = PS2KeyboardDevice::try_to_initialize(*this);
  86. if (!m_keyboard_device) {
  87. dbgln("I8042: Keyboard device failed to initialize, disable");
  88. m_first_port_available = false;
  89. configuration &= ~1;
  90. configuration |= 1 << 4;
  91. SpinlockLocker lock(m_lock);
  92. do_wait_then_write(I8042_STATUS, 0x60);
  93. do_wait_then_write(I8042_BUFFER, configuration);
  94. }
  95. }
  96. if (m_second_port_available) {
  97. m_mouse_device = VMWareMouseDevice::try_to_initialize(*this);
  98. if (!m_mouse_device) {
  99. m_mouse_device = PS2MouseDevice::try_to_initialize(*this);
  100. if (!m_mouse_device) {
  101. dbgln("I8042: Mouse device failed to initialize, disable");
  102. m_second_port_available = false;
  103. configuration |= 1 << 5;
  104. SpinlockLocker lock(m_lock);
  105. do_wait_then_write(I8042_STATUS, 0x60);
  106. do_wait_then_write(I8042_BUFFER, configuration);
  107. }
  108. }
  109. }
  110. // Enable IRQs after both are detected and initialized
  111. if (m_keyboard_device)
  112. m_keyboard_device->enable_interrupts();
  113. if (m_mouse_device)
  114. m_mouse_device->enable_interrupts();
  115. }
  116. bool I8042Controller::irq_process_input_buffer(HIDDevice::Type)
  117. {
  118. VERIFY(Processor::current_in_irq());
  119. u8 status = IO::in8(I8042_STATUS);
  120. if (!(status & I8042_BUFFER_FULL))
  121. return false;
  122. HIDDevice::Type data_for_device = ((status & I8042_WHICH_BUFFER) == I8042_MOUSE_BUFFER) ? HIDDevice::Type::Mouse : HIDDevice::Type::Keyboard;
  123. u8 byte = IO::in8(I8042_BUFFER);
  124. if (data_for_device == HIDDevice::Type::Mouse) {
  125. VERIFY(m_mouse_device);
  126. static_cast<PS2MouseDevice&>(*m_mouse_device).irq_handle_byte_read(byte);
  127. return true;
  128. }
  129. if (data_for_device == HIDDevice::Type::Keyboard) {
  130. VERIFY(m_keyboard_device);
  131. static_cast<PS2KeyboardDevice&>(*m_keyboard_device).irq_handle_byte_read(byte);
  132. return true;
  133. }
  134. return false;
  135. }
  136. void I8042Controller::do_drain()
  137. {
  138. for (;;) {
  139. u8 status = IO::in8(I8042_STATUS);
  140. if (!(status & I8042_BUFFER_FULL))
  141. return;
  142. IO::in8(I8042_BUFFER);
  143. }
  144. }
  145. bool I8042Controller::do_reset_device(HIDDevice::Type device)
  146. {
  147. VERIFY(device != HIDDevice::Type::Unknown);
  148. VERIFY(m_lock.is_locked());
  149. VERIFY(!Processor::current_in_irq());
  150. if (do_send_command(device, 0xff) != I8042_ACK)
  151. return false;
  152. // Wait until we get the self-test result
  153. return do_wait_then_read(I8042_BUFFER) == 0xaa;
  154. }
  155. u8 I8042Controller::do_send_command(HIDDevice::Type device, u8 command)
  156. {
  157. VERIFY(device != HIDDevice::Type::Unknown);
  158. VERIFY(m_lock.is_locked());
  159. VERIFY(!Processor::current_in_irq());
  160. return do_write_to_device(device, command);
  161. }
  162. u8 I8042Controller::do_send_command(HIDDevice::Type device, u8 command, u8 data)
  163. {
  164. VERIFY(device != HIDDevice::Type::Unknown);
  165. VERIFY(m_lock.is_locked());
  166. VERIFY(!Processor::current_in_irq());
  167. u8 response = do_write_to_device(device, command);
  168. if (response == I8042_ACK)
  169. response = do_write_to_device(device, data);
  170. return response;
  171. }
  172. u8 I8042Controller::do_write_to_device(HIDDevice::Type device, u8 data)
  173. {
  174. VERIFY(device != HIDDevice::Type::Unknown);
  175. VERIFY(m_lock.is_locked());
  176. VERIFY(!Processor::current_in_irq());
  177. int attempts = 0;
  178. u8 response;
  179. do {
  180. if (device != HIDDevice::Type::Keyboard) {
  181. prepare_for_output();
  182. IO::out8(I8042_STATUS, 0xd4);
  183. }
  184. prepare_for_output();
  185. IO::out8(I8042_BUFFER, data);
  186. response = do_wait_then_read(I8042_BUFFER);
  187. } while (response == I8042_RESEND && ++attempts < 3);
  188. if (attempts >= 3)
  189. dbgln("Failed to write byte to device, gave up");
  190. return response;
  191. }
  192. u8 I8042Controller::do_read_from_device(HIDDevice::Type device)
  193. {
  194. VERIFY(device != HIDDevice::Type::Unknown);
  195. prepare_for_input(device);
  196. return IO::in8(I8042_BUFFER);
  197. }
  198. void I8042Controller::prepare_for_input(HIDDevice::Type device)
  199. {
  200. VERIFY(m_lock.is_locked());
  201. const u8 buffer_type = device == HIDDevice::Type::Keyboard ? I8042_KEYBOARD_BUFFER : I8042_MOUSE_BUFFER;
  202. for (;;) {
  203. u8 status = IO::in8(I8042_STATUS);
  204. if ((status & I8042_BUFFER_FULL) && (device == HIDDevice::Type::Unknown || ((status & I8042_WHICH_BUFFER) == buffer_type)))
  205. return;
  206. }
  207. }
  208. void I8042Controller::prepare_for_output()
  209. {
  210. VERIFY(m_lock.is_locked());
  211. for (;;) {
  212. if (!(IO::in8(I8042_STATUS) & 2))
  213. return;
  214. }
  215. }
  216. void I8042Controller::do_wait_then_write(u8 port, u8 data)
  217. {
  218. VERIFY(m_lock.is_locked());
  219. prepare_for_output();
  220. IO::out8(port, data);
  221. }
  222. u8 I8042Controller::do_wait_then_read(u8 port)
  223. {
  224. VERIFY(m_lock.is_locked());
  225. prepare_for_input(HIDDevice::Type::Unknown);
  226. return IO::in8(port);
  227. }
  228. }