diff --git a/EDUReViver.suo b/EDUReViver.suo index bdb45b2..60405fc 100644 Binary files a/EDUReViver.suo and b/EDUReViver.suo differ diff --git a/EDUReViver/EDUReViver.vcxproj b/EDUReViver/EDUReViver.vcxproj index b9779c6..5cdc8dc 100644 --- a/EDUReViver/EDUReViver.vcxproj +++ b/EDUReViver/EDUReViver.vcxproj @@ -168,6 +168,7 @@ + diff --git a/EDUReViver/EDUReViver.vcxproj.filters b/EDUReViver/EDUReViver.vcxproj.filters index 777264a..37f6000 100644 --- a/EDUReViver/EDUReViver.vcxproj.filters +++ b/EDUReViver/EDUReViver.vcxproj.filters @@ -50,5 +50,8 @@ Header Files + + Header Files + \ No newline at end of file diff --git a/EDUReViver/main.cpp b/EDUReViver/main.cpp index 5a83f2a..290d8cb 100644 --- a/EDUReViver/main.cpp +++ b/EDUReViver/main.cpp @@ -106,8 +106,7 @@ enum payloadmode { }; -#define CLOSE_AND_EXIT(code) freeJLinks(devvec);\ - UnloadWinusb();\ +#define CLOSE_AND_EXIT(code) UnloadWinusb();\ return code; void printmismatch(const char* name, bool mismatch) @@ -119,6 +118,8 @@ void printmismatch(const char* name, bool mismatch) } } + + int main(int argc, char * argv[]) { //#ifdef _DEBUG @@ -150,25 +151,40 @@ int main(int argc, char * argv[]) } } if (payloadname == 0) { - printf("V10ReViver -run [options]\n"); + printf("EDUReViver -run [options]\n"); return -1; } if (LoadWinusb() != 0) { printf("No WinUSB support because WinUSB.dll is corrupt or missing.\n");; } - JLinkDevVec devvec; - if (!getJLinks(devvec)) { + startupKeeper(); + atexit(shutdownKeeper); + JLinkInfoVec infovec; + if (!LinkKeeper::getJLinksSnap(infovec)) { errprintf("Failed to find device!\n"); CLOSE_AND_EXIT(0); - } else if (devvec.size() > 1) { - errprintf("Only support one device, please unplug other probes!\n"); - CLOSE_AND_EXIT(0); + } else if (infovec.size() > 1) { + int i = 1; + for (JLinkInfoVec::const_iterator it = infovec.begin(); it != infovec.end(); it++, i++) { + printf("%d: %s [%d] sn %d%s\n", i, it->locationInfo.hubName.c_str(), it->locationInfo.devPort, it->winSerial, it->isWinusb?" WinUSB":""); + } + printf("Input device index: "); + scanf_s("%d", &i); + getchar(); + if (1 <= i && i <= infovec.size()) { + LinkKeeper::selectDevice(infovec.at(i - 1).locationInfo); + } else { + errprintf("Out of index!\n"); + CLOSE_AND_EXIT(0); + } + } else { + LinkKeeper::selectDevice(infovec.at(0).locationInfo); // one device } uint8_t dataBuffer[512] = {0}; bool isv10 = false; - jlinkLoopReadFirmwareVersion(&devvec[0], dataBuffer); + LinkKeeper::loopReadFirmwareVersion(dataBuffer); dataBuffer[0x70] = 0; //isv9 = strstr((const char*)dataBuffer, "V9") != 0; isv10 = (strstr((const char*)dataBuffer, "V10") != 0) || (strstr((const char*)dataBuffer, "V11") != 0) || (strstr((const char*)dataBuffer, "V12") != 0); @@ -182,7 +198,7 @@ int main(int argc, char * argv[]) errprintf("Only support v10,v11,v12 devices.\n"); CLOSE_AND_EXIT(0); } - // check genius hardware + // check genuine hardware const patcher_config* config = find_patcher_config((char*)dataBuffer); uint32_t sn, snchecksum; uint8_t snuidbuf[36]; @@ -191,7 +207,7 @@ int main(int argc, char * argv[]) bool touchfeatures = _stricmp(payloadname, "revive") == 0; bool touchsn = _stricmp(payloadname, "setsn") == 0; bool touchcrp = _stricmp(payloadname, "swd") == 0; - if (jlinkCommandReadOTS(&devvec[0], dataBuffer)) { + if (LinkKeeper::commandReadOTS(dataBuffer)) { sn = *(uint32_t*)dataBuffer; snchecksum = *(uint32_t*)(dataBuffer + 4); otssign = dataBuffer + 0x100; @@ -207,7 +223,7 @@ int main(int argc, char * argv[]) bool otssignok = false; void* myapp = 0; int applen = 0; - if (jlinkCommandReadUID(&devvec[0], &uidlen, &snuidbuf[4])) { + if (LinkKeeper::commandReadUID(&uidlen, &snuidbuf[4])) { char* uidstr = base64_encode(&snuidbuf[4], uidlen); char* signstr = base64_encode((uint8_t*)otssign, 0x100); char* reply = 0; @@ -249,7 +265,7 @@ int main(int argc, char * argv[]) uint32_t dumpsize = config?0x8000:0x80000; // dump bootloader/firmware and parse char* fwdump = (char*)malloc(dumpsize); - if (jlinkDumpFullFirmware(&devvec[0], 0x1A000000, dumpsize, fwdump)) { + if (LinkKeeper::dumpFullFirmware(0x1A000000, dumpsize, fwdump)) { bool bootloaderok = is_offical_bootloader(fwdump); if (touchcrp) { printCRPlevel(*(uint32_t*)&fwdump[0x2FC]); @@ -289,7 +305,7 @@ int main(int argc, char * argv[]) } uint32_t oldif; - if (jlinkCommandSendSelectInterface(&devvec[0], 3, &oldif)) { + if (LinkKeeper::commandSendSelectInterface(3, &oldif)) { printf("Change interface: %d -> 3\n", oldif); } else { errprintf("Select interface failed!\n"); @@ -334,7 +350,7 @@ int main(int argc, char * argv[]) *(uint32_t*)&m4rxret[0x28] = config->lr | 1; // 要返回dispatchcmd m4rxcmd = assembly_cmd_payload(&cmdlen, m4rxret, sizeof(m4rxret), config, 0); } - jlinkSendCommand(&devvec[0], m4rxcmd, cmdlen, &readed, sizeof(readed)); + LinkKeeper::sendCommand(m4rxcmd, cmdlen, &readed, sizeof(readed)); free(m4rxcmd); } else { // 双次溢出 @@ -347,7 +363,7 @@ int main(int argc, char * argv[]) }; *(uint32_t*)&patcher[0x20] = config->lr + 1; // 第一次要返回dispatchcmd cmd_fine_write_read* patchercmd = assembly_cmd_payload(&cmdlen, patcher, sizeof(patcher), config, 0); - jlinkSendCommand(&devvec[0], patchercmd, cmdlen, &readed, sizeof(readed)); + LinkKeeper::sendCommand(patchercmd, cmdlen, &readed, sizeof(readed)); free(patchercmd); M0patched = true; // 此时代码可以使用连续的0x2C/0x28内容, 其他注意事项同上 @@ -376,7 +392,7 @@ int main(int argc, char * argv[]) *(uint32_t*)&m0ldr[0x28] = config->lr | 1; ldrcmd = assembly_cmd_payload(&cmdlen, m0ldr, sizeof(m0ldr), config, -0x18); } - jlinkSendCommand(&devvec[0], ldrcmd, cmdlen, NULL, 0); + LinkKeeper::sendCommand(ldrcmd, cmdlen, NULL, 0); free(ldrcmd); } // SES固件 R4~R6无可用空间情况的第二次溢出, 为了兼容未来固件(但不能不知R4~R6值) @@ -389,7 +405,7 @@ int main(int argc, char * argv[]) *(uint32_t*)&m4rxret[0x1C] = config->usbrx | 1; *(uint32_t*)&m4rxret[0x20] = config->lr | 1; // 要返回dispatchcmd cmd_fine_write_read* m4rxcmd = assembly_cmd_payload(&cmdlen, m4rxret, sizeof(m4rxret), config, 0); - jlinkSendCommand(&devvec[0], m4rxcmd, cmdlen, &readed, sizeof(readed)); + LinkKeeper::sendCommand(m4rxcmd, cmdlen, &readed, sizeof(readed)); free(m4rxcmd); } } @@ -400,20 +416,21 @@ int main(int argc, char * argv[]) // 超写模式, 不需接收器部分, 最后需重启 // 特殊payload: 不带返回指针, 单2C/28 gap cmd_fine_write_read* m4loopcmd = assembly_cmd_payload(&cmdlen, myapp, applen, config, -0x18); - jlinkSendCommand(&devvec[0], m4loopcmd, cmdlen, NULL, 0); + LinkKeeper::prepareReconnect(); + LinkKeeper::sendCommand(m4loopcmd, cmdlen, NULL, 0); free(m4loopcmd); } else { // 填充到800发出(因为接收器要接满800,可以改loader变为400/200) int applenfull = 0x800; myapp = realloc(myapp, 0x800); memset((char*)myapp + applen, 0, applenfull - applen); - jlinkSendCommand(&devvec[0], myapp, applenfull, NULL, 0); + LinkKeeper::sendCommand(myapp, applenfull, NULL, 0); } free(myapp); // 清理步骤, 如果打过M0补丁, 则恢复补丁, 重启版除外, 等他重启 if (M0patched && mode != pmM4Reset) { uint32_t oldif2; - if (jlinkCommandSendSelectInterface(&devvec[0], oldif, &oldif2)) { + if (LinkKeeper::commandSendSelectInterface(oldif, &oldif2)) { printf("Change interface: %d -> %d\n", oldif2, oldif); } else { errprintf("Select interface failed!\n"); @@ -421,19 +438,13 @@ int main(int argc, char * argv[]) } } if (mode == pmM4Reset) { - freeJLinks(devvec); - printf("Waiting device re-connect...\n"); - SleepEx(5000, TRUE); - if (!getJLinks(devvec)) { - errprintf("Failed to find device!\n"); - return 0; - } else if (devvec.size() > 1) { - errprintf("Only support single device, please unplug other probes!\n"); + if (!LinkKeeper::waitReconnect(5000, 100)) { + errprintf("Failed to reconnect in 5 sec!\n"); CLOSE_AND_EXIT(0); } - jlinkLoopReadFirmwareVersion(&devvec[0], dataBuffer); + LinkKeeper::loopReadFirmwareVersion(dataBuffer); if (is_BTL_version((char*)dataBuffer)) { printf("Found BTL Mode.\n"); } else { @@ -441,7 +452,7 @@ int main(int argc, char * argv[]) } quickdump(0, dataBuffer, 0x70); } - if ((touchfeatures || touchsn) && jlinkCommandReadOTS(&devvec[0], dataBuffer)) { + if ((touchfeatures || touchsn) && LinkKeeper::commandReadOTS(dataBuffer)) { if (touchsn) { sn = *(uint32_t*)dataBuffer; snchecksum = *(uint32_t*)(dataBuffer + 4); @@ -455,12 +466,12 @@ int main(int argc, char * argv[]) } if (touchcrp) { uint32_t crp; - if (jlinkDumpFullFirmware(&devvec[0], 0x1A0002FC, 4, &crp)) { + if (LinkKeeper::dumpFullFirmware(0x1A0002FC, 4, &crp)) { printCRPlevel(crp); } } - freeJLinks(devvec); + shutdownKeeper(); UnloadWinusb(); #ifdef _DEBUG _getch(); diff --git a/EDUReViver/usbconn.cpp b/EDUReViver/usbconn.cpp index 1314820..adc6373 100644 --- a/EDUReViver/usbconn.cpp +++ b/EDUReViver/usbconn.cpp @@ -3,7 +3,9 @@ #include #include //#include -#include +//#include +#include +#include #include "usbconn.h" #include "addon_func.h" @@ -78,9 +80,159 @@ int UnloadWinusb() return 0; } +void extractDevID(char *devid, size_t len, const char *devpath); +bool lookupTopSeggerDevID(DEVINST* devinst, uint16_t vid, char* devid, char* hubid, char* hubname, int* port); +size_t g_recvpos = 0; + +void hublocation::clear() +{ + hubDevID.clear(); + hubName.clear(); + devPort = 0; +} + +void JlinkDevice::open() +{ + if (deviceFile == INVALID_HANDLE_VALUE) { + if (isWinusb) { + HANDLE deviceFile = CreateFileA(devicePath.c_str(), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL); + if (deviceFile == INVALID_HANDLE_VALUE) { + return; + } + + WINUSB_INTERFACE_HANDLE winusbHandle; + if (!WinUsb_Initialize(deviceFile, &winusbHandle)) { + printf("Failed to invoke WinUsb_Initialize, last error %lu\n", GetLastError()); + CloseHandle(deviceFile); + return; + } + uint8_t desc[0x200]; + ULONG desclen = 0x200; + if (!WinUsb_GetDescriptor(winusbHandle, USB_CONFIGURATION_DESCRIPTOR_TYPE, 0, 0, desc, desclen, &desclen)) { + printf("Failed to invoke WinUsb_GetDescriptor, last error %lu\n", GetLastError()); + CloseHandle(deviceFile); + return; + } + uint8_t inep = 0, outep = 0; + PUSB_CONFIGURATION_DESCRIPTOR confdesc = (PUSB_CONFIGURATION_DESCRIPTOR)desc; + PUSB_INTERFACE_DESCRIPTOR ifdesc = (PUSB_INTERFACE_DESCRIPTOR)&desc[confdesc->bLength]; + for (int i = 0; i < confdesc->bNumInterfaces; i++, ifdesc++) { + PUSB_ENDPOINT_DESCRIPTOR epdesc = (PUSB_ENDPOINT_DESCRIPTOR)((char*)ifdesc + ifdesc->bLength); + for (int j = 0; j < ifdesc->bNumEndpoints; j++, epdesc++) { + if ((epdesc->bmAttributes & 3) == 2) { + if (epdesc->bEndpointAddress & 0x80) { + inep = epdesc->bEndpointAddress; // 0x81 + } else { + outep = epdesc->bEndpointAddress; // 0x01 + } + } + } + if (inep && outep) { + break; + } + } + CHAR rawio = TRUE; + WinUsb_SetPipePolicy(winusbHandle, outep, RAW_IO, sizeof(rawio), &rawio); + WinUsb_SetPipePolicy(winusbHandle, inep, RAW_IO, sizeof(rawio), &rawio); + //ULONG transize; + //ULONG transizelen = sizeof(transize); + //WinUsb_GetPipePolicy(winusbHandle, outep, MAXIMUM_TRANSFER_SIZE, &transizelen, &transize); + //transizelen = sizeof(transize); + //WinUsb_GetPipePolicy(winusbHandle, inep, MAXIMUM_TRANSFER_SIZE, &transizelen, &transize); + WINUSB_SETUP_PACKET setup = {0x41, 0x01, 0x0040, 0x0000, 0x0000}; + ULONG transfered = 0; + if (!WinUsb_ControlTransfer(winusbHandle, setup, NULL, 0, &transfered, NULL)) { + printf("Fail to invoke WinUsb_ControlTransfer, last error %lu\n", GetLastError()); + } + DWORD timeout = 1000; + WinUsb_SetPipePolicy(winusbHandle, outep, PIPE_TRANSFER_TIMEOUT, sizeof(timeout), &timeout); + WinUsb_SetPipePolicy(winusbHandle, inep, PIPE_TRANSFER_TIMEOUT, sizeof(timeout), &timeout); + + this->deviceFile = deviceFile; + this->interfaceHandle = winusbHandle; + this->readPipe = inep; // 0x81 + this->writePipe = outep; // 0x01 + } else { + HANDLE deviceFile = CreateFileA(devicePath.c_str(), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if (deviceFile == INVALID_HANDLE_VALUE) { + return; + } + //char InBuffer[64]; + //DWORD BytesReturned = 0; + //DeviceIoControl(deviceFile, 0x220468u, InBuffer, 0x40u, InBuffer, 0x40u, &BytesReturned, 0); + //quickdump(0, (unsigned char*)InBuffer, sizeof(InBuffer)); + char pipeFileName[1024] = {0}; + strcpy_s(pipeFileName, devicePath.c_str()); + strcat_s(pipeFileName, "\\pipe00"); + HANDLE readPipeFile = CreateFileA(pipeFileName, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if (readPipeFile == INVALID_HANDLE_VALUE) { + CloseHandle(deviceFile); + return; + } + + strcpy_s(pipeFileName, devicePath.c_str()); + strcat_s(pipeFileName, "\\pipe01"); + HANDLE writePipeFile = CreateFileA(pipeFileName, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if (writePipeFile == INVALID_HANDLE_VALUE) { + CloseHandle(deviceFile); + CloseHandle(readPipeFile); + return; + } + + this->deviceFile = deviceFile; + this->readPipeFile = readPipeFile; + this->writePipeFile = writePipeFile; + } + } +} + +void JlinkDevice::close() +{ + if (deviceFile != INVALID_HANDLE_VALUE) { + if (isWinusb) { + WinUsb_Free(interfaceHandle); + } else { + CloseHandle(readPipeFile); + CloseHandle(writePipeFile); + } + CloseHandle(deviceFile); + deviceFile = INVALID_HANDLE_VALUE; + g_recvpos = 0; + } +} + +void extractDevProp(const char* devpath, JlinkDevice &dev) +{ + char devid[MAX_DEVICE_ID_LEN]; + extractDevID(devid, sizeof(devid), devpath); + DEVINST inst; + if (CM_Locate_DevNodeA(&inst, devid, 0) == CR_SUCCESS) { + char hubid[MAX_DEVICE_ID_LEN]; + char hubname[MAX_DEVICE_ID_LEN]; + int devport = -1; + if (lookupTopSeggerDevID(&inst, 0x1366, devid, hubid, hubname, &devport)) { + if (const char* vidstr = strchr(devid, '\\')) { + vidstr++; + uint32_t lvid, lpid; + if (sscanf_s(vidstr, "VID_%04x&PID_%04x", &lvid, &lpid) == 2) { + dev.pid = lpid; + dev.vid = lvid; + } + if (const char* snstr = strchr(vidstr, '\\')) { + snstr++; + dev.winSerial = atoi(snstr); + } + dev.locationInfo.hubDevID.assign(hubid); + dev.locationInfo.hubName.assign(hubname); + dev.locationInfo.devPort = devport; + } + } + } +} + bool getWinUSBLinks(JLinkDevVec& vec, const GUID* guid) { - HDEVINFO devInfoSet = SetupDiGetClassDevsW(guid, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE); + HDEVINFO devInfoSet = SetupDiGetClassDevsA(guid, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE); SP_DEVICE_INTERFACE_DATA interfaceData = {0}; interfaceData.cbSize = sizeof(interfaceData); @@ -90,15 +242,15 @@ bool getWinUSBLinks(JLinkDevVec& vec, const GUID* guid) } DWORD requiredSize = 0; - SetupDiGetDeviceInterfaceDetailW(devInfoSet, &interfaceData, NULL, 0, &requiredSize, NULL); + SetupDiGetDeviceInterfaceDetailA(devInfoSet, &interfaceData, NULL, 0, &requiredSize, NULL); - PSP_DEVICE_INTERFACE_DETAIL_DATA interfaceDetailData = (PSP_DEVICE_INTERFACE_DETAIL_DATA)malloc(requiredSize); - interfaceDetailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA); - if (!SetupDiGetDeviceInterfaceDetailW(devInfoSet, &interfaceData, interfaceDetailData, requiredSize, &requiredSize, NULL)) { + PSP_DEVICE_INTERFACE_DETAIL_DATA_A interfaceDetailData = (PSP_DEVICE_INTERFACE_DETAIL_DATA_A)malloc(requiredSize); + interfaceDetailData->cbSize = sizeof(*interfaceDetailData); + if (!SetupDiGetDeviceInterfaceDetailA(devInfoSet, &interfaceData, interfaceDetailData, requiredSize, &requiredSize, NULL)) { free(interfaceDetailData); continue; } - HANDLE deviceFile = CreateFileW(interfaceDetailData->DevicePath, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL); + HANDLE deviceFile = CreateFileA(interfaceDetailData->DevicePath, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL); if (deviceFile == INVALID_HANDLE_VALUE) { free(interfaceDetailData); continue; @@ -109,8 +261,8 @@ bool getWinUSBLinks(JLinkDevVec& vec, const GUID* guid) printf("Failed to invoke WinUsb_Initialize, last error %lu\n", GetLastError()); CloseHandle(deviceFile); free(interfaceDetailData); - //continue; - return false; + continue; + //return false; } uint8_t desc[0x200]; ULONG desclen = 0x200; @@ -118,7 +270,8 @@ bool getWinUSBLinks(JLinkDevVec& vec, const GUID* guid) printf("Failed to invoke WinUsb_GetDescriptor, last error %lu\n", GetLastError()); CloseHandle(deviceFile); free(interfaceDetailData); - return false; + continue; + //return false; } uint8_t inep = 0, outep = 0; PUSB_CONFIGURATION_DESCRIPTOR confdesc = (PUSB_CONFIGURATION_DESCRIPTOR)desc; @@ -161,36 +314,25 @@ bool getWinUSBLinks(JLinkDevVec& vec, const GUID* guid) dev.interfaceHandle = winusbHandle; dev.readPipe = inep; // 0x81 dev.writePipe = outep; // 0x01 - //"PCI\\VEN_%x&DEV_%x&SUBSYS_%x&REV_%x" - //"\\?\usb#vid_1366&pid_1020#000260113630#{c78607e8-de76-458b-b7c1-5c14a6f3a1d2}" - //"\\?\usb#vid_1366&pid_1024&mi_02#9&1a05735c&0&0002#{c78607e8-de76-458b-b7c1-5c14a6f3a1d2}" - if (const wchar_t* vidstr = wcschr((const wchar_t*)interfaceDetailData->DevicePath, L'#')) { - vidstr++; - uint32_t lvid, lpid; - if (swscanf_s(vidstr, L"vid_%04x&pid_%04x", &lvid, &lpid) == 2) { - dev.pid = lpid; - dev.vid = lvid; - } - if (const wchar_t* snstr = wcschr(vidstr, L'#')) { - snstr++; - dev.serial = wcstoul(snstr, NULL, 0); - } - } + // "\\?\usb#vid_1366&pid_1020#000260113630#{c78607e8-de76-458b-b7c1-5c14a6f3a1d2}" winusb2 + // "\\?\usb#vid_1366&pid_1024&mi_02#9&1a05735c&0&0002#{c78607e8-de76-458b-b7c1-5c14a6f3a1d2}" composite + // "USB\VID_1366&PID_1024&MI_02\9&1A05735C&0&0002" + extractDevProp(interfaceDetailData->DevicePath, dev); + vec.push_back(dev); free(interfaceDetailData); } return true; } -bool getSeggerJlinks(JLinkDevVec& vec) +bool getSeggerJlinks(JLinkDevVec& vec, const GUID* guid) { - GUID classGuid = { 0x54654E76, 0xdcf7, 0x4a7f, {0x87, 0x8A, 0x4E, 0x8F, 0xCA, 0x0A, 0xCC, 0x9A} }; - HDEVINFO devInfoSet = SetupDiGetClassDevsW(&classGuid, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE); + HDEVINFO devInfoSet = SetupDiGetClassDevsA(guid, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE); SP_DEVICE_INTERFACE_DATA interfaceData = {0}; interfaceData.cbSize = sizeof(interfaceData); for (DWORD i = 0; ; i++) { - if (!SetupDiEnumDeviceInterfaces(devInfoSet, NULL, &classGuid, i, &interfaceData)) { + if (!SetupDiEnumDeviceInterfaces(devInfoSet, NULL, guid, i, &interfaceData)) { if (GetLastError() == ERROR_NO_MORE_ITEMS) { break; } else { @@ -199,35 +341,31 @@ bool getSeggerJlinks(JLinkDevVec& vec) } DWORD requiredSize = 0; - SetupDiGetDeviceInterfaceDetailW(devInfoSet, &interfaceData, NULL, 0, &requiredSize, NULL); - PSP_DEVICE_INTERFACE_DETAIL_DATA interfaceDetailData = (PSP_DEVICE_INTERFACE_DETAIL_DATA)malloc(requiredSize); - interfaceDetailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA); - if (!SetupDiGetDeviceInterfaceDetailW(devInfoSet, &interfaceData, interfaceDetailData, requiredSize, &requiredSize, NULL)) { + SetupDiGetDeviceInterfaceDetailA(devInfoSet, &interfaceData, NULL, 0, &requiredSize, NULL); + PSP_DEVICE_INTERFACE_DETAIL_DATA_A interfaceDetailData = (PSP_DEVICE_INTERFACE_DETAIL_DATA_A)malloc(requiredSize); + interfaceDetailData->cbSize = sizeof(*interfaceDetailData); + if (!SetupDiGetDeviceInterfaceDetailA(devInfoSet, &interfaceData, interfaceDetailData, requiredSize, &requiredSize, NULL)) { free(interfaceDetailData); continue; } - HANDLE deviceFile = CreateFileW(interfaceDetailData->DevicePath, GENERIC_WRITE | GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + HANDLE deviceFile = CreateFileA(interfaceDetailData->DevicePath, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (deviceFile == INVALID_HANDLE_VALUE) { free(interfaceDetailData); continue; } - //char InBuffer[64]; - //DWORD BytesReturned = 0; - //DeviceIoControl(deviceFile, 0x220468u, InBuffer, 0x40u, InBuffer, 0x40u, &BytesReturned, 0); - //quickdump(0, (unsigned char*)InBuffer, sizeof(InBuffer)); - wchar_t pipeFileName[1024] = {0}; - wcscpy_s(pipeFileName, interfaceDetailData->DevicePath); - wcscat_s(pipeFileName, L"\\pipe00"); - HANDLE readPipeFile = CreateFileW(pipeFileName, GENERIC_WRITE | GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + char pipeFileName[1024] = {0}; + strcpy_s(pipeFileName, interfaceDetailData->DevicePath); + strcat_s(pipeFileName, "\\pipe00"); + HANDLE readPipeFile = CreateFileA(pipeFileName, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (readPipeFile == INVALID_HANDLE_VALUE) { CloseHandle(deviceFile); free(interfaceDetailData); continue; } - wcscpy_s(pipeFileName, interfaceDetailData->DevicePath); - wcscat_s(pipeFileName, L"\\pipe01"); - HANDLE writePipeFile = CreateFileW(pipeFileName, GENERIC_WRITE | GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + strcpy_s(pipeFileName, interfaceDetailData->DevicePath); + strcat_s(pipeFileName, "\\pipe01"); + HANDLE writePipeFile = CreateFileA(pipeFileName, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (writePipeFile == INVALID_HANDLE_VALUE) { CloseHandle(deviceFile); CloseHandle(readPipeFile); @@ -240,21 +378,10 @@ bool getSeggerJlinks(JLinkDevVec& vec) dev.deviceFile = deviceFile; dev.readPipeFile = readPipeFile; dev.writePipeFile = writePipeFile; - // TODO: get usb port path - //"PCI\\VEN_%x&DEV_%x&SUBSYS_%x&REV_%x" - //0x00e5d95c "\\?\usb#vid_1366&pid_0101#000260113630#{54654e76-dcf7-4a7f-878a-4e8fca0acc9a}" - if (const wchar_t* vidstr = wcschr((const wchar_t*)interfaceDetailData->DevicePath, L'#')) { - vidstr++; - uint32_t lvid, lpid; - if (swscanf_s(vidstr, L"vid_%04x&pid_%04x", &lvid, &lpid) == 2) { - dev.pid = lpid; - dev.vid = lvid; - } - if (const wchar_t* snstr = wcschr(vidstr, L'#')) { - snstr++; - dev.serial = wcstoul(snstr, NULL, 0); - } - } + // DONE: get usb port path + // "\\?\usb#vid_1366&pid_0101#000260113630#{54654e76-dcf7-4a7f-878a-4e8fca0acc9a}" segger2 + extractDevProp(interfaceDetailData->DevicePath, dev); + vec.push_back(dev); free(interfaceDetailData); } @@ -263,34 +390,457 @@ bool getSeggerJlinks(JLinkDevVec& vec) bool getJLinks(JLinkDevVec& vec) { - GUID classGuid1 = { 0xC78607E8, 0xDE76, 0x458B, {0xB7, 0xC1, 0x5C, 0x14, 0xA6, 0xF3, 0xA1, 0xD2} }; - getSeggerJlinks(vec); - //size_t oldcnt = vec.size(); - getWinUSBLinks(vec, &classGuid1); - //if (vec.size() == oldcnt) { - // GUID classGuid2 = {0xA5DCBF10, 0x6530, 0x11D2, 0x90, 0x1F, 0x00, 0xC0, 0x4F, 0xB9, 0x51, 0xED}; - // getWinUSBLinks(vec, &classGuid2); - //} + getSeggerJlinks(vec, &seggerguid2); + getWinUSBLinks(vec, &winusbguid2); return vec.size() > 0; } -size_t g_recvpos = 0; - void freeJLinks(JLinkDevVec& vec) { - for (JLinkDevVec::const_iterator it = vec.begin(); it != vec.end(); it++) { - if (it->isWinusb) { - WinUsb_Free(it->interfaceHandle); - } else { - CloseHandle(it->readPipeFile); - CloseHandle(it->writePipeFile); - } - CloseHandle(it->deviceFile); + for (JLinkDevVec::iterator it = vec.begin(); it != vec.end(); it++) { + it->close(); } g_recvpos = 0; vec.clear(); } +LRESULT CALLBACK LinkKeeper::ListernerWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + PDEV_BROADCAST_DEVICEINTERFACE_A devif = (PDEV_BROADCAST_DEVICEINTERFACE_A)lParam; + switch (message) { + case WM_DEVICECHANGE: + //printf("Received device change!\n"); + switch (wParam) { + case DBT_DEVICEARRIVAL: + printf("%s connected\n", devif->dbcc_name); + LinkKeeper::processDeviceNotification(devif->dbcc_name, &devif->dbcc_classguid, true); + break; + case DBT_DEVICEREMOVECOMPLETE: + printf("%s removed\n", devif->dbcc_name); + LinkKeeper::processDeviceNotification(devif->dbcc_name, &devif->dbcc_classguid, true); + break; + } + break; + default: + return DefWindowProcA(hWnd, message, wParam, lParam); + } + return 0; +} + +DWORD WINAPI LinkKeeper::ListenerExecute(LPVOID arg) { + LinkKeeper* self = (LinkKeeper*)arg; + WNDCLASSA windowClass = {}; + windowClass.lpfnWndProc = ListernerWndProc; + windowClass.lpszClassName = "ListenerWindow"; + if (!RegisterClassA(&windowClass)) { + return 1; + } + HWND messageWindow = CreateWindowA(windowClass.lpszClassName, 0, 0, 0, 0, 0, 0, HWND_MESSAGE, 0, 0, 0); + DEV_BROADCAST_DEVICEINTERFACE_A NotificationFilter; + + ZeroMemory(&NotificationFilter, sizeof(NotificationFilter)); + NotificationFilter.dbcc_size = sizeof(NotificationFilter); + NotificationFilter.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE; + NotificationFilter.dbcc_classguid = seggerguid2; + HDEVNOTIFY notify1 = RegisterDeviceNotificationA(messageWindow, &NotificationFilter, DEVICE_NOTIFY_WINDOW_HANDLE); + NotificationFilter.dbcc_classguid = winusbguid2; + HDEVNOTIFY notify2 = RegisterDeviceNotificationA(messageWindow, &NotificationFilter, DEVICE_NOTIFY_WINDOW_HANDLE); + MSG msg; + while (GetMessage(&msg, 0, 0, 0) > 0 && self->fKeeping) { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + UnregisterDeviceNotification(notify1); + UnregisterDeviceNotification(notify2); + DestroyWindow(messageWindow); + return msg.wParam; +} + +LinkKeeper* theKeeper = 0; +GUID winusbguid2 = { 0xC78607E8, 0xDE76, 0x458B, {0xB7, 0xC1, 0x5C, 0x14, 0xA6, 0xF3, 0xA1, 0xD2} }; +GUID seggerguid2 = { 0x54654E76, 0xdcf7, 0x4a7f, {0x87, 0x8A, 0x4E, 0x8F, 0xCA, 0x0A, 0xCC, 0x9A} }; + +void startupKeeper() +{ + theKeeper = new LinkKeeper(); + theKeeper->createKeeperThread(); + theKeeper->scanJLinks(); +} + +void shutdownKeeper() +{ + if (LinkKeeper* keeper = (LinkKeeper*)InterlockedExchange((LONG*)&theKeeper, 0)) { + keeper->closeKeeperThread(); + keeper->freeJLinks(); + delete keeper; + } +} + +LinkKeeper::LinkKeeper():fKeeping(true), fWaitReconnect(false) +{ + +} + +void LinkKeeper::createKeeperThread() +{ + fKeeping = true; + fKeeperThread = ::CreateThread(NULL, 0, ListenerExecute, this, 0, NULL); +} + +void LinkKeeper::closeKeeperThread() +{ + fKeeping = false; + WaitForSingleObject(fKeeperThread, 1000); +} + +int LinkKeeper::scanJLinks() +{ + size_t oldsize = fDevices.size(); + enumerateDevices(&seggerguid2, false); + enumerateDevices(&winusbguid2, true); + return fDevices.size() - oldsize; +} + +void LinkKeeper::freeJLinks() +{ + for (JLinkDevMap::iterator it = fDevices.begin(); it != fDevices.end(); it++) { + it->second.close(); + } + //g_recvpos = 0; + fDevices.clear(); +} + +bool LinkKeeper::enumerateDevices(const GUID* guid, bool isWinUSB) +{ + HDEVINFO devInfoSet = SetupDiGetClassDevsA(guid, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE); + SP_DEVICE_INTERFACE_DATA interfaceData = {0}; + interfaceData.cbSize = sizeof(interfaceData); + + for (DWORD i = 0; ; i++) { + if (!SetupDiEnumDeviceInterfaces(devInfoSet, NULL, guid, i, &interfaceData)) { + if (GetLastError() == ERROR_NO_MORE_ITEMS) { + break; + } else { + continue; + } + } + + DWORD requiredSize = 0; + SetupDiGetDeviceInterfaceDetailA(devInfoSet, &interfaceData, NULL, 0, &requiredSize, NULL); + PSP_DEVICE_INTERFACE_DETAIL_DATA_A interfaceDetailData = (PSP_DEVICE_INTERFACE_DETAIL_DATA_A)malloc(requiredSize); + interfaceDetailData->cbSize = sizeof(*interfaceDetailData); + if (!SetupDiGetDeviceInterfaceDetailA(devInfoSet, &interfaceData, interfaceDetailData, requiredSize, &requiredSize, NULL)) { + free(interfaceDetailData); + continue; + } + + JlinkDevice dev; + dev.isWinusb = isWinUSB; + dev.devicePath = interfaceDetailData->DevicePath; + // "\\?\usb#vid_1366&pid_0101#000260113630#{54654e76-dcf7-4a7f-878a-4e8fca0acc9a}" segger2 + // "\\?\usb#vid_1366&pid_1020#000260113630#{c78607e8-de76-458b-b7c1-5c14a6f3a1d2}" winusb2 + // "\\?\usb#vid_1366&pid_1024&mi_02#9&1a05735c&0&0002#{c78607e8-de76-458b-b7c1-5c14a6f3a1d2}" composite + // "USB\VID_1366&PID_1024&MI_02\9&1A05735C&0&0002" + extractDevProp(interfaceDetailData->DevicePath, dev); + free(interfaceDetailData); + dev.deviceFile = INVALID_HANDLE_VALUE; + if (fDevices.find(dev.locationInfo) == fDevices.end()) { + fDevices.insert(std::make_pair(dev.locationInfo, dev)); + } + } + return true; +} + +JlinkDevice* LinkKeeper::getCurrDevice() +{ + if (fUsedDevice.hubDevID.empty()) { + errprintf("Some connection error occurred. No device selected.\n"); + return 0; + } + JLinkDevMap::iterator it = fDevices.find(fUsedDevice); + if (it != fDevices.end()) { + it->second.open(); + return &it->second; + } else { + errprintf("Selected device missing from USB port (%s)!\n", fUsedDevice.hubDevID.c_str()); + return 0; + } +} + +bool LinkKeeper::processDeviceNotification(const char* devpath, const GUID* guid, bool add) +{ + bool issegger2 = memcmp(guid, &seggerguid2, sizeof(seggerguid2)) == 0; + bool iswinusb2 = memcmp(guid, &winusbguid2, sizeof(winusbguid2)) == 0; + if (issegger2 || iswinusb2) { + JlinkDevice dev; + extractDevProp(devpath, dev); + if (add) { + dev.isWinusb = iswinusb2; + if (theKeeper->fDevices.find(dev.locationInfo) == theKeeper->fDevices.end()) { + theKeeper->fDevices.insert(std::make_pair(dev.locationInfo, dev)); + if (theKeeper->fUsedDevice == dev.locationInfo && theKeeper->fWaitReconnect) { + theKeeper->fWaitReconnect = false; + } + } + } else { + if (theKeeper->fUsedDevice == dev.locationInfo && theKeeper->fWaitReconnect == false) { + theKeeper->fUsedDevice.clear(); + } + JLinkDevMap::iterator it = theKeeper->fDevices.find(dev.locationInfo); + if (it != theKeeper->fDevices.end()) { + it->second.close(); + theKeeper->fDevices.erase(dev.locationInfo); + } + } + } + return true; +} + +int LinkKeeper::getJLinksSnap(JLinkInfoVec& vec) +{ + int cnt = 0; + for (JLinkDevMap::const_iterator it = theKeeper->fDevices.begin(); it != theKeeper->fDevices.end(); it++) { + vec.push_back(it->second); + cnt++; + } + return cnt; +} + +bool LinkKeeper::selectDevice(const hublocation& location) +{ + if (theKeeper->fDevices.find(location) != theKeeper->fDevices.end()) { + theKeeper->fUsedDevice = location; + return true; + } + return false; +} + +void LinkKeeper::prepareReconnect() +{ + theKeeper->fWaitReconnect = true; +} + +bool LinkKeeper::waitReconnect(uint32_t timeout, uint32_t step) +{ + DWORD newtick = GetTickCount() + timeout; + while (GetTickCount() < newtick) { + if (theKeeper->fWaitReconnect == false) { + return true; + } + SleepEx(step, TRUE); + } + return !theKeeper->fWaitReconnect; +} + +bool LinkKeeper::sendCommand(void const* commandBuffer, uint32_t commandLength, void* resultBuffer, uint32_t resultHeaderLength) +{ + JlinkDevice* dev = theKeeper->getCurrDevice(); + if (dev) { + return jlinkSendCommand(dev, commandBuffer, commandLength, resultBuffer, resultHeaderLength); + } + return false; +} + +bool LinkKeeper::continueReadResult(void* resultBuffer, uint32_t resultLength) +{ + JlinkDevice* dev = theKeeper->getCurrDevice(); + if (dev) { + return jlinkContinueReadResult(dev, resultBuffer, resultLength); + } + return false; +} + +bool LinkKeeper::commandReadFirmwareVersion(void* dataBuffer) +{ + JlinkDevice* dev = theKeeper->getCurrDevice(); + if (dev) { + return jlinkCommandReadFirmwareVersion(dev, dataBuffer); + } + return false; +} + +bool LinkKeeper::loopReadFirmwareVersion(void* dataBuffer) +{ + JlinkDevice* dev = theKeeper->getCurrDevice(); + if (dev) { + return jlinkLoopReadFirmwareVersion(dev, dataBuffer); + } + return false; +} + +bool LinkKeeper::commandReadEmulatorMemory(uint32_t address, uint32_t length, void* dataBuffer) +{ + JlinkDevice* dev = theKeeper->getCurrDevice(); + if (dev) { + return jlinkCommandReadEmulatorMemory(dev, address, length, dataBuffer); + } + return false; +} + +bool LinkKeeper::commandSetEmulateOption(uint32_t option, uint32_t val, uint32_t* status) +{ + JlinkDevice* dev = theKeeper->getCurrDevice(); + if (dev) { + return jlinkCommandSetEmulateOption(dev, option, val, status); + } + return false; +} + +bool LinkKeeper::commandSendUpdateFirmware(uint8_t* reply) +{ + JlinkDevice* dev = theKeeper->getCurrDevice(); + if (dev) { + return jlinkCommandSendUpdateFirmware(dev, reply); + } + return false; +} + +bool LinkKeeper::commandSendSelectInterface(uint8_t newif, uint32_t* oldif) +{ + JlinkDevice* dev = theKeeper->getCurrDevice(); + if (dev) { + return jlinkCommandSendSelectInterface(dev, newif, oldif); + } + return false; +} + +bool LinkKeeper::dumpFullFirmware(uint32_t addr, uint32_t size, void* buf) +{ + JlinkDevice* dev = theKeeper->getCurrDevice(); + if (dev) { + return jlinkDumpFullFirmware(dev, addr, size, buf); + } + return false; +} + +bool LinkKeeper::commandReadUID(uint32_t* size, void* dataBuffer) +{ + JlinkDevice* dev = theKeeper->getCurrDevice(); + if (dev) { + return jlinkCommandReadUID(dev, size, dataBuffer); + } + return false; +} + +bool LinkKeeper::commandReadOTS(void* dataBuffer) +{ + JlinkDevice* dev = theKeeper->getCurrDevice(); + if (dev) { + return jlinkCommandReadOTS(dev, dataBuffer); + } + return false; +} + +void extractDevID(char *devid, size_t len, const char *devpath){ + while (char c = *devpath++) { + switch(c) { + case '\\': + case '?': + continue; + case '{': + if (*(devid - 1) == '\\') { + devid--; + } + len = 1; + break; + case '#': + if (--len) { + *devid++ = '\\'; + } + break; + default: + if (--len) { + *devid++ = toupper(c); + } + } + if (len == 1) { + break; + } + } + *devid = 0; +} + +/* f18a0e88-c30c-11d0-8815-00a0c906bed8 */ +GUID GUID_DEVINTERFACE_USB_HUB = { 0xf18a0e88, 0xc30c, 0x11d0, {0x88, 0x15, 0x00, 0xa0, 0xc9, 0x06, 0xbe, 0xd8} }; + +bool lookupTopSeggerDevID(DEVINST* devinst, uint16_t vid, char* devid, char* hubid, char* hubname, int* port) { + DEVINST parent; + char parentid[MAX_DEVICE_ID_LEN]; + char vidstr[9]; + sprintf_s(vidstr, sizeof(vidstr), "VID_%04X", vid); + while (CM_Get_Parent(&parent, *devinst, 0) == CR_SUCCESS) { + if (CM_Get_Device_IDA(parent, parentid, MAX_DEVICE_ID_LEN, 0) != CR_SUCCESS) { + return false; + } + if (strstr(parentid, vidstr) == 0) { + // 此时devinst是复合, parent是hub + if (hubid) { + strcpy_s(hubid, MAX_DEVICE_ID_LEN, parentid); + } + // rewind devid + ULONG datatype; + bool ok = CM_Get_Device_IDA(*devinst, devid, MAX_DEVICE_ID_LEN, 0) == CR_SUCCESS; + char buf[512]; + ULONG buflen = sizeof(buf); + if (CM_Get_DevNode_Registry_PropertyA(parent, CM_DRP_DEVICEDESC, &datatype, buf, &buflen, 0) == CR_SUCCESS) { + strcpy_s(hubname, MAX_DEVICE_ID_LEN, buf); + } + // Detect connection port + buflen = sizeof(buf); + if (CM_Get_DevNode_Registry_PropertyA(*devinst, CM_DRP_LOCATION_INFORMATION, &datatype, buf, &buflen, 0) == CR_SUCCESS) { + // under WinXP, location info is friendly name "J-Link" + if (strncmp(buf, "Port_#", sizeof "Port_#" - 1) == 0) { + *port = atoi(&buf[6]); + return ok; + } + } + WCHAR keyname[512]; + ULONG keynamelen = 512; + if (CM_Get_DevNode_Registry_PropertyW(*devinst, CM_DRP_DRIVER, &datatype, keyname, &keynamelen, 0) != CR_SUCCESS) { + *port = 0; + return ok; + } + // tricky WinXP support (from USBView) + // devid to devpath + if (CM_Get_Device_Interface_ListA((LPGUID)&GUID_DEVINTERFACE_USB_HUB, parentid, buf, 512, 0) == CR_SUCCESS) { + // TODO: cache lookup table + HANDLE hubhandle = CreateFileA(buf, GENERIC_WRITE, FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0); + USB_NODE_INFORMATION hubinfo; + DWORD readed; + if (DeviceIoControl(hubhandle, IOCTL_USB_GET_NODE_INFORMATION, &hubinfo, sizeof(hubinfo), &hubinfo, sizeof(hubinfo), &readed, NULL)) { + for (int i = 0; i < hubinfo.u.HubInformation.HubDescriptor.bNumberOfPorts; i++) { + USB_NODE_CONNECTION_INFORMATION conninfo; + conninfo.ConnectionIndex = i + 1; + if (DeviceIoControl(hubhandle, IOCTL_USB_GET_NODE_CONNECTION_INFORMATION, &conninfo, sizeof(conninfo), &conninfo, sizeof(conninfo), &readed, NULL)) { + if (conninfo.ConnectionStatus == DeviceConnected) { + USB_NODE_CONNECTION_DRIVERKEY_NAME nodename; + nodename.ConnectionIndex = i + 1; + if (DeviceIoControl(hubhandle, IOCTL_USB_GET_NODE_CONNECTION_DRIVERKEY_NAME, &nodename, sizeof(nodename), &nodename, sizeof(nodename), &readed, NULL)) { + ULONG infosize = nodename.ActualLength; + USB_NODE_CONNECTION_DRIVERKEY_NAME* pnodename = (USB_NODE_CONNECTION_DRIVERKEY_NAME*)malloc(infosize); + pnodename->ConnectionIndex = i + 1; + if (DeviceIoControl(hubhandle, IOCTL_USB_GET_NODE_CONNECTION_DRIVERKEY_NAME, pnodename, infosize, pnodename, infosize, &readed, NULL)) { + if (wcsicmp(keyname, pnodename->DriverKeyName) == 0) { + *port = i + 1; + free(pnodename); + break; + } + } + free(pnodename); + } + } + } + } + } + CloseHandle(hubhandle); + } + return ok; + } + *devinst = parent; // 逐步将devinst替换为顶层复合设备 + } + return true; +} + unsigned char g_recvbuf[0x1000]; bool jlinkSendCommand(JlinkDevice* dev, void const* commandBuffer, uint32_t commandLength, void* resultBuffer, uint32_t resultHeaderLength) diff --git a/EDUReViver/usbconn.h b/EDUReViver/usbconn.h index 5d7c714..e356539 100644 --- a/EDUReViver/usbconn.h +++ b/EDUReViver/usbconn.h @@ -4,59 +4,45 @@ #define WIN32_LEAN_AND_MEAN #include #include +#include +#include #include +#include "usbtypes.h" -typedef PVOID WINUSB_INTERFACE_HANDLE, *PWINUSB_INTERFACE_HANDLE; -#define USB_CONFIGURATION_DESCRIPTOR_TYPE 0x02 -#define RAW_IO 0x07 -#define PIPE_TRANSFER_TIMEOUT 0x03 -#define MAXIMUM_TRANSFER_SIZE 0x08 - -#pragma pack(push, 1) -typedef struct _USB_CONFIGURATION_DESCRIPTOR { - UCHAR bLength; - UCHAR bDescriptorType; - USHORT wTotalLength; - UCHAR bNumInterfaces; - UCHAR bConfigurationValue; - UCHAR iConfiguration; - UCHAR bmAttributes; - UCHAR MaxPower; -} USB_CONFIGURATION_DESCRIPTOR, *PUSB_CONFIGURATION_DESCRIPTOR; - -typedef struct _USB_INTERFACE_DESCRIPTOR { - UCHAR bLength; - UCHAR bDescriptorType; - UCHAR bInterfaceNumber; - UCHAR bAlternateSetting; - UCHAR bNumEndpoints; - UCHAR bInterfaceClass; - UCHAR bInterfaceSubClass; - UCHAR bInterfaceProtocol; - UCHAR iInterface; -} USB_INTERFACE_DESCRIPTOR, *PUSB_INTERFACE_DESCRIPTOR; - -typedef struct _USB_ENDPOINT_DESCRIPTOR { - UCHAR bLength; - UCHAR bDescriptorType; - UCHAR bEndpointAddress; - UCHAR bmAttributes; - USHORT wMaxPacketSize; - UCHAR bInterval; -} USB_ENDPOINT_DESCRIPTOR, *PUSB_ENDPOINT_DESCRIPTOR; +struct hublocation { + std::string hubDevID; + std::string hubName; + int devPort; + bool operator==(const hublocation& rhs) const + { + return (hubDevID == rhs.hubDevID && devPort == rhs.devPort); + } + void clear(); +}; -typedef struct _WINUSB_SETUP_PACKET { - UCHAR RequestType; - UCHAR Request; - USHORT Value; - USHORT Index; - USHORT Length; -} WINUSB_SETUP_PACKET, *PWINUSB_SETUP_PACKET; -#pragma pack(pop) +struct hublocless{ + bool operator()(const hublocation& lhs, const hublocation& rhs) const { + int hubcomp = lhs.hubDevID.compare(rhs.hubDevID); + if (hubcomp == 0) { + return lhs.devPort < rhs.devPort; + } else { + return hubcomp < 0; + } + } +}; -struct JlinkDevice { +// DeviceManager/Registry +struct JlinkDeviceInfo { bool isWinusb; + uint16_t pid; + uint16_t vid; + uint32_t winSerial; + std::string devicePath; + hublocation locationInfo; +}; + +struct JlinkDevice : JlinkDeviceInfo { HANDLE deviceFile; union { struct { @@ -69,24 +55,65 @@ struct JlinkDevice { UCHAR writePipe; // 81 }; }; - uint16_t pid; - uint16_t vid; - uint32_t serial; + void open(); + void close(); }; +typedef std::vector JLinkInfoVec; typedef std::vector JLinkDevVec; +class LinkKeeper { +private: + typedef std::map JLinkDevMap; // location, device + JLinkDevMap fDevices; + hublocation fUsedDevice; // location + HANDLE fKeeperThread; + bool fKeeping; + bool fWaitReconnect; +public: + LinkKeeper(); + void createKeeperThread(); + void closeKeeperThread(); + int scanJLinks(); + void freeJLinks(); +private: + bool enumerateDevices(const GUID* guid, bool isWinUSB); + JlinkDevice* getCurrDevice(); +private: + static DWORD WINAPI ListenerExecute(LPVOID arg); + static LRESULT CALLBACK ListernerWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam); +public: + static bool processDeviceNotification(const char* devpath, const GUID* guid, bool add); + static int getJLinksSnap(JLinkInfoVec& vec); + static bool selectDevice(const hublocation& location); + static void prepareReconnect(); + static bool waitReconnect(uint32_t timeout, uint32_t step); + static bool sendCommand(void const* commandBuffer, uint32_t commandLength, void* resultBuffer, uint32_t resultHeaderLength); + static bool continueReadResult(void* resultBuffer, uint32_t resultLength); + static bool commandReadFirmwareVersion(void* dataBuffer); + static bool loopReadFirmwareVersion(void* dataBuffer); + static bool commandReadEmulatorMemory(uint32_t address, uint32_t length, void* dataBuffer); + static bool commandSetEmulateOption(uint32_t option, uint32_t val, uint32_t* status); + static bool commandSendUpdateFirmware(uint8_t* reply); + static bool commandSendSelectInterface(uint8_t newif, uint32_t* oldif); + static bool dumpFullFirmware(uint32_t addr, uint32_t size, void* buf); + static bool commandReadUID(uint32_t* size, void* dataBuffer); + static bool commandReadOTS(void* dataBuffer); +}; + +extern LinkKeeper* theKeeper; +extern GUID winusbguid2; +extern GUID seggerguid2; + + +void startupKeeper(); +void shutdownKeeper(); + int LoadWinusb(); int UnloadWinusb(); -bool hotlinkSendCommand(WINUSB_INTERFACE_HANDLE winusbHandle, void const* commandBuffer, uint32_t commandLength, void* resultBuffer, uint32_t resultHeaderLength); -bool hotlinkContinueReadResult(WINUSB_INTERFACE_HANDLE winusbHandle, void* resultBuffer, uint32_t resultLength); -bool hotlinkReadLenResult(WINUSB_INTERFACE_HANDLE winusbHandle, void* recbuf, size_t* reclen); -bool hotlinkSendRec(WINUSB_INTERFACE_HANDLE winusbHandle, void const* recbuf, size_t reclen, int32_t* retcode); -bool hotlinkRecvRecPasv(WINUSB_INTERFACE_HANDLE winusbHandle, int32_t* retcode, void* recbuf, size_t* reclen); - -bool getWinUSBLinks(JLinkDevVec& vec); -bool getSeggerJlinks(JLinkDevVec& vec, GUID* guid); +bool getWinUSBLinks(JLinkDevVec& vec, const GUID* guid); +bool getSeggerJlinks(JLinkDevVec& vec, const GUID* guid); bool getJLinks(JLinkDevVec& vec); void freeJLinks(JLinkDevVec& vec); #ifdef WRITERTHREAD diff --git a/EDUReViver/usbtypes.h b/EDUReViver/usbtypes.h new file mode 100644 index 0000000..2926923 --- /dev/null +++ b/EDUReViver/usbtypes.h @@ -0,0 +1,261 @@ +#ifndef _USB_TYPES_H +#define _USB_TYPES_H + +#define WIN32_LEAN_AND_MEAN +#include +#include +//#include + + +typedef PVOID WINUSB_INTERFACE_HANDLE, *PWINUSB_INTERFACE_HANDLE; +#define USB_CONFIGURATION_DESCRIPTOR_TYPE 0x02 +#define RAW_IO 0x07 +#define PIPE_TRANSFER_TIMEOUT 0x03 +#define MAXIMUM_TRANSFER_SIZE 0x08 + +#pragma pack(push, 1) +typedef struct _USB_CONFIGURATION_DESCRIPTOR { + UCHAR bLength; + UCHAR bDescriptorType; + USHORT wTotalLength; + UCHAR bNumInterfaces; + UCHAR bConfigurationValue; + UCHAR iConfiguration; + UCHAR bmAttributes; + UCHAR MaxPower; +} USB_CONFIGURATION_DESCRIPTOR, *PUSB_CONFIGURATION_DESCRIPTOR; + +typedef struct _USB_INTERFACE_DESCRIPTOR { + UCHAR bLength; + UCHAR bDescriptorType; + UCHAR bInterfaceNumber; + UCHAR bAlternateSetting; + UCHAR bNumEndpoints; + UCHAR bInterfaceClass; + UCHAR bInterfaceSubClass; + UCHAR bInterfaceProtocol; + UCHAR iInterface; +} USB_INTERFACE_DESCRIPTOR, *PUSB_INTERFACE_DESCRIPTOR; + +typedef struct _USB_ENDPOINT_DESCRIPTOR { + UCHAR bLength; + UCHAR bDescriptorType; + UCHAR bEndpointAddress; + UCHAR bmAttributes; + USHORT wMaxPacketSize; + UCHAR bInterval; +} USB_ENDPOINT_DESCRIPTOR, *PUSB_ENDPOINT_DESCRIPTOR; + +typedef struct _WINUSB_SETUP_PACKET { + UCHAR RequestType; + UCHAR Request; + USHORT Value; + USHORT Index; + USHORT Length; +} WINUSB_SETUP_PACKET, *PWINUSB_SETUP_PACKET; + +////////////////////////////////////////////////////////////////////////// +// usb100.h +typedef struct _USB_HUB_DESCRIPTOR { + UCHAR bDescriptorLength; // Length of this descriptor + UCHAR bDescriptorType; // Hub configuration type + UCHAR bNumberOfPorts; // number of ports on this hub + USHORT wHubCharacteristics; // Hub Charateristics + UCHAR bPowerOnToPowerGood; // port power on till power good in 2ms + UCHAR bHubControlCurrent; // max current in mA + // + // room for 255 ports power control and removable bitmask + UCHAR bRemoveAndPowerMask[64]; +} USB_HUB_DESCRIPTOR, *PUSB_HUB_DESCRIPTOR; + +typedef struct _USB_DEVICE_DESCRIPTOR { + UCHAR bLength; + UCHAR bDescriptorType; + USHORT bcdUSB; + UCHAR bDeviceClass; + UCHAR bDeviceSubClass; + UCHAR bDeviceProtocol; + UCHAR bMaxPacketSize0; + USHORT idVendor; + USHORT idProduct; + USHORT bcdDevice; + UCHAR iManufacturer; + UCHAR iProduct; + UCHAR iSerialNumber; + UCHAR bNumConfigurations; +} USB_DEVICE_DESCRIPTOR, *PUSB_DEVICE_DESCRIPTOR; + +////////////////////////////////////////////////////////////////////////// + + +////////////////////////////////////////////////////////////////////////// +// usbiodef.h +#define FILE_DEVICE_USB FILE_DEVICE_UNKNOWN + +#define USB_GET_NODE_INFORMATION 258 +#define USB_GET_NODE_CONNECTION_INFORMATION 259 +#define USB_GET_NODE_CONNECTION_NAME 261 +#define USB_GET_NODE_CONNECTION_DRIVERKEY_NAME 264 +////////////////////////////////////////////////////////////////////////// + + +////////////////////////////////////////////////////////////////////////// +// usbioctl.h +typedef enum _USB_HUB_NODE { + UsbHub, + UsbMIParent +} USB_HUB_NODE; + +typedef struct _USB_HUB_INFORMATION { + /* + copy of data from hub descriptor + */ + USB_HUB_DESCRIPTOR HubDescriptor; + + BOOLEAN HubIsBusPowered; + +} USB_HUB_INFORMATION, *PUSB_HUB_INFORMATION; + +typedef struct _USB_MI_PARENT_INFORMATION { + ULONG NumberOfInterfaces; +} USB_MI_PARENT_INFORMATION, *PUSB_MI_PARENT_INFORMATION; + +typedef struct _USB_NODE_INFORMATION { + USB_HUB_NODE NodeType; /* hub, mi parent */ + union { + USB_HUB_INFORMATION HubInformation; + USB_MI_PARENT_INFORMATION MiParentInformation; + } u; +} USB_NODE_INFORMATION, *PUSB_NODE_INFORMATION; + +typedef struct _USB_PIPE_INFO { + USB_ENDPOINT_DESCRIPTOR EndpointDescriptor; + ULONG ScheduleOffset; +} USB_PIPE_INFO, *PUSB_PIPE_INFO; + + +#if (_WIN32_WINNT >= 0x0600) +/* + For Windows Longhorn +*/ + +typedef enum _USB_CONNECTION_STATUS { + NoDeviceConnected, + DeviceConnected, + + /* failure codes, these map to fail reasons */ + DeviceFailedEnumeration, + DeviceGeneralFailure, + DeviceCausedOvercurrent, + DeviceNotEnoughPower, + DeviceNotEnoughBandwidth, + DeviceHubNestedTooDeeply, + DeviceInLegacyHub, + DeviceEnumerating, + DeviceReset +} USB_CONNECTION_STATUS, *PUSB_CONNECTION_STATUS; + +#elif (_WIN32_WINNT >= 0x0501) + +/* + For Windows XP +*/ + +typedef enum _USB_CONNECTION_STATUS { + NoDeviceConnected, + DeviceConnected, + + /* failure codes, these map to fail reasons */ + DeviceFailedEnumeration, + DeviceGeneralFailure, + DeviceCausedOvercurrent, + DeviceNotEnoughPower, + DeviceNotEnoughBandwidth, + DeviceHubNestedTooDeeply, + DeviceInLegacyHub +} USB_CONNECTION_STATUS, *PUSB_CONNECTION_STATUS; + +#else + +/* + For Windows 2000 +*/ + +typedef enum _USB_CONNECTION_STATUS { + NoDeviceConnected, + DeviceConnected, + + /* failure codes, these map to fail reasons */ + DeviceFailedEnumeration, + DeviceGeneralFailure, + DeviceCausedOvercurrent, + DeviceNotEnoughPower, + DeviceNotEnoughBandwidth +} USB_CONNECTION_STATUS, *PUSB_CONNECTION_STATUS; + +#endif + +#define IOCTL_USB_GET_NODE_INFORMATION \ + CTL_CODE(FILE_DEVICE_USB, \ + USB_GET_NODE_INFORMATION, \ + METHOD_BUFFERED, \ + FILE_ANY_ACCESS) + +#define IOCTL_USB_GET_NODE_CONNECTION_INFORMATION \ + CTL_CODE(FILE_DEVICE_USB, \ + USB_GET_NODE_CONNECTION_INFORMATION, \ + METHOD_BUFFERED, \ + FILE_ANY_ACCESS) + +#define IOCTL_USB_GET_NODE_CONNECTION_NAME \ + CTL_CODE(FILE_DEVICE_USB, \ + USB_GET_NODE_CONNECTION_NAME, \ + METHOD_BUFFERED, \ + FILE_ANY_ACCESS) + +#define IOCTL_USB_GET_NODE_CONNECTION_DRIVERKEY_NAME \ + CTL_CODE(FILE_DEVICE_USB, \ + USB_GET_NODE_CONNECTION_DRIVERKEY_NAME, \ + METHOD_BUFFERED, \ + FILE_ANY_ACCESS) + +/** IOCTL_USB_GET_NODE_CONNECTION_INFORMATION **/ +#pragma warning( disable : 4200 ) +#pragma warning( disable : 4201 ) +typedef struct _USB_NODE_CONNECTION_INFORMATION { + ULONG ConnectionIndex; /* INPUT */ + /* usb device descriptor returned by this device + during enumeration */ + USB_DEVICE_DESCRIPTOR DeviceDescriptor; /* OUTPUT */ + UCHAR CurrentConfigurationValue;/* OUTPUT */ + BOOLEAN LowSpeed;/* OUTPUT */ + BOOLEAN DeviceIsHub;/* OUTPUT */ + USHORT DeviceAddress;/* OUTPUT */ + ULONG NumberOfOpenPipes;/* OUTPUT */ + USB_CONNECTION_STATUS ConnectionStatus;/* OUTPUT */ + USB_PIPE_INFO PipeList[0];/* OUTPUT */ +} USB_NODE_CONNECTION_INFORMATION, *PUSB_NODE_CONNECTION_INFORMATION; +#pragma warning( default : 4200 ) +#pragma warning( default : 4201 ) + +/** IOCTL_USB_GET_NODE_CONNECTION_DRIVERKEY_NAME **/ +typedef struct _USB_NODE_CONNECTION_DRIVERKEY_NAME { + ULONG ConnectionIndex; /* INPUT */ + ULONG ActualLength; /* OUTPUT */ + /* unicode name for the devnode */ + WCHAR DriverKeyName[1]; /* OUTPUT */ +} USB_NODE_CONNECTION_DRIVERKEY_NAME, *PUSB_NODE_CONNECTION_DRIVERKEY_NAME; + +/** IOCTL_USB_GET_NODE_CONNECTION_NAME **/ +typedef struct _USB_NODE_CONNECTION_NAME { + ULONG ConnectionIndex; /* INPUT */ + ULONG ActualLength; /* OUTPUT */ + /* unicode symbolic name for this node if it is a hub or parent driver + null if this node is a device. */ + WCHAR NodeName[1]; /* OUTPUT */ +} USB_NODE_CONNECTION_NAME, *PUSB_NODE_CONNECTION_NAME; +////////////////////////////////////////////////////////////////////////// +#pragma pack(pop) + + +#endif diff --git a/README.md b/README.md index 48c320e..fb37917 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ J-Link EDU Reviver 使用方法 -------- -从右侧[releases](https://github.com/banxian/EDUReviver/releases)页面下载最新[可执行文件包](https://github.com/banxian/EDUReviver/releases/download/v0.3.3-beta2/EDUReviver_b033_wdk.zip). +从右侧[releases](https://github.com/banxian/EDUReviver/releases)页面下载最新[可执行文件包](https://github.com/banxian/EDUReviver/releases/download/v0.3.5-beta/EDUReviver_bin_b035.zip). 解压所有文件到目录中, 进入目录在命令行下执行想要的命令 EDUReViver -run blinky