USBHub.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332
  1. /*
  2. * Copyright (c) 2021, Luke Wilde <lukew@serenityos.org>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include <Kernel/Bus/USB/SysFSUSB.h>
  7. #include <Kernel/Bus/USB/USBClasses.h>
  8. #include <Kernel/Bus/USB/USBController.h>
  9. #include <Kernel/Bus/USB/USBHub.h>
  10. #include <Kernel/Bus/USB/USBRequest.h>
  11. #include <Kernel/StdLib.h>
  12. namespace Kernel::USB {
  13. KResultOr<NonnullRefPtr<Hub>> Hub::try_create_root_hub(NonnullRefPtr<USBController> controller, DeviceSpeed device_speed)
  14. {
  15. auto pipe_or_error = Pipe::try_create_pipe(controller, Pipe::Type::Control, Pipe::Direction::Bidirectional, 0, 8, 0);
  16. if (pipe_or_error.is_error())
  17. return pipe_or_error.error();
  18. auto hub = try_make_ref_counted<Hub>(controller, device_speed, pipe_or_error.release_value());
  19. if (!hub)
  20. return ENOMEM;
  21. // NOTE: Enumeration does not happen here, as the controller must know what the device address is at all times during enumeration to intercept requests.
  22. return hub.release_nonnull();
  23. }
  24. KResultOr<NonnullRefPtr<Hub>> Hub::try_create_from_device(Device const& device)
  25. {
  26. auto pipe_or_error = Pipe::try_create_pipe(device.controller(), Pipe::Type::Control, Pipe::Direction::Bidirectional, 0, device.device_descriptor().max_packet_size, device.address());
  27. if (pipe_or_error.is_error())
  28. return pipe_or_error.error();
  29. auto hub = try_make_ref_counted<Hub>(device, pipe_or_error.release_value());
  30. if (!hub)
  31. return ENOMEM;
  32. auto result = hub->enumerate_and_power_on_hub();
  33. if (result.is_error())
  34. return result;
  35. return hub.release_nonnull();
  36. }
  37. Hub::Hub(NonnullRefPtr<USBController> controller, DeviceSpeed device_speed, NonnullOwnPtr<Pipe> default_pipe)
  38. : Device(move(controller), 1 /* Port 1 */, device_speed, move(default_pipe))
  39. {
  40. }
  41. Hub::Hub(Device const& device, NonnullOwnPtr<Pipe> default_pipe)
  42. : Device(device, move(default_pipe))
  43. {
  44. }
  45. KResult Hub::enumerate_and_power_on_hub()
  46. {
  47. // USBDevice::enumerate_device must be called before this.
  48. VERIFY(m_address > 0);
  49. if (m_device_descriptor.device_class != USB_CLASS_HUB) {
  50. dbgln("USB Hub: Trying to enumerate and power on a device that says it isn't a hub.");
  51. return EINVAL;
  52. }
  53. dbgln_if(USB_DEBUG, "USB Hub: Enumerating and powering on for address {}", m_address);
  54. USBHubDescriptor descriptor {};
  55. // Get the first hub descriptor. All hubs are required to have a hub descriptor at index 0. USB 2.0 Specification Section 11.24.2.5.
  56. auto transfer_length_or_error = m_default_pipe->control_transfer(USB_REQUEST_TRANSFER_DIRECTION_DEVICE_TO_HOST | USB_REQUEST_TYPE_CLASS, HubRequest::GET_DESCRIPTOR, (DESCRIPTOR_TYPE_HUB << 8), 0, sizeof(USBHubDescriptor), &descriptor);
  57. if (transfer_length_or_error.is_error())
  58. return transfer_length_or_error.error();
  59. // FIXME: This be "not equal to" instead of "less than", but control transfers report a higher transfer length than expected.
  60. if (transfer_length_or_error.value() < sizeof(USBHubDescriptor)) {
  61. dbgln("USB Hub: Unexpected hub descriptor size. Expected {}, got {}", sizeof(USBHubDescriptor), transfer_length_or_error.value());
  62. return EIO;
  63. }
  64. if constexpr (USB_DEBUG) {
  65. dbgln("USB Hub Descriptor for {:04x}:{:04x}", m_vendor_id, m_product_id);
  66. dbgln("Number of Downstream Ports: {}", descriptor.number_of_downstream_ports);
  67. dbgln("Hub Characteristics: 0x{:04x}", descriptor.hub_characteristics);
  68. dbgln("Power On to Power Good Time: {} ms ({} * 2ms)", descriptor.power_on_to_power_good_time * 2, descriptor.power_on_to_power_good_time);
  69. dbgln("Hub Controller Current: {} mA", descriptor.hub_controller_current);
  70. }
  71. // FIXME: Queue the status change interrupt
  72. // Enable all the ports
  73. for (u8 port_index = 0; port_index < descriptor.number_of_downstream_ports; ++port_index) {
  74. auto result = m_default_pipe->control_transfer(USB_REQUEST_TRANSFER_DIRECTION_HOST_TO_DEVICE | USB_REQUEST_TYPE_CLASS | USB_REQUEST_RECIPIENT_OTHER, HubRequest::SET_FEATURE, HubFeatureSelector::PORT_POWER, port_index + 1, 0, nullptr);
  75. if (result.is_error())
  76. dbgln("USB: Failed to power on port {} on hub at address {}.", port_index + 1, m_address);
  77. }
  78. // Wait for the ports to power up. power_on_to_power_good_time is in units of 2 ms and we want in us, so multiply by 2000.
  79. IO::delay(descriptor.power_on_to_power_good_time * 2000);
  80. memcpy(&m_hub_descriptor, &descriptor, sizeof(USBHubDescriptor));
  81. return KSuccess;
  82. }
  83. // USB 2.0 Specification Section 11.24.2.7
  84. KResult Hub::get_port_status(u8 port, HubStatus& hub_status)
  85. {
  86. // Ports are 1-based.
  87. if (port == 0 || port > m_hub_descriptor.number_of_downstream_ports)
  88. return EINVAL;
  89. auto transfer_length_or_error = m_default_pipe->control_transfer(USB_REQUEST_TRANSFER_DIRECTION_DEVICE_TO_HOST | USB_REQUEST_TYPE_CLASS | USB_REQUEST_RECIPIENT_OTHER, HubRequest::GET_STATUS, 0, port, sizeof(HubStatus), &hub_status);
  90. if (transfer_length_or_error.is_error())
  91. return transfer_length_or_error.error();
  92. // FIXME: This be "not equal to" instead of "less than", but control transfers report a higher transfer length than expected.
  93. if (transfer_length_or_error.value() < sizeof(HubStatus)) {
  94. dbgln("USB Hub: Unexpected hub status size. Expected {}, got {}.", sizeof(HubStatus), transfer_length_or_error.value());
  95. return EIO;
  96. }
  97. return KSuccess;
  98. }
  99. // USB 2.0 Specification Section 11.24.2.2
  100. KResult Hub::clear_port_feature(u8 port, HubFeatureSelector feature_selector)
  101. {
  102. // Ports are 1-based.
  103. if (port == 0 || port > m_hub_descriptor.number_of_downstream_ports)
  104. return EINVAL;
  105. auto result = m_default_pipe->control_transfer(USB_REQUEST_TRANSFER_DIRECTION_HOST_TO_DEVICE | USB_REQUEST_TYPE_CLASS | USB_REQUEST_RECIPIENT_OTHER, HubRequest::CLEAR_FEATURE, feature_selector, port, 0, nullptr);
  106. if (result.is_error())
  107. return result.error();
  108. return KSuccess;
  109. }
  110. // USB 2.0 Specification Section 11.24.2.13
  111. KResult Hub::set_port_feature(u8 port, HubFeatureSelector feature_selector)
  112. {
  113. // Ports are 1-based.
  114. if (port == 0 || port > m_hub_descriptor.number_of_downstream_ports)
  115. return EINVAL;
  116. auto result = m_default_pipe->control_transfer(USB_REQUEST_TRANSFER_DIRECTION_HOST_TO_DEVICE | USB_REQUEST_TYPE_CLASS | USB_REQUEST_RECIPIENT_OTHER, HubRequest::SET_FEATURE, feature_selector, port, 0, nullptr);
  117. if (result.is_error())
  118. return result.error();
  119. return KSuccess;
  120. }
  121. void Hub::remove_children_from_sysfs()
  122. {
  123. for (auto& child : m_children)
  124. SysFSUSBBusDirectory::the().unplug(child);
  125. }
  126. void Hub::check_for_port_updates()
  127. {
  128. for (u8 port_number = 1; port_number < m_hub_descriptor.number_of_downstream_ports + 1; ++port_number) {
  129. dbgln_if(USB_DEBUG, "USB Hub: Checking for port updates on port {}...", port_number);
  130. HubStatus port_status {};
  131. auto result = get_port_status(port_number, port_status);
  132. if (result.is_error()) {
  133. dbgln("USB Hub: Error occurred when getting status for port {}: {}. Checking next port instead.", port_number, result.error());
  134. continue;
  135. }
  136. if (port_status.change & PORT_STATUS_CONNECT_STATUS_CHANGED) {
  137. // Clear the connection status change notification.
  138. result = clear_port_feature(port_number, HubFeatureSelector::C_PORT_CONNECTION);
  139. if (result.is_error()) {
  140. dbgln("USB Hub: Error occurred when clearing port connection change for port {}: {}.", port_number, result.error());
  141. return;
  142. }
  143. if (port_status.status & PORT_STATUS_CURRENT_CONNECT_STATUS) {
  144. dbgln("USB Hub: Device attached to port {}!", port_number);
  145. // Debounce the port. USB 2.0 Specification Page 150
  146. // Debounce interval is 100 ms (100000 us). USB 2.0 Specification Page 188 Table 7-14.
  147. constexpr u32 debounce_interval = 100 * 1000;
  148. // We must check if the device disconnected every so often. If it disconnects, we must reset the debounce timer.
  149. // This doesn't seem to be specified. Let's check every 10ms (10000 us).
  150. constexpr u32 debounce_disconnect_check_interval = 10 * 1000;
  151. u32 debounce_timer = 0;
  152. dbgln_if(USB_DEBUG, "USB Hub: Debouncing...");
  153. // FIXME: Timeout
  154. while (debounce_timer < debounce_interval) {
  155. IO::delay(debounce_disconnect_check_interval);
  156. debounce_timer += debounce_disconnect_check_interval;
  157. result = get_port_status(port_number, port_status);
  158. if (result.is_error()) {
  159. dbgln("USB Hub: Error occurred when getting status while debouncing port {}: {}.", port_number, result.error());
  160. return;
  161. }
  162. if (!(port_status.change & PORT_STATUS_CONNECT_STATUS_CHANGED))
  163. continue;
  164. dbgln_if(USB_DEBUG, "USB Hub: Connection status changed while debouncing, resetting debounce timer.");
  165. debounce_timer = 0;
  166. result = clear_port_feature(port_number, HubFeatureSelector::C_PORT_CONNECTION);
  167. if (result.is_error()) {
  168. dbgln("USB Hub: Error occurred when clearing port connection change while debouncing port {}: {}.", port_number, result.error());
  169. return;
  170. }
  171. }
  172. // Reset the port
  173. dbgln_if(USB_DEBUG, "USB Hub: Debounce finished. Driving reset...");
  174. result = set_port_feature(port_number, HubFeatureSelector::PORT_RESET);
  175. if (result.is_error()) {
  176. dbgln("USB Hub: Error occurred when resetting port {}: {}.", port_number, result.error());
  177. return;
  178. }
  179. // FIXME: Timeout
  180. for (;;) {
  181. // Wait at least 10 ms for the port to reset.
  182. // This is T DRST in the USB 2.0 Specification Page 186 Table 7-13.
  183. constexpr u16 reset_delay = 10 * 1000;
  184. IO::delay(reset_delay);
  185. result = get_port_status(port_number, port_status);
  186. if (result.is_error()) {
  187. dbgln("USB Hub: Error occurred when getting status while resetting port {}: {}.", port_number, result.error());
  188. return;
  189. }
  190. if (port_status.change & PORT_STATUS_RESET_CHANGED)
  191. break;
  192. }
  193. // Stop asserting reset. This also causes the port to become enabled.
  194. result = clear_port_feature(port_number, HubFeatureSelector::C_PORT_RESET);
  195. if (result.is_error()) {
  196. dbgln("USB Hub: Error occurred when resetting port {}: {}.", port_number, result.error());
  197. return;
  198. }
  199. // Wait 10 ms for the port to recover.
  200. // This is T RSTRCY in the USB 2.0 Specification Page 188 Table 7-14.
  201. constexpr u16 reset_recovery_delay = 10 * 1000;
  202. IO::delay(reset_recovery_delay);
  203. dbgln_if(USB_DEBUG, "USB Hub: Reset complete!");
  204. // The port is ready to go. This is where we start communicating with the device to set up a driver for it.
  205. result = get_port_status(port_number, port_status);
  206. if (result.is_error()) {
  207. dbgln("USB Hub: Error occurred when getting status for port {} after reset: {}.", port_number, result.error());
  208. return;
  209. }
  210. // FIXME: Check for high speed.
  211. auto speed = port_status.status & PORT_STATUS_LOW_SPEED_DEVICE_ATTACHED ? USB::Device::DeviceSpeed::LowSpeed : USB::Device::DeviceSpeed::FullSpeed;
  212. auto device_or_error = USB::Device::try_create(m_controller, port_number, speed);
  213. if (device_or_error.is_error()) {
  214. dbgln("USB Hub: Failed to create device for port {}: {}", port_number, device_or_error.error());
  215. return;
  216. }
  217. auto device = device_or_error.release_value();
  218. dbgln_if(USB_DEBUG, "USB Hub: Created device with address {}!", device->address());
  219. if (device->device_descriptor().device_class == USB_CLASS_HUB) {
  220. auto hub_or_error = Hub::try_create_from_device(*device);
  221. if (hub_or_error.is_error()) {
  222. dbgln("USB Hub: Failed to upgrade device to hub for port {}: {}", port_number, device_or_error.error());
  223. return;
  224. }
  225. dbgln_if(USB_DEBUG, "USB Hub: Upgraded device at address {} to hub!", device->address());
  226. auto hub = hub_or_error.release_value();
  227. m_children.append(hub);
  228. SysFSUSBBusDirectory::the().plug(hub);
  229. } else {
  230. m_children.append(device);
  231. SysFSUSBBusDirectory::the().plug(device);
  232. }
  233. } else {
  234. dbgln("USB Hub: Device detached on port {}!", port_number);
  235. RefPtr<Device> device_to_remove = nullptr;
  236. for (auto& child : m_children) {
  237. if (port_number == child.port()) {
  238. device_to_remove = &child;
  239. break;
  240. }
  241. }
  242. if (device_to_remove) {
  243. m_children.remove(*device_to_remove);
  244. SysFSUSBBusDirectory::the().unplug(*device_to_remove);
  245. if (device_to_remove->device_descriptor().device_class == USB_CLASS_HUB) {
  246. auto* hub_child = static_cast<Hub*>(device_to_remove.ptr());
  247. hub_child->remove_children_from_sysfs();
  248. }
  249. } else {
  250. dbgln_if(USB_DEBUG, "USB Hub: No child set up on port {}, ignoring detachment.", port_number);
  251. }
  252. }
  253. }
  254. }
  255. for (auto& child : m_children) {
  256. if (child.device_descriptor().device_class == USB_CLASS_HUB) {
  257. auto& hub_child = static_cast<Hub&>(child);
  258. dbgln_if(USB_DEBUG, "USB Hub: Checking for port updates on child hub at address {}...", child.address());
  259. hub_child.check_for_port_updates();
  260. }
  261. }
  262. }
  263. }