int LibusbDevice::SubmitTransfer(std::unique_ptr<CtrlMessage> cmd) { if (!m_device_attached) return LIBUSB_ERROR_NOT_FOUND; DEBUG_LOG(IOS_USB, "[%04x:%04x %d] Control: bRequestType=%02x bRequest=%02x wValue=%04x" " wIndex=%04x wLength=%04x", m_vid, m_pid, m_active_interface, cmd->request_type, cmd->request, cmd->value, cmd->index, cmd->length); switch ((cmd->request_type << 8) | cmd->request) { // The following requests have to go through libusb and cannot be directly sent to the device. case USBHDR(DIR_HOST2DEVICE, TYPE_STANDARD, REC_INTERFACE, REQUEST_SET_INTERFACE): { INFO_LOG(IOS_USB, "[%04x:%04x %d] REQUEST_SET_INTERFACE index=%04x value=%04x", m_vid, m_pid, m_active_interface, cmd->index, cmd->value); if (static_cast<u8>(cmd->index) != m_active_interface) { const int ret = ChangeInterface(static_cast<u8>(cmd->index)); if (ret < 0) { ERROR_LOG(IOS_USB, "[%04x:%04x %d] Failed to change interface to %d: %s", m_vid, m_pid, m_active_interface, cmd->index, libusb_error_name(ret)); return ret; } } const int ret = SetAltSetting(static_cast<u8>(cmd->value)); if (ret == 0) m_ios.EnqueueIPCReply(cmd->ios_request, cmd->length); return ret; } case USBHDR(DIR_HOST2DEVICE, TYPE_STANDARD, REC_DEVICE, REQUEST_SET_CONFIGURATION): { INFO_LOG(IOS_USB, "[%04x:%04x %d] REQUEST_SET_CONFIGURATION index=%04x value=%04x", m_vid, m_pid, m_active_interface, cmd->index, cmd->value); ReleaseAllInterfacesForCurrentConfig(); const int ret = libusb_set_configuration(m_handle, cmd->value); if (ret == 0) { ClaimAllInterfaces(cmd->value); m_ios.EnqueueIPCReply(cmd->ios_request, cmd->length); } return ret; } } const size_t size = cmd->length + LIBUSB_CONTROL_SETUP_SIZE; auto buffer = std::make_unique<u8[]>(size); libusb_fill_control_setup(buffer.get(), cmd->request_type, cmd->request, cmd->value, cmd->index, cmd->length); Memory::CopyFromEmu(buffer.get() + LIBUSB_CONTROL_SETUP_SIZE, cmd->data_address, cmd->length); libusb_transfer* transfer = libusb_alloc_transfer(0); transfer->flags |= LIBUSB_TRANSFER_FREE_TRANSFER; libusb_fill_control_transfer(transfer, m_handle, buffer.release(), CtrlTransferCallback, this, 0); m_transfer_endpoints[0].AddTransfer(std::move(cmd), transfer); return libusb_submit_transfer(transfer); }
IPCCommandResult CWII_IPC_HLE_Device_usb_oh0_46d_a03::IOCtlV(u32 CommandAddress) { IPCCommandResult SendReply = GetNoReply(); SIOCtlVBuffer CommandBuffer(CommandAddress); switch (CommandBuffer.Parameter) { case USBV0_IOCTL_CTRLMSG: { USBSetupPacket setup_packet; setup_packet.bmRequestType = *( u8*)Memory::GetPointer(CommandBuffer.InBuffer[0].m_Address); setup_packet.bRequest = *( u8*)Memory::GetPointer(CommandBuffer.InBuffer[1].m_Address); setup_packet.wValue = *(u16*)Memory::GetPointer(CommandBuffer.InBuffer[2].m_Address); setup_packet.wIndex = *(u16*)Memory::GetPointer(CommandBuffer.InBuffer[3].m_Address); setup_packet.wLength = *(u16*)Memory::GetPointer(CommandBuffer.InBuffer[4].m_Address); const u32 payload_addr = CommandBuffer.PayloadBuffer[0].m_Address; #define DIR_TO_DEV 0 #define DIR_TO_HOST 1 #define TYPE_STANDARD 0 #define TYPE_CLASS 1 #define TYPE_VENDOR 2 #define RECP_DEV 0 #define RECP_INT 1 #define RECP_ENDP 2 #define USBHDR(dir, type, recipient, request) \ ((((dir << 7) | (type << 5) | recipient) << 8) | request) switch (((u16)setup_packet.bmRequestType << 8) | setup_packet.bRequest) { case USBHDR(DIR_TO_HOST, TYPE_STANDARD, RECP_DEV, 6): // GET_DESCRIPTOR switch (setup_packet.wValue >> 8) { // CONFIGURATION case 2: { const usb_configurationdesc config = { 9, 2, 121, 2, 1, 3, 0x80, 30 }; if (setup_packet.wLength == 9) { memcpy(Memory::GetPointer(payload_addr), &config, setup_packet.wLength); } else { #define LE24(x) (x & 0xff), ((x >> 8) & 0xff), (x >> 16) #pragma pack(push, 1) struct { usb_configurationdesc config; usb_interfacedesc int0; struct audiocontrol_hdr { u8 bLength; u8 bDescriptorType; u8 bDescriptorSubtype; }; struct { audiocontrol_hdr hdr; u16 bcdADC; u16 wTotalLength; u8 bInCollection; u8 baInterfaceNr; } audiocontrol_header; struct { audiocontrol_hdr hdr; u8 bTerminalID; u16 wTerminalType; u8 bAssocTerminal; u8 bNrChannels; u16 wChannelConfig; u8 iChannelNames; u8 iTerminal; } audiocontrol_input_terminal; struct { audiocontrol_hdr hdr; u8 bUnitID; u8 bSourceID; u8 bControlSize; u8 bmaControls0; u8 bmaControls1; u8 iFeature; } audiocontrol_feature_unit; struct { audiocontrol_hdr hdr; u8 bTerminalID; u16 wTerminalType; u8 bAssocTerminal; u8 bSourceID; u8 iTerminal; } audiocontrol_output_terminal; usb_interfacedesc int1; usb_interfacedesc int2; struct { audiocontrol_hdr hdr; u8 bTerminalLink; u8 bDelay; u16 wFormatTag; } audiocontrol_as_general; struct { audiocontrol_hdr hdr; u8 bFormatType; u8 bNrChannels; u8 bSubframeSize; u8 bBitResolution; u8 bSamFreqType; u8 tSamFreq[3 * 5]; } audiocontrol_format_type; usb_endpointdesc endp; struct { audiocontrol_hdr hdr; u8 bmAttributes; u8 bLockDelayUnits; u16 wLockDelay; } audiocontrol_ep_general; } const fullconfig = { config, { 9, 4, 0, 0, 0, 1, 1, 0, 0 }, { 9, 36, 1, 0x100, 39, 1, 1 }, { 12, 36, 2, 13, 0x201, 0, 1, 0, 0, 0 }, { 9, 36, 6, 2, 13, 1, 3, 0 }, { 9, 36, 3, 10, 0x101, 0, 2, 0 }, { 9, 4, 1, 0, 0, 1, 2, 0, 0 }, { 9, 4, 1, 1, 1, 1, 2, 0, 0 }, { 7, 36, 1, 10, 0, 1 }, { 23, 36, 2, 1, 1, 2, 16, 5, LE24(8000), LE24(11025), LE24(22050), LE24(44100), LE24(48000) }, { 9, 5, 0x84, 13, 0x60, 1, 0, 0 }, { 7, 37, 1, 1, 2, 1 } }; #pragma pack(pop) #undef LE24 memcpy(Memory::GetPointer(payload_addr), &fullconfig, setup_packet.wLength); } Memory::Write_U32(sizeof(USBSetupPacket) + setup_packet.wLength, CommandAddress + 4); return GetDefaultReply(); } break; default: goto outerdefault; } break; case USBHDR(DIR_TO_HOST, TYPE_CLASS, RECP_INT, 0x82): case USBHDR(DIR_TO_HOST, TYPE_CLASS, RECP_INT, 0x83): if (setup_packet.bRequest & 1) Memory::Write_U16(0x7fff, payload_addr); else Memory::Write_U16(0x8000, payload_addr); break; case USBHDR(DIR_TO_DEV, TYPE_CLASS, RECP_ENDP, 1): { u32 freq = *(u32*)Memory::GetPointer(payload_addr) & 0xffffff; WARN_LOG(OSHLE, "set freq: %x", freq); } break; case USBHDR(DIR_TO_DEV, TYPE_STANDARD, RECP_INT, 11): break; outerdefault: default: WARN_LOG(OSHLE, "UNK %02x %02x %04x %04x", setup_packet.bmRequestType, setup_packet.bRequest, setup_packet.wValue, setup_packet.wLength); break; } // command finished, send a reply to command WII_IPC_HLE_Interface::EnqueueReply(CommandBuffer.m_Address); } break; case USBV0_IOCTL_ISOMSG: { // endp 81 = mic -> console // endp 03 = console -> mic u8 endpoint = Memory::Read_U8(CommandBuffer.InBuffer[0].m_Address); u16 length = Memory::Read_U16(CommandBuffer.InBuffer[1].m_Address); u8 num_packets = Memory::Read_U8(CommandBuffer.InBuffer[2].m_Address); u16 *packet_sizes = (u16*)Memory::GetPointer(CommandBuffer.PayloadBuffer[0].m_Address); u8 *packets = Memory::GetPointer(CommandBuffer.PayloadBuffer[1].m_Address); u16 packet_len = Common::swap16(packet_sizes[0]); WARN_LOG(OSHLE, "%i to endpoint %02x", packet_len, endpoint); /* for (int i = 0; i < num_packets; i++) { u16 packet_len = Common::swap16(packet_sizes[i]); WARN_LOG(OSHLE, "packet %i [%i] to endpoint %02x", i, packet_len, endpoint); WARN_LOG(OSHLE, "%s", ArrayToString(packets, packet_len, 16).c_str()); packets += packet_len; } */ if (endpoint == AUDIO_IN) for (u16 *sample = (u16*)packets; sample != (u16*)(packets + length); sample++) *sample = 0; // TODO actual responses should obey some kinda timey thing SendReply = GetDefaultReply(); } break; default: WARN_LOG(OSHLE, "%s - IOCtlV:", GetDeviceName().c_str()); WARN_LOG(OSHLE, " Parameter: 0x%x", CommandBuffer.Parameter); WARN_LOG(OSHLE, " NumberIn: 0x%08x", CommandBuffer.NumberInBuffer); WARN_LOG(OSHLE, " NumberOut: 0x%08x", CommandBuffer.NumberPayloadBuffer); WARN_LOG(OSHLE, " BufferVector: 0x%08x", CommandBuffer.BufferVector); //DumpAsync(CommandBuffer.BufferVector, CommandBuffer.NumberInBuffer, CommandBuffer.NumberPayloadBuffer, LogTypes::OSHLE, LogTypes::LWARNING); break; } Memory::Write_U32(0, CommandAddress + 4); return SendReply; }
IPCCommandResult CWII_IPC_HLE_Device_usb_oh0_57e_308::IOCtlV(u32 CommandAddress) { IPCCommandResult SendReply = GetNoReply(); SIOCtlVBuffer CommandBuffer(CommandAddress); switch (CommandBuffer.Parameter) { case USBV0_IOCTL_CTRLMSG: { USBSetupPacket setup_packet; setup_packet.bmRequestType = *( u8*)Memory::GetPointer(CommandBuffer.InBuffer[0].m_Address); setup_packet.bRequest = *( u8*)Memory::GetPointer(CommandBuffer.InBuffer[1].m_Address); setup_packet.wValue = *(u16*)Memory::GetPointer(CommandBuffer.InBuffer[2].m_Address); setup_packet.wIndex = *(u16*)Memory::GetPointer(CommandBuffer.InBuffer[3].m_Address); setup_packet.wLength = *(u16*)Memory::GetPointer(CommandBuffer.InBuffer[4].m_Address); const u32 payload_addr = CommandBuffer.PayloadBuffer[0].m_Address; static bool initialized = false; #define DIR_TO_DEV 0 #define DIR_TO_HOST 1 #define TYPE_STANDARD 0 #define TYPE_VENDOR 2 #define RECP_DEV 0 #define RECP_INT 1 #define RECP_ENDP 2 #define USBHDR(dir, type, recipient, request) \ ((((dir << 7) | (type << 5) | recipient) << 8) | request) switch (((u16)setup_packet.bmRequestType << 8) | setup_packet.bRequest) { case USBHDR(DIR_TO_DEV, TYPE_STANDARD, RECP_INT, 11): _dbg_assert_(OSHLE, setup_packet.wValue == 1); break; case USBHDR(DIR_TO_HOST, TYPE_STANDARD, RECP_INT, 10): Memory::Write_U8(1, payload_addr); break; case USBHDR(DIR_TO_HOST, TYPE_VENDOR, RECP_INT, 6): if (!initialized) Memory::Write_U8(0, payload_addr), initialized = true; else Memory::Write_U8(1, payload_addr); break; case USBHDR(DIR_TO_DEV, TYPE_VENDOR, RECP_INT, 1): SetRegister(payload_addr); break; case USBHDR(DIR_TO_HOST, TYPE_VENDOR, RECP_INT, 2): GetRegister(payload_addr); break; case USBHDR(DIR_TO_DEV, TYPE_VENDOR, RECP_INT, 0): initialized = false; break; default: WARN_LOG(OSHLE, "UNK %02x %02x %04x %04x", setup_packet.bmRequestType, setup_packet.bRequest, setup_packet.wValue, setup_packet.wLength); break; } // command finished, send a reply to command WII_IPC_HLE_Interface::EnqueueReply(CommandBuffer.m_Address); } break; case USBV0_IOCTL_BLKMSG: { u8 Command = Memory::Read_U8(CommandBuffer.InBuffer[0].m_Address); switch (Command) { // used for sending firmware case DATA_OUT: { u16 len = Memory::Read_U16(CommandBuffer.InBuffer[1].m_Address); WARN_LOG(OSHLE, "SEND DATA %x %x %x", len, CommandBuffer.PayloadBuffer[0].m_Address, CommandBuffer.PayloadBuffer[0].m_Size); SendReply = GetDefaultReply(); } break; default: WARN_LOG(OSHLE, "UNK BLKMSG %i", Command); break; } } break; case USBV0_IOCTL_ISOMSG: { // endp 81 = mic -> console // endp 03 = console -> mic u8 endpoint = Memory::Read_U8(CommandBuffer.InBuffer[0].m_Address); u16 length = Memory::Read_U16(CommandBuffer.InBuffer[1].m_Address); u8 num_packets = Memory::Read_U8(CommandBuffer.InBuffer[2].m_Address); u16 *packet_sizes = (u16*)Memory::GetPointer(CommandBuffer.PayloadBuffer[0].m_Address); u8 *packets = Memory::GetPointer(CommandBuffer.PayloadBuffer[1].m_Address); /* for (int i = 0; i < num_packets; i++) { u16 packet_len = Common::swap16(packet_sizes[i]); WARN_LOG(OSHLE, "packet %i [%i] to endpoint %02x", i, packet_len, endpoint); WARN_LOG(OSHLE, "%s", ArrayToString(packets, packet_len, 16).c_str()); packets += packet_len; } */ if (endpoint == AUDIO_IN) for (u16 *sample = (u16*)packets; sample != (u16*)(packets + length); sample++) *sample = 0x8000; // TODO actual responses should obey some kinda timey thing SendReply = GetDefaultReply(); } break; default: WARN_LOG(OSHLE, "%s - IOCtlV:", GetDeviceName().c_str()); WARN_LOG(OSHLE, " Parameter: 0x%x", CommandBuffer.Parameter); WARN_LOG(OSHLE, " NumberIn: 0x%08x", CommandBuffer.NumberInBuffer); WARN_LOG(OSHLE, " NumberOut: 0x%08x", CommandBuffer.NumberPayloadBuffer); WARN_LOG(OSHLE, " BufferVector: 0x%08x", CommandBuffer.BufferVector); //DumpAsync(CommandBuffer.BufferVector, CommandBuffer.NumberInBuffer, CommandBuffer.NumberPayloadBuffer, LogTypes::OSHLE, LogTypes::LWARNING); break; } Memory::Write_U32(0, CommandAddress + 4); return SendReply; }