From e834c24eea2ca87e35f4c0f8c9bbdf007d859372 Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Fri, 4 Sep 2020 09:59:38 +0200 Subject: [PATCH] Kernel/USB: Start fleshing out a basic UHCI controller driver :^) Let's see if we can talk to some USB devices. We will now detect a UHCI controller if present on the PCI bus. --- Kernel/CMakeLists.txt | 1 + Kernel/Devices/UHCIController.cpp | 77 +++++++++++++++++++++++++++++++ Kernel/Devices/UHCIController.h | 66 ++++++++++++++++++++++++++ Kernel/init.cpp | 3 ++ Meta/run.sh | 2 + 5 files changed, 149 insertions(+) create mode 100644 Kernel/Devices/UHCIController.cpp create mode 100644 Kernel/Devices/UHCIController.h diff --git a/Kernel/CMakeLists.txt b/Kernel/CMakeLists.txt index 592d4b9430..1b7d04e10e 100644 --- a/Kernel/CMakeLists.txt +++ b/Kernel/CMakeLists.txt @@ -33,6 +33,7 @@ set(KERNEL_SOURCES Devices/RandomDevice.cpp Devices/SB16.cpp Devices/SerialDevice.cpp + Devices/UHCIController.cpp Devices/VMWareBackdoor.cpp Devices/ZeroDevice.cpp DoubleBuffer.cpp diff --git a/Kernel/Devices/UHCIController.cpp b/Kernel/Devices/UHCIController.cpp new file mode 100644 index 0000000000..5b1b118cb1 --- /dev/null +++ b/Kernel/Devices/UHCIController.cpp @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2020, Andreas Kling + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include + +namespace Kernel { + +static constexpr u16 UHCI_HOST_CONTROLLER_RESET = 0x0002; + +void UHCIController::detect() +{ + PCI::enumerate([&](const PCI::Address& address, PCI::ID id) { + if (address.is_null()) + return; + + if (PCI::get_class(address) == 0xc && PCI::get_subclass(address) == 0x03 && PCI::get_programming_interface(address) == 0) { + new UHCIController(address, id); + } + }); +} + +UHCIController::UHCIController(PCI::Address address, PCI::ID id) + : PCI::Device(address) + , m_io_base(PCI::get_BAR4(pci_address()) & ~1) +{ + klog() << "UHCI: Controller found " << id << " @ " << address; + klog() << "UHCI: I/O base " << m_io_base; + klog() << "UHCI: Interrupt line: " << PCI::get_interrupt_line(pci_address()); + + reset(); +} + +UHCIController::~UHCIController() +{ +} + +void UHCIController::reset() +{ + write_usbcmd(UHCI_HOST_CONTROLLER_RESET); + + for (;;) { + if (read_usbcmd() & UHCI_HOST_CONTROLLER_RESET) + continue; + break; + } + + klog() << "UHCI: Reset completed!"; +} + +void UHCIController::handle_irq(const RegisterState&) +{ +} + +} diff --git a/Kernel/Devices/UHCIController.h b/Kernel/Devices/UHCIController.h new file mode 100644 index 0000000000..4816cfd990 --- /dev/null +++ b/Kernel/Devices/UHCIController.h @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2020, Andreas Kling + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include + +namespace Kernel { + +class UHCIController final : public PCI::Device { +public: + static void detect(); + virtual ~UHCIController() override; + + void reset(); + +private: + UHCIController(PCI::Address, PCI::ID); + + u16 read_usbcmd() { return m_io_base.offset(0).in(); } + u16 read_usbsts() { return m_io_base.offset(0x2).in(); } + u16 read_usbintr() { return m_io_base.offset(0x4).in(); } + 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); } + void write_usbintr(u16 value) { m_io_base.offset(0x4).out(value); } + 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; + + PCI::Address m_address; + IOAddress m_io_base; +}; + +} diff --git a/Kernel/init.cpp b/Kernel/init.cpp index d38b91da18..c0d317b915 100644 --- a/Kernel/init.cpp +++ b/Kernel/init.cpp @@ -46,6 +46,7 @@ #include #include #include +#include #include #include #include @@ -246,6 +247,8 @@ void init_stage2() } } + UHCIController::detect(); + E1000NetworkAdapter::detect(); RTL8139NetworkAdapter::detect(); diff --git a/Meta/run.sh b/Meta/run.sh index 90ddf3804c..2bcee755db 100755 --- a/Meta/run.sh +++ b/Meta/run.sh @@ -39,6 +39,7 @@ $SERENITY_EXTRA_QEMU_ARGS -device VGA,vgamem_mb=64 -drive file=${SERENITY_DISK_IMAGE},format=raw,index=0,media=disk -device ich9-ahci +-usb -debugcon stdio -soundhw pcspk -soundhw sb16 @@ -55,6 +56,7 @@ $SERENITY_EXTRA_QEMU_ARGS -device piix3-ide -drive file=${SERENITY_DISK_IMAGE},id=disk,if=none -device ide-hd,bus=ide.6,drive=disk,unit=0 +-usb -debugcon stdio -soundhw pcspk -soundhw sb16