diff --git a/ControllerUSB/include/Controllers/XboxOneAdapter.h b/ControllerUSB/include/Controllers/XboxOneAdapter.h index 28f9bfe..0f02406 100644 --- a/ControllerUSB/include/Controllers/XboxOneAdapter.h +++ b/ControllerUSB/include/Controllers/XboxOneAdapter.h @@ -39,6 +39,10 @@ public: virtual ControllerType GetType() { return CONTROLLER_XBOXONEW; } + Status LoadFirmwarePart(uint32_t offset, uint8_t *start, uint8_t *end); Status SendInitBytes(); Status ControlWrite(IUSBInterface *interface, uint16_t address, uint32_t value, VendorRequest request = MT_VEND_MULTI_WRITE); + + static void LoadConfig(const ControllerConfig *config, const char *path); + virtual ControllerConfig *GetConfig(); }; \ No newline at end of file diff --git a/ControllerUSB/include/Controllers/XboxOneAdapter/Firmware.h b/ControllerUSB/include/Controllers/XboxOneAdapter/Firmware.h index 047c8fe..012afda 100644 --- a/ControllerUSB/include/Controllers/XboxOneAdapter/Firmware.h +++ b/ControllerUSB/include/Controllers/XboxOneAdapter/Firmware.h @@ -7,3 +7,45 @@ #define MT_FW_CHUNK_SIZE 0x3800 #define MT_DMA_COMPLETE 0xc0000000 #define MT_FW_LOAD_IVB 0x12 + +#define MT_FCE_DMA_ADDR 0x0230 +#define MT_FCE_DMA_LEN 0x0234 +#define MT_USB_DMA_CFG 0x0238 + +#define MT_USB_U3DMA_CFG 0x9018 +#define MT_FCE_PSE_CTRL 0x0800 +#define MT_TX_CPU_FROM_FCE_BASE_PTR 0x09a0 +#define MT_TX_CPU_FROM_FCE_MAX_COUNT 0x09a4 +#define MT_TX_CPU_FROM_FCE_CPU_DESC_IDX 0x09a8 +#define MT_FCE_PDMA_GLOBAL_CONF 0x09c4 +#define MT_FCE_SKIP_FS 0x0a6c + +struct FwHeader +{ + uint32_t ilmLength; + uint32_t dlmLength; + uint16_t buildVersion; + uint16_t firmwareVersion; + uint32_t padding; + char buildTime[16]; +} __attribute__((packed)); + +union DmaConfig { + struct + { + uint32_t rxBulkAggTimeout : 8; + uint32_t rxBulkAggLimit : 8; + uint32_t udmaTxWlDrop : 1; + uint32_t wakeupEnabled : 1; + uint32_t rxDropOrPad : 1; + uint32_t txClear : 1; + uint32_t txopHalt : 1; + uint32_t rxBulkAggEnabled : 1; + uint32_t rxBulkEnabled : 1; + uint32_t txBulkEnabled : 1; + uint32_t epOutValid : 6; + uint32_t rxBusy : 1; + uint32_t txBusy : 1; + } __attribute__((packed)); + uint32_t value; +}; diff --git a/ControllerUSB/source/Controllers/XboxOneAdapter.cpp b/ControllerUSB/source/Controllers/XboxOneAdapter.cpp index 5b4c155..ccd0d2e 100644 --- a/ControllerUSB/source/Controllers/XboxOneAdapter.cpp +++ b/ControllerUSB/source/Controllers/XboxOneAdapter.cpp @@ -2,6 +2,11 @@ #include "Controllers/XboxOneAdapter/Firmware.h" #include #include "../../source/log.h" +#include +#include "cstring" + +static ControllerConfig _xboxoneadapterConfig{}; +static char firmwarePath[100]; XboxOneAdapter::XboxOneAdapter(std::unique_ptr &&interface) : IController(std::move(interface)) @@ -108,41 +113,115 @@ void XboxOneAdapter::CloseInterfaces() Status XboxOneAdapter::SendInitBytes() { Status rc; - rc = ControlWrite(m_interface, 0x9018, 0, MT_VEND_WRITE_CFG); - if (S_FAILED(rc)) - return rc; - rc = ControlWrite(m_interface, 0x0800, 0x01); - if (S_FAILED(rc)) - return rc; - rc = ControlWrite(m_interface, 0x09a0, 0x400230); - if (S_FAILED(rc)) - return rc; - rc = ControlWrite(m_interface, 0x09a4, 0x01); - if (S_FAILED(rc)) - return rc; - rc = ControlWrite(m_interface, 0x09a8, 0x01); - if (S_FAILED(rc)) - return rc; - rc = ControlWrite(m_interface, 0x09c4, 0x44); - if (S_FAILED(rc)) - return rc; - rc = ControlWrite(m_interface, 0x0a6c, 0x03); + DmaConfig config = {}; + + config.rxBulkEnabled = 1; + config.txBulkEnabled = 1; + + ControlWrite(m_interface, MT_USB_U3DMA_CFG, config.value, MT_VEND_WRITE_CFG); + ControlWrite(m_interface, MT_FCE_PSE_CTRL, 0x01); + ControlWrite(m_interface, MT_TX_CPU_FROM_FCE_BASE_PTR, 0x400230); + ControlWrite(m_interface, MT_TX_CPU_FROM_FCE_MAX_COUNT, 0x01); + ControlWrite(m_interface, MT_TX_CPU_FROM_FCE_CPU_DESC_IDX, 0x01); + ControlWrite(m_interface, MT_FCE_PDMA_GLOBAL_CONF, 0x44); + ControlWrite(m_interface, MT_FCE_SKIP_FS, 0x03); + + WriteToLog("firmware path: ", firmwarePath); + if (!firmwarePath || *firmwarePath == '\0') + { + WriteToLog("But the string is empty!"); + return 256; + } + + std::ifstream fs(firmwarePath, std::ios::binary); + if (fs.fail()) + return 235; + + WriteToLog("Opening file..."); + + std::vector firmware(std::istreambuf_iterator(fs), {}); + + WriteToLog("File opened!"); + + fs.close(); + + WriteToLog("writing ", firmware.size(), " bytes..."); + + FwHeader *header = reinterpret_cast(firmware.data()); + + uint8_t *ilmStart = reinterpret_cast(header) + sizeof(FwHeader); + uint8_t *dlmStart = ilmStart + header->ilmLength; + uint8_t *dlmEnd = dlmStart + header->dlmLength; + + WriteToLog("Writing 1st part"); + + rc = LoadFirmwarePart(MT_MCU_ILM_OFFSET, ilmStart, dlmStart); if (S_FAILED(rc)) return rc; + WriteToLog("Writing 2nd part"); + rc = LoadFirmwarePart(MT_MCU_DLM_OFFSET, dlmStart, dlmEnd); + if (S_FAILED(rc)) + return rc; + + WriteToLog("Wrote"); + return 0; } +Status XboxOneAdapter::LoadFirmwarePart(uint32_t offset, uint8_t *start, uint8_t *end) +{ + // Send firmware in chunks + Status rc = -1; + for (uint8_t *chunk = start; chunk < end; chunk += MT_FW_CHUNK_SIZE) + { + uint32_t address = (uint32_t)(offset + chunk - start); + uint32_t remaining = (uint32_t)(end - chunk); + uint16_t length = remaining > MT_FW_CHUNK_SIZE ? MT_FW_CHUNK_SIZE : remaining; + + rc = ControlWrite(m_interface, MT_FCE_DMA_ADDR, address, MT_VEND_WRITE_CFG); + if (S_FAILED(rc)) + return rc; + + rc = ControlWrite(m_interface, MT_FCE_DMA_LEN, length << 16, MT_VEND_WRITE_CFG); + if (S_FAILED(rc)) + return rc; + + uint8_t data[length + 8]{0x00, 0x38, 0x00, 0x10}; + + for (int i = 0; i != length; ++i) + { + data[i + 4] = chunk[i]; + } + + rc = m_outPipe->Write(data, sizeof(data)); + if (S_FAILED(rc)) + return rc; + } + return rc; +} + Status XboxOneAdapter::ControlWrite(IUSBInterface *interface, uint16_t address, uint32_t value, VendorRequest request) { Status rc; if (request == MT_VEND_DEV_MODE) { - rc = interface->ControlTransfer(0x42, request, address, 0, 0, nullptr); + rc = interface->ControlTransfer(0x40, request, address, 0, 0, nullptr); } else { - rc = interface->ControlTransfer(0x42, request, address, 0, sizeof(uint32_t), &value); + rc = interface->ControlTransfer(0x40, request, address, 0, sizeof(uint32_t), &value); } return rc; +} + +void XboxOneAdapter::LoadConfig(const ControllerConfig *config, const char *path) +{ + _xboxoneadapterConfig = *config; + strcpy(firmwarePath, path); +} + +ControllerConfig *XboxOneAdapter::GetConfig() +{ + return &_xboxoneadapterConfig; } \ No newline at end of file diff --git a/config/sys-con/config_xboxoneadapter.ini b/config/sys-con/config_xboxoneadapter.ini new file mode 100644 index 0000000..c019b3e --- /dev/null +++ b/config/sys-con/config_xboxoneadapter.ini @@ -0,0 +1 @@ +firmware_path = /config/sys-con/firmware/XboxOneAdapter.bin \ No newline at end of file diff --git a/config/sys-con/firmware/XboxOneAdapter.bin b/config/sys-con/firmware/XboxOneAdapter.bin new file mode 100644 index 0000000..22624d5 Binary files /dev/null and b/config/sys-con/firmware/XboxOneAdapter.bin differ diff --git a/source/configFile.cpp b/source/configFile.cpp index 0e7be37..f4320e1 100644 --- a/source/configFile.cpp +++ b/source/configFile.cpp @@ -14,6 +14,7 @@ #define XBOXCONFIG "config_xboxorig.ini" #define XBOX360CONFIG "config_xbox360.ini" #define XBOXONECONFIG "config_xboxone.ini" +#define XBOXONEADAPTERCONFIG "config_xboxoneadapter.ini" #define DUALSHOCK3CONFIG "config_dualshock3.ini" #define DUALSHOCK4CONFIG "config_dualshock4.ini" @@ -51,6 +52,7 @@ static ControllerButton _StringToKey(const char *text) } static ControllerConfig temp_config; +static char firmwarePath[100]; static int _ParseConfigLine(void *dummy, const char *section, const char *name, const char *value) { @@ -92,6 +94,11 @@ static int _ParseConfigLine(void *dummy, const char *section, const char *name, temp_config.swapDPADandLSTICK = (strcmp(value, "true") ? false : true); return 1; } + else if (strcmp(name, "firmware_path") == 0) + { + strcpy(firmwarePath, value); + return 1; + } return 0; } @@ -120,6 +127,11 @@ void LoadAllConfigs() else WriteToLog("Failed to read from xbox one config!"); + if (R_SUCCEEDED(_ReadFromConfig(CONFIG_PATH XBOXONEADAPTERCONFIG))) + XboxOneAdapter::LoadConfig(&temp_config, firmwarePath); + else + WriteToLog("Failed to read from xbox one adapter config!"); + if (R_SUCCEEDED(_ReadFromConfig(CONFIG_PATH XBOX360CONFIG))) { Xbox360Controller::LoadConfig(&temp_config); @@ -147,6 +159,7 @@ bool CheckForFileChanges() static time_t xboxConfigLastModified; static time_t xbox360ConfigLastModified; static time_t xboxOneConfigLastModified; + static time_t xboxOneAdapterConfigLastModified; static time_t dualshock3ConfigLastModified; static time_t dualshock4ConfigLastModified; struct stat result; @@ -192,5 +205,11 @@ bool CheckForFileChanges() dualshock4ConfigLastModified = result.st_mtime; filesChanged = true; } + if (stat(CONFIG_PATH XBOXONEADAPTERCONFIG, &result) == 0) + if (xboxOneAdapterConfigLastModified != result.st_mtime) + { + xboxOneAdapterConfigLastModified = result.st_mtime; + filesChanged = true; + } return filesChanged; } \ No newline at end of file