2#include "pedigree/kernel/LockGuard.h"
3#include "pedigree/kernel/Log.h"
4#include "pedigree/kernel/machine/Pci.h"
5#include "pedigree/kernel/process/TerminationDeferral.h"
6#include "pedigree/kernel/processor/Processor.h"
7#include "pedigree/kernel/time/Time.h"
12struct FirmwareConfig {
14 bool read32(uint16_t offset, uint32_t& value) {
15 return PciBus::instance().readConfig32(device, offset, value);
17 bool write32(uint16_t offset, uint32_t value) {
18 return PciBus::instance().writeConfig32(device, offset, value);
20 bool write8(uint16_t offset, uint8_t value) {
21 return PciBus::instance().writeConfig8(device, offset, value);
24 Time::delay(Time::Multiplier::Millisecond);
29bool Ehci::acquireFirmware(uint16_t capability) {
30 FirmwareConfig config{
this};
31 const auto result = m_Handoff.
acquire(capability, config);
32 if (result == EhciHandoff::AcquireResult::Acquired ||
33 result == EhciHandoff::AcquireResult::AlreadyUnowned)
35 const char* reason =
"configuration access failed";
37 case EhciHandoff::AcquireResult::InvalidCapability:
38 reason =
"invalid legacy capability";
40 case EhciHandoff::AcquireResult::OwnershipTimeout:
41 reason =
"BIOS ownership did not clear within 1 second";
43 case EhciHandoff::AcquireResult::OwnershipMismatch:
44 reason =
"OS ownership was not retained";
46 case EhciHandoff::AcquireResult::SmiDisableFailure:
47 reason =
"legacy SMI controls did not disable";
52 ERROR(
"EHCI: firmware handoff failed: " << reason);
56void Ehci::returnToFirmware() {
57 if (!m_Handoff.wasBiosOwned())
59 FirmwareConfig config{
this};
60 if (m_HardwareTouched) {
63 constexpr uint16_t CommandMask = 2 | 4 | 0x400;
64 if (!PciBus::instance().updateCommand(
this, CommandMask, m_FirmwarePciCommand & CommandMask)) {
65 ERROR(
"EHCI: firmware recovery could not restore PCI access; controller remains stopped");
69 const auto result = m_Handoff.acquired() ? m_Handoff.
release(config, m_ControllerStopped)
71 if (result == EhciHandoff::ReleaseResult::FirmwareConfirmed)
72 NOTICE(
"EHCI: firmware reclaimed controller; legacy input recovery requested");
73 else if (result == EhciHandoff::ReleaseResult::Released)
74 WARNING(
"EHCI: OS ownership released; firmware did not confirm reclaim within 1 second");
75 else if (result != EhciHandoff::ReleaseResult::NotOwned)
76 ERROR(
"EHCI: firmware recovery failed; legacy USB input may remain unavailable");
79bool Ehci::beginStartupActivity() {
81 return m_Startup.begin();
84void Ehci::endStartupActivity(UsbStartup::Outcome outcome) {
86 if (m_Startup.finish(outcome))
90void Ehci::completeInitialPort(
size_t port) {
92 const uint16_t bit = uint16_t{1} << port;
93 if (!(m_InitialPortMask & bit))
95 m_InitialPortMask &= ~bit;
96 if (!m_InitialPortMask && m_Startup.finish(UsbStartup::Outcome::Neutral))
100void Ehci::startFirmwareRecovery() {
102 if (!m_Handoff.wasBiosOwned())
104 m_RecoveryThread.adopt(
106 m_RecoveryThread->setName(
"EHCI firmware recovery");
110int Ehci::recoverFirmware(
void* parameter) {
112 auto* controller =
static_cast<Ehci*
>(parameter);
115 if (controller->m_RecoveryStopping)
117 WARNING(
"EHCI: startup failed before a device driver became usable; returning to firmware");
118 controller->shutdownController();
119 controller->returnToFirmware();
Device * getParent() const
ReleaseResult withdrawRequest(Config &config, size_t pollLimit=DefaultPollLimit)
AcquireResult acquire(uint16_t offset, Config &config, size_t pollLimit=DefaultPollLimit)
ReleaseResult release(Config &config, bool callerQuiescedOrNeverTouched, size_t pollLimit=DefaultPollLimit)
static ProcessorInformation & information()
MUST_USE_RESULT bool acquireForCompletion(size_t n=1, size_t timeoutSecs=0, size_t timeoutUsecs=0)