mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-06-16 04:07:51 +00:00
Compare commits
7 Commits
c66b5943a5
...
75fa0febfd
Author | SHA1 | Date | |
---|---|---|---|
![]() |
75fa0febfd | ||
![]() |
82092abd84 | ||
![]() |
ffbeae6ce6 | ||
![]() |
fe07476f73 | ||
![]() |
73cc751af1 | ||
![]() |
07af649b09 | ||
![]() |
6da3f5f26a |
2
Externals/SDL/SDL
vendored
2
Externals/SDL/SDL
vendored
@ -1 +1 @@
|
||||
Subproject commit 8d604353a53853fa56d1bdce0363535605ca868f
|
||||
Subproject commit c9a6709bd21750f1ad9597be21abace78c6378c9
|
@ -165,9 +165,27 @@ int HIDKeyboard::SubmitTransfer(std::unique_ptr<CtrlMessage> cmd)
|
||||
}
|
||||
case USBHDR(DIR_HOST2DEVICE, TYPE_CLASS, REC_INTERFACE, HIDRequestCodes::SET_IDLE):
|
||||
{
|
||||
WARN_LOG_FMT(IOS_USB, "SET_IDLE not implemented (value={:04x}, index={})", cmd->value,
|
||||
cmd->index);
|
||||
// TODO: Handle idle duration and implement NAK
|
||||
const u8 duration = cmd->value >> 8;
|
||||
const u8 report_id = cmd->value & 0xFF;
|
||||
|
||||
{
|
||||
std::lock_guard lock(m_pending_lock);
|
||||
if (duration == 0)
|
||||
{
|
||||
m_idle_duration.reset();
|
||||
INFO_LOG_FMT(IOS_USB, "SET_IDLE duration to indefinite (report_id={:02x}, index={})",
|
||||
report_id, cmd->index);
|
||||
}
|
||||
else
|
||||
{
|
||||
const auto idle_duration =
|
||||
4 * duration; // 4 millisecond resolution (see HID specification)
|
||||
m_idle_duration = std::chrono::milliseconds(idle_duration);
|
||||
INFO_LOG_FMT(IOS_USB, "SET_IDLE duration to {} milliseconds (report_id={:02x}, index={})",
|
||||
idle_duration, report_id, cmd->index);
|
||||
}
|
||||
}
|
||||
|
||||
ios.EnqueueIPCReply(cmd->ios_request, IPC_SUCCESS);
|
||||
break;
|
||||
}
|
||||
@ -207,23 +225,15 @@ int HIDKeyboard::SubmitTransfer(std::unique_ptr<BulkMessage> cmd)
|
||||
|
||||
int HIDKeyboard::SubmitTransfer(std::unique_ptr<IntrMessage> cmd)
|
||||
{
|
||||
static auto start_time = std::chrono::steady_clock::now();
|
||||
const auto current_time = std::chrono::steady_clock::now();
|
||||
|
||||
const bool should_poll =
|
||||
(current_time - start_time) >= POLLING_RATE && ControlReference::GetInputGate();
|
||||
const Common::HIDPressedState state =
|
||||
should_poll ? m_keyboard_context->GetPressedState() : m_last_state;
|
||||
|
||||
// We can't use cmd->ScheduleTransferCompletion here as it might provoke
|
||||
// invalid memory access with scheduled transfers when CancelTransfer is called.
|
||||
EnqueueTransfer(std::move(cmd), state);
|
||||
|
||||
if (should_poll)
|
||||
auto transfer = std::make_shared<PendingTransfer>(std::move(cmd));
|
||||
{
|
||||
m_last_state = std::move(state);
|
||||
start_time = std::chrono::steady_clock::now();
|
||||
std::lock_guard lock(m_pending_lock);
|
||||
m_pending_tranfers.insert(transfer);
|
||||
}
|
||||
m_worker.EmplaceItem(transfer);
|
||||
|
||||
return IPC_SUCCESS;
|
||||
}
|
||||
|
||||
@ -236,47 +246,45 @@ int HIDKeyboard::SubmitTransfer(std::unique_ptr<IsoMessage> cmd)
|
||||
return IPC_SUCCESS;
|
||||
}
|
||||
|
||||
void HIDKeyboard::EnqueueTransfer(std::unique_ptr<IntrMessage> msg,
|
||||
const Common::HIDPressedState& state)
|
||||
{
|
||||
msg->FillBuffer(reinterpret_cast<const u8*>(&state), sizeof(state));
|
||||
auto transfer = std::make_shared<PendingTransfer>(std::move(msg));
|
||||
m_worker.EmplaceItem(transfer);
|
||||
{
|
||||
std::lock_guard lock(m_pending_lock);
|
||||
m_pending_tranfers.insert(transfer);
|
||||
}
|
||||
}
|
||||
|
||||
void HIDKeyboard::HandlePendingTransfer(std::shared_ptr<PendingTransfer> transfer)
|
||||
{
|
||||
static constexpr auto SLEEP_DURATION = POLLING_RATE / 2;
|
||||
|
||||
std::unique_lock lock(m_pending_lock);
|
||||
if (transfer->IsCanceled())
|
||||
return;
|
||||
|
||||
while (!transfer->IsReady())
|
||||
Common::HIDPressedState state;
|
||||
if (ControlReference::GetInputGate())
|
||||
state = m_keyboard_context->GetPressedState();
|
||||
|
||||
while (state == m_last_state && transfer->Idle(m_idle_duration))
|
||||
{
|
||||
lock.unlock();
|
||||
std::this_thread::sleep_for(POLLING_RATE / 2);
|
||||
std::this_thread::sleep_for(SLEEP_DURATION);
|
||||
lock.lock();
|
||||
|
||||
if (transfer->IsCanceled())
|
||||
return;
|
||||
|
||||
if (ControlReference::GetInputGate())
|
||||
state = m_keyboard_context->GetPressedState();
|
||||
}
|
||||
|
||||
transfer->Do();
|
||||
transfer->Do(state);
|
||||
m_pending_tranfers.erase(transfer);
|
||||
m_last_state = std::move(state);
|
||||
}
|
||||
|
||||
void HIDKeyboard::CancelPendingTransfers()
|
||||
{
|
||||
m_worker.Cancel();
|
||||
{
|
||||
std::lock_guard lock(m_pending_lock);
|
||||
for (auto& transfer : m_pending_tranfers)
|
||||
transfer->Cancel();
|
||||
m_pending_tranfers.clear();
|
||||
}
|
||||
m_worker.Cancel();
|
||||
}
|
||||
|
||||
HIDKeyboard::PendingTransfer::PendingTransfer(std::unique_ptr<IntrMessage> msg)
|
||||
@ -293,9 +301,17 @@ HIDKeyboard::PendingTransfer::~PendingTransfer()
|
||||
m_msg->ScheduleTransferCompletion(-5, 0);
|
||||
}
|
||||
|
||||
bool HIDKeyboard::PendingTransfer::IsReady() const
|
||||
bool HIDKeyboard::PendingTransfer::Idle(
|
||||
std::optional<std::chrono::milliseconds> idle_duration) const
|
||||
{
|
||||
return (std::chrono::steady_clock::now() - m_time) >= POLLING_RATE;
|
||||
if (!idle_duration.has_value())
|
||||
{
|
||||
// Based on the HID specification for Set_Idle Request:
|
||||
// - inhibit reporting forever,
|
||||
// - only reporting when a change is detected in the report data
|
||||
return true;
|
||||
}
|
||||
return (std::chrono::steady_clock::now() - m_time) < *idle_duration;
|
||||
}
|
||||
|
||||
bool HIDKeyboard::PendingTransfer::IsCanceled() const
|
||||
@ -303,8 +319,9 @@ bool HIDKeyboard::PendingTransfer::IsCanceled() const
|
||||
return m_is_canceled;
|
||||
}
|
||||
|
||||
void HIDKeyboard::PendingTransfer::Do()
|
||||
void HIDKeyboard::PendingTransfer::Do(const Common::HIDPressedState& state)
|
||||
{
|
||||
m_msg->FillBuffer(reinterpret_cast<const u8*>(&state), sizeof(state));
|
||||
m_msg->ScheduleTransferCompletion(IPC_SUCCESS, 0);
|
||||
m_pending = false;
|
||||
}
|
||||
|
@ -47,9 +47,9 @@ private:
|
||||
PendingTransfer(std::unique_ptr<IntrMessage> msg);
|
||||
~PendingTransfer();
|
||||
|
||||
bool IsReady() const;
|
||||
bool Idle(std::optional<std::chrono::milliseconds> idle_duration) const;
|
||||
bool IsCanceled() const;
|
||||
void Do();
|
||||
void Do(const Common::HIDPressedState& state);
|
||||
void Cancel();
|
||||
|
||||
private:
|
||||
@ -59,13 +59,13 @@ private:
|
||||
bool m_pending = true;
|
||||
};
|
||||
|
||||
void EnqueueTransfer(std::unique_ptr<IntrMessage> msg, const Common::HIDPressedState& state);
|
||||
void HandlePendingTransfer(std::shared_ptr<PendingTransfer> transfer);
|
||||
void CancelPendingTransfers();
|
||||
|
||||
Common::WorkQueueThreadSP<std::shared_ptr<PendingTransfer>> m_worker;
|
||||
std::mutex m_pending_lock;
|
||||
std::set<std::shared_ptr<PendingTransfer>> m_pending_tranfers;
|
||||
std::optional<std::chrono::milliseconds> m_idle_duration;
|
||||
|
||||
HIDProtocol m_current_protocol = HIDProtocol::Report;
|
||||
Common::HIDPressedState m_last_state;
|
||||
|
Loading…
Reference in New Issue
Block a user