mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-11-22 23:50:19 +00:00
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 :^)
This commit is contained in:
parent
a5f895d251
commit
770a729e59
Notes:
sideshowbarker
2024-07-19 00:00:51 +09:00
Author: https://github.com/Quaker762 Commit: https://github.com/SerenityOS/serenity/commit/770a729e597 Pull-request: https://github.com/SerenityOS/serenity/pull/4019 Reviewed-by: https://github.com/Lubrsi Reviewed-by: https://github.com/awesomekling
3 changed files with 65 additions and 1 deletions
|
@ -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<Thread> 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();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -31,6 +31,8 @@
|
|||
#include <Kernel/Devices/USB/UHCIDescriptorTypes.h>
|
||||
#include <Kernel/IO.h>
|
||||
#include <Kernel/PCI/Device.h>
|
||||
#include <Kernel/Process.h>
|
||||
#include <Kernel/Time/TimeManagement.h>
|
||||
#include <Kernel/VM/ContiguousVMObject.h>
|
||||
|
||||
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<u16>(); }
|
||||
u32 read_flbaseadd() { return m_io_base.offset(0x8).in<u32>(); }
|
||||
u8 read_sofmod() { return m_io_base.offset(0xc).in<u8>(); }
|
||||
u16 read_portsc1() { return m_io_base.offset(0x10).in<u16>(); }
|
||||
u16 read_portsc2() { return m_io_base.offset(0x12).in<u16>(); }
|
||||
|
||||
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;
|
||||
|
||||
|
|
|
@ -247,6 +247,7 @@ void init_stage2(void*)
|
|||
}
|
||||
|
||||
USB::UHCIController::detect();
|
||||
USB::UHCIController::the().spawn_port_proc();
|
||||
|
||||
E1000NetworkAdapter::detect();
|
||||
RTL8139NetworkAdapter::detect();
|
||||
|
|
Loading…
Reference in a new issue