From b5ec6609052d7c4f1d37cc2d7dd29a447cfaa6fa Mon Sep 17 00:00:00 2001 From: Matthew Parlane Date: Tue, 1 Jan 2013 19:24:53 +1300 Subject: [PATCH] Async USB HID :D --- .../Src/IPC_HLE/WII_IPC_HLE_Device_hid.cpp | 127 ++++++++++-------- .../Core/Src/IPC_HLE/WII_IPC_HLE_Device_hid.h | 4 + 2 files changed, 78 insertions(+), 53 deletions(-) diff --git a/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_hid.cpp b/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_hid.cpp index b0b3f349aa..2996cdf563 100644 --- a/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_hid.cpp +++ b/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_hid.cpp @@ -44,17 +44,58 @@ void CWII_IPC_HLE_Device_hid::checkUsbUpdates(CWII_IPC_HLE_Device_hid* hid) timeval tv; tv.tv_sec = 0; tv.tv_usec = 500; - while (hid->usb_thread_running) + { + + static u16 timeToFill = 0; + if (timeToFill == 0) + { + if (hid->deviceCommandAddress != 0){ + hid->FillOutDevices(Memory::Read_U32(hid->deviceCommandAddress + 0x18), Memory::Read_U32(hid->deviceCommandAddress + 0x1C)); + + Memory::Write_U32(8, hid->deviceCommandAddress); + // IOS seems to write back the command that was responded to + Memory::Write_U32(/*COMMAND_IOCTL*/ 6, hid->deviceCommandAddress + 8); + + // Return value + Memory::Write_U32(0, hid->deviceCommandAddress + 4); + + WII_IPC_HLE_Interface::EnqReply(hid->deviceCommandAddress); + hid->deviceCommandAddress = 0; + } + } + timeToFill+=8; libusb_handle_events_timeout(NULL, &tv); + } return; } +void CWII_IPC_HLE_Device_hid::handleUsbUpdates(struct libusb_transfer *transfer) +{ + int ret = HIDERR_NO_DEVICE_FOUND; + u32 replyAddress = (u32)(size_t)transfer->user_data; + if (transfer->status == LIBUSB_TRANSFER_COMPLETED) + { + ret = transfer->length; + } + + Memory::Write_U32(8, replyAddress); + // IOS seems to write back the command that was responded to + Memory::Write_U32(/*COMMAND_IOCTL*/ 6, replyAddress + 8); + + // Return value + Memory::Write_U32(ret, replyAddress + 4); + + WII_IPC_HLE_Interface::EnqReply(replyAddress); + //DEBUG_LOG(WII_IPC_HID, "OMG OMG OMG I GOT A CALLBACK, IMMA BE FAMOUS %d %d %d", transfer->actual_length, transfer->length, transfer->status); +} + CWII_IPC_HLE_Device_hid::CWII_IPC_HLE_Device_hid(u32 _DeviceID, const std::string& _rDeviceName) : IWII_IPC_HLE_Device(_DeviceID, _rDeviceName) { + deviceCommandAddress = 0; memset(hidDeviceAliases, 0, sizeof(hidDeviceAliases)); libusb_init(NULL); @@ -94,35 +135,10 @@ bool CWII_IPC_HLE_Device_hid::Close(u32 _CommandAddress, bool _bForce) return true; } -static u32 replyAddress = 0; -static bool hasRun = false; - u32 CWII_IPC_HLE_Device_hid::Update() { - static u16 timeToFill = 0; + u32 work_done = 0; - - if (timeToFill == 0) - { - if (replyAddress != 0){ - FillOutDevices(Memory::Read_U32(replyAddress + 0x18), Memory::Read_U32(replyAddress + 0x1C)); - - Memory::Write_U32(8, replyAddress); - // IOS seems to write back the command that was responded to - Memory::Write_U32(/*COMMAND_IOCTL*/ 6, replyAddress + 8); - - // Return value - Memory::Write_U32(0, replyAddress + 4); - - WII_IPC_HLE_Interface::EnqReply(replyAddress); - replyAddress = 0; - hasRun = false; - } - } - - timeToFill+=8; - - work_done = 1; return work_done; } @@ -141,7 +157,7 @@ bool CWII_IPC_HLE_Device_hid::IOCtl(u32 _CommandAddress) { DEBUG_LOG(WII_IPC_HID, "HID::IOCtl(Get Attached) (BufferIn: (%08x, %i), BufferOut: (%08x, %i)", BufferIn, BufferInSize, BufferOut, BufferOutSize); - replyAddress = _CommandAddress; + deviceCommandAddress = _CommandAddress; return false; break; } @@ -175,14 +191,13 @@ bool CWII_IPC_HLE_Device_hid::IOCtl(u32 _CommandAddress) ERROR CODES: -4 Cant find device specified */ - int ret = -1; u32 dev_num = Memory::Read_U32(BufferIn+0x10); - u8 requestType = Memory::Read_U8(BufferIn+0x14); - u8 request = Memory::Read_U8(BufferIn+0x15); - u16 value = Memory::Read_U16(BufferIn+0x16); - u16 index = Memory::Read_U16(BufferIn+0x18); - u16 size = Memory::Read_U16(BufferIn+0x1A); + u8 bmRequestType = Memory::Read_U8(BufferIn+0x14); + u8 bRequest = Memory::Read_U8(BufferIn+0x15); + u16 wValue = Memory::Read_U16(BufferIn+0x16); + u16 wIndex = Memory::Read_U16(BufferIn+0x18); + u16 wLength = Memory::Read_U16(BufferIn+0x1A); u32 data = Memory::Read_U32(BufferIn+0x1C); ReturnValue = HIDERR_NO_DEVICE_FOUND; @@ -194,25 +209,25 @@ bool CWII_IPC_HLE_Device_hid::IOCtl(u32 _CommandAddress) DEBUG_LOG(WII_IPC_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; - ret = libusb_control_transfer (dev_handle, requestType, request, value, index, (unsigned char*)Memory::GetPointer(data), size, 0); - if(ret>=0) - { - ret += sizeof(libusb_control_setup); - ReturnValue = ret; - } + u8 * buffer = (u8*)malloc(wLength + LIBUSB_CONTROL_SETUP_SIZE); + libusb_fill_control_setup(buffer, bmRequestType, bRequest, wValue, wIndex, wLength); + memcpy(buffer + LIBUSB_CONTROL_SETUP_SIZE, Memory::GetPointer(data), wLength); + libusb_fill_control_transfer(transfer, dev_handle, buffer, handleUsbUpdates, (void*)(size_t)_CommandAddress, /* no timeout */ 0); + libusb_submit_transfer(transfer); - DEBUG_LOG(WII_IPC_HID, "HID::IOCtl(Control)(%02X, %02X) = %d (BufferIn: (%08x, %i), BufferOut: (%08x, %i) = %d", - requestType, request, ReturnValue, BufferIn, BufferInSize, BufferOut, BufferOutSize, ret); + //DEBUG_LOG(WII_IPC_HID, "HID::IOCtl(Control)(%02X, %02X) (BufferIn: (%08x, %i), BufferOut: (%08x, %i)", + // bmRequestType, bRequest, BufferIn, BufferInSize, BufferOut, BufferOutSize); + // It's the async way! + return false; break; } case IOCTL_HID_INTERRUPT_OUT: case IOCTL_HID_INTERRUPT_IN: { - - int transfered = 0; - int ret; u32 dev_num = Memory::Read_U32(BufferIn+0x10); u32 endpoint = Memory::Read_U32(BufferIn+0x14); u32 length = Memory::Read_U32(BufferIn+0x18); @@ -229,15 +244,17 @@ bool CWII_IPC_HLE_Device_hid::IOCtl(u32 _CommandAddress) break; } - ret = libusb_interrupt_transfer(dev_handle, endpoint, (unsigned char*)Memory::GetPointer(data), length, &transfered, 40 ); - if(ret == 0) - { - ReturnValue = transfered; - } - - DEBUG_LOG(WII_IPC_HID, "HID::IOCtl(Interrupt %s)(%d,%d,%X) = %d (BufferIn: (%08x, %i), BufferOut: (%08x, %i)", - Parameter == IOCTL_HID_INTERRUPT_IN ? "In" : "Out", endpoint, length, data, ReturnValue, BufferIn, BufferInSize, BufferOut, BufferOutSize); + 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)_CommandAddress, 0); + libusb_submit_transfer(transfer); + //DEBUG_LOG(WII_IPC_HID, "HID::IOCtl(Interrupt %s)(%d,%d,%X) (BufferIn: (%08x, %i), BufferOut: (%08x, %i)", + // Parameter == IOCTL_HID_INTERRUPT_IN ? "In" : "Out", endpoint, length, data, BufferIn, BufferInSize, BufferOut, BufferOutSize); + + // It's the async way! + return false; break; } default: @@ -444,6 +461,7 @@ void CWII_IPC_HLE_Device_hid::FillOutDevices(u32 BufferOut, u32 BufferOutSize) if(hidDeviceAliases[i] != 0 && check_cur != check) { DEBUG_LOG(WII_IPC_HID, "Removing: device %d %hX %hX", i, check, check_cur); + std::lock_guard lk(s_open_devices); if (open_devices.find(i) != open_devices.end()) { libusb_device_handle *handle = open_devices[i]; @@ -478,6 +496,9 @@ libusb_device_handle * CWII_IPC_HLE_Device_hid::GetDeviceByDevNum(u32 devNum) if(devNum >= MAX_DEVICE_DEVNUM) return NULL; + + std::lock_guard lk(s_open_devices); + if (open_devices.find(devNum) != open_devices.end()) { handle = open_devices[devNum]; diff --git a/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_hid.h b/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_hid.h index 58c3c88da2..b0b1dbda46 100644 --- a/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_hid.h +++ b/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_hid.h @@ -120,6 +120,7 @@ private: } WiiHIDEndpointDescriptor; + u32 deviceCommandAddress; void FillOutDevices(u32 BufferOut, u32 BufferOutSize); int GetAvaiableDevNum(u16 idVendor, u16 idProduct, u8 bus, u8 port, u16 check); @@ -132,10 +133,13 @@ private: int Align(int num, int alignment); static void checkUsbUpdates(CWII_IPC_HLE_Device_hid* hid); + static void handleUsbUpdates(struct libusb_transfer *transfer); struct libusb_device_handle * GetDeviceByDevNum(u32 devNum); std::map open_devices; + std::mutex s_open_devices; std::map device_identifiers; + std::thread usb_thread; bool usb_thread_running;