UHCIController.cpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468
  1. /*
  2. * Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
  3. * Copyright (c) 2020, Jesse Buhagiar <jooster669@gmail.com>
  4. * All rights reserved.
  5. *
  6. * Redistribution and use in source and binary forms, with or without
  7. * modification, are permitted provided that the following conditions are met:
  8. *
  9. * 1. Redistributions of source code must retain the above copyright notice, this
  10. * list of conditions and the following disclaimer.
  11. *
  12. * 2. Redistributions in binary form must reproduce the above copyright notice,
  13. * this list of conditions and the following disclaimer in the documentation
  14. * and/or other materials provided with the distribution.
  15. *
  16. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  17. * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  18. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  19. * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
  20. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  21. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  22. * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  23. * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  24. * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  25. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  26. */
  27. #include <Kernel/Debug.h>
  28. #include <Kernel/Devices/USB/UHCIController.h>
  29. #include <Kernel/Process.h>
  30. #include <Kernel/StdLib.h>
  31. #include <Kernel/Time/TimeManagement.h>
  32. #include <Kernel/VM/AnonymousVMObject.h>
  33. #include <Kernel/VM/MemoryManager.h>
  34. #define UHCI_ENABLED 1
  35. static constexpr u8 MAXIMUM_NUMBER_OF_TDS = 128; // Upper pool limit. This consumes the second page we have allocated
  36. static constexpr u8 MAXIMUM_NUMBER_OF_QHS = 64;
  37. namespace Kernel::USB {
  38. static UHCIController* s_the;
  39. static constexpr u16 UHCI_USBCMD_RUN = 0x0001;
  40. static constexpr u16 UHCI_USBCMD_HOST_CONTROLLER_RESET = 0x0002;
  41. static constexpr u16 UHCI_USBCMD_GLOBAL_RESET = 0x0004;
  42. static constexpr u16 UHCI_USBCMD_ENTER_GLOBAL_SUSPEND_MODE = 0x0008;
  43. static constexpr u16 UHCI_USBCMD_FORCE_GLOBAL_RESUME = 0x0010;
  44. static constexpr u16 UHCI_USBCMD_SOFTWARE_DEBUG = 0x0020;
  45. static constexpr u16 UHCI_USBCMD_CONFIGURE_FLAG = 0x0040;
  46. static constexpr u16 UHCI_USBCMD_MAX_PACKET = 0x0080;
  47. static constexpr u16 UHCI_USBSTS_HOST_CONTROLLER_HALTED = 0x0020;
  48. static constexpr u16 UHCI_USBSTS_HOST_CONTROLLER_PROCESS_ERROR = 0x0010;
  49. static constexpr u16 UHCI_USBSTS_PCI_BUS_ERROR = 0x0008;
  50. static constexpr u16 UHCI_USBSTS_RESUME_RECEIVED = 0x0004;
  51. static constexpr u16 UHCI_USBSTS_USB_ERROR_INTERRUPT = 0x0002;
  52. static constexpr u16 UHCI_USBSTS_USB_INTERRUPT = 0x0001;
  53. static constexpr u8 UHCI_USBINTR_TIMEOUT_CRC_ENABLE = 0x01;
  54. static constexpr u8 UHCI_USBINTR_RESUME_INTR_ENABLE = 0x02;
  55. static constexpr u8 UHCI_USBINTR_IOC_ENABLE = 0x04;
  56. static constexpr u8 UHCI_USBINTR_SHORT_PACKET_INTR_ENABLE = 0x08;
  57. static constexpr u16 UHCI_FRAMELIST_FRAME_COUNT = 1024; // Each entry is 4 bytes in our allocated page
  58. static constexpr u16 UHCI_FRAMELIST_FRAME_INVALID = 0x0001;
  59. // Port stuff
  60. static constexpr u8 UHCI_ROOT_PORT_COUNT = 2;
  61. static constexpr u16 UHCI_PORTSC_CURRRENT_CONNECT_STATUS = 0x0001;
  62. static constexpr u16 UHCI_PORTSC_CONNECT_STATUS_CHANGED = 0x0002;
  63. static constexpr u16 UHCI_PORTSC_PORT_ENABLED = 0x0004;
  64. static constexpr u16 UHCI_PORTSC_PORT_ENABLE_CHANGED = 0x0008;
  65. static constexpr u16 UHCI_PORTSC_LINE_STATUS = 0x0030;
  66. static constexpr u16 UHCI_PORTSC_RESUME_DETECT = 0x40;
  67. static constexpr u16 UHCI_PORTSC_LOW_SPEED_DEVICE = 0x0100;
  68. static constexpr u16 UHCI_PORTSC_PORT_RESET = 0x0200;
  69. static constexpr u16 UHCI_PORTSC_SUSPEND = 0x1000;
  70. // *BSD and a few other drivers seem to use this number
  71. static constexpr u8 UHCI_NUMBER_OF_ISOCHRONOUS_TDS = 128;
  72. static constexpr u16 UHCI_NUMBER_OF_FRAMES = 1024;
  73. UHCIController& UHCIController::the()
  74. {
  75. return *s_the;
  76. }
  77. void UHCIController::detect()
  78. {
  79. #if !UHCI_ENABLED
  80. return;
  81. #endif
  82. PCI::enumerate([&](const PCI::Address& address, PCI::ID id) {
  83. if (address.is_null())
  84. return;
  85. if (PCI::get_class(address) == 0xc && PCI::get_subclass(address) == 0x03 && PCI::get_programming_interface(address) == 0) {
  86. if (!s_the)
  87. s_the = new UHCIController(address, id);
  88. }
  89. });
  90. }
  91. UHCIController::UHCIController(PCI::Address address, PCI::ID id)
  92. : PCI::Device(address)
  93. , m_io_base(PCI::get_BAR4(pci_address()) & ~1)
  94. {
  95. dmesgln("UHCI: Controller found {} @ {}", id, address);
  96. dmesgln("UHCI: I/O base {}", m_io_base);
  97. dmesgln("UHCI: Interrupt line: {}", PCI::get_interrupt_line(pci_address()));
  98. reset();
  99. start();
  100. spawn_port_proc();
  101. }
  102. UHCIController::~UHCIController()
  103. {
  104. }
  105. void UHCIController::reset()
  106. {
  107. stop();
  108. write_usbcmd(UHCI_USBCMD_HOST_CONTROLLER_RESET);
  109. // FIXME: Timeout
  110. for (;;) {
  111. if (read_usbcmd() & UHCI_USBCMD_HOST_CONTROLLER_RESET)
  112. continue;
  113. break;
  114. }
  115. // Let's allocate the physical page for the Frame List (which is 4KiB aligned)
  116. auto framelist_vmobj = ContiguousVMObject::create_with_size(PAGE_SIZE);
  117. m_framelist = MemoryManager::the().allocate_kernel_region_with_vmobject(*framelist_vmobj, PAGE_SIZE, "UHCI Framelist", Region::Access::Write);
  118. klog() << "UHCI: Allocated framelist at physical address " << m_framelist->physical_page(0)->paddr();
  119. klog() << "UHCI: Framelist is at virtual address " << m_framelist->vaddr();
  120. write_sofmod(64); // 1mS frame time
  121. create_structures();
  122. setup_schedule();
  123. write_flbaseadd(m_framelist->physical_page(0)->paddr().get()); // Frame list (physical) address
  124. write_frnum(0); // Set the initial frame number
  125. // Enable all interrupt types
  126. write_frnum(UHCI_USBINTR_TIMEOUT_CRC_ENABLE | UHCI_USBINTR_RESUME_INTR_ENABLE | UHCI_USBINTR_IOC_ENABLE | UHCI_USBINTR_SHORT_PACKET_INTR_ENABLE);
  127. klog() << "UHCI: Reset completed!";
  128. }
  129. void UHCIController::create_structures()
  130. {
  131. // Let's allocate memory for botht the QH and TD pools
  132. // First the QH pool and all of the Interrupt QH's
  133. auto qh_pool_vmobject = ContiguousVMObject::create_with_size(2 * PAGE_SIZE);
  134. m_qh_pool = MemoryManager::the().allocate_kernel_region_with_vmobject(*qh_pool_vmobject, 2 * PAGE_SIZE, "UHCI Queue Head Pool", Region::Access::Write);
  135. memset(m_qh_pool->vaddr().as_ptr(), 0, 2 * PAGE_SIZE); // Zero out both pages
  136. // Let's populate our free qh list (so we have some we can allocate later on)
  137. m_free_qh_pool.resize(MAXIMUM_NUMBER_OF_TDS);
  138. for (size_t i = 0; i < m_free_qh_pool.size(); i++) {
  139. auto placement_addr = reinterpret_cast<void*>(m_qh_pool->vaddr().get() + (i * sizeof(QueueHead)));
  140. auto paddr = static_cast<u32>(m_qh_pool->physical_page(0)->paddr().get() + (i * sizeof(QueueHead)));
  141. m_free_qh_pool.at(i) = new (placement_addr) QueueHead(paddr);
  142. }
  143. // Create the Full Speed, Low Speed Control and Bulk Queue Heads
  144. m_interrupt_transfer_queue = allocate_queue_head();
  145. m_lowspeed_control_qh = allocate_queue_head();
  146. m_fullspeed_control_qh = allocate_queue_head();
  147. m_bulk_qh = allocate_queue_head();
  148. m_dummy_qh = allocate_queue_head();
  149. // Now the Transfer Descriptor pool
  150. auto td_pool_vmobject = ContiguousVMObject::create_with_size(2 * PAGE_SIZE);
  151. m_td_pool = MemoryManager::the().allocate_kernel_region_with_vmobject(*td_pool_vmobject, 2 * PAGE_SIZE, "UHCI Transfer Descriptor Pool", Region::Access::Write);
  152. memset(m_td_pool->vaddr().as_ptr(), 0, 2 * PAGE_SIZE);
  153. // Set up the Isochronous Transfer Descriptor list
  154. m_iso_td_list.resize(UHCI_NUMBER_OF_ISOCHRONOUS_TDS);
  155. for (size_t i = 0; i < m_iso_td_list.size(); i++) {
  156. auto placement_addr = reinterpret_cast<void*>(m_td_pool->vaddr().get() + (i * sizeof(Kernel::USB::TransferDescriptor)));
  157. auto paddr = static_cast<u32>(m_td_pool->physical_page(0)->paddr().get() + (i * sizeof(Kernel::USB::TransferDescriptor)));
  158. // Place a new Transfer Descriptor with a 1:1 in our region
  159. // The pointer returned by `new()` lines up exactly with the value
  160. // that we store in `paddr`, meaning our member functions directly
  161. // access the raw descriptor (that we later send to the controller)
  162. m_iso_td_list.at(i) = new (placement_addr) Kernel::USB::TransferDescriptor(paddr);
  163. auto transfer_descriptor = m_iso_td_list.at(i);
  164. transfer_descriptor->set_in_use(true); // Isochronous transfers are ALWAYS marked as in use (in case we somehow get allocated one...)
  165. transfer_descriptor->set_isochronous();
  166. transfer_descriptor->link_queue_head(m_interrupt_transfer_queue->paddr());
  167. #if UHCI_VERBOSE_DEBUG
  168. transfer_descriptor->print();
  169. #endif
  170. }
  171. m_free_td_pool.resize(MAXIMUM_NUMBER_OF_TDS);
  172. for (size_t i = 0; i < m_free_td_pool.size(); i++) {
  173. auto placement_addr = reinterpret_cast<void*>(m_td_pool->vaddr().offset(PAGE_SIZE).get() + (i * sizeof(Kernel::USB::TransferDescriptor)));
  174. auto paddr = static_cast<u32>(m_td_pool->physical_page(1)->paddr().get() + (i * sizeof(Kernel::USB::TransferDescriptor)));
  175. // Place a new Transfer Descriptor with a 1:1 in our region
  176. // The pointer returned by `new()` lines up exactly with the value
  177. // that we store in `paddr`, meaning our member functions directly
  178. // access the raw descriptor (that we later send to the controller)
  179. m_free_td_pool.at(i) = new (placement_addr) Kernel::USB::TransferDescriptor(paddr);
  180. #if UHCI_VERBOSE_DEBUG
  181. auto transfer_descriptor = m_free_td_pool.at(i);
  182. transfer_descriptor->print();
  183. #endif
  184. }
  185. #if UHCI_DEBUG
  186. klog() << "UHCI: Pool information:";
  187. klog() << "\tqh_pool: " << PhysicalAddress(m_qh_pool->physical_page(0)->paddr()) << ", length: " << m_qh_pool->range().size();
  188. klog() << "\ttd_pool: " << PhysicalAddress(m_td_pool->physical_page(0)->paddr()) << ", length: " << m_td_pool->range().size();
  189. #endif
  190. }
  191. void UHCIController::setup_schedule()
  192. {
  193. //
  194. // https://github.com/alkber/minix3-usbsubsystem/blob/master/usb/uhci-hcd.c
  195. //
  196. // This lad probably has the best explanation as to how this is actually done. I'll try and
  197. // explain it here to so that there's no need for anyone to go hunting for this shit again, because
  198. // the USB spec and Intel explain next to nothing.
  199. // According to the USB spec (and the UHCI datasheet), 90% of the bandwidth should be used for
  200. // Isochronous and """Interrupt""" related transfers, with the rest being used for control and bulk
  201. // transfers.
  202. // That is, most of the time, the schedule is going to be executing either an Isochronous transfer
  203. // in our framelist, or an Interrupt transfer. The allocation in `create_structures` reflects this.
  204. //
  205. // Each frame has it's own Isochronous transfer Transfer Descriptor(s) that point to each other
  206. // horizontally in the list. The end of these transfers then point to the Interrupt Queue Headers,
  207. // in which we can attach Transfer Descriptors (related to Interrupt Transfers). These are attached
  208. // to the Queue Head _vertically_. We need to ensure that these are executed every 8ms, so they are inserted
  209. // at different points in the schedule (TODO: How do we do this?!?!). After the Interrupt Transfer Queue Heads,
  210. // we attach the Control Queue Heads. We need two in total, one for Low Speed devices, and one for Full Speed
  211. // USB devices. Finally, we attach the Bulk Transfer Queue Head.
  212. // Not specified in the datasheet, however, is another Queue Head with an "inactive" Transfer Descriptor. This
  213. // is to circumvent a bug in the silicon of the PIIX4's UHCI controller.
  214. // https://github.com/openbsd/src/blob/master/sys/dev/usb/uhci.c#L390
  215. //
  216. m_interrupt_transfer_queue->link_next_queue_head(m_lowspeed_control_qh);
  217. m_interrupt_transfer_queue->terminate_element_link_ptr();
  218. m_lowspeed_control_qh->link_next_queue_head(m_fullspeed_control_qh);
  219. m_lowspeed_control_qh->terminate_element_link_ptr();
  220. m_fullspeed_control_qh->link_next_queue_head(m_bulk_qh);
  221. m_fullspeed_control_qh->terminate_element_link_ptr();
  222. m_bulk_qh->link_next_queue_head(m_dummy_qh);
  223. m_bulk_qh->terminate_element_link_ptr();
  224. auto piix4_td_hack = allocate_transfer_descriptor();
  225. piix4_td_hack->terminate();
  226. piix4_td_hack->set_max_len(0x7ff); // Null data packet
  227. piix4_td_hack->set_device_address(0x7f);
  228. piix4_td_hack->set_packet_id(PacketID::IN);
  229. m_dummy_qh->terminate_with_stray_descriptor(piix4_td_hack);
  230. m_dummy_qh->terminate_element_link_ptr();
  231. u32* framelist = reinterpret_cast<u32*>(m_framelist->vaddr().as_ptr());
  232. for (int frame = 0; frame < UHCI_NUMBER_OF_FRAMES; frame++) {
  233. // Each frame pointer points to iso_td % NUM_ISO_TDS
  234. framelist[frame] = m_iso_td_list.at(frame % UHCI_NUMBER_OF_ISOCHRONOUS_TDS)->paddr();
  235. // klog() << PhysicalAddress(framelist[frame]);
  236. }
  237. m_interrupt_transfer_queue->print();
  238. m_lowspeed_control_qh->print();
  239. m_fullspeed_control_qh->print();
  240. m_bulk_qh->print();
  241. m_dummy_qh->print();
  242. }
  243. QueueHead* UHCIController::allocate_queue_head() const
  244. {
  245. for (QueueHead* queue_head : m_free_qh_pool) {
  246. if (!queue_head->in_use()) {
  247. queue_head->set_in_use(true);
  248. #if UHCI_DEBUG
  249. klog() << "UHCI: Allocated a new Queue Head! Located @ " << VirtualAddress(queue_head) << "(" << PhysicalAddress(queue_head->paddr()) << ")";
  250. #endif
  251. return queue_head;
  252. }
  253. }
  254. ASSERT_NOT_REACHED(); // Let's just assert for now, this should never happen
  255. return nullptr; // Huh!? We're outta queue heads!
  256. }
  257. TransferDescriptor* UHCIController::allocate_transfer_descriptor() const
  258. {
  259. for (TransferDescriptor* transfer_descriptor : m_free_td_pool) {
  260. if (!transfer_descriptor->in_use()) {
  261. transfer_descriptor->set_in_use(true);
  262. #if UHCI_DEBUG
  263. klog() << "UHCI: Allocated a new Transfer Descriptor! Located @ " << VirtualAddress(transfer_descriptor) << "(" << PhysicalAddress(transfer_descriptor->paddr()) << ")";
  264. #endif
  265. return transfer_descriptor;
  266. }
  267. }
  268. ASSERT_NOT_REACHED(); // Let's just assert for now, this should never happen
  269. return nullptr; // Huh?! We're outta TDs!!
  270. }
  271. void UHCIController::stop()
  272. {
  273. write_usbcmd(read_usbcmd() & ~UHCI_USBCMD_RUN);
  274. // FIXME: Timeout
  275. for (;;) {
  276. if (read_usbsts() & UHCI_USBSTS_HOST_CONTROLLER_HALTED)
  277. break;
  278. }
  279. }
  280. void UHCIController::start()
  281. {
  282. write_usbcmd(read_usbcmd() | UHCI_USBCMD_RUN);
  283. // FIXME: Timeout
  284. for (;;) {
  285. if (!(read_usbsts() & UHCI_USBSTS_HOST_CONTROLLER_HALTED))
  286. break;
  287. }
  288. klog() << "UHCI: Started!";
  289. }
  290. struct setup_packet {
  291. u8 bmRequestType;
  292. u8 bRequest;
  293. u16 wValue;
  294. u16 wIndex;
  295. u16 wLength;
  296. };
  297. void UHCIController::do_debug_transfer()
  298. {
  299. klog() << "UHCI: Attempting a dummy transfer...";
  300. // Okay, let's set up the buffer so we can write some data
  301. auto vmobj = ContiguousVMObject::create_with_size(PAGE_SIZE);
  302. m_td_buffer_region = MemoryManager::the().allocate_kernel_region_with_vmobject(*vmobj, PAGE_SIZE, "UHCI Debug Data Region", Region::Access::Write);
  303. // We need to set up THREE Transfer descriptors here
  304. // 1. The SETUP packet TD
  305. // 2. The DATA packet
  306. // 3. The ACK TD that will be filled by the device
  307. // We can use the buffer pool provided above to do this, using nasty pointer offsets!
  308. auto setup_td = allocate_transfer_descriptor();
  309. auto data_td = allocate_transfer_descriptor();
  310. auto response_td = allocate_transfer_descriptor();
  311. dbgln("BUFFER PHYSICAL ADDRESS = {}", m_td_buffer_region->physical_page(0)->paddr());
  312. setup_packet* packet = reinterpret_cast<setup_packet*>(m_td_buffer_region->vaddr().as_ptr());
  313. packet->bmRequestType = 0x81;
  314. packet->bRequest = 0x06;
  315. packet->wValue = 0x2200;
  316. packet->wIndex = 0x0;
  317. packet->wLength = 8;
  318. // Let's begin....
  319. setup_td->set_status(0x18800000);
  320. setup_td->set_token(0x00E0002D);
  321. setup_td->set_buffer_address(m_td_buffer_region->physical_page(0)->paddr().get());
  322. data_td->set_status(0x18800000);
  323. data_td->set_token(0x00E80069);
  324. data_td->set_buffer_address(m_td_buffer_region->physical_page(0)->paddr().get() + 16);
  325. response_td->set_status(0x19800000);
  326. response_td->set_token(0xFFE800E1);
  327. setup_td->insert_next_transfer_descriptor(data_td);
  328. data_td->insert_next_transfer_descriptor(response_td);
  329. response_td->terminate();
  330. setup_td->print();
  331. data_td->print();
  332. response_td->print();
  333. // Now let's (attempt) to attach to one of the queue heads
  334. m_lowspeed_control_qh->attach_transfer_descriptor_chain(setup_td);
  335. }
  336. void UHCIController::spawn_port_proc()
  337. {
  338. RefPtr<Thread> usb_hotplug_thread;
  339. timespec sleep_time {};
  340. sleep_time.tv_sec = 1;
  341. Process::create_kernel_process(usb_hotplug_thread, "UHCIHotplug", [&, sleep_time] {
  342. for (;;) {
  343. for (int port = 0; port < UHCI_ROOT_PORT_COUNT; port++) {
  344. u16 port_data = 0;
  345. if (port == 1) {
  346. // Let's see what's happening on port 1
  347. // Current status
  348. port_data = read_portsc1();
  349. if (port_data & UHCI_PORTSC_CONNECT_STATUS_CHANGED) {
  350. if (port_data & UHCI_PORTSC_CURRRENT_CONNECT_STATUS) {
  351. dmesgln("UHCI: Device attach detected on Root Port 1!");
  352. // Reset the port
  353. port_data = read_portsc1();
  354. write_portsc1(port_data | UHCI_PORTSC_PORT_RESET);
  355. for (size_t i = 0; i < 50000; ++i)
  356. IO::in8(0x80);
  357. write_portsc1(port_data & ~UHCI_PORTSC_PORT_RESET);
  358. for (size_t i = 0; i < 100000; ++i)
  359. IO::in8(0x80);
  360. write_portsc1(port_data & (~UHCI_PORTSC_PORT_ENABLE_CHANGED | ~UHCI_PORTSC_CONNECT_STATUS_CHANGED));
  361. } else {
  362. dmesgln("UHCI: Device detach detected on Root Port 1!");
  363. }
  364. port_data = read_portsc1();
  365. write_portsc1(port_data | UHCI_PORTSC_PORT_ENABLED);
  366. dbgln("port should be enabled now: {:#04x}\n", read_portsc1());
  367. do_debug_transfer();
  368. }
  369. } else {
  370. port_data = UHCIController::the().read_portsc2();
  371. if (port_data & UHCI_PORTSC_CONNECT_STATUS_CHANGED) {
  372. if (port_data & UHCI_PORTSC_CURRRENT_CONNECT_STATUS) {
  373. dmesgln("UHCI: Device attach detected on Root Port 2!");
  374. } else {
  375. dmesgln("UHCI: Device detach detected on Root Port 2!");
  376. }
  377. UHCIController::the().write_portsc2(
  378. UHCI_PORTSC_CONNECT_STATUS_CHANGED);
  379. }
  380. }
  381. }
  382. (void)Thread::current()->sleep(sleep_time);
  383. }
  384. });
  385. }
  386. void UHCIController::handle_irq(const RegisterState&)
  387. {
  388. // Shared IRQ. Not ours!
  389. if (!read_usbsts())
  390. return;
  391. if constexpr (UHCI_DEBUG) {
  392. dbgln("UHCI: Interrupt happened!");
  393. dbgln("Value of USBSTS: {:#04x}", read_usbsts());
  394. }
  395. }
  396. }