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):
|
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,
|
const u8 duration = cmd->value >> 8;
|
||||||
cmd->index);
|
const u8 report_id = cmd->value & 0xFF;
|
||||||
// TODO: Handle idle duration and implement NAK
|
|
||||||
|
{
|
||||||
|
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);
|
ios.EnqueueIPCReply(cmd->ios_request, IPC_SUCCESS);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -207,23 +225,15 @@ int HIDKeyboard::SubmitTransfer(std::unique_ptr<BulkMessage> cmd)
|
|||||||
|
|
||||||
int HIDKeyboard::SubmitTransfer(std::unique_ptr<IntrMessage> 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
|
// We can't use cmd->ScheduleTransferCompletion here as it might provoke
|
||||||
// invalid memory access with scheduled transfers when CancelTransfer is called.
|
// invalid memory access with scheduled transfers when CancelTransfer is called.
|
||||||
EnqueueTransfer(std::move(cmd), state);
|
auto transfer = std::make_shared<PendingTransfer>(std::move(cmd));
|
||||||
|
|
||||||
if (should_poll)
|
|
||||||
{
|
{
|
||||||
m_last_state = std::move(state);
|
std::lock_guard lock(m_pending_lock);
|
||||||
start_time = std::chrono::steady_clock::now();
|
m_pending_tranfers.insert(transfer);
|
||||||
}
|
}
|
||||||
|
m_worker.EmplaceItem(transfer);
|
||||||
|
|
||||||
return IPC_SUCCESS;
|
return IPC_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -236,47 +246,45 @@ int HIDKeyboard::SubmitTransfer(std::unique_ptr<IsoMessage> cmd)
|
|||||||
return IPC_SUCCESS;
|
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)
|
void HIDKeyboard::HandlePendingTransfer(std::shared_ptr<PendingTransfer> transfer)
|
||||||
{
|
{
|
||||||
|
static constexpr auto SLEEP_DURATION = POLLING_RATE / 2;
|
||||||
|
|
||||||
std::unique_lock lock(m_pending_lock);
|
std::unique_lock lock(m_pending_lock);
|
||||||
if (transfer->IsCanceled())
|
if (transfer->IsCanceled())
|
||||||
return;
|
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();
|
lock.unlock();
|
||||||
std::this_thread::sleep_for(POLLING_RATE / 2);
|
std::this_thread::sleep_for(SLEEP_DURATION);
|
||||||
lock.lock();
|
lock.lock();
|
||||||
|
|
||||||
if (transfer->IsCanceled())
|
if (transfer->IsCanceled())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if (ControlReference::GetInputGate())
|
||||||
|
state = m_keyboard_context->GetPressedState();
|
||||||
}
|
}
|
||||||
|
|
||||||
transfer->Do();
|
transfer->Do(state);
|
||||||
m_pending_tranfers.erase(transfer);
|
m_pending_tranfers.erase(transfer);
|
||||||
|
m_last_state = std::move(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
void HIDKeyboard::CancelPendingTransfers()
|
void HIDKeyboard::CancelPendingTransfers()
|
||||||
{
|
{
|
||||||
m_worker.Cancel();
|
|
||||||
{
|
{
|
||||||
std::lock_guard lock(m_pending_lock);
|
std::lock_guard lock(m_pending_lock);
|
||||||
for (auto& transfer : m_pending_tranfers)
|
for (auto& transfer : m_pending_tranfers)
|
||||||
transfer->Cancel();
|
transfer->Cancel();
|
||||||
m_pending_tranfers.clear();
|
m_pending_tranfers.clear();
|
||||||
}
|
}
|
||||||
|
m_worker.Cancel();
|
||||||
}
|
}
|
||||||
|
|
||||||
HIDKeyboard::PendingTransfer::PendingTransfer(std::unique_ptr<IntrMessage> msg)
|
HIDKeyboard::PendingTransfer::PendingTransfer(std::unique_ptr<IntrMessage> msg)
|
||||||
@ -293,9 +301,17 @@ HIDKeyboard::PendingTransfer::~PendingTransfer()
|
|||||||
m_msg->ScheduleTransferCompletion(-5, 0);
|
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
|
bool HIDKeyboard::PendingTransfer::IsCanceled() const
|
||||||
@ -303,8 +319,9 @@ bool HIDKeyboard::PendingTransfer::IsCanceled() const
|
|||||||
return m_is_canceled;
|
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_msg->ScheduleTransferCompletion(IPC_SUCCESS, 0);
|
||||||
m_pending = false;
|
m_pending = false;
|
||||||
}
|
}
|
||||||
|
@ -47,9 +47,9 @@ private:
|
|||||||
PendingTransfer(std::unique_ptr<IntrMessage> msg);
|
PendingTransfer(std::unique_ptr<IntrMessage> msg);
|
||||||
~PendingTransfer();
|
~PendingTransfer();
|
||||||
|
|
||||||
bool IsReady() const;
|
bool Idle(std::optional<std::chrono::milliseconds> idle_duration) const;
|
||||||
bool IsCanceled() const;
|
bool IsCanceled() const;
|
||||||
void Do();
|
void Do(const Common::HIDPressedState& state);
|
||||||
void Cancel();
|
void Cancel();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -59,13 +59,13 @@ private:
|
|||||||
bool m_pending = true;
|
bool m_pending = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
void EnqueueTransfer(std::unique_ptr<IntrMessage> msg, const Common::HIDPressedState& state);
|
|
||||||
void HandlePendingTransfer(std::shared_ptr<PendingTransfer> transfer);
|
void HandlePendingTransfer(std::shared_ptr<PendingTransfer> transfer);
|
||||||
void CancelPendingTransfers();
|
void CancelPendingTransfers();
|
||||||
|
|
||||||
Common::WorkQueueThreadSP<std::shared_ptr<PendingTransfer>> m_worker;
|
Common::WorkQueueThreadSP<std::shared_ptr<PendingTransfer>> m_worker;
|
||||||
std::mutex m_pending_lock;
|
std::mutex m_pending_lock;
|
||||||
std::set<std::shared_ptr<PendingTransfer>> m_pending_tranfers;
|
std::set<std::shared_ptr<PendingTransfer>> m_pending_tranfers;
|
||||||
|
std::optional<std::chrono::milliseconds> m_idle_duration;
|
||||||
|
|
||||||
HIDProtocol m_current_protocol = HIDProtocol::Report;
|
HIDProtocol m_current_protocol = HIDProtocol::Report;
|
||||||
Common::HIDPressedState m_last_state;
|
Common::HIDPressedState m_last_state;
|
||||||
|
Loading…
Reference in New Issue
Block a user