Async USB HID :D

This commit is contained in:
Matthew Parlane 2013-01-01 19:24:53 +13:00
parent 8fdc8af1cb
commit b5ec660905
2 changed files with 78 additions and 53 deletions

View File

@ -44,17 +44,58 @@ void CWII_IPC_HLE_Device_hid::checkUsbUpdates(CWII_IPC_HLE_Device_hid* hid)
timeval tv; timeval tv;
tv.tv_sec = 0; tv.tv_sec = 0;
tv.tv_usec = 500; tv.tv_usec = 500;
while (hid->usb_thread_running) 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); libusb_handle_events_timeout(NULL, &tv);
}
return; 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) CWII_IPC_HLE_Device_hid::CWII_IPC_HLE_Device_hid(u32 _DeviceID, const std::string& _rDeviceName)
: IWII_IPC_HLE_Device(_DeviceID, _rDeviceName) : IWII_IPC_HLE_Device(_DeviceID, _rDeviceName)
{ {
deviceCommandAddress = 0;
memset(hidDeviceAliases, 0, sizeof(hidDeviceAliases)); memset(hidDeviceAliases, 0, sizeof(hidDeviceAliases));
libusb_init(NULL); libusb_init(NULL);
@ -94,35 +135,10 @@ bool CWII_IPC_HLE_Device_hid::Close(u32 _CommandAddress, bool _bForce)
return true; return true;
} }
static u32 replyAddress = 0;
static bool hasRun = false;
u32 CWII_IPC_HLE_Device_hid::Update() u32 CWII_IPC_HLE_Device_hid::Update()
{ {
static u16 timeToFill = 0;
u32 work_done = 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; 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)", DEBUG_LOG(WII_IPC_HID, "HID::IOCtl(Get Attached) (BufferIn: (%08x, %i), BufferOut: (%08x, %i)",
BufferIn, BufferInSize, BufferOut, BufferOutSize); BufferIn, BufferInSize, BufferOut, BufferOutSize);
replyAddress = _CommandAddress; deviceCommandAddress = _CommandAddress;
return false; return false;
break; break;
} }
@ -175,14 +191,13 @@ bool CWII_IPC_HLE_Device_hid::IOCtl(u32 _CommandAddress)
ERROR CODES: ERROR CODES:
-4 Cant find device specified -4 Cant find device specified
*/ */
int ret = -1;
u32 dev_num = Memory::Read_U32(BufferIn+0x10); u32 dev_num = Memory::Read_U32(BufferIn+0x10);
u8 requestType = Memory::Read_U8(BufferIn+0x14); u8 bmRequestType = Memory::Read_U8(BufferIn+0x14);
u8 request = Memory::Read_U8(BufferIn+0x15); u8 bRequest = Memory::Read_U8(BufferIn+0x15);
u16 value = Memory::Read_U16(BufferIn+0x16); u16 wValue = Memory::Read_U16(BufferIn+0x16);
u16 index = Memory::Read_U16(BufferIn+0x18); u16 wIndex = Memory::Read_U16(BufferIn+0x18);
u16 size = Memory::Read_U16(BufferIn+0x1A); u16 wLength = Memory::Read_U16(BufferIn+0x1A);
u32 data = Memory::Read_U32(BufferIn+0x1C); u32 data = Memory::Read_U32(BufferIn+0x1C);
ReturnValue = HIDERR_NO_DEVICE_FOUND; 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); DEBUG_LOG(WII_IPC_HID, "Could not find handle: %X", dev_num);
break; 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); u8 * buffer = (u8*)malloc(wLength + LIBUSB_CONTROL_SETUP_SIZE);
if(ret>=0) libusb_fill_control_setup(buffer, bmRequestType, bRequest, wValue, wIndex, wLength);
{ memcpy(buffer + LIBUSB_CONTROL_SETUP_SIZE, Memory::GetPointer(data), wLength);
ret += sizeof(libusb_control_setup); libusb_fill_control_transfer(transfer, dev_handle, buffer, handleUsbUpdates, (void*)(size_t)_CommandAddress, /* no timeout */ 0);
ReturnValue = ret; libusb_submit_transfer(transfer);
}
DEBUG_LOG(WII_IPC_HID, "HID::IOCtl(Control)(%02X, %02X) = %d (BufferIn: (%08x, %i), BufferOut: (%08x, %i) = %d", //DEBUG_LOG(WII_IPC_HID, "HID::IOCtl(Control)(%02X, %02X) (BufferIn: (%08x, %i), BufferOut: (%08x, %i)",
requestType, request, ReturnValue, BufferIn, BufferInSize, BufferOut, BufferOutSize, ret); // bmRequestType, bRequest, BufferIn, BufferInSize, BufferOut, BufferOutSize);
// It's the async way!
return false;
break; break;
} }
case IOCTL_HID_INTERRUPT_OUT: case IOCTL_HID_INTERRUPT_OUT:
case IOCTL_HID_INTERRUPT_IN: case IOCTL_HID_INTERRUPT_IN:
{ {
int transfered = 0;
int ret;
u32 dev_num = Memory::Read_U32(BufferIn+0x10); u32 dev_num = Memory::Read_U32(BufferIn+0x10);
u32 endpoint = Memory::Read_U32(BufferIn+0x14); u32 endpoint = Memory::Read_U32(BufferIn+0x14);
u32 length = Memory::Read_U32(BufferIn+0x18); u32 length = Memory::Read_U32(BufferIn+0x18);
@ -229,15 +244,17 @@ bool CWII_IPC_HLE_Device_hid::IOCtl(u32 _CommandAddress)
break; break;
} }
ret = libusb_interrupt_transfer(dev_handle, endpoint, (unsigned char*)Memory::GetPointer(data), length, &transfered, 40 ); struct libusb_transfer *transfer = libusb_alloc_transfer(0);
if(ret == 0) transfer->flags |= LIBUSB_TRANSFER_FREE_TRANSFER;
{ libusb_fill_interrupt_transfer(transfer, dev_handle, endpoint, Memory::GetPointer(data), length,
ReturnValue = transfered; handleUsbUpdates, (void*)(size_t)_CommandAddress, 0);
} libusb_submit_transfer(transfer);
DEBUG_LOG(WII_IPC_HID, "HID::IOCtl(Interrupt %s)(%d,%d,%X) = %d (BufferIn: (%08x, %i), BufferOut: (%08x, %i)", //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, ReturnValue, BufferIn, BufferInSize, BufferOut, BufferOutSize); // Parameter == IOCTL_HID_INTERRUPT_IN ? "In" : "Out", endpoint, length, data, BufferIn, BufferInSize, BufferOut, BufferOutSize);
// It's the async way!
return false;
break; break;
} }
default: default:
@ -444,6 +461,7 @@ void CWII_IPC_HLE_Device_hid::FillOutDevices(u32 BufferOut, u32 BufferOutSize)
if(hidDeviceAliases[i] != 0 && check_cur != check) if(hidDeviceAliases[i] != 0 && check_cur != check)
{ {
DEBUG_LOG(WII_IPC_HID, "Removing: device %d %hX %hX", i, check, check_cur); DEBUG_LOG(WII_IPC_HID, "Removing: device %d %hX %hX", i, check, check_cur);
std::lock_guard<std::mutex> lk(s_open_devices);
if (open_devices.find(i) != open_devices.end()) if (open_devices.find(i) != open_devices.end())
{ {
libusb_device_handle *handle = open_devices[i]; 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) if(devNum >= MAX_DEVICE_DEVNUM)
return NULL; return NULL;
std::lock_guard<std::mutex> lk(s_open_devices);
if (open_devices.find(devNum) != open_devices.end()) if (open_devices.find(devNum) != open_devices.end())
{ {
handle = open_devices[devNum]; handle = open_devices[devNum];

View File

@ -120,6 +120,7 @@ private:
} WiiHIDEndpointDescriptor; } WiiHIDEndpointDescriptor;
u32 deviceCommandAddress;
void FillOutDevices(u32 BufferOut, u32 BufferOutSize); void FillOutDevices(u32 BufferOut, u32 BufferOutSize);
int GetAvaiableDevNum(u16 idVendor, u16 idProduct, u8 bus, u8 port, u16 check); int GetAvaiableDevNum(u16 idVendor, u16 idProduct, u8 bus, u8 port, u16 check);
@ -132,10 +133,13 @@ private:
int Align(int num, int alignment); int Align(int num, int alignment);
static void checkUsbUpdates(CWII_IPC_HLE_Device_hid* hid); static void checkUsbUpdates(CWII_IPC_HLE_Device_hid* hid);
static void handleUsbUpdates(struct libusb_transfer *transfer);
struct libusb_device_handle * GetDeviceByDevNum(u32 devNum); struct libusb_device_handle * GetDeviceByDevNum(u32 devNum);
std::map<u32,libusb_device_handle*> open_devices; std::map<u32,libusb_device_handle*> open_devices;
std::mutex s_open_devices;
std::map<std::string,int> device_identifiers; std::map<std::string,int> device_identifiers;
std::thread usb_thread; std::thread usb_thread;
bool usb_thread_running; bool usb_thread_running;