diff --git a/Source/Core/Core/CMakeLists.txt b/Source/Core/Core/CMakeLists.txt
index 65dbc8868a..a2e9516f44 100644
--- a/Source/Core/Core/CMakeLists.txt
+++ b/Source/Core/Core/CMakeLists.txt
@@ -146,6 +146,7 @@ set(SRCS ActionReplay.cpp
IPC_HLE/WII_IPC_HLE_Device_sdio_slot0.cpp
IPC_HLE/WII_IPC_HLE_Device_usb.cpp
IPC_HLE/WII_IPC_HLE_Device_usb_kbd.cpp
+ IPC_HLE/WII_IPC_HLE_Device_usb_ven.cpp
IPC_HLE/WII_IPC_HLE_WiiMote.cpp
IPC_HLE/WiiMote_HID_Attr.cpp
PowerPC/MMU.cpp
diff --git a/Source/Core/Core/Core.vcxproj b/Source/Core/Core/Core.vcxproj
index 549960306b..e89a1d6a41 100644
--- a/Source/Core/Core/Core.vcxproj
+++ b/Source/Core/Core/Core.vcxproj
@@ -186,6 +186,7 @@
+
@@ -389,6 +390,7 @@
+
diff --git a/Source/Core/Core/Core.vcxproj.filters b/Source/Core/Core/Core.vcxproj.filters
index 7fda04b8e9..bc12b068ac 100644
--- a/Source/Core/Core/Core.vcxproj.filters
+++ b/Source/Core/Core/Core.vcxproj.filters
@@ -724,6 +724,9 @@
PowerPC\Jit64Common
+
+ IPC HLE %28IOS/Starlet%29\USB
+
@@ -1237,6 +1240,9 @@
PowerPC\Jit64Common
+
+ IPC HLE %28IOS/Starlet%29\USB
+
diff --git a/Source/Core/Core/IPC_HLE/WII_IPC_HLE.cpp b/Source/Core/Core/IPC_HLE/WII_IPC_HLE.cpp
index 1720790b75..581c6a9d74 100644
--- a/Source/Core/Core/IPC_HLE/WII_IPC_HLE.cpp
+++ b/Source/Core/Core/IPC_HLE/WII_IPC_HLE.cpp
@@ -52,6 +52,7 @@ They will also generate a true or false return for UpdateInterrupts() in WII_IPC
#include "Core/IPC_HLE/WII_IPC_HLE_Device_stm.h"
#include "Core/IPC_HLE/WII_IPC_HLE_Device_usb.h"
#include "Core/IPC_HLE/WII_IPC_HLE_Device_usb_kbd.h"
+#include "Core/IPC_HLE/WII_IPC_HLE_Device_usb_ven.h"
#if defined(__LIBUSB__) || defined(_WIN32)
#include "Core/IPC_HLE/WII_IPC_HLE_Device_hid.h"
@@ -147,6 +148,7 @@ void Init()
AddDevice("/dev/net/ip/top");
AddDevice("/dev/net/ssl");
AddDevice("/dev/usb/kbd");
+ AddDevice("/dev/usb/ven");
AddDevice("/dev/sdio/slot0");
AddDevice("/dev/sdio/slot1");
#if defined(__LIBUSB__) || defined(_WIN32)
diff --git a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_usb_ven.cpp b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_usb_ven.cpp
new file mode 100644
index 0000000000..1be147894e
--- /dev/null
+++ b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_usb_ven.cpp
@@ -0,0 +1,125 @@
+// Copyright 2016 Dolphin Emulator Project
+// Licensed under GPLv2+
+// Refer to the license.txt file included.
+
+#include "Common/StringUtil.h"
+
+#include "Core/IPC_HLE/WII_IPC_HLE_Device_usb_ven.h"
+
+CWII_IPC_HLE_Device_usb_ven::CWII_IPC_HLE_Device_usb_ven(u32 _DeviceID,
+ const std::string& _rDeviceName)
+ : IWII_IPC_HLE_Device(_DeviceID, _rDeviceName)
+{
+}
+
+CWII_IPC_HLE_Device_usb_ven::~CWII_IPC_HLE_Device_usb_ven()
+{
+}
+
+IPCCommandResult CWII_IPC_HLE_Device_usb_ven::Open(u32 _CommandAddress, u32 _Mode)
+{
+ Memory::Write_U32(GetDeviceID(), _CommandAddress + 4);
+ m_Active = true;
+ return GetDefaultReply();
+}
+
+IPCCommandResult CWII_IPC_HLE_Device_usb_ven::Close(u32 _CommandAddress, bool _bForce)
+{
+ if (!_bForce)
+ Memory::Write_U32(0, _CommandAddress + 4);
+
+ m_Active = false;
+ return GetDefaultReply();
+}
+
+IPCCommandResult CWII_IPC_HLE_Device_usb_ven::IOCtlV(u32 _CommandAddress)
+{
+ SIOCtlVBuffer CommandBuffer(_CommandAddress);
+
+ DEBUG_LOG(OSHLE, "%s - IOCtlV:", GetDeviceName().c_str());
+ DEBUG_LOG(OSHLE, " Parameter: 0x%x", CommandBuffer.Parameter);
+ DEBUG_LOG(OSHLE, " NumberIn: 0x%08x", CommandBuffer.NumberInBuffer);
+ DEBUG_LOG(OSHLE, " NumberOut: 0x%08x", CommandBuffer.NumberPayloadBuffer);
+ DEBUG_LOG(OSHLE, " BufferVector: 0x%08x", CommandBuffer.BufferVector);
+ DumpAsync(CommandBuffer.BufferVector, CommandBuffer.NumberInBuffer,
+ CommandBuffer.NumberPayloadBuffer);
+
+ Memory::Write_U32(0, _CommandAddress + 4);
+ return GetNoReply();
+}
+
+IPCCommandResult CWII_IPC_HLE_Device_usb_ven::IOCtl(u32 _CommandAddress)
+{
+ IPCCommandResult Reply = GetNoReply();
+ u32 Command = Memory::Read_U32(_CommandAddress + 0x0c);
+ u32 BufferIn = Memory::Read_U32(_CommandAddress + 0x10);
+ u32 BufferInSize = Memory::Read_U32(_CommandAddress + 0x14);
+ u32 BufferOut = Memory::Read_U32(_CommandAddress + 0x18);
+ u32 BufferOutSize = Memory::Read_U32(_CommandAddress + 0x1c);
+
+ DEBUG_LOG(OSHLE, "%s - IOCtl: %x", GetDeviceName().c_str(), Command);
+ DEBUG_LOG(OSHLE, "%x:%x %x:%x", BufferIn, BufferInSize, BufferOut, BufferOutSize);
+
+ switch (Command)
+ {
+ case USBV5_IOCTL_GETVERSION:
+ Memory::Write_U32(0x50001, BufferOut);
+ Reply = GetDefaultReply();
+ break;
+
+ case USBV5_IOCTL_GETDEVICECHANGE:
+ {
+ // sent on change
+ static bool firstcall = true;
+ if (firstcall)
+ {
+ Reply = GetDefaultReply();
+ firstcall = false;
+ }
+
+ // num devices
+ Memory::Write_U32(0, _CommandAddress + 4);
+ return Reply;
+ }
+ break;
+
+ case USBV5_IOCTL_ATTACHFINISH:
+ Reply = GetDefaultReply();
+ break;
+
+ case USBV5_IOCTL_SUSPEND_RESUME:
+ DEBUG_LOG(OSHLE, "Device: %i Resumed: %i", Memory::Read_U32(BufferIn),
+ Memory::Read_U32(BufferIn + 4));
+ Reply = GetDefaultReply();
+ break;
+
+ case USBV5_IOCTL_GETDEVPARAMS:
+ {
+ s32 device = Memory::Read_U32(BufferIn);
+ u32 unk = Memory::Read_U32(BufferIn + 4);
+
+ DEBUG_LOG(OSHLE, "USBV5_IOCTL_GETDEVPARAMS device: %i unk: %i", device, unk);
+
+ Memory::Write_U32(0, BufferOut);
+
+ Reply = GetDefaultReply();
+ }
+ break;
+
+ default:
+ DEBUG_LOG(OSHLE, "%x:%x %x:%x", BufferIn, BufferInSize, BufferOut, BufferOutSize);
+ break;
+ }
+
+ Memory::Write_U32(0, _CommandAddress + 4);
+ return Reply;
+}
+
+u32 CWII_IPC_HLE_Device_usb_ven::Update()
+{
+ return IWII_IPC_HLE_Device::Update();
+}
+
+void CWII_IPC_HLE_Device_usb_ven::DoState(PointerWrap& p)
+{
+}
diff --git a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_usb_ven.h b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_usb_ven.h
new file mode 100644
index 0000000000..88f4ecaf26
--- /dev/null
+++ b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_usb_ven.h
@@ -0,0 +1,43 @@
+// Copyright 2016 Dolphin Emulator Project
+// Licensed under GPLv2+
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "Core/IPC_HLE/WII_IPC_HLE.h"
+#include "Core/IPC_HLE/WII_IPC_HLE_Device.h"
+
+class CWII_IPC_HLE_Device_usb_ven : public IWII_IPC_HLE_Device
+{
+public:
+ CWII_IPC_HLE_Device_usb_ven(u32 _DeviceID, const std::string& _rDeviceName);
+
+ ~CWII_IPC_HLE_Device_usb_ven() override;
+
+ virtual IPCCommandResult Open(u32 _CommandAddress, u32 _Mode);
+ virtual IPCCommandResult Close(u32 _CommandAddress, bool _bForce);
+
+ virtual IPCCommandResult IOCtlV(u32 _CommandAddress);
+ virtual IPCCommandResult IOCtl(u32 _CommandAddress);
+
+ virtual u32 Update();
+
+ void DoState(PointerWrap& p);
+
+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
+ };
+};