From 770a729e597702c0a32855b73dfc11fd8469316e Mon Sep 17 00:00:00 2001 From: Jesse Buhagiar Date: Sun, 3 Jan 2021 00:12:54 +1100 Subject: [PATCH] Kernel/USB: Add basic root port detection/management We can now read/write to the two root ports exposed to the UHCI controller, and detect when a device is plugged in or out via a kernel process that constantly scans the port for any changes. This is very basic, but is a bit of fun to see the kernel detecting hardware on the fly :^) --- Kernel/Devices/USB/UHCIController.cpp | 58 ++++++++++++++++++++++++++- Kernel/Devices/USB/UHCIController.h | 7 ++++ Kernel/init.cpp | 1 + 3 files changed, 65 insertions(+), 1 deletion(-) diff --git a/Kernel/Devices/USB/UHCIController.cpp b/Kernel/Devices/USB/UHCIController.cpp index 372db51729..0d82f7e702 100644 --- a/Kernel/Devices/USB/UHCIController.cpp +++ b/Kernel/Devices/USB/UHCIController.cpp @@ -66,6 +66,18 @@ static constexpr u8 UHCI_USBINTR_SHORT_PACKET_INTR_ENABLE = 0x08; static constexpr u16 UHCI_FRAMELIST_FRAME_COUNT = 1024; // Each entry is 4 bytes in our allocated page static constexpr u16 UHCI_FRAMELIST_FRAME_INVALID = 0x0001; +// Port stuff +static constexpr u8 UHCI_ROOT_PORT_COUNT = 2; +static constexpr u16 UHCI_PORTSC_CURRRENT_CONNECT_STATUS = 0x0001; +static constexpr u16 UHCI_PORTSC_CONNECT_STATUS_CHANGED = 0x0002; +static constexpr u16 UHCI_PORTSC_PORT_ENABLED = 0x0004; +static constexpr u16 UHCI_PORTSC_PORT_ENABLE_CHANGED = 0x0008; +static constexpr u16 UHCI_PORTSC_LINE_STATUS = 0x0030; +static constexpr u16 UHCI_PORTSC_RESUME_DETECT = 0x40; +static constexpr u16 UHCI_PORTSC_LOW_SPEED_DEVICE = 0x0100; +static constexpr u16 UHCI_PORTSC_PORT_RESET = 0x0200; +static constexpr u16 UHCI_PORTSC_SUSPEND = 0x1000; + // *BSD and a few other drivers seem to use this number static constexpr u8 UHCI_NUMBER_OF_ISOCHRONOUS_TDS = 128; static constexpr u16 UHCI_NUMBER_OF_FRAMES = 1024; @@ -338,9 +350,53 @@ void UHCIController::start() klog() << "UHCI: Started!"; } +void UHCIController::spawn_port_proc() +{ + RefPtr usb_hotplug_thread; + timespec sleep_time; + + sleep_time.tv_sec = 1; + Process::create_kernel_process(usb_hotplug_thread, "UHCIHotplug", [sleep_time] { + for (;;) { + for (int port = 0; port < UHCI_ROOT_PORT_COUNT; port++) { + u16 port_data = 0; + + if (port == 1) { + // Let's see what's happening on port 1 + port_data = UHCIController::the().read_portsc1(); + if (port_data & UHCI_PORTSC_CONNECT_STATUS_CHANGED) { + if (port_data & UHCI_PORTSC_CURRRENT_CONNECT_STATUS) { + klog() << "UHCI: Device attach detected on Root Port 1!"; + } else { + klog() << "UHCI: Device detach detected on Root Port 1!"; + } + + UHCIController::the().write_portsc1( + UHCI_PORTSC_CONNECT_STATUS_CHANGED); + } + } else { + port_data = UHCIController::the().read_portsc2(); + if (port_data & UHCI_PORTSC_CONNECT_STATUS_CHANGED) { + if (port_data & UHCI_PORTSC_CURRRENT_CONNECT_STATUS) { + klog() << "UHCI: Device attach detected on Root Port 2!"; + } else { + klog() << "UHCI: Device detach detected on Root Port 2!"; + } + + UHCIController::the().write_portsc2( + UHCI_PORTSC_CONNECT_STATUS_CHANGED); + } + } + } + Thread::current()->sleep(sleep_time); + } + }); +} + void UHCIController::handle_irq(const RegisterState&) { - dbg() << "UHCI: Interrupt happened!"; + klog() << "UHCI: Interrupt happened!"; + klog() << "Value of USBSTS: " << read_usbsts(); } } diff --git a/Kernel/Devices/USB/UHCIController.h b/Kernel/Devices/USB/UHCIController.h index 7f6cf165be..6d721f5c8e 100644 --- a/Kernel/Devices/USB/UHCIController.h +++ b/Kernel/Devices/USB/UHCIController.h @@ -31,6 +31,8 @@ #include #include #include +#include +#include #include namespace Kernel::USB { @@ -45,6 +47,7 @@ public: void reset(); void stop(); void start(); + void spawn_port_proc(); private: UHCIController(PCI::Address, PCI::ID); @@ -55,6 +58,8 @@ private: u16 read_frnum() { return m_io_base.offset(0x6).in(); } u32 read_flbaseadd() { return m_io_base.offset(0x8).in(); } u8 read_sofmod() { return m_io_base.offset(0xc).in(); } + u16 read_portsc1() { return m_io_base.offset(0x10).in(); } + u16 read_portsc2() { return m_io_base.offset(0x12).in(); } void write_usbcmd(u16 value) { m_io_base.offset(0).out(value); } void write_usbsts(u16 value) { m_io_base.offset(0x2).out(value); } @@ -62,6 +67,8 @@ private: void write_frnum(u16 value) { m_io_base.offset(0x6).out(value); } void write_flbaseadd(u32 value) { m_io_base.offset(0x8).out(value); } void write_sofmod(u8 value) { m_io_base.offset(0xc).out(value); } + void write_portsc1(u16 value) { m_io_base.offset(0x10).out(value); } + void write_portsc2(u16 value) { m_io_base.offset(0x12).out(value); } virtual void handle_irq(const RegisterState&) override; diff --git a/Kernel/init.cpp b/Kernel/init.cpp index 8beb09ea94..10df5abf99 100644 --- a/Kernel/init.cpp +++ b/Kernel/init.cpp @@ -247,6 +247,7 @@ void init_stage2(void*) } USB::UHCIController::detect(); + USB::UHCIController::the().spawn_port_proc(); E1000NetworkAdapter::detect(); RTL8139NetworkAdapter::detect();