예제 #1
0
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);
}
예제 #2
0
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;
}
예제 #3
0
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;
}