diff --git a/Source/Core/Common/Logging/Log.h b/Source/Core/Common/Logging/Log.h index ce46bcb8e2..3ef07acbf1 100644 --- a/Source/Core/Common/Logging/Log.h +++ b/Source/Core/Common/Logging/Log.h @@ -31,7 +31,6 @@ enum LOG_TYPE IOS_DI, IOS_ES, IOS_FILEIO, - IOS_HID, IOS_NET, IOS_SD, IOS_SSL, diff --git a/Source/Core/Common/Logging/LogManager.cpp b/Source/Core/Common/Logging/LogManager.cpp index 4cb786095b..964a8df973 100644 --- a/Source/Core/Common/Logging/LogManager.cpp +++ b/Source/Core/Common/Logging/LogManager.cpp @@ -65,7 +65,6 @@ LogManager::LogManager() m_Log[LogTypes::IOS_DI] = new LogContainer("IOS_DI", "IOS - Drive Interface"); m_Log[LogTypes::IOS_ES] = new LogContainer("IOS_ES", "IOS - ETicket Services"); m_Log[LogTypes::IOS_FILEIO] = new LogContainer("IOS_FILEIO", "IOS - FileIO"); - m_Log[LogTypes::IOS_HID] = new LogContainer("IOS_HID", "IOS - USB_HID"); m_Log[LogTypes::IOS_SD] = new LogContainer("IOS_SD", "IOS - SDIO"); m_Log[LogTypes::IOS_SSL] = new LogContainer("IOS_SSL", "IOS - SSL"); m_Log[LogTypes::IOS_STM] = new LogContainer("IOS_STM", "IOS - State Transition Manager"); diff --git a/Source/Core/Core/CMakeLists.txt b/Source/Core/Core/CMakeLists.txt index 44bae6b2c6..594608b377 100644 --- a/Source/Core/Core/CMakeLists.txt +++ b/Source/Core/Core/CMakeLists.txt @@ -157,7 +157,9 @@ set(SRCS ActionReplay.cpp IOS/USB/Host.cpp IOS/USB/OH0/OH0.cpp IOS/USB/OH0/OH0Device.cpp + IOS/USB/USB_HID/HIDv4.cpp IOS/USB/USBV0.cpp + IOS/USB/USBV4.cpp IOS/USB/USB_KBD.cpp IOS/USB/USB_VEN.cpp IOS/USB/Bluetooth/BTBase.cpp @@ -268,7 +270,6 @@ if(LIBUSB_FOUND) # Using shared LibUSB set(LIBS ${LIBS} ${LIBUSB_LIBRARIES}) set(SRCS ${SRCS} IOS/USB/LibusbDevice.cpp - IOS/USB/USB_HIDv4.cpp IOS/USB/Bluetooth/BTReal.cpp) endif() diff --git a/Source/Core/Core/Core.vcxproj b/Source/Core/Core/Core.vcxproj index 912c038179..7983948be3 100644 --- a/Source/Core/Core/Core.vcxproj +++ b/Source/Core/Core/Core.vcxproj @@ -194,14 +194,9 @@ + - - - 4200;%(DisableSpecificWarnings) - + @@ -431,8 +426,9 @@ + - + diff --git a/Source/Core/Core/Core.vcxproj.filters b/Source/Core/Core/Core.vcxproj.filters index 0c7ba536db..3b9ad3503a 100644 --- a/Source/Core/Core/Core.vcxproj.filters +++ b/Source/Core/Core/Core.vcxproj.filters @@ -785,10 +785,13 @@ IOS\USB + + IOS\USB + IOS\USB - + IOS\USB @@ -1377,10 +1380,13 @@ IOS\USB + + IOS\USB + IOS\USB - + IOS\USB diff --git a/Source/Core/Core/IOS/IPC.cpp b/Source/Core/Core/IOS/IPC.cpp index 16443efa7e..0db81b2efc 100644 --- a/Source/Core/Core/IOS/IPC.cpp +++ b/Source/Core/Core/IOS/IPC.cpp @@ -51,6 +51,7 @@ #include "Core/IOS/USB/Bluetooth/BTReal.h" #include "Core/IOS/USB/OH0/OH0.h" #include "Core/IOS/USB/OH0/OH0Device.h" +#include "Core/IOS/USB/USB_HID/HIDv4.h" #include "Core/IOS/USB/USB_KBD.h" #include "Core/IOS/USB/USB_VEN.h" #include "Core/IOS/WFS/WFSI.h" @@ -61,10 +62,6 @@ namespace CoreTiming struct EventType; } // namespace CoreTiming -#if defined(__LIBUSB__) -#include "Core/IOS/USB/USB_HIDv4.h" -#endif - namespace IOS { namespace HLE @@ -513,11 +510,7 @@ void Reinit() AddDevice("/dev/usb/ven"); AddDevice("/dev/sdio/slot0"); AddDevice("/dev/sdio/slot1"); -#if defined(__LIBUSB__) AddDevice("/dev/usb/hid"); -#else - AddDevice("/dev/usb/hid"); -#endif AddDevice("/dev/usb/oh0"); AddDevice("/dev/usb/oh1"); AddDevice("/dev/usb/wfssrv"); diff --git a/Source/Core/Core/IOS/USB/USBV4.cpp b/Source/Core/Core/IOS/USB/USBV4.cpp new file mode 100644 index 0000000000..fae4e2011a --- /dev/null +++ b/Source/Core/Core/IOS/USB/USBV4.cpp @@ -0,0 +1,97 @@ +// Copyright 2017 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +#include +#include +#include + +#include "Common/CommonFuncs.h" +#include "Common/CommonTypes.h" +#include "Core/HW/Memmap.h" +#include "Core/IOS/Device.h" +#include "Core/IOS/USB/USBV4.h" + +namespace IOS +{ +namespace HLE +{ +namespace USB +{ +// Source: https://wiibrew.org/w/index.php?title=/dev/usb/hid&oldid=96809 +#pragma pack(push, 1) +struct HIDRequest +{ + u8 padding[16]; + s32 device_no; + union + { + struct + { + u8 bmRequestType; + u8 bmRequest; + u16 wValue; + u16 wIndex; + u16 wLength; + } control; + struct + { + u32 endpoint; + u32 length; + } interrupt; + struct + { + u8 bIndex; + } string; + }; + u32 data_addr; +}; +#pragma pack(pop) + +V4CtrlMessage::V4CtrlMessage(const IOCtlRequest& ioctl) : CtrlMessage(ioctl, -1) +{ + HIDRequest hid_request; + Memory::CopyFromEmu(&hid_request, ioctl.buffer_in, sizeof(hid_request)); + request_type = hid_request.control.bmRequestType; + request = hid_request.control.bmRequest; + value = Common::swap16(hid_request.control.wValue); + index = Common::swap16(hid_request.control.wIndex); + length = Common::swap16(hid_request.control.wLength); + data_address = Common::swap32(hid_request.data_addr); +} + +// Since this is just a standard control request, but with additional requirements +// (US for the language and replacing non-ASCII characters with '?'), +// we can simply submit it as a usual control request. +V4GetUSStringMessage::V4GetUSStringMessage(const IOCtlRequest& ioctl) : CtrlMessage(ioctl, -1) +{ + HIDRequest hid_request; + Memory::CopyFromEmu(&hid_request, ioctl.buffer_in, sizeof(hid_request)); + request_type = 0x80; + request = REQUEST_GET_DESCRIPTOR; + value = (0x03 << 8) | hid_request.string.bIndex; + index = 0x0409; // language US + length = 255; + data_address = Common::swap32(hid_request.data_addr); +} + +void V4GetUSStringMessage::OnTransferComplete() const +{ + const std::locale& c_locale = std::locale::classic(); + std::string message = Memory::GetString(data_address); + std::replace_if(message.begin(), message.end(), + [&c_locale](char c) { return !std::isprint(c, c_locale); }, '?'); + Memory::CopyToEmu(data_address, message.c_str(), message.size()); +} + +V4IntrMessage::V4IntrMessage(const IOCtlRequest& ioctl) : IntrMessage(ioctl, -1) +{ + HIDRequest hid_request; + Memory::CopyFromEmu(&hid_request, ioctl.buffer_in, sizeof(hid_request)); + length = static_cast(Common::swap32(hid_request.interrupt.length)); + endpoint = static_cast(Common::swap32(hid_request.interrupt.endpoint)); + data_address = Common::swap32(hid_request.data_addr); +} +} // namespace USB +} // namespace HLE +} // namespace IOS diff --git a/Source/Core/Core/IOS/USB/USBV4.h b/Source/Core/Core/IOS/USB/USBV4.h new file mode 100644 index 0000000000..93ccd7ee21 --- /dev/null +++ b/Source/Core/Core/IOS/USB/USBV4.h @@ -0,0 +1,50 @@ +// Copyright 2017 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +#pragma once + +#include "Common/CommonTypes.h" +#include "Core/IOS/USB/Common.h" + +// Used by an early version of /dev/usb/hid. + +namespace IOS +{ +namespace HLE +{ +struct IOCtlRequest; + +namespace USB +{ +enum V4Requests +{ + IOCTL_USBV4_GETDEVICECHANGE = 0, + IOCTL_USBV4_SET_SUSPEND = 1, + IOCTL_USBV4_CTRLMSG = 2, + IOCTL_USBV4_INTRMSG_IN = 3, + IOCTL_USBV4_INTRMSG_OUT = 4, + IOCTL_USBV4_GET_US_STRING = 5, + IOCTL_USBV4_GETVERSION = 6, + IOCTL_USBV4_SHUTDOWN = 7, + IOCTL_USBV4_CANCELINTERRUPT = 8, +}; + +struct V4CtrlMessage final : CtrlMessage +{ + explicit V4CtrlMessage(const IOCtlRequest& ioctl); +}; + +struct V4GetUSStringMessage final : CtrlMessage +{ + explicit V4GetUSStringMessage(const IOCtlRequest& ioctl); + void OnTransferComplete() const override; +}; + +struct V4IntrMessage final : IntrMessage +{ + explicit V4IntrMessage(const IOCtlRequest& ioctl); +}; +} // namespace USB +} // namespace HLE +} // namespace IOS diff --git a/Source/Core/Core/IOS/USB/USB_HID/HIDv4.cpp b/Source/Core/Core/IOS/USB/USB_HID/HIDv4.cpp new file mode 100644 index 0000000000..4734490f1c --- /dev/null +++ b/Source/Core/Core/IOS/USB/USB_HID/HIDv4.cpp @@ -0,0 +1,230 @@ +// Copyright 2017 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +#include +#include + +#include "Common/Align.h" +#include "Common/ChunkFile.h" +#include "Common/CommonFuncs.h" +#include "Common/Logging/Log.h" +#include "Core/CoreTiming.h" +#include "Core/HW/Memmap.h" +#include "Core/IOS/Device.h" +#include "Core/IOS/USB/Common.h" +#include "Core/IOS/USB/USBV4.h" +#include "Core/IOS/USB/USB_HID/HIDv4.h" + +namespace IOS +{ +namespace HLE +{ +namespace Device +{ +USB_HIDv4::USB_HIDv4(u32 device_id, const std::string& device_name) + : USBHost(device_id, device_name) +{ +} + +USB_HIDv4::~USB_HIDv4() +{ + StopThreads(); +} + +IPCCommandResult USB_HIDv4::IOCtl(const IOCtlRequest& request) +{ + request.Log(GetDeviceName(), LogTypes::IOS_USB); + switch (request.request) + { + case USB::IOCTL_USBV4_GETVERSION: + return GetDefaultReply(VERSION); + case USB::IOCTL_USBV4_GETDEVICECHANGE: + return GetDeviceChange(request); + case USB::IOCTL_USBV4_SHUTDOWN: + return Shutdown(request); + case USB::IOCTL_USBV4_SET_SUSPEND: + // Not implemented in IOS + return GetDefaultReply(IPC_SUCCESS); + case USB::IOCTL_USBV4_CANCELINTERRUPT: + return CancelInterrupt(request); + case USB::IOCTL_USBV4_GET_US_STRING: + case USB::IOCTL_USBV4_CTRLMSG: + case USB::IOCTL_USBV4_INTRMSG_IN: + case USB::IOCTL_USBV4_INTRMSG_OUT: + { + if (request.buffer_in == 0 || request.buffer_in_size != 32) + return GetDefaultReply(IPC_EINVAL); + const auto device = GetDeviceByIOSID(Memory::Read_U32(request.buffer_in + 16)); + if (!device->Attach(0)) + return GetDefaultReply(IPC_EINVAL); + return HandleTransfer(device, request.request, + [&, this]() { return SubmitTransfer(*device, request); }); + } + default: + request.DumpUnknown(GetDeviceName(), LogTypes::IOS_USB); + return GetDefaultReply(IPC_SUCCESS); + } +} + +IPCCommandResult USB_HIDv4::CancelInterrupt(const IOCtlRequest& request) +{ + if (request.buffer_in == 0 || request.buffer_in_size != 8) + return GetDefaultReply(IPC_EINVAL); + + auto device = GetDeviceByIOSID(Memory::Read_U32(request.buffer_in)); + if (!device) + return GetDefaultReply(IPC_ENOENT); + device->CancelTransfer(Memory::Read_U8(request.buffer_in + 4)); + return GetDefaultReply(IPC_SUCCESS); +} + +IPCCommandResult USB_HIDv4::GetDeviceChange(const IOCtlRequest& request) +{ + std::lock_guard lk{m_devicechange_hook_address_mutex}; + if (request.buffer_out == 0 || request.buffer_out_size != 0x600) + return GetDefaultReply(IPC_EINVAL); + + m_devicechange_hook_request = std::make_unique(request.address); + // On the first call, the reply is sent immediately (instead of on device insertion/removal) + if (m_devicechange_first_call) + { + TriggerDeviceChangeReply(); + m_devicechange_first_call = false; + } + return GetNoReply(); +} + +IPCCommandResult USB_HIDv4::Shutdown(const IOCtlRequest& request) +{ + std::lock_guard lk{m_devicechange_hook_address_mutex}; + if (m_devicechange_hook_request != 0) + { + Memory::Write_U32(0xffffffff, m_devicechange_hook_request->buffer_out); + EnqueueReply(*m_devicechange_hook_request, -1); + m_devicechange_hook_request.reset(); + } + return GetDefaultReply(IPC_SUCCESS); +} + +s32 USB_HIDv4::SubmitTransfer(USB::Device& device, const IOCtlRequest& request) +{ + switch (request.request) + { + case USB::IOCTL_USBV4_CTRLMSG: + return device.SubmitTransfer(std::make_unique(request)); + case USB::IOCTL_USBV4_GET_US_STRING: + return device.SubmitTransfer(std::make_unique(request)); + case USB::IOCTL_USBV4_INTRMSG_IN: + case USB::IOCTL_USBV4_INTRMSG_OUT: + return device.SubmitTransfer(std::make_unique(request)); + default: + return IPC_EINVAL; + } +} + +void USB_HIDv4::DoState(PointerWrap& p) +{ + p.Do(m_devicechange_first_call); + u32 hook_address = m_devicechange_hook_request ? m_devicechange_hook_request->address : 0; + p.Do(hook_address); + if (hook_address != 0) + m_devicechange_hook_request = std::make_unique(hook_address); + else + m_devicechange_hook_request.reset(); + + p.Do(m_ios_ids); + p.Do(m_device_ids); + + USBHost::DoState(p); +} + +std::shared_ptr USB_HIDv4::GetDeviceByIOSID(const s32 ios_id) const +{ + std::lock_guard lk{m_id_map_mutex}; + const auto iterator = m_ios_ids.find(ios_id); + if (iterator == m_ios_ids.cend()) + return nullptr; + return GetDeviceById(iterator->second); +} + +void USB_HIDv4::OnDeviceChange(ChangeEvent event, std::shared_ptr device) +{ + { + std::lock_guard id_map_lock{m_id_map_mutex}; + if (event == ChangeEvent::Inserted) + { + s32 new_id = 0; + while (m_ios_ids.find(new_id) != m_ios_ids.cend()) + ++new_id; + m_ios_ids[new_id] = device->GetId(); + m_device_ids[device->GetId()] = new_id; + } + else if (event == ChangeEvent::Removed && + m_device_ids.find(device->GetId()) != m_device_ids.cend()) + { + m_ios_ids.erase(m_device_ids.at(device->GetId())); + m_device_ids.erase(device->GetId()); + } + } + + { + std::lock_guard lk{m_devicechange_hook_address_mutex}; + TriggerDeviceChangeReply(); + } +} + +bool USB_HIDv4::ShouldAddDevice(const USB::Device& device) const +{ + return device.HasClass(HID_CLASS); +} + +void USB_HIDv4::TriggerDeviceChangeReply() +{ + if (!m_devicechange_hook_request) + return; + + { + std::lock_guard lk(m_devices_mutex); + const u32 dest = m_devicechange_hook_request->buffer_out; + u32 offset = 0; + for (const auto& device : m_devices) + { + const std::vector device_section = GetDeviceEntry(*device.second.get()); + if (offset + device_section.size() > m_devicechange_hook_request->buffer_out_size - 1) + { + WARN_LOG(IOS_USB, "Too many devices connected, skipping"); + break; + } + Memory::CopyToEmu(dest + offset, device_section.data(), device_section.size()); + offset += Common::AlignUp(static_cast(device_section.size()), 4); + } + // IOS writes 0xffffffff to the buffer when there are no more devices + Memory::Write_U32(0xffffffff, dest + offset); + } + + EnqueueReply(*m_devicechange_hook_request, IPC_SUCCESS, 0, CoreTiming::FromThread::ANY); + m_devicechange_hook_request.reset(); +} + +std::vector USB_HIDv4::GetDeviceEntry(const USB::Device& device) const +{ + std::lock_guard id_map_lock{m_id_map_mutex}; + + // The structure for a device section is as follows: + // 0-4 bytes: total size of the device data, including the size and the device ID + // 4-8 bytes: device ID + // the rest of the buffer is device descriptors data + std::vector entry(8); + const std::vector descriptors = device.GetDescriptorsUSBV4(); + const u32 entry_size = Common::swap32(static_cast(entry.size() + descriptors.size())); + const u32 ios_device_id = Common::swap32(m_device_ids.at(device.GetId())); + std::memcpy(entry.data(), &entry_size, sizeof(entry_size)); + std::memcpy(entry.data() + 4, &ios_device_id, sizeof(ios_device_id)); + entry.insert(entry.end(), descriptors.begin(), descriptors.end()); + + return entry; +} +} // namespace Device +} // namespace HLE +} // namespace IOS diff --git a/Source/Core/Core/IOS/USB/USB_HID/HIDv4.h b/Source/Core/Core/IOS/USB/USB_HID/HIDv4.h new file mode 100644 index 0000000000..4048f3c339 --- /dev/null +++ b/Source/Core/Core/IOS/USB/USB_HID/HIDv4.h @@ -0,0 +1,62 @@ +// Copyright 2017 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +#pragma once + +#include +#include +#include +#include +#include + +#include "Common/CommonTypes.h" +#include "Core/IOS/IPC.h" +#include "Core/IOS/USB/Host.h" + +class PointerWrap; + +namespace IOS +{ +namespace HLE +{ +namespace Device +{ +class USB_HIDv4 final : public USBHost +{ +public: + USB_HIDv4(u32 device_id, const std::string& device_name); + ~USB_HIDv4() override; + + IPCCommandResult IOCtl(const IOCtlRequest& request) override; + + void DoState(PointerWrap& p) override; + +private: + std::shared_ptr GetDeviceByIOSID(s32 ios_id) const; + + IPCCommandResult CancelInterrupt(const IOCtlRequest& request); + IPCCommandResult GetDeviceChange(const IOCtlRequest& request); + IPCCommandResult Shutdown(const IOCtlRequest& request); + s32 SubmitTransfer(USB::Device& device, const IOCtlRequest& request); + + void TriggerDeviceChangeReply(); + std::vector GetDeviceEntry(const USB::Device& device) const; + void OnDeviceChange(ChangeEvent, std::shared_ptr) override; + bool ShouldAddDevice(const USB::Device& device) const override; + + static constexpr u32 VERSION = 0x40001; + static constexpr u8 HID_CLASS = 0x03; + + bool m_devicechange_first_call = true; + std::mutex m_devicechange_hook_address_mutex; + std::unique_ptr m_devicechange_hook_request; + + mutable std::mutex m_id_map_mutex; + // IOS device IDs <=> USB device IDs + std::map m_ios_ids; + std::map m_device_ids; +}; +} // namespace Device +} // namespace HLE +} // namespace IOS diff --git a/Source/Core/Core/IOS/USB/USB_HIDv4.cpp b/Source/Core/Core/IOS/USB/USB_HIDv4.cpp deleted file mode 100644 index f52fe5607a..0000000000 --- a/Source/Core/Core/IOS/USB/USB_HIDv4.cpp +++ /dev/null @@ -1,575 +0,0 @@ -// Copyright 2012 Dolphin Emulator Project -// Licensed under GPLv2+ -// Refer to the license.txt file included. - -#include -#include -#include -#include -#include - -#include - -#include "Common/Align.h" -#include "Common/CommonFuncs.h" -#include "Common/Logging/Log.h" -#include "Core/Core.h" -#include "Core/CoreTiming.h" -#include "Core/Debugger/Debugger_SymbolMap.h" -#include "Core/HW/Memmap.h" -#include "Core/IOS/IPC.h" -#include "Core/IOS/USB/USB_HIDv4.h" - -namespace IOS -{ -namespace HLE -{ -namespace Device -{ -constexpr int MAX_DEVICE_DEVNUM = 256; -static u64 hidDeviceAliases[MAX_DEVICE_DEVNUM]; - -// Regular thread -void USB_HIDv4::checkUsbUpdates(USB_HIDv4* hid) -{ - timeval tv; - tv.tv_sec = 0; - tv.tv_usec = 500; - while (hid->usb_thread_running) - { - static u16 timeToFill = 0; - if (timeToFill == 0) - { - std::lock_guard lk(hid->m_device_list_reply_mutex); - if (hid->deviceCommandAddress != 0) - { - IOCtlRequest request{hid->deviceCommandAddress}; - hid->FillOutDevices(request); - EnqueueReply(request, IPC_SUCCESS, 0, CoreTiming::FromThread::NON_CPU); - hid->deviceCommandAddress = 0; - } - } - timeToFill += 8; - libusb_handle_events_timeout(nullptr, &tv); - } - - return; -} - -void USB_HIDv4::handleUsbUpdates(struct libusb_transfer* transfer) -{ - s32 ret = IPC_EINVAL; - u32 replyAddress = (u32)(size_t)transfer->user_data; - if (transfer->status == LIBUSB_TRANSFER_COMPLETED) - { - ret = transfer->length; - } - - IOCtlRequest request{replyAddress}; - EnqueueReply(request, ret, 0, CoreTiming::FromThread::NON_CPU); -} - -USB_HIDv4::USB_HIDv4(u32 device_id, const std::string& device_name) : Device(device_id, device_name) -{ - deviceCommandAddress = 0; - memset(hidDeviceAliases, 0, sizeof(hidDeviceAliases)); - int ret = libusb_init(nullptr); - if (ret) - { - ERROR_LOG(IOS_HID, "libusb_init failed with error: %d", ret); - } - else - { - usb_thread_running = true; - usb_thread = std::thread(checkUsbUpdates, this); - } -} - -USB_HIDv4::~USB_HIDv4() -{ - bool deinit_libusb = false; - if (usb_thread_running) - { - usb_thread_running = false; - usb_thread.join(); - deinit_libusb = true; - } - - for (const auto& device : m_open_devices) - { - libusb_close(device.second); - } - m_open_devices.clear(); - - if (deinit_libusb) - libusb_exit(nullptr); -} - -IPCCommandResult USB_HIDv4::IOCtl(const IOCtlRequest& request) -{ - if (Core::g_want_determinism) - { - return GetDefaultReply(IPC_EACCES); - } - - s32 return_value = IPC_SUCCESS; - switch (request.request) - { - case IOCTL_HID_GET_ATTACHED: - { - deviceCommandAddress = request.address; - return GetNoReply(); - } - case IOCTL_HID_OPEN: - { - // hid version, apparently - return_value = 0x40001; - break; - } - case IOCTL_HID_SET_SUSPEND: - { - // not actually implemented in IOS - return_value = IPC_SUCCESS; - break; - } - case IOCTL_HID_CANCEL_INTERRUPT: - { - return_value = IPC_SUCCESS; - break; - } - case IOCTL_HID_CONTROL: - { - /* - ERROR CODES: - -4 Can't find device specified - */ - - u32 dev_num = Memory::Read_U32(request.buffer_in + 0x10); - u8 bmRequestType = Memory::Read_U8(request.buffer_in + 0x14); - u8 bRequest = Memory::Read_U8(request.buffer_in + 0x15); - u16 wValue = Memory::Read_U16(request.buffer_in + 0x16); - u16 wIndex = Memory::Read_U16(request.buffer_in + 0x18); - u16 wLength = Memory::Read_U16(request.buffer_in + 0x1A); - u32 data = Memory::Read_U32(request.buffer_in + 0x1C); - - return_value = IPC_EINVAL; - - libusb_device_handle* dev_handle = GetDeviceByDevNum(dev_num); - - if (dev_handle == nullptr) - { - INFO_LOG(IOS_HID, "Could not find handle: %X", dev_num); - break; - } - struct libusb_transfer* transfer = libusb_alloc_transfer(0); - transfer->flags |= LIBUSB_TRANSFER_FREE_BUFFER | LIBUSB_TRANSFER_FREE_TRANSFER; - - u8* buffer = (u8*)malloc(wLength + LIBUSB_CONTROL_SETUP_SIZE); - libusb_fill_control_setup(buffer, bmRequestType, bRequest, wValue, wIndex, wLength); - Memory::CopyFromEmu(buffer + LIBUSB_CONTROL_SETUP_SIZE, data, wLength); - libusb_fill_control_transfer(transfer, dev_handle, buffer, handleUsbUpdates, - (void*)(size_t)request.address, /* no timeout */ 0); - libusb_submit_transfer(transfer); - - // DEBUG_LOG(IOS_HID, "HID::IOCtl(Control)(%02X, %02X) (BufferIn: (%08x, %i), - // request.buffer_out: - // (%08x, %i)", - // bmRequestType, bRequest, BufferIn, request.buffer_in_size, request.buffer_out, - // request.buffer_out_size); - - // It's the async way! - return GetNoReply(); - } - case IOCTL_HID_INTERRUPT_OUT: - case IOCTL_HID_INTERRUPT_IN: - { - u32 dev_num = Memory::Read_U32(request.buffer_in + 0x10); - u32 endpoint = Memory::Read_U32(request.buffer_in + 0x14); - u32 length = Memory::Read_U32(request.buffer_in + 0x18); - - u32 data = Memory::Read_U32(request.buffer_in + 0x1C); - - return_value = IPC_EINVAL; - - libusb_device_handle* dev_handle = GetDeviceByDevNum(dev_num); - - if (dev_handle == nullptr) - { - INFO_LOG(IOS_HID, "Could not find handle: %X", dev_num); - break; - } - - struct libusb_transfer* transfer = libusb_alloc_transfer(0); - transfer->flags |= LIBUSB_TRANSFER_FREE_TRANSFER; - libusb_fill_interrupt_transfer(transfer, dev_handle, endpoint, Memory::GetPointer(data), length, - handleUsbUpdates, (void*)(size_t)request.address, 0); - libusb_submit_transfer(transfer); - - // It's the async way! - return GetNoReply(); - } - case IOCTL_HID_SHUTDOWN: - { - std::lock_guard lk(m_device_list_reply_mutex); - if (deviceCommandAddress != 0) - { - IOCtlRequest pending_request{deviceCommandAddress}; - Memory::Write_U32(0xFFFFFFFF, pending_request.buffer_out); - EnqueueReply(pending_request, -1); - deviceCommandAddress = 0; - } - INFO_LOG(IOS_HID, "HID::IOCtl(Shutdown) (BufferIn: (%08x, %i), BufferOut: (%08x, %i)", - request.buffer_in, request.buffer_in_size, request.buffer_out, - request.buffer_out_size); - break; - } - default: - request.Log(GetDeviceName(), LogTypes::IOS_HID); - } - - return GetDefaultReply(return_value); -} - -bool USB_HIDv4::ClaimDevice(libusb_device_handle* dev) -{ - int ret = 0; - if ((ret = libusb_kernel_driver_active(dev, 0)) == 1) - { - if ((ret = libusb_detach_kernel_driver(dev, 0)) && ret != LIBUSB_ERROR_NOT_SUPPORTED) - { - ERROR_LOG(IOS_HID, "libusb_detach_kernel_driver failed with error: %d", ret); - return false; - } - } - else if (ret != 0 && ret != LIBUSB_ERROR_NOT_SUPPORTED) - { - ERROR_LOG(IOS_HID, "libusb_kernel_driver_active error ret = %d", ret); - return false; - } - - if ((ret = libusb_claim_interface(dev, 0))) - { - ERROR_LOG(IOS_HID, "libusb_claim_interface failed with error: %d", ret); - return false; - } - - return true; -} - -IPCCommandResult USB_HIDv4::IOCtlV(const IOCtlVRequest& request) -{ - Dolphin_Debugger::PrintCallstack(LogTypes::IOS_HID, LogTypes::LWARNING); - request.DumpUnknown(GetDeviceName(), LogTypes::IOS_HID); - return GetDefaultReply(IPC_SUCCESS); -} - -void USB_HIDv4::ConvertDeviceToWii(USB::DeviceDescriptor* dest, const libusb_device_descriptor* src) -{ - dest->bLength = src->bLength; - dest->bDescriptorType = src->bDescriptorType; - dest->bcdUSB = Common::swap16(src->bcdUSB); - dest->bDeviceClass = src->bDeviceClass; - dest->bDeviceSubClass = src->bDeviceSubClass; - dest->bDeviceProtocol = src->bDeviceProtocol; - dest->bMaxPacketSize0 = src->bMaxPacketSize0; - dest->idVendor = Common::swap16(src->idVendor); - dest->idProduct = Common::swap16(src->idProduct); - dest->bcdDevice = Common::swap16(src->bcdDevice); - dest->iManufacturer = src->iManufacturer; - dest->iProduct = src->iProduct; - dest->iSerialNumber = src->iSerialNumber; - dest->bNumConfigurations = src->bNumConfigurations; -} - -void USB_HIDv4::ConvertConfigToWii(USB::ConfigDescriptor* dest, const libusb_config_descriptor* src) -{ - memcpy(dest, src, sizeof(USB::ConfigDescriptor)); - dest->wTotalLength = Common::swap16(dest->wTotalLength); -} - -void USB_HIDv4::ConvertInterfaceToWii(USB::InterfaceDescriptor* dest, - const libusb_interface_descriptor* src) -{ - memcpy(dest, src, sizeof(USB::InterfaceDescriptor)); -} - -void USB_HIDv4::ConvertEndpointToWii(USB::EndpointDescriptor* dest, - const libusb_endpoint_descriptor* src) -{ - memcpy(dest, src, sizeof(USB::EndpointDescriptor)); - dest->wMaxPacketSize = Common::swap16(dest->wMaxPacketSize); -} - -void USB_HIDv4::FillOutDevices(const IOCtlRequest& request) -{ - static u16 check = 1; - int OffsetBuffer = request.buffer_out; - int OffsetStart = 0; - // int OffsetDevice = 0; - int d, c, ic, i, e; /* config, interface container, interface, endpoint */ - - libusb_device** list; - // libusb_device *found = nullptr; - ssize_t cnt = libusb_get_device_list(nullptr, &list); - INFO_LOG(IOS_HID, "Found %ld viable USB devices.", cnt); - for (d = 0; d < cnt; d++) - { - libusb_device* device = list[d]; - struct libusb_device_descriptor desc; - int dRet = libusb_get_device_descriptor(device, &desc); - if (dRet) - { - // could not aquire the descriptor, no point in trying to use it. - WARN_LOG(IOS_HID, "libusb_get_device_descriptor failed with error: %d", dRet); - continue; - } - OffsetStart = OffsetBuffer; - OffsetBuffer += 4; // skip length for now, fill at end - - OffsetBuffer += 4; // skip devNum for now - - USB::DeviceDescriptor wii_device; - ConvertDeviceToWii(&wii_device, &desc); - Memory::CopyToEmu(OffsetBuffer, &wii_device, wii_device.bLength); - OffsetBuffer += Common::AlignUp(wii_device.bLength, 4); - bool deviceValid = true; - bool isHID = false; - - for (c = 0; deviceValid && c < desc.bNumConfigurations; c++) - { - struct libusb_config_descriptor* config = nullptr; - int cRet = libusb_get_config_descriptor(device, c, &config); - // do not try to use usb devices with more than one interface, games can crash - if (cRet == 0 && config->bNumInterfaces <= MAX_HID_INTERFACES) - { - USB::ConfigDescriptor wii_config; - ConvertConfigToWii(&wii_config, config); - Memory::CopyToEmu(OffsetBuffer, &wii_config, wii_config.bLength); - OffsetBuffer += Common::AlignUp(wii_config.bLength, 4); - - for (ic = 0; ic < config->bNumInterfaces; ic++) - { - const struct libusb_interface* interfaceContainer = &config->interface[ic]; - - for (i = 0; i < interfaceContainer->num_altsetting; i++) - { - const struct libusb_interface_descriptor* interface = - &interfaceContainer->altsetting[i]; - - if (interface->bInterfaceClass == LIBUSB_CLASS_HID) - isHID = true; - - USB::InterfaceDescriptor wii_interface; - ConvertInterfaceToWii(&wii_interface, interface); - Memory::CopyToEmu(OffsetBuffer, &wii_interface, wii_interface.bLength); - OffsetBuffer += Common::AlignUp(wii_interface.bLength, 4); - - for (e = 0; e < interface->bNumEndpoints; e++) - { - const struct libusb_endpoint_descriptor* endpoint = &interface->endpoint[e]; - - USB::EndpointDescriptor wii_endpoint; - ConvertEndpointToWii(&wii_endpoint, endpoint); - Memory::CopyToEmu(OffsetBuffer, &wii_endpoint, wii_endpoint.bLength); - OffsetBuffer += Common::AlignUp(wii_endpoint.bLength, 4); - - } // endpoints - } // interfaces - } // interface containters - libusb_free_config_descriptor(config); - config = nullptr; - } - else - { - if (cRet) - WARN_LOG(IOS_HID, "libusb_get_config_descriptor failed with: %d", cRet); - deviceValid = false; - OffsetBuffer = OffsetStart; - } - } // configs - - if (!isHID) - { - deviceValid = false; - OffsetBuffer = OffsetStart; - } - - if (deviceValid) - { - Memory::Write_U32(OffsetBuffer - OffsetStart, OffsetStart); // fill in length - - int devNum = GetAvailableDevNum(desc.idVendor, desc.idProduct, libusb_get_bus_number(device), - libusb_get_device_address(device), check); - if (devNum < 0) - { - // too many devices to handle. - ERROR_LOG(IOS_HID, "Exhausted device list, there are way too many usb devices plugged in."); - OffsetBuffer = OffsetStart; - continue; - } - - INFO_LOG(IOS_HID, "Found device with Vendor: %X Product: %X Devnum: %d", desc.idVendor, - desc.idProduct, devNum); - - Memory::Write_U32(devNum, OffsetStart + 4); // write device num - } - } - - // Find devices that no longer exists and free them - for (i = 0; i < MAX_DEVICE_DEVNUM; i++) - { - u16 check_cur = (u16)(hidDeviceAliases[i] >> 48); - if (hidDeviceAliases[i] != 0 && check_cur != check) - { - INFO_LOG(IOS_HID, "Removing: device %d %hX %hX", i, check, check_cur); - std::lock_guard lk(m_open_devices_mutex); - if (m_open_devices.find(i) != m_open_devices.end()) - { - libusb_device_handle* handle = m_open_devices[i]; - libusb_close(handle); - m_open_devices.erase(i); - } - hidDeviceAliases[i] = 0; - } - } - check++; - - libusb_free_device_list(list, 1); - - Memory::Write_U32(0xFFFFFFFF, OffsetBuffer); // no more devices -} - -libusb_device_handle* USB_HIDv4::GetDeviceByDevNum(u32 devNum) -{ - libusb_device** list; - libusb_device_handle* handle = nullptr; - ssize_t cnt; - - if (devNum >= MAX_DEVICE_DEVNUM) - return nullptr; - - std::lock_guard lk(m_open_devices_mutex); - - if (m_open_devices.find(devNum) != m_open_devices.end()) - { - handle = m_open_devices[devNum]; - if (libusb_kernel_driver_active(handle, 0) != LIBUSB_ERROR_NO_DEVICE) - { - return handle; - } - else - { - libusb_close(handle); - m_open_devices.erase(devNum); - } - } - - cnt = libusb_get_device_list(nullptr, &list); - - if (cnt < 0) - return nullptr; - -#ifdef _WIN32 - static bool has_warned_about_drivers = false; -#endif - - for (ssize_t i = 0; i < cnt; i++) - { - libusb_device* device = list[i]; - struct libusb_device_descriptor desc; - int dRet = libusb_get_device_descriptor(device, &desc); - u8 bus = libusb_get_bus_number(device); - u8 port = libusb_get_device_address(device); - u64 unique_id = - ((u64)desc.idVendor << 32) | ((u64)desc.idProduct << 16) | ((u64)bus << 8) | (u64)port; - if ((hidDeviceAliases[devNum] & HID_ID_MASK) == unique_id) - { - int ret = libusb_open(device, &handle); - if (ret) - { - if (ret == LIBUSB_ERROR_ACCESS) - { - if (dRet) - { - ERROR_LOG(IOS_HID, "Dolphin does not have access to this device: Bus %03d Device " - "%03d: ID ????:???? (couldn't get id).", - bus, port); - } - else - { - ERROR_LOG( - IOS_HID, - "Dolphin does not have access to this device: Bus %03d Device %03d: ID %04X:%04X.", - bus, port, desc.idVendor, desc.idProduct); - } - } -#ifdef _WIN32 - else if (ret == LIBUSB_ERROR_NOT_SUPPORTED) - { - if (!has_warned_about_drivers) - { - // Max of one warning. - has_warned_about_drivers = true; - WARN_LOG(IOS_HID, "Please install the libusb drivers for the device %04X:%04X", - desc.idVendor, desc.idProduct); - } - } -#endif - else - { - ERROR_LOG(IOS_HID, "libusb_open failed to open device with error = %d", ret); - } - continue; - } - - if (!ClaimDevice(handle)) - { - ERROR_LOG(IOS_HID, "Could not claim the device for handle: %X", devNum); - libusb_close(handle); - continue; - } - - m_open_devices[devNum] = handle; - break; - } - else - { - handle = nullptr; - } - } - - libusb_free_device_list(list, 1); - - return handle; -} - -int USB_HIDv4::GetAvailableDevNum(u16 idVendor, u16 idProduct, u8 bus, u8 port, u16 check) -{ - int pos = -1; - u64 unique_id = ((u64)idVendor << 32) | ((u64)idProduct << 16) | ((u64)bus << 8) | (u64)port; - - for (int i = 0; i < MAX_DEVICE_DEVNUM; i++) - { - u64 id = hidDeviceAliases[i] & HID_ID_MASK; - if (id == 0 && pos == -1) - { - pos = i; - } - else if (id == unique_id) - { - hidDeviceAliases[i] = id | ((u64)check << 48); - return i; - } - } - - if (pos != -1) - { - hidDeviceAliases[pos] = unique_id | ((u64)check << 48); - return pos; - } - - return -1; -} -} // namespace Device -} // namespace HLE -} // namespace IOS diff --git a/Source/Core/Core/IOS/USB/USB_HIDv4.h b/Source/Core/Core/IOS/USB/USB_HIDv4.h deleted file mode 100644 index 0732a91b44..0000000000 --- a/Source/Core/Core/IOS/USB/USB_HIDv4.h +++ /dev/null @@ -1,89 +0,0 @@ -// Copyright 2012 Dolphin Emulator Project -// Licensed under GPLv2+ -// Refer to the license.txt file included. - -#pragma once - -#include -#include -#include -#include -#include - -#include "Common/CommonTypes.h" -#include "Core/IOS/Device.h" -#include "Core/IOS/IPC.h" -#include "Core/IOS/USB/Common.h" - -// Forward declare things which we need from libusb header. -// This prevents users of this file from indirectly pulling in libusb. -#if defined(_WIN32) -#define LIBUSB_CALL WINAPI -#else -#define LIBUSB_CALL -#endif -struct libusb_config_descriptor; -struct libusb_device_descriptor; -struct libusb_device_handle; -struct libusb_endpoint_descriptor; -struct libusb_interface_descriptor; -struct libusb_transfer; - -namespace IOS -{ -namespace HLE -{ -#define HID_ID_MASK 0x0000FFFFFFFFFFFF -#define MAX_HID_INTERFACES 1 - -namespace Device -{ -class USB_HIDv4 : public Device -{ -public: - USB_HIDv4(u32 _DeviceID, const std::string& _rDeviceName); - - virtual ~USB_HIDv4(); - - IPCCommandResult IOCtlV(const IOCtlVRequest& request) override; - IPCCommandResult IOCtl(const IOCtlRequest& request) override; - -private: - enum - { - IOCTL_HID_GET_ATTACHED = 0x00, - IOCTL_HID_SET_SUSPEND = 0x01, - IOCTL_HID_CONTROL = 0x02, - IOCTL_HID_INTERRUPT_IN = 0x03, - IOCTL_HID_INTERRUPT_OUT = 0x04, - IOCTL_HID_GET_US_STRING = 0x05, - IOCTL_HID_OPEN = 0x06, - IOCTL_HID_SHUTDOWN = 0x07, - IOCTL_HID_CANCEL_INTERRUPT = 0x08, - }; - - u32 deviceCommandAddress; - void FillOutDevices(const IOCtlRequest& request); - int GetAvailableDevNum(u16 idVendor, u16 idProduct, u8 bus, u8 port, u16 check); - bool ClaimDevice(libusb_device_handle* dev); - - void ConvertDeviceToWii(USB::DeviceDescriptor* dest, const libusb_device_descriptor* src); - void ConvertConfigToWii(USB::ConfigDescriptor* dest, const libusb_config_descriptor* src); - void ConvertInterfaceToWii(USB::InterfaceDescriptor* dest, - const libusb_interface_descriptor* src); - void ConvertEndpointToWii(USB::EndpointDescriptor* dest, const libusb_endpoint_descriptor* src); - - static void checkUsbUpdates(USB_HIDv4* hid); - static void LIBUSB_CALL handleUsbUpdates(libusb_transfer* transfer); - - libusb_device_handle* GetDeviceByDevNum(u32 devNum); - std::map m_open_devices; - std::mutex m_open_devices_mutex; - std::mutex m_device_list_reply_mutex; - - std::thread usb_thread; - bool usb_thread_running; -}; -} // namespace Device -} // namespace HLE -} // namespace IOS