// The front SD slot
IPCCommandResult CWII_IPC_HLE_Device_sdio_slot0::IOCtl(u32 _CommandAddress)
{
    u32 Cmd = Memory::Read_U32(_CommandAddress + 0xC);

    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);

    // As a safety precaution we fill the out buffer with zeros to avoid
    // returning nonsense values
    Memory::Memset(BufferOut, 0, BufferOutSize);

    u32 ReturnValue = 0;
    switch (Cmd)
    {
    case IOCTL_WRITEHCR:
    {
        u32 reg = Memory::Read_U32(BufferIn);
        u32 val = Memory::Read_U32(BufferIn + 16);

        DEBUG_LOG(WII_IPC_SD, "IOCTL_WRITEHCR 0x%08x - 0x%08x", reg, val);

        if (reg >= 0x200)
        {
            DEBUG_LOG(WII_IPC_SD, "IOCTL_WRITEHCR out of range");
            break;
        }

        if ((reg == HCR_CLOCKCONTROL) && (val & 1))
        {
            // Clock is set to oscillate, enable bit 1 to say it's stable
            m_Registers[reg] = val | 2;
        }
        else if ((reg == HCR_SOFTWARERESET) && val)
        {
            // When a reset is specified, the register gets cleared
            m_Registers[reg] = 0;
        }
        else
        {
            // Default to just storing the new value
            m_Registers[reg] = val;
        }
    }
    break;

    case IOCTL_READHCR:
    {
        u32 reg = Memory::Read_U32(BufferIn);

        if (reg >= 0x200)
        {
            DEBUG_LOG(WII_IPC_SD, "IOCTL_READHCR out of range");
            break;
        }

        u32 val = m_Registers[reg];
        DEBUG_LOG(WII_IPC_SD, "IOCTL_READHCR 0x%08x - 0x%08x", reg, val);

        // Just reading the register
        Memory::Write_U32(val, BufferOut);
    }
    break;

    case IOCTL_RESETCARD:
        DEBUG_LOG(WII_IPC_SD, "IOCTL_RESETCARD");
        if (m_Card)
            m_Status |= CARD_INITIALIZED;
        // Returns 16bit RCA and 16bit 0s (meaning success)
        Memory::Write_U32(0x9f620000, BufferOut);
        break;

    case IOCTL_SETCLK:
    {
        DEBUG_LOG(WII_IPC_SD, "IOCTL_SETCLK");
        // libogc only sets it to 1 and makes sure the return isn't negative...
        // one half of the sdclk divisor: a power of two or zero.
        u32 clock = Memory::Read_U32(BufferIn);
        if (clock != 1)
            INFO_LOG(WII_IPC_SD, "Setting to %i, interesting", clock);
    }
    break;

    case IOCTL_SENDCMD:
        INFO_LOG(WII_IPC_SD, "IOCTL_SENDCMD %x IPC:%08x", Memory::Read_U32(BufferIn), _CommandAddress);
        ReturnValue = ExecuteCommand(BufferIn, BufferInSize, 0, 0, BufferOut, BufferOutSize);
        break;

    case IOCTL_GETSTATUS:
        if (SConfig::GetInstance().m_WiiSDCard)
            m_Status |= CARD_INSERTED;
        else
            m_Status = CARD_NOT_EXIST;
        INFO_LOG(WII_IPC_SD, "IOCTL_GETSTATUS. Replying that SD card is %s%s",
                 (m_Status & CARD_INSERTED) ? "inserted" : "not present",
                 (m_Status & CARD_INITIALIZED) ? " and initialized" : "");
        Memory::Write_U32(m_Status, BufferOut);
        break;

    case IOCTL_GETOCR:
        DEBUG_LOG(WII_IPC_SD, "IOCTL_GETOCR");
        Memory::Write_U32(0x80ff8000, BufferOut);
        break;

    default:
        ERROR_LOG(WII_IPC_SD, "Unknown SD IOCtl command (0x%08x)", Cmd);
        break;
    }

    // INFO_LOG(WII_IPC_SD, "InBuffer");
    // DumpCommands(BufferIn, BufferInSize / 4, LogTypes::WII_IPC_SD);
    // INFO_LOG(WII_IPC_SD, "OutBuffer");
    // DumpCommands(BufferOut, BufferOutSize/4, LogTypes::WII_IPC_SD);

    if (ReturnValue == RET_EVENT_REGISTER)
    {
        // async
        m_event.addr = _CommandAddress;
        Memory::Write_U32(0, _CommandAddress + 0x4);
        // Check if the condition is already true
        EventNotify();
        return GetNoReply();
    }
    else if (ReturnValue == RET_EVENT_UNREGISTER)
    {
        // release returns 0
        // unknown sd int
        // technically we do it out of order, oh well
        EnqueueReply(m_event.addr, EVENT_INVALID);
        m_event.addr = 0;
        m_event.type = EVENT_NONE;
        Memory::Write_U32(0, _CommandAddress + 0x4);
        return GetDefaultReply();
    }
    else
    {
        Memory::Write_U32(ReturnValue, _CommandAddress + 0x4);
        return GetDefaultReply();
    }
}
Esempio n. 2
0
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);

  INFO_LOG(OSHLE, "%s - IOCtl: %x", GetDeviceName().c_str(), Command);
  INFO_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;
}
IPCCommandResult CWII_IPC_HLE_Device_hid::IOCtl(u32 _CommandAddress)
{
    if (Core::g_want_determinism)
    {
        Memory::Write_U32(-1, _CommandAddress + 0x4);
        return GetDefaultReply();
    }

    u32 Parameter     = Memory::Read_U32(_CommandAddress + 0xC);
    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);

    u32 ReturnValue = 0;
    switch (Parameter)
    {
    case IOCTL_HID_GET_ATTACHED:
    {
        DEBUG_LOG(WII_IPC_HID, "HID::IOCtl(Get Attached) (BufferIn: (%08x, %i), BufferOut: (%08x, %i)",
                  BufferIn, BufferInSize, BufferOut, BufferOutSize);
        deviceCommandAddress = _CommandAddress;
        return GetNoReply();
    }
    case IOCTL_HID_OPEN:
    {
        DEBUG_LOG(WII_IPC_HID, "HID::IOCtl(Open) (BufferIn: (%08x, %i), BufferOut: (%08x, %i)",
                  BufferIn, BufferInSize, BufferOut, BufferOutSize);

        //hid version, apparently
        ReturnValue = 0x40001;
        break;
    }
    case IOCTL_HID_SET_SUSPEND:
    {
        DEBUG_LOG(WII_IPC_HID, "HID::IOCtl(Set Suspend) (BufferIn: (%08x, %i), BufferOut: (%08x, %i)",
                  BufferIn, BufferInSize, BufferOut, BufferOutSize);
        // not actually implemented in IOS
        ReturnValue = 0;
        break;
    }
    case IOCTL_HID_CANCEL_INTERRUPT:
    {
        DEBUG_LOG(WII_IPC_HID, "HID::IOCtl(Cancel Interrupt) (BufferIn: (%08x, %i), BufferOut: (%08x, %i)",
                  BufferIn, BufferInSize, BufferOut, BufferOutSize);
        ReturnValue = 0;
        break;
    }
    case IOCTL_HID_CONTROL:
    {
        /*
        	ERROR CODES:
        	-4 Can't find device specified
        */

        u32 dev_num = Memory::Read_U32(BufferIn + 0x10);
        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;

        libusb_device_handle * dev_handle = GetDeviceByDevNum(dev_num);

        if (dev_handle == nullptr)
        {
            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;

        u8 * buffer = (u8*)malloc(wLength + LIBUSB_CONTROL_SETUP_SIZE);
        libusb_fill_control_setup(buffer, bmRequestType, bRequest, wValue, wIndex, wLength);
        Memory::CopyFromEmu(buffer + LIBUSB_CONTROL_SETUP_SIZE, 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) (BufferIn: (%08x, %i), BufferOut: (%08x, %i)",
        //          bmRequestType, bRequest, BufferIn, BufferInSize, BufferOut, BufferOutSize);

        // It's the async way!
        return GetNoReply();
    }
    case IOCTL_HID_INTERRUPT_OUT:
    case IOCTL_HID_INTERRUPT_IN:
    {
        u32 dev_num = Memory::Read_U32(BufferIn + 0x10);
        u32 endpoint = Memory::Read_U32(BufferIn + 0x14);
        u32 length = Memory::Read_U32(BufferIn + 0x18);

        u32 data = Memory::Read_U32(BufferIn + 0x1C);

        ReturnValue = HIDERR_NO_DEVICE_FOUND;

        libusb_device_handle * dev_handle = GetDeviceByDevNum(dev_num);

        if (dev_handle == nullptr)
        {
            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_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 GetNoReply();
    }
    case IOCTL_HID_SHUTDOWN:
    {
        std::lock_guard<std::mutex> lk(m_device_list_reply_mutex);
        if (deviceCommandAddress != 0)
        {
            Memory::Write_U32(0xFFFFFFFF, Memory::Read_U32(deviceCommandAddress + 0x18));

            // The original hardware overwrites the command type with the async reply type.
            Memory::Write_U32(IPC_REP_ASYNC, deviceCommandAddress);
            // IOS also seems to write back the command that was responded to in the FD field.
            Memory::Write_U32(IPC_CMD_IOCTL, deviceCommandAddress + 8);

            // Return value
            Memory::Write_U32(-1, deviceCommandAddress + 4);
            WII_IPC_HLE_Interface::EnqueueReply(deviceCommandAddress);
            deviceCommandAddress = 0;
        }
        DEBUG_LOG(WII_IPC_HID, "HID::IOCtl(Shutdown) (BufferIn: (%08x, %i), BufferOut: (%08x, %i)",
                  BufferIn, BufferInSize, BufferOut, BufferOutSize);
        break;
    }
    default:
    {
        DEBUG_LOG(WII_IPC_HID, "HID::IOCtl(0x%x) (BufferIn: (%08x, %i), BufferOut: (%08x, %i)",
                  Parameter, BufferIn, BufferInSize, BufferOut, BufferOutSize);
        break;
    }
    }

    Memory::Write_U32(ReturnValue, _CommandAddress + 4);

    return GetDefaultReply();
}
Esempio n. 4
0
IPCCommandResult NetIPTop::IOCtl(const IOCtlRequest& request)
{
  if (Core::g_want_determinism)
  {
    return GetDefaultReply(IPC_EACCES);
  }

  s32 return_value = 0;
  switch (request.request)
  {
  case IOCTL_SO_STARTUP:
  {
    request.Log(GetDeviceName(), LogTypes::IOS_WC24);
    break;
  }
  case IOCTL_SO_SOCKET:
  {
    u32 af = Memory::Read_U32(request.buffer_in);
    u32 type = Memory::Read_U32(request.buffer_in + 4);
    u32 prot = Memory::Read_U32(request.buffer_in + 8);

    WiiSockMan& sm = WiiSockMan::GetInstance();
    return_value = sm.NewSocket(af, type, prot);
    INFO_LOG(IOS_NET, "IOCTL_SO_SOCKET "
                      "Socket: %08x (%d,%d,%d), BufferIn: (%08x, %i), BufferOut: (%08x, %i)",
             return_value, af, type, prot, request.buffer_in, request.buffer_in_size,
             request.buffer_out, request.buffer_out_size);
    break;
  }
  case IOCTL_SO_ICMPSOCKET:
  {
    u32 pf = Memory::Read_U32(request.buffer_in);

    WiiSockMan& sm = WiiSockMan::GetInstance();
    return_value = sm.NewSocket(pf, SOCK_RAW, IPPROTO_ICMP);
    INFO_LOG(IOS_NET, "IOCTL_SO_ICMPSOCKET(%x) %d", pf, return_value);
    break;
  }
  case IOCTL_SO_CLOSE:
  case IOCTL_SO_ICMPCLOSE:
  {
    u32 fd = Memory::Read_U32(request.buffer_in);
    WiiSockMan& sm = WiiSockMan::GetInstance();
    return_value = sm.DeleteSocket(fd);
    INFO_LOG(IOS_NET, "%s(%x) %x",
             request.request == IOCTL_SO_ICMPCLOSE ? "IOCTL_SO_ICMPCLOSE" : "IOCTL_SO_CLOSE", fd,
             return_value);
    break;
  }
  case IOCTL_SO_ACCEPT:
  case IOCTL_SO_BIND:
  case IOCTL_SO_CONNECT:
  case IOCTL_SO_FCNTL:
  {
    u32 fd = Memory::Read_U32(request.buffer_in);
    WiiSockMan& sm = WiiSockMan::GetInstance();
    sm.DoSock(fd, request, static_cast<NET_IOCTL>(request.request));
    return GetNoReply();
  }
  /////////////////////////////////////////////////////////////
  //                  TODO: Tidy all below                   //
  /////////////////////////////////////////////////////////////
  case IOCTL_SO_SHUTDOWN:
  {
    request.Log(GetDeviceName(), LogTypes::IOS_WC24);

    u32 fd = Memory::Read_U32(request.buffer_in);
    u32 how = Memory::Read_U32(request.buffer_in + 4);
    int ret = shutdown(fd, how);
    return_value = WiiSockMan::GetNetErrorCode(ret, "SO_SHUTDOWN", false);
    break;
  }
  case IOCTL_SO_LISTEN:
  {
    u32 fd = Memory::Read_U32(request.buffer_in);
    u32 BACKLOG = Memory::Read_U32(request.buffer_in + 0x04);
    u32 ret = listen(fd, BACKLOG);
    return_value = WiiSockMan::GetNetErrorCode(ret, "SO_LISTEN", false);
    request.Log(GetDeviceName(), LogTypes::IOS_WC24);
    break;
  }
  case IOCTL_SO_GETSOCKOPT:
  {
    u32 fd = Memory::Read_U32(request.buffer_out);
    u32 level = Memory::Read_U32(request.buffer_out + 4);
    u32 optname = Memory::Read_U32(request.buffer_out + 8);

    request.Log(GetDeviceName(), LogTypes::IOS_WC24);

    // Do the level/optname translation
    int nat_level = -1, nat_optname = -1;

    for (auto& map : opt_level_mapping)
      if (level == map[1])
        nat_level = map[0];

    for (auto& map : opt_name_mapping)
      if (optname == map[1])
        nat_optname = map[0];

    u8 optval[20];
    u32 optlen = 4;

    int ret = getsockopt(fd, nat_level, nat_optname, (char*)&optval, (socklen_t*)&optlen);
    return_value = WiiSockMan::GetNetErrorCode(ret, "SO_GETSOCKOPT", false);

    Memory::Write_U32(optlen, request.buffer_out + 0xC);
    Memory::CopyToEmu(request.buffer_out + 0x10, optval, optlen);

    if (optname == SO_ERROR)
    {
      s32 last_error = WiiSockMan::GetInstance().GetLastNetError();

      Memory::Write_U32(sizeof(s32), request.buffer_out + 0xC);
      Memory::Write_U32(last_error, request.buffer_out + 0x10);
    }
    break;
  }

  case IOCTL_SO_SETSOCKOPT:
  {
    u32 fd = Memory::Read_U32(request.buffer_in);
    u32 level = Memory::Read_U32(request.buffer_in + 4);
    u32 optname = Memory::Read_U32(request.buffer_in + 8);
    u32 optlen = Memory::Read_U32(request.buffer_in + 0xc);
    u8 optval[20];
    optlen = std::min(optlen, (u32)sizeof(optval));
    Memory::CopyFromEmu(optval, request.buffer_in + 0x10, optlen);

    INFO_LOG(IOS_NET, "IOCTL_SO_SETSOCKOPT(%08x, %08x, %08x, %08x) "
                      "BufferIn: (%08x, %i), BufferOut: (%08x, %i)"
                      "%02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx "
                      "%02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx",
             fd, level, optname, optlen, request.buffer_in, request.buffer_in_size,
             request.buffer_out, request.buffer_out_size, optval[0], optval[1], optval[2],
             optval[3], optval[4], optval[5], optval[6], optval[7], optval[8], optval[9],
             optval[10], optval[11], optval[12], optval[13], optval[14], optval[15], optval[16],
             optval[17], optval[18], optval[19]);

    // TODO: bug booto about this, 0x2005 most likely timeout related, default value on Wii is ,
    // 0x2001 is most likely tcpnodelay
    if (level == 6 && (optname == 0x2005 || optname == 0x2001))
    {
      return_value = 0;
      break;
    }

    // Do the level/optname translation
    int nat_level = -1, nat_optname = -1;

    for (auto& map : opt_level_mapping)
      if (level == map[1])
        nat_level = map[0];

    for (auto& map : opt_name_mapping)
      if (optname == map[1])
        nat_optname = map[0];

    if (nat_level == -1 || nat_optname == -1)
    {
      INFO_LOG(IOS_NET, "SO_SETSOCKOPT: unknown level %d or optname %d", level, optname);

      // Default to the given level/optname. They match on Windows...
      nat_level = level;
      nat_optname = optname;
    }

    int ret = setsockopt(fd, nat_level, nat_optname, (char*)optval, optlen);
    return_value = WiiSockMan::GetNetErrorCode(ret, "SO_SETSOCKOPT", false);
    break;
  }
  case IOCTL_SO_GETSOCKNAME:
  {
    u32 fd = Memory::Read_U32(request.buffer_in);

    request.Log(GetDeviceName(), LogTypes::IOS_WC24);

    sockaddr sa;
    socklen_t sa_len;
    sa_len = sizeof(sa);
    int ret = getsockname(fd, &sa, &sa_len);

    if (request.buffer_out_size < 2 + sizeof(sa.sa_data))
      WARN_LOG(IOS_NET, "IOCTL_SO_GETSOCKNAME output buffer is too small. Truncating");

    if (request.buffer_out_size > 0)
      Memory::Write_U8(request.buffer_out_size, request.buffer_out);
    if (request.buffer_out_size > 1)
      Memory::Write_U8(sa.sa_family & 0xFF, request.buffer_out + 1);
    if (request.buffer_out_size > 2)
      Memory::CopyToEmu(request.buffer_out + 2, &sa.sa_data,
                        std::min<size_t>(sizeof(sa.sa_data), request.buffer_out_size - 2));
    return_value = ret;
    break;
  }
  case IOCTL_SO_GETPEERNAME:
  {
    u32 fd = Memory::Read_U32(request.buffer_in);

    sockaddr sa;
    socklen_t sa_len;
    sa_len = sizeof(sa);

    int ret = getpeername(fd, &sa, &sa_len);

    if (request.buffer_out_size < 2 + sizeof(sa.sa_data))
      WARN_LOG(IOS_NET, "IOCTL_SO_GETPEERNAME output buffer is too small. Truncating");

    if (request.buffer_out_size > 0)
      Memory::Write_U8(request.buffer_out_size, request.buffer_out);
    if (request.buffer_out_size > 1)
      Memory::Write_U8(AF_INET, request.buffer_out + 1);
    if (request.buffer_out_size > 2)
      Memory::CopyToEmu(request.buffer_out + 2, &sa.sa_data,
                        std::min<size_t>(sizeof(sa.sa_data), request.buffer_out_size - 2));

    INFO_LOG(IOS_NET, "IOCTL_SO_GETPEERNAME(%x)", fd);

    return_value = ret;
    break;
  }

  case IOCTL_SO_GETHOSTID:
  {
    request.Log(GetDeviceName(), LogTypes::IOS_WC24);

#ifdef _WIN32
    DWORD forwardTableSize, ipTableSize, result;
    DWORD ifIndex = -1;
    std::unique_ptr<MIB_IPFORWARDTABLE> forwardTable;
    std::unique_ptr<MIB_IPADDRTABLE> ipTable;

    forwardTableSize = 0;
    if (GetIpForwardTable(nullptr, &forwardTableSize, FALSE) == ERROR_INSUFFICIENT_BUFFER)
    {
      forwardTable =
          std::unique_ptr<MIB_IPFORWARDTABLE>((PMIB_IPFORWARDTABLE) operator new(forwardTableSize));
    }

    ipTableSize = 0;
    if (GetIpAddrTable(nullptr, &ipTableSize, FALSE) == ERROR_INSUFFICIENT_BUFFER)
    {
      ipTable = std::unique_ptr<MIB_IPADDRTABLE>((PMIB_IPADDRTABLE) operator new(ipTableSize));
    }

    // find the interface IP used for the default route and use that
    result = GetIpForwardTable(forwardTable.get(), &forwardTableSize, FALSE);
    while (result == NO_ERROR ||
           result == ERROR_MORE_DATA)  // can return ERROR_MORE_DATA on XP even after the first call
    {
      for (DWORD i = 0; i < forwardTable->dwNumEntries; ++i)
      {
        if (forwardTable->table[i].dwForwardDest == 0)
        {
          ifIndex = forwardTable->table[i].dwForwardIfIndex;
          break;
        }
      }

      if (result == NO_ERROR || ifIndex != -1)
        break;

      result = GetIpForwardTable(forwardTable.get(), &forwardTableSize, FALSE);
    }

    if (ifIndex != -1 && GetIpAddrTable(ipTable.get(), &ipTableSize, FALSE) == NO_ERROR)
    {
      for (DWORD i = 0; i < ipTable->dwNumEntries; ++i)
      {
        if (ipTable->table[i].dwIndex == ifIndex)
        {
          return_value = Common::swap32(ipTable->table[i].dwAddr);
          break;
        }
      }
    }
#endif

    // default placeholder, in case of failure
    if (return_value == 0)
      return_value = 192 << 24 | 168 << 16 | 1 << 8 | 150;
    break;
  }

  case IOCTL_SO_INETATON:
  {
    std::string hostname = Memory::GetString(request.buffer_in);
    struct hostent* remoteHost = gethostbyname(hostname.c_str());

    if (remoteHost == nullptr || remoteHost->h_addr_list == nullptr ||
        remoteHost->h_addr_list[0] == nullptr)
    {
      INFO_LOG(IOS_NET, "IOCTL_SO_INETATON = -1 "
                        "%s, BufferIn: (%08x, %i), BufferOut: (%08x, %i), IP Found: None",
               hostname.c_str(), request.buffer_in, request.buffer_in_size, request.buffer_out,
               request.buffer_out_size);
      return_value = 0;
    }
    else
    {
      Memory::Write_U32(Common::swap32(*(u32*)remoteHost->h_addr_list[0]), request.buffer_out);
      INFO_LOG(IOS_NET, "IOCTL_SO_INETATON = 0 "
                        "%s, BufferIn: (%08x, %i), BufferOut: (%08x, %i), IP Found: %08X",
               hostname.c_str(), request.buffer_in, request.buffer_in_size, request.buffer_out,
               request.buffer_out_size, Common::swap32(*(u32*)remoteHost->h_addr_list[0]));
      return_value = 1;
    }
    break;
  }

  case IOCTL_SO_INETPTON:
  {
    std::string address = Memory::GetString(request.buffer_in);
    INFO_LOG(IOS_NET, "IOCTL_SO_INETPTON "
                      "(Translating: %s)",
             address.c_str());
    return_value = inet_pton(address.c_str(), Memory::GetPointer(request.buffer_out + 4));
    break;
  }

  case IOCTL_SO_INETNTOP:
  {
    // u32 af = Memory::Read_U32(BufferIn);
    // u32 validAddress = Memory::Read_U32(request.buffer_in + 4);
    // u32 src = Memory::Read_U32(request.buffer_in + 8);
    char ip_s[16];
    sprintf(ip_s, "%i.%i.%i.%i", Memory::Read_U8(request.buffer_in + 8),
            Memory::Read_U8(request.buffer_in + 8 + 1), Memory::Read_U8(request.buffer_in + 8 + 2),
            Memory::Read_U8(request.buffer_in + 8 + 3));
    INFO_LOG(IOS_NET, "IOCTL_SO_INETNTOP %s", ip_s);
    Memory::CopyToEmu(request.buffer_out, (u8*)ip_s, strlen(ip_s));
    break;
  }

  case IOCTL_SO_POLL:
  {
    // Map Wii/native poll events types
    struct
    {
      int native;
      int wii;
    } mapping[] = {
        {POLLRDNORM, 0x0001}, {POLLRDBAND, 0x0002}, {POLLPRI, 0x0004}, {POLLWRNORM, 0x0008},
        {POLLWRBAND, 0x0010}, {POLLERR, 0x0020},    {POLLHUP, 0x0040}, {POLLNVAL, 0x0080},
    };

    u32 unknown = Memory::Read_U32(request.buffer_in);
    u32 timeout = Memory::Read_U32(request.buffer_in + 4);

    int nfds = request.buffer_out_size / 0xc;
    if (nfds == 0)
      ERROR_LOG(IOS_NET, "Hidden POLL");

    std::vector<pollfd_t> ufds(nfds);

    for (int i = 0; i < nfds; ++i)
    {
      ufds[i].fd = Memory::Read_U32(request.buffer_out + 0xc * i);           // fd
      int events = Memory::Read_U32(request.buffer_out + 0xc * i + 4);       // events
      ufds[i].revents = Memory::Read_U32(request.buffer_out + 0xc * i + 8);  // revents

      // Translate Wii to native events
      int unhandled_events = events;
      ufds[i].events = 0;
      for (auto& map : mapping)
      {
        if (events & map.wii)
          ufds[i].events |= map.native;
        unhandled_events &= ~map.wii;
      }
      DEBUG_LOG(IOS_NET, "IOCTL_SO_POLL(%d) "
                         "Sock: %08x, Unknown: %08x, Events: %08x, "
                         "NativeEvents: %08x",
                i, ufds[i].fd, unknown, events, ufds[i].events);

      // Do not pass return-only events to the native poll
      ufds[i].events &= ~(POLLERR | POLLHUP | POLLNVAL | UNSUPPORTED_WSAPOLL);

      if (unhandled_events)
        ERROR_LOG(IOS_NET, "SO_POLL: unhandled Wii event types: %04x", unhandled_events);
    }

    int ret = poll(ufds.data(), nfds, timeout);
    ret = WiiSockMan::GetNetErrorCode(ret, "SO_POLL", false);

    for (int i = 0; i < nfds; ++i)
    {
      // Translate native to Wii events
      int revents = 0;
      for (auto& map : mapping)
      {
        if (ufds[i].revents & map.native)
          revents |= map.wii;
      }

      // No need to change fd or events as they are input only.
      // Memory::Write_U32(ufds[i].fd, request.buffer_out + 0xc*i); //fd
      // Memory::Write_U32(events, request.buffer_out + 0xc*i + 4); //events
      Memory::Write_U32(revents, request.buffer_out + 0xc * i + 8);  // revents

      DEBUG_LOG(IOS_NET, "IOCTL_SO_POLL socket %d wevents %08X events %08X revents %08X", i,
                revents, ufds[i].events, ufds[i].revents);
    }

    return_value = ret;
    break;
  }

  case IOCTL_SO_GETHOSTBYNAME:
  {
    if (request.buffer_out_size != 0x460)
    {
      ERROR_LOG(IOS_NET, "Bad buffer size for IOCTL_SO_GETHOSTBYNAME");
      return_value = -1;
      break;
    }

    std::string hostname = Memory::GetString(request.buffer_in);
    hostent* remoteHost = gethostbyname(hostname.c_str());

    INFO_LOG(IOS_NET, "IOCTL_SO_GETHOSTBYNAME "
                      "Address: %s, BufferIn: (%08x, %i), BufferOut: (%08x, %i)",
             hostname.c_str(), request.buffer_in, request.buffer_in_size, request.buffer_out,
             request.buffer_out_size);

    if (remoteHost)
    {
      for (int i = 0; remoteHost->h_aliases[i]; ++i)
      {
        DEBUG_LOG(IOS_NET, "alias%i:%s", i, remoteHost->h_aliases[i]);
      }

      for (int i = 0; remoteHost->h_addr_list[i]; ++i)
      {
        u32 ip = Common::swap32(*(u32*)(remoteHost->h_addr_list[i]));
        std::string ip_s = StringFromFormat("%i.%i.%i.%i", ip >> 24, (ip >> 16) & 0xff,
                                            (ip >> 8) & 0xff, ip & 0xff);
        DEBUG_LOG(IOS_NET, "addr%i:%s", i, ip_s.c_str());
      }

      // Host name; located immediately after struct
      static const u32 GETHOSTBYNAME_STRUCT_SIZE = 0x10;
      static const u32 GETHOSTBYNAME_IP_LIST_OFFSET = 0x110;
      // Limit host name length to avoid buffer overflow.
      u32 name_length = (u32)strlen(remoteHost->h_name) + 1;
      if (name_length > (GETHOSTBYNAME_IP_LIST_OFFSET - GETHOSTBYNAME_STRUCT_SIZE))
      {
        ERROR_LOG(IOS_NET, "Hostname too long in IOCTL_SO_GETHOSTBYNAME");
        return_value = -1;
        break;
      }
      Memory::CopyToEmu(request.buffer_out + GETHOSTBYNAME_STRUCT_SIZE, remoteHost->h_name,
                        name_length);
      Memory::Write_U32(request.buffer_out + GETHOSTBYNAME_STRUCT_SIZE, request.buffer_out);

      // IP address list; located at offset 0x110.
      u32 num_ip_addr = 0;
      while (remoteHost->h_addr_list[num_ip_addr])
        num_ip_addr++;
      // Limit number of IP addresses to avoid buffer overflow.
      // (0x460 - 0x340) / sizeof(pointer) == 72
      static const u32 GETHOSTBYNAME_MAX_ADDRESSES = 71;
      num_ip_addr = std::min(num_ip_addr, GETHOSTBYNAME_MAX_ADDRESSES);
      for (u32 i = 0; i < num_ip_addr; ++i)
      {
        u32 addr = request.buffer_out + GETHOSTBYNAME_IP_LIST_OFFSET + i * 4;
        Memory::Write_U32_Swap(*(u32*)(remoteHost->h_addr_list[i]), addr);
      }

      // List of pointers to IP addresses; located at offset 0x340.
      // This must be exact: PPC code to convert the struct hardcodes
      // this offset.
      static const u32 GETHOSTBYNAME_IP_PTR_LIST_OFFSET = 0x340;
      Memory::Write_U32(request.buffer_out + GETHOSTBYNAME_IP_PTR_LIST_OFFSET,
                        request.buffer_out + 12);
      for (u32 i = 0; i < num_ip_addr; ++i)
      {
        u32 addr = request.buffer_out + GETHOSTBYNAME_IP_PTR_LIST_OFFSET + i * 4;
        Memory::Write_U32(request.buffer_out + GETHOSTBYNAME_IP_LIST_OFFSET + i * 4, addr);
      }
      Memory::Write_U32(0, request.buffer_out + GETHOSTBYNAME_IP_PTR_LIST_OFFSET + num_ip_addr * 4);

      // Aliases - empty. (Hardware doesn't return anything.)
      Memory::Write_U32(request.buffer_out + GETHOSTBYNAME_IP_PTR_LIST_OFFSET + num_ip_addr * 4,
                        request.buffer_out + 4);

      // Returned struct must be ipv4.
      _assert_msg_(IOS_NET,
                   remoteHost->h_addrtype == AF_INET && remoteHost->h_length == sizeof(u32),
                   "returned host info is not IPv4");
      Memory::Write_U16(AF_INET, request.buffer_out + 8);
      Memory::Write_U16(sizeof(u32), request.buffer_out + 10);

      return_value = 0;
    }
    else
    {
      return_value = -1;
    }

    break;
  }

  case IOCTL_SO_ICMPCANCEL:
    ERROR_LOG(IOS_NET, "IOCTL_SO_ICMPCANCEL");

  default:
    request.DumpUnknown(GetDeviceName(), LogTypes::IOS_NET);
  }
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;
}
IPCCommandResult CWII_IPC_HLE_Device_usb_ven::IOCtl(u32 CommandAddress)
{
	IPCCommandResult SendReply = 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);

	WARN_LOG(OSHLE, "%s - IOCtl:%x", GetDeviceName().c_str(), Command);
	WARN_LOG(OSHLE, "%x:%x %x:%x", BufferIn, BufferInSize, BufferOut, BufferOutSize);

	switch (Command)
	{
	case USBV5_IOCTL_GETVERSION:
		Memory::Write_U32(0x50001, BufferOut);
		SendReply = GetDefaultReply();
		break;

	case USBV5_IOCTL_GETDEVICECHANGE:
		{
		// fd
		Memory::Write_U32(0xcd000030, BufferOut);
		// vid, pid
		Memory::Write_U32(0x046d0a03, BufferOut + 4);
		// token
		//Memory::Write_U32(0, BufferOut + 8);
		
		// sent on change
		static bool firstcall = true;
		if (firstcall)
			SendReply = GetDefaultReply(), firstcall = false;
		// num devices
		Memory::Write_U32(1, CommandAddress + 4);
		return SendReply;
		}
		break;

	case USBV5_IOCTL_ATTACHFINISH:
		SendReply = GetDefaultReply();
		break;

	case USBV5_IOCTL_SUSPEND_RESUME:
		WARN_LOG(OSHLE, "device:%i resumed:%i", Memory::Read_U32(BufferIn), Memory::Read_U32(BufferIn + 4));
		SendReply = GetDefaultReply();
		break;

	case USBV5_IOCTL_GETDEVPARAMS:
		{
		s32 device = Memory::Read_U32(BufferIn);
		u32 unk = Memory::Read_U32(BufferIn + 4);

		WARN_LOG(OSHLE, "USBV5_IOCTL_GETDEVPARAMS device:%i unk:%i", device, unk);

		Memory::Write_U32(0, BufferOut);

		SendReply = GetDefaultReply();
		}
		break;

	default:
		//WARN_LOG(OSHLE, "%x:%x %x:%x", BufferIn, BufferInSize, BufferOut, BufferOutSize);
		break;
	}

	Memory::Write_U32(0, CommandAddress + 4);
	return SendReply;
}