IOS: Implement USB_VEN (/dev/usb/ven)
This commit is contained in:
parent
c9f4889437
commit
b63b6111b3
|
@ -158,10 +158,11 @@ set(SRCS ActionReplay.cpp
|
|||
IOS/USB/OH0/OH0.cpp
|
||||
IOS/USB/OH0/OH0Device.cpp
|
||||
IOS/USB/USB_HID/HIDv4.cpp
|
||||
IOS/USB/USB_VEN/VEN.cpp
|
||||
IOS/USB/USBV0.cpp
|
||||
IOS/USB/USBV4.cpp
|
||||
IOS/USB/USBV5.cpp
|
||||
IOS/USB/USB_KBD.cpp
|
||||
IOS/USB/USB_VEN.cpp
|
||||
IOS/USB/Bluetooth/BTBase.cpp
|
||||
IOS/USB/Bluetooth/BTEmu.cpp
|
||||
IOS/USB/Bluetooth/BTStub.cpp
|
||||
|
|
|
@ -195,10 +195,11 @@
|
|||
<ClCompile Include="IOS\USB\OH0\OH0.cpp" />
|
||||
<ClCompile Include="IOS\USB\OH0\OH0Device.cpp" />
|
||||
<ClCompile Include="IOS\USB\USB_HID\HIDv4.cpp" />
|
||||
<ClCompile Include="IOS\USB\USB_VEN\VEN.cpp" />
|
||||
<ClCompile Include="IOS\USB\USBV0.cpp" />
|
||||
<ClCompile Include="IOS\USB\USBV4.cpp" />
|
||||
<ClCompile Include="IOS\USB\USBV5.cpp" />
|
||||
<ClCompile Include="IOS\USB\USB_KBD.cpp" />
|
||||
<ClCompile Include="IOS\USB\USB_VEN.cpp" />
|
||||
<ClCompile Include="IOS\USB\Bluetooth\BTBase.cpp" />
|
||||
<ClCompile Include="IOS\USB\Bluetooth\BTEmu.cpp" />
|
||||
<ClCompile Include="IOS\USB\Bluetooth\BTStub.cpp" />
|
||||
|
@ -427,10 +428,11 @@
|
|||
<ClInclude Include="IOS\USB\OH0\OH0.h" />
|
||||
<ClInclude Include="IOS\USB\OH0\OH0Device.h" />
|
||||
<ClInclude Include="IOS\USB\USB_HID\HIDv4.h" />
|
||||
<ClInclude Include="IOS\USB\USB_VEN\VEN.h" />
|
||||
<ClInclude Include="IOS\USB\USBV0.h" />
|
||||
<ClInclude Include="IOS\USB\USBV4.h" />
|
||||
<ClInclude Include="IOS\USB\USBV5.h" />
|
||||
<ClInclude Include="IOS\USB\USB_KBD.h" />
|
||||
<ClInclude Include="IOS\USB\USB_VEN.h" />
|
||||
<ClInclude Include="IOS\USB\Bluetooth\BTBase.h" />
|
||||
<ClInclude Include="IOS\USB\Bluetooth\BTEmu.h" />
|
||||
<ClInclude Include="IOS\USB\Bluetooth\BTStub.h" />
|
||||
|
|
|
@ -788,16 +788,19 @@
|
|||
<ClCompile Include="IOS\USB\USB_HID\HIDv4.cpp">
|
||||
<Filter>IOS\USB</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="IOS\USB\USB_VEN\VEN.cpp">
|
||||
<Filter>IOS\USB</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="IOS\USB\USBV0.cpp">
|
||||
<Filter>IOS\USB</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="IOS\USB\USBV4.cpp">
|
||||
<Filter>IOS\USB</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="IOS\USB\USB_KBD.cpp">
|
||||
<ClCompile Include="IOS\USB\USBV5.cpp">
|
||||
<Filter>IOS\USB</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="IOS\USB\USB_VEN.cpp">
|
||||
<ClCompile Include="IOS\USB\USB_KBD.cpp">
|
||||
<Filter>IOS\USB</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="IOS\WFS\WFSI.cpp">
|
||||
|
@ -1383,16 +1386,19 @@
|
|||
<ClInclude Include="IOS\USB\USB_HID\HIDv4.h">
|
||||
<Filter>IOS\USB</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="IOS\USB\USB_VEN\VEN.h">
|
||||
<Filter>IOS\USB</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="IOS\USB\USBV0.h">
|
||||
<Filter>IOS\USB</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="IOS\USB\USBV4.h">
|
||||
<Filter>IOS\USB</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="IOS\USB\USB_KBD.h">
|
||||
<ClInclude Include="IOS\USB\USBV5.h">
|
||||
<Filter>IOS\USB</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="IOS\USB\USB_VEN.h">
|
||||
<ClInclude Include="IOS\USB\USB_KBD.h">
|
||||
<Filter>IOS\USB</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="IOS\WFS\WFSI.h">
|
||||
|
|
|
@ -53,7 +53,7 @@
|
|||
#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/USB/USB_VEN/VEN.h"
|
||||
#include "Core/IOS/WFS/WFSI.h"
|
||||
#include "Core/IOS/WFS/WFSSRV.h"
|
||||
|
||||
|
@ -507,12 +507,12 @@ void Reinit()
|
|||
AddDevice<Device::NetIPTop>("/dev/net/ip/top");
|
||||
AddDevice<Device::NetSSL>("/dev/net/ssl");
|
||||
AddDevice<Device::USB_KBD>("/dev/usb/kbd");
|
||||
AddDevice<Device::USB_VEN>("/dev/usb/ven");
|
||||
AddDevice<Device::SDIOSlot0>("/dev/sdio/slot0");
|
||||
AddDevice<Device::Stub>("/dev/sdio/slot1");
|
||||
AddDevice<Device::USB_HIDv4>("/dev/usb/hid");
|
||||
AddDevice<Device::OH0>("/dev/usb/oh0");
|
||||
AddDevice<Device::Stub>("/dev/usb/oh1");
|
||||
AddDevice<Device::USB_VEN>("/dev/usb/ven");
|
||||
AddDevice<Device::WFSSRV>("/dev/usb/wfssrv");
|
||||
AddDevice<Device::WFSI>("/dev/wfsi");
|
||||
}
|
||||
|
|
|
@ -0,0 +1,55 @@
|
|||
// Copyright 2017 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <numeric>
|
||||
#include <vector>
|
||||
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Core/HW/Memmap.h"
|
||||
#include "Core/IOS/Device.h"
|
||||
#include "Core/IOS/USB/USBV5.h"
|
||||
|
||||
namespace IOS
|
||||
{
|
||||
namespace HLE
|
||||
{
|
||||
namespace USB
|
||||
{
|
||||
V5CtrlMessage::V5CtrlMessage(const IOCtlVRequest& ioctlv)
|
||||
: CtrlMessage(ioctlv, Memory::Read_U32(ioctlv.in_vectors[0].address + 16))
|
||||
{
|
||||
request_type = Memory::Read_U8(ioctlv.in_vectors[0].address + 8);
|
||||
request = Memory::Read_U8(ioctlv.in_vectors[0].address + 9);
|
||||
value = Memory::Read_U16(ioctlv.in_vectors[0].address + 10);
|
||||
index = Memory::Read_U16(ioctlv.in_vectors[0].address + 12);
|
||||
length = Memory::Read_U16(ioctlv.in_vectors[0].address + 14);
|
||||
}
|
||||
|
||||
V5BulkMessage::V5BulkMessage(const IOCtlVRequest& ioctlv)
|
||||
: BulkMessage(ioctlv, Memory::Read_U32(ioctlv.in_vectors[0].address + 8))
|
||||
{
|
||||
length = Memory::Read_U16(ioctlv.in_vectors[0].address + 12);
|
||||
endpoint = Memory::Read_U8(ioctlv.in_vectors[0].address + 18);
|
||||
}
|
||||
|
||||
V5IntrMessage::V5IntrMessage(const IOCtlVRequest& ioctlv)
|
||||
: IntrMessage(ioctlv, Memory::Read_U32(ioctlv.in_vectors[0].address + 8))
|
||||
{
|
||||
length = Memory::Read_U16(ioctlv.in_vectors[0].address + 12);
|
||||
endpoint = Memory::Read_U8(ioctlv.in_vectors[0].address + 14);
|
||||
}
|
||||
|
||||
V5IsoMessage::V5IsoMessage(const IOCtlVRequest& ioctlv)
|
||||
: IsoMessage(ioctlv, Memory::Read_U32(ioctlv.in_vectors[0].address + 8))
|
||||
{
|
||||
num_packets = Memory::Read_U8(ioctlv.in_vectors[0].address + 16);
|
||||
endpoint = Memory::Read_U8(ioctlv.in_vectors[0].address + 17);
|
||||
packet_sizes_addr = Memory::Read_U32(ioctlv.in_vectors[0].address + 12);
|
||||
for (size_t i = 0; i < num_packets; ++i)
|
||||
packet_sizes.push_back(Memory::Read_U16(static_cast<u32>(packet_sizes_addr + i * sizeof(u16))));
|
||||
length = std::accumulate(packet_sizes.begin(), packet_sizes.end(), 0);
|
||||
}
|
||||
} // namespace USB
|
||||
} // namespace HLE
|
||||
} // namespace IOS
|
|
@ -0,0 +1,58 @@
|
|||
// 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 late USB interfaces for /dev/usb/ven and /dev/usb/hid (since IOS57 which
|
||||
// reorganised the USB modules in IOS).
|
||||
|
||||
namespace IOS
|
||||
{
|
||||
namespace HLE
|
||||
{
|
||||
struct IOCtlRequest;
|
||||
|
||||
namespace USB
|
||||
{
|
||||
enum V5Requests
|
||||
{
|
||||
IOCTL_USBV5_GETVERSION = 0,
|
||||
IOCTL_USBV5_GETDEVICECHANGE = 1,
|
||||
IOCTL_USBV5_SHUTDOWN = 2,
|
||||
IOCTL_USBV5_GETDEVPARAMS = 3,
|
||||
IOCTL_USBV5_ATTACHFINISH = 6,
|
||||
IOCTL_USBV5_SETALTERNATE = 7,
|
||||
IOCTL_USBV5_SUSPEND_RESUME = 16,
|
||||
IOCTL_USBV5_CANCELENDPOINT = 17,
|
||||
IOCTLV_USBV5_CTRLMSG = 18,
|
||||
IOCTLV_USBV5_INTRMSG = 19,
|
||||
IOCTLV_USBV5_ISOMSG = 20,
|
||||
IOCTLV_USBV5_BULKMSG = 21
|
||||
};
|
||||
|
||||
struct V5CtrlMessage final : CtrlMessage
|
||||
{
|
||||
explicit V5CtrlMessage(const IOCtlVRequest& ioctlv);
|
||||
};
|
||||
|
||||
struct V5BulkMessage final : BulkMessage
|
||||
{
|
||||
explicit V5BulkMessage(const IOCtlVRequest& ioctlv);
|
||||
};
|
||||
|
||||
struct V5IntrMessage final : IntrMessage
|
||||
{
|
||||
explicit V5IntrMessage(const IOCtlVRequest& ioctlv);
|
||||
};
|
||||
|
||||
struct V5IsoMessage final : IsoMessage
|
||||
{
|
||||
explicit V5IsoMessage(const IOCtlVRequest& cmd_buffer);
|
||||
};
|
||||
} // namespace USB
|
||||
} // namespace HLE
|
||||
} // namespace IOS
|
|
@ -1,83 +0,0 @@
|
|||
// Copyright 2016 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "Core/IOS/USB/USB_VEN.h"
|
||||
#include "Common/Logging/Log.h"
|
||||
#include "Core/HW/Memmap.h"
|
||||
|
||||
namespace IOS
|
||||
{
|
||||
namespace HLE
|
||||
{
|
||||
namespace Device
|
||||
{
|
||||
USB_VEN::USB_VEN(u32 device_id, const std::string& device_name) : Device(device_id, device_name)
|
||||
{
|
||||
}
|
||||
|
||||
IPCCommandResult USB_VEN::IOCtlV(const IOCtlVRequest& request)
|
||||
{
|
||||
request.Dump(GetDeviceName());
|
||||
return GetNoReply();
|
||||
}
|
||||
|
||||
IPCCommandResult USB_VEN::IOCtl(const IOCtlRequest& request)
|
||||
{
|
||||
request.Log(GetDeviceName(), LogTypes::OSHLE);
|
||||
|
||||
IPCCommandResult reply = GetDefaultReply(IPC_SUCCESS);
|
||||
switch (request.request)
|
||||
{
|
||||
case USBV5_IOCTL_GETVERSION:
|
||||
Memory::Write_U32(0x50001, request.buffer_out);
|
||||
reply = GetDefaultReply(IPC_SUCCESS);
|
||||
break;
|
||||
|
||||
case USBV5_IOCTL_GETDEVICECHANGE:
|
||||
{
|
||||
// sent on change
|
||||
static bool firstcall = true;
|
||||
if (firstcall)
|
||||
{
|
||||
reply = GetDefaultReply(IPC_SUCCESS);
|
||||
firstcall = false;
|
||||
}
|
||||
|
||||
// num devices
|
||||
reply = GetDefaultReply(0);
|
||||
return reply;
|
||||
}
|
||||
break;
|
||||
|
||||
case USBV5_IOCTL_ATTACHFINISH:
|
||||
reply = GetDefaultReply(IPC_SUCCESS);
|
||||
break;
|
||||
|
||||
case USBV5_IOCTL_SUSPEND_RESUME:
|
||||
DEBUG_LOG(OSHLE, "Device: %i Resumed: %i", Memory::Read_U32(request.buffer_in),
|
||||
Memory::Read_U32(request.buffer_in + 4));
|
||||
reply = GetDefaultReply(IPC_SUCCESS);
|
||||
break;
|
||||
|
||||
case USBV5_IOCTL_GETDEVPARAMS:
|
||||
{
|
||||
s32 device = Memory::Read_U32(request.buffer_in);
|
||||
u32 unk = Memory::Read_U32(request.buffer_in + 4);
|
||||
|
||||
DEBUG_LOG(OSHLE, "USBV5_IOCTL_GETDEVPARAMS device: %i unk: %i", device, unk);
|
||||
|
||||
Memory::Write_U32(0, request.buffer_out);
|
||||
|
||||
reply = GetDefaultReply(IPC_SUCCESS);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
request.Log(GetDeviceName(), LogTypes::OSHLE, LogTypes::LDEBUG);
|
||||
}
|
||||
return reply;
|
||||
}
|
||||
} // namespace Device
|
||||
} // namespace HLE
|
||||
} // namespace IOS
|
|
@ -1,46 +0,0 @@
|
|||
// Copyright 2016 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Core/IOS/Device.h"
|
||||
#include "Core/IOS/IPC.h"
|
||||
|
||||
namespace IOS
|
||||
{
|
||||
namespace HLE
|
||||
{
|
||||
namespace Device
|
||||
{
|
||||
class USB_VEN final : public Device
|
||||
{
|
||||
public:
|
||||
USB_VEN(u32 device_id, const std::string& device_name);
|
||||
|
||||
IPCCommandResult IOCtlV(const IOCtlVRequest& request) override;
|
||||
IPCCommandResult IOCtl(const IOCtlRequest& request) override;
|
||||
|
||||
private:
|
||||
enum USBIOCtl
|
||||
{
|
||||
USBV5_IOCTL_GETVERSION = 0,
|
||||
USBV5_IOCTL_GETDEVICECHANGE = 1,
|
||||
USBV5_IOCTL_SHUTDOWN = 2,
|
||||
USBV5_IOCTL_GETDEVPARAMS = 3,
|
||||
USBV5_IOCTL_ATTACHFINISH = 6,
|
||||
USBV5_IOCTL_SETALTERNATE = 7,
|
||||
USBV5_IOCTL_SUSPEND_RESUME = 16,
|
||||
USBV5_IOCTL_CANCELENDPOINT = 17,
|
||||
USBV5_IOCTL_CTRLMSG = 18,
|
||||
USBV5_IOCTL_INTRMSG = 19,
|
||||
USBV5_IOCTL_ISOMSG = 20,
|
||||
USBV5_IOCTL_BULKMSG = 21
|
||||
};
|
||||
};
|
||||
} // namespace Device
|
||||
} // namespace HLE
|
||||
} // namespace IOS
|
|
@ -0,0 +1,333 @@
|
|||
// Copyright 2017 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <cstring>
|
||||
|
||||
#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/USBV5.h"
|
||||
#include "Core/IOS/USB/USB_VEN/VEN.h"
|
||||
|
||||
namespace IOS
|
||||
{
|
||||
namespace HLE
|
||||
{
|
||||
namespace Device
|
||||
{
|
||||
USB_VEN::USB_VEN(u32 device_id, const std::string& device_name) : USBHost(device_id, device_name)
|
||||
{
|
||||
}
|
||||
|
||||
USB_VEN::~USB_VEN()
|
||||
{
|
||||
StopThreads();
|
||||
}
|
||||
|
||||
ReturnCode USB_VEN::Open(const OpenRequest& request)
|
||||
{
|
||||
const u32 ios_major_version = GetVersion();
|
||||
if (ios_major_version != 57 && ios_major_version != 58 && ios_major_version != 59)
|
||||
return IPC_ENOENT;
|
||||
return USBHost::Open(request);
|
||||
}
|
||||
|
||||
IPCCommandResult USB_VEN::IOCtl(const IOCtlRequest& request)
|
||||
{
|
||||
request.Log(GetDeviceName(), LogTypes::IOS_USB);
|
||||
switch (request.request)
|
||||
{
|
||||
case USB::IOCTL_USBV5_GETVERSION:
|
||||
Memory::Write_U32(VERSION, request.buffer_out);
|
||||
return GetDefaultReply(IPC_SUCCESS);
|
||||
case USB::IOCTL_USBV5_GETDEVICECHANGE:
|
||||
return GetDeviceChange(request);
|
||||
case USB::IOCTL_USBV5_SHUTDOWN:
|
||||
return Shutdown(request);
|
||||
case USB::IOCTL_USBV5_GETDEVPARAMS:
|
||||
return HandleDeviceIOCtl(request, &USB_VEN::GetDeviceInfo);
|
||||
case USB::IOCTL_USBV5_ATTACHFINISH:
|
||||
return GetDefaultReply(IPC_SUCCESS);
|
||||
case USB::IOCTL_USBV5_SETALTERNATE:
|
||||
return HandleDeviceIOCtl(request, &USB_VEN::SetAlternateSetting);
|
||||
case USB::IOCTL_USBV5_SUSPEND_RESUME:
|
||||
return HandleDeviceIOCtl(request, &USB_VEN::SuspendResume);
|
||||
case USB::IOCTL_USBV5_CANCELENDPOINT:
|
||||
return HandleDeviceIOCtl(request, &USB_VEN::CancelEndpoint);
|
||||
default:
|
||||
request.DumpUnknown(GetDeviceName(), LogTypes::IOS_USB, LogTypes::LERROR);
|
||||
return GetDefaultReply(IPC_SUCCESS);
|
||||
}
|
||||
}
|
||||
|
||||
IPCCommandResult USB_VEN::IOCtlV(const IOCtlVRequest& request)
|
||||
{
|
||||
static const std::map<u32, u32> s_num_vectors = {
|
||||
{USB::IOCTLV_USBV5_CTRLMSG, 2},
|
||||
{USB::IOCTLV_USBV5_INTRMSG, 2},
|
||||
{USB::IOCTLV_USBV5_BULKMSG, 2},
|
||||
{USB::IOCTLV_USBV5_ISOMSG, 4},
|
||||
};
|
||||
|
||||
switch (request.request)
|
||||
{
|
||||
case USB::IOCTLV_USBV5_CTRLMSG:
|
||||
case USB::IOCTLV_USBV5_INTRMSG:
|
||||
case USB::IOCTLV_USBV5_BULKMSG:
|
||||
case USB::IOCTLV_USBV5_ISOMSG:
|
||||
{
|
||||
if (request.in_vectors.size() + request.io_vectors.size() != s_num_vectors.at(request.request))
|
||||
return GetDefaultReply(IPC_EINVAL);
|
||||
|
||||
const s32 device_id = Memory::Read_U32(request.in_vectors[0].address);
|
||||
auto device = GetDeviceByIOSID(device_id);
|
||||
if (!device || !device->Attach(GetInterfaceNumber(device_id)))
|
||||
return GetDefaultReply(IPC_ENOENT);
|
||||
return HandleTransfer(device, request.request,
|
||||
[&, this]() { return SubmitTransfer(*device, request); });
|
||||
}
|
||||
default:
|
||||
return GetDefaultReply(IPC_EINVAL);
|
||||
}
|
||||
}
|
||||
|
||||
void USB_VEN::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<IOCtlRequest>(hook_address);
|
||||
else
|
||||
m_devicechange_hook_request.reset();
|
||||
|
||||
p.Do(m_device_number);
|
||||
p.Do(m_ios_ids);
|
||||
p.Do(m_device_ids);
|
||||
USBHost::DoState(p);
|
||||
}
|
||||
|
||||
std::shared_ptr<USB::Device> USB_VEN::GetDeviceByIOSID(const s32 ios_id) const
|
||||
{
|
||||
std::lock_guard<std::mutex> lk{m_id_map_mutex};
|
||||
const auto iter = m_ios_ids.find(ios_id);
|
||||
if (iter == m_ios_ids.cend())
|
||||
return nullptr;
|
||||
return GetDeviceById(iter->second);
|
||||
}
|
||||
|
||||
u8 USB_VEN::GetInterfaceNumber(const s32 ios_id) const
|
||||
{
|
||||
const s32 id = Common::swap32(ios_id);
|
||||
DeviceID device_id;
|
||||
std::memcpy(&device_id, &id, sizeof(id));
|
||||
return device_id.interface_plus_1e - 0x1e;
|
||||
}
|
||||
|
||||
IPCCommandResult USB_VEN::CancelEndpoint(USB::Device& device, const IOCtlRequest& request)
|
||||
{
|
||||
const u8 endpoint = static_cast<u8>(Memory::Read_U32(request.buffer_in + 2 * sizeof(s32)));
|
||||
device.CancelTransfer(endpoint);
|
||||
return GetDefaultReply(IPC_SUCCESS);
|
||||
}
|
||||
|
||||
IPCCommandResult USB_VEN::GetDeviceChange(const IOCtlRequest& request)
|
||||
{
|
||||
std::lock_guard<std::mutex> lk{m_devicechange_hook_address_mutex};
|
||||
m_devicechange_hook_request = std::make_unique<IOCtlRequest>(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_VEN::GetDeviceInfo(USB::Device& device, const IOCtlRequest& request)
|
||||
{
|
||||
const s32 device_id = Memory::Read_U32(request.buffer_in);
|
||||
if (request.buffer_out == 0 || request.buffer_out_size != 0xc0)
|
||||
return GetDefaultReply(IPC_EINVAL);
|
||||
|
||||
const u8 alt_setting = Memory::Read_U8(request.buffer_in + 8);
|
||||
auto descriptors = device.GetDescriptorsUSBV5(GetInterfaceNumber(device_id), alt_setting);
|
||||
if (descriptors.empty())
|
||||
return GetDefaultReply(IPC_ENOENT);
|
||||
|
||||
descriptors.resize(request.buffer_out_size - 20);
|
||||
if (descriptors.size() > request.buffer_out_size - 20)
|
||||
WARN_LOG(IOS_USB, "Buffer is too large. Only the first 172 bytes will be copied.");
|
||||
|
||||
Memory::Memset(request.buffer_out, 0, request.buffer_out_size);
|
||||
Memory::Write_U32(device_id, request.buffer_out);
|
||||
Memory::Write_U32(1, request.buffer_out + 4);
|
||||
Memory::CopyToEmu(request.buffer_out + 20, descriptors.data(), descriptors.size());
|
||||
|
||||
return GetDefaultReply(IPC_SUCCESS);
|
||||
}
|
||||
|
||||
IPCCommandResult USB_VEN::SetAlternateSetting(USB::Device& device, const IOCtlRequest& request)
|
||||
{
|
||||
const s32 device_id = Memory::Read_U32(request.buffer_in);
|
||||
if (!device.Attach(GetInterfaceNumber(device_id)))
|
||||
return GetDefaultReply(-1);
|
||||
|
||||
const u8 alt_setting = Memory::Read_U8(request.buffer_in + 2 * sizeof(s32));
|
||||
|
||||
const bool success = device.SetAltSetting(alt_setting) == 0;
|
||||
return GetDefaultReply(success ? IPC_SUCCESS : IPC_EINVAL);
|
||||
}
|
||||
|
||||
IPCCommandResult USB_VEN::Shutdown(const IOCtlRequest& request)
|
||||
{
|
||||
if (request.buffer_in != 0 || request.buffer_in_size != 0 || request.buffer_out != 0 ||
|
||||
request.buffer_out_size != 0)
|
||||
{
|
||||
return GetDefaultReply(IPC_EINVAL);
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> lk{m_devicechange_hook_address_mutex};
|
||||
if (m_devicechange_hook_request)
|
||||
{
|
||||
EnqueueReply(*m_devicechange_hook_request, IPC_SUCCESS);
|
||||
m_devicechange_hook_request.reset();
|
||||
}
|
||||
return GetDefaultReply(IPC_SUCCESS);
|
||||
}
|
||||
|
||||
IPCCommandResult USB_VEN::SuspendResume(USB::Device& device, const IOCtlRequest& request)
|
||||
{
|
||||
const s32 device_id = Memory::Read_U32(request.buffer_in);
|
||||
const s32 resumed = Memory::Read_U32(request.buffer_in + 2 * sizeof(s32));
|
||||
|
||||
// Note: this is unimplemented because there's no easy way to do this in a
|
||||
// platform-independant way (libusb does not support power management).
|
||||
INFO_LOG(IOS_USB, "[%04x:%04x %d] Received %s command", device.GetVid(), device.GetPid(),
|
||||
GetInterfaceNumber(device_id), resumed == 0 ? "suspend" : "resume");
|
||||
return GetDefaultReply(IPC_SUCCESS);
|
||||
}
|
||||
|
||||
s32 USB_VEN::SubmitTransfer(USB::Device& device, const IOCtlVRequest& ioctlv)
|
||||
{
|
||||
switch (ioctlv.request)
|
||||
{
|
||||
case USB::IOCTLV_USBV5_CTRLMSG:
|
||||
return device.SubmitTransfer(std::make_unique<USB::V5CtrlMessage>(ioctlv));
|
||||
case USB::IOCTLV_USBV5_INTRMSG:
|
||||
return device.SubmitTransfer(std::make_unique<USB::V5IntrMessage>(ioctlv));
|
||||
case USB::IOCTLV_USBV5_BULKMSG:
|
||||
return device.SubmitTransfer(std::make_unique<USB::V5BulkMessage>(ioctlv));
|
||||
case USB::IOCTLV_USBV5_ISOMSG:
|
||||
return device.SubmitTransfer(std::make_unique<USB::V5IsoMessage>(ioctlv));
|
||||
default:
|
||||
return IPC_EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
IPCCommandResult USB_VEN::HandleDeviceIOCtl(const IOCtlRequest& request, Handler handler)
|
||||
{
|
||||
if (request.buffer_in == 0 || request.buffer_in_size != 0x20)
|
||||
return GetDefaultReply(IPC_EINVAL);
|
||||
|
||||
const s32 device_id = Memory::Read_U32(request.buffer_in);
|
||||
const auto device = GetDeviceByIOSID(device_id);
|
||||
if (!device)
|
||||
return GetDefaultReply(IPC_ENOENT);
|
||||
return handler(this, *device, request);
|
||||
}
|
||||
|
||||
void USB_VEN::OnDeviceChange(const ChangeEvent event, std::shared_ptr<USB::Device> device)
|
||||
{
|
||||
std::lock_guard<std::mutex> id_map_lock{m_id_map_mutex};
|
||||
if (event == ChangeEvent::Inserted)
|
||||
{
|
||||
for (const auto& interface : device->GetInterfaces(0))
|
||||
{
|
||||
if (interface.bAlternateSetting != 0)
|
||||
continue;
|
||||
|
||||
DeviceID id;
|
||||
id.unknown = 0xe7;
|
||||
id.interface_plus_1e = interface.bInterfaceNumber + 0x1e;
|
||||
id.zero = 0x00;
|
||||
id.counter = m_device_number;
|
||||
|
||||
s32 ios_device_id = 0;
|
||||
std::memcpy(&ios_device_id, &id, sizeof(id));
|
||||
ios_device_id = Common::swap32(ios_device_id);
|
||||
m_ios_ids[ios_device_id] = device->GetId();
|
||||
m_device_ids[device->GetId()].insert(ios_device_id);
|
||||
}
|
||||
}
|
||||
else if (event == ChangeEvent::Removed)
|
||||
{
|
||||
for (const s32 ios_id : m_device_ids[device->GetId()])
|
||||
m_ios_ids.erase(ios_id);
|
||||
m_device_ids.erase(device->GetId());
|
||||
}
|
||||
}
|
||||
|
||||
void USB_VEN::OnDeviceChangeEnd()
|
||||
{
|
||||
std::lock_guard<std::mutex> lk{m_devicechange_hook_address_mutex};
|
||||
TriggerDeviceChangeReply();
|
||||
++m_device_number;
|
||||
}
|
||||
|
||||
void USB_VEN::TriggerDeviceChangeReply()
|
||||
{
|
||||
if (!m_devicechange_hook_request)
|
||||
return;
|
||||
|
||||
std::lock_guard<std::mutex> id_map_lock{m_id_map_mutex};
|
||||
u8 num_devices = 0;
|
||||
const size_t max_num = m_devicechange_hook_request->buffer_out_size / sizeof(DeviceEntry);
|
||||
for (const auto& ios_device : m_ios_ids)
|
||||
{
|
||||
if (num_devices >= max_num)
|
||||
{
|
||||
WARN_LOG(IOS_USB, "Too many devices (%d ≥ %zu), skipping", num_devices, max_num);
|
||||
break;
|
||||
}
|
||||
|
||||
const s32 ios_device_id = ios_device.first;
|
||||
const auto device = GetDeviceById(m_ios_ids.at(ios_device_id));
|
||||
if (!device)
|
||||
continue;
|
||||
const u8 interface_number = GetInterfaceNumber(ios_device_id);
|
||||
|
||||
// IOS's device list contains entries of the form:
|
||||
// e7 XX 00 YY VV VV PP PP 00 YY DD AA
|
||||
// ^^^^^^^^^^^ ^^^^^ ^^^^^ ^^ ^^^^^ ^^
|
||||
// Device ID VID PID ?? See ID Number of alt settings
|
||||
//
|
||||
// XX is 1e (for a device plugged in to the left port) + DD (interface number).
|
||||
// YY is a counter that starts at 21 and is incremented on every device change.
|
||||
// DD is the interface number (since VEN exposes each interface as a separate device).
|
||||
|
||||
DeviceEntry entry;
|
||||
entry.device_id = Common::swap32(ios_device_id);
|
||||
entry.vid = Common::swap16(device->GetVid());
|
||||
entry.pid = Common::swap16(device->GetPid());
|
||||
entry.unknown = 0x00;
|
||||
entry.device_number = ios_device_id & 0xff;
|
||||
entry.interface_number = interface_number;
|
||||
entry.num_altsettings = device->GetNumberOfAltSettings(interface_number);
|
||||
|
||||
Memory::CopyToEmu(m_devicechange_hook_request->buffer_out + sizeof(entry) * num_devices++,
|
||||
&entry, sizeof(entry));
|
||||
}
|
||||
|
||||
EnqueueReply(*m_devicechange_hook_request, num_devices, 0, CoreTiming::FromThread::ANY);
|
||||
m_devicechange_hook_request.reset();
|
||||
INFO_LOG(IOS_USB, "%d device(s), including interfaces", num_devices);
|
||||
}
|
||||
} // namespace Device
|
||||
} // namespace HLE
|
||||
} // namespace IOS
|
|
@ -0,0 +1,95 @@
|
|||
// Copyright 2017 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Core/IOS/Device.h"
|
||||
#include "Core/IOS/IPC.h"
|
||||
#include "Core/IOS/USB/Host.h"
|
||||
|
||||
class PointerWrap;
|
||||
|
||||
namespace IOS
|
||||
{
|
||||
namespace HLE
|
||||
{
|
||||
namespace Device
|
||||
{
|
||||
class USB_VEN final : public USBHost
|
||||
{
|
||||
public:
|
||||
USB_VEN(u32 device_id, const std::string& device_name);
|
||||
~USB_VEN() override;
|
||||
|
||||
ReturnCode Open(const OpenRequest& request) override;
|
||||
IPCCommandResult IOCtl(const IOCtlRequest& request) override;
|
||||
IPCCommandResult IOCtlV(const IOCtlVRequest& request) override;
|
||||
|
||||
void DoState(PointerWrap& p) override;
|
||||
|
||||
private:
|
||||
#pragma pack(push, 1)
|
||||
struct DeviceID
|
||||
{
|
||||
u8 unknown;
|
||||
u8 interface_plus_1e;
|
||||
u8 zero;
|
||||
u8 counter;
|
||||
};
|
||||
|
||||
struct DeviceEntry
|
||||
{
|
||||
s32 device_id;
|
||||
u16 vid;
|
||||
u16 pid;
|
||||
u8 unknown;
|
||||
u8 device_number;
|
||||
u8 interface_number;
|
||||
u8 num_altsettings;
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
std::shared_ptr<USB::Device> GetDeviceByIOSID(s32 ios_id) const;
|
||||
u8 GetInterfaceNumber(s32 ios_id) const;
|
||||
|
||||
IPCCommandResult CancelEndpoint(USB::Device& device, const IOCtlRequest& request);
|
||||
IPCCommandResult GetDeviceChange(const IOCtlRequest& request);
|
||||
IPCCommandResult GetDeviceInfo(USB::Device& device, const IOCtlRequest& request);
|
||||
IPCCommandResult SetAlternateSetting(USB::Device& device, const IOCtlRequest& request);
|
||||
IPCCommandResult Shutdown(const IOCtlRequest& request);
|
||||
IPCCommandResult SuspendResume(USB::Device& device, const IOCtlRequest& request);
|
||||
s32 SubmitTransfer(USB::Device& device, const IOCtlVRequest& request);
|
||||
|
||||
using Handler = std::function<IPCCommandResult(USB_VEN*, USB::Device&, const IOCtlRequest&)>;
|
||||
IPCCommandResult HandleDeviceIOCtl(const IOCtlRequest& request, Handler handler);
|
||||
|
||||
void OnDeviceChange(ChangeEvent, std::shared_ptr<USB::Device>) override;
|
||||
void OnDeviceChangeEnd() override;
|
||||
void TriggerDeviceChangeReply();
|
||||
|
||||
static constexpr u32 VERSION = 0x50001;
|
||||
|
||||
bool m_devicechange_first_call = true;
|
||||
std::mutex m_devicechange_hook_address_mutex;
|
||||
std::unique_ptr<IOCtlRequest> m_devicechange_hook_request;
|
||||
|
||||
mutable std::mutex m_id_map_mutex;
|
||||
u8 m_device_number = 0x21;
|
||||
// IOS device IDs => USB device IDs (one to one)
|
||||
std::map<s32, u64> m_ios_ids;
|
||||
// USB device IDs => IOS device IDs (one to many, because VEN exposes one device per interface)
|
||||
std::map<u64, std::set<s32>> m_device_ids;
|
||||
};
|
||||
} // namespace Device
|
||||
} // namespace HLE
|
||||
} // namespace IOS
|
Loading…
Reference in New Issue