297 lines
9.7 KiB
C
297 lines
9.7 KiB
C
/*
|
|
* This file is part of the Black Magic Debug project.
|
|
*
|
|
* Copyright (C) 2020 Uwe Bonnes (bon@elektron.ikp.physik.tu-darmstadt.de)
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
/* Find all known serial connected debuggers */
|
|
|
|
#include "general.h"
|
|
#include <dirent.h>
|
|
#include <errno.h>
|
|
#include "bmp_hosted.h"
|
|
#include "version.h"
|
|
|
|
void bmp_ident(bmp_info_t *info)
|
|
{
|
|
PRINT_INFO("Black Magic Debug App (for BMP only) %s\n", FIRMWARE_VERSION);
|
|
if (!info)
|
|
return;
|
|
PRINT_INFO("Using:\n %s %s %s\n", info->manufacturer, info->version, info->serial);
|
|
}
|
|
|
|
void libusb_exit_function(bmp_info_t *info) {(void)info;};
|
|
|
|
|
|
#ifdef __APPLE__
|
|
int find_debuggers(BMP_CL_OPTIONS_t *cl_opts, bmp_info_t *info)
|
|
{
|
|
DEBUG_WARN("Please implement find_debuggers for MACOS!\n");
|
|
(void)cl_opts;
|
|
(void)info;
|
|
return -1;
|
|
}
|
|
#elif defined(__WIN32__) || defined(__CYGWIN__)
|
|
|
|
|
|
/* This source has been used as an example:
|
|
* https://stackoverflow.com/questions/3438366/setupdigetdeviceproperty-usage-example */
|
|
|
|
#include <windows.h>
|
|
#include <setupapi.h>
|
|
#include <cfgmgr32.h> // for MAX_DEVICE_ID_LEN, CM_Get_Parent and CM_Get_Device_ID
|
|
#include <tchar.h>
|
|
#include <stdio.h>
|
|
|
|
/* include DEVPKEY_Device_BusReportedDeviceDesc from WinDDK\7600.16385.1\inc\api\devpropdef.h */
|
|
#ifdef DEFINE_DEVPROPKEY
|
|
#undef DEFINE_DEVPROPKEY
|
|
#endif
|
|
#define DEFINE_DEVPROPKEY(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8, pid) const DEVPROPKEY DECLSPEC_SELECTANY name = { { l, w1, w2, { b1, b2, b3, b4, b5, b6, b7, b8 } }, pid }
|
|
|
|
/* include DEVPKEY_Device_BusReportedDeviceDesc from WinDDK\7600.16385.1\inc\api\devpkey.h */
|
|
DEFINE_DEVPROPKEY(DEVPKEY_Device_BusReportedDeviceDesc, 0x540b947e, 0x8b40, 0x45bc, 0xa8, 0xa2, 0x6a, 0x0b, 0x89, 0x4c, 0xbd, 0xa2, 4); // DEVPROP_TYPE_STRING
|
|
|
|
/* List all USB devices with some additional information.
|
|
* Unfortunately, this code is quite ugly. */
|
|
int find_debuggers(BMP_CL_OPTIONS_t *cl_opts, bmp_info_t *info)
|
|
{
|
|
unsigned i;
|
|
DWORD dwSize;
|
|
DEVPROPTYPE ulPropertyType;
|
|
CONFIGRET status;
|
|
HDEVINFO hDevInfo;
|
|
SP_DEVINFO_DATA DeviceInfoData;
|
|
TCHAR szDeviceInstanceID [MAX_DEVICE_ID_LEN];
|
|
WCHAR busReportedDeviceSesc[4096];
|
|
int probes_found = 0;
|
|
bool is_printing_probes_info = cl_opts->opt_list_only != 0;
|
|
|
|
info->bmp_type = BMP_TYPE_BMP;
|
|
|
|
hDevInfo = SetupDiGetClassDevs (0, "USB", NULL, DIGCF_ALLCLASSES | DIGCF_PRESENT);
|
|
if (hDevInfo == INVALID_HANDLE_VALUE)
|
|
return -1;
|
|
print_probes_info:
|
|
for (i = 0; ; i++) {
|
|
char serial_number[sizeof info->serial];
|
|
DeviceInfoData.cbSize = sizeof (DeviceInfoData);
|
|
if (!SetupDiEnumDeviceInfo(hDevInfo, i, &DeviceInfoData))
|
|
break;
|
|
|
|
status = CM_Get_Device_ID(DeviceInfoData.DevInst, szDeviceInstanceID , MAX_PATH, 0);
|
|
if (status != CR_SUCCESS)
|
|
continue;
|
|
|
|
if (!sscanf(szDeviceInstanceID, "USB\\VID_1D50&PID_6018\\%s", serial_number))
|
|
continue;
|
|
|
|
if (SetupDiGetDevicePropertyW (hDevInfo, &DeviceInfoData, &DEVPKEY_Device_BusReportedDeviceDesc,
|
|
&ulPropertyType, (BYTE*)busReportedDeviceSesc, sizeof busReportedDeviceSesc, &dwSize, 0))
|
|
{
|
|
probes_found ++;
|
|
if (is_printing_probes_info)
|
|
{
|
|
DEBUG_WARN("%2d: %s, %ls\n", probes_found,
|
|
serial_number, busReportedDeviceSesc);
|
|
}
|
|
else
|
|
{
|
|
bool probe_identified = true;
|
|
if ((cl_opts->opt_serial && strstr(serial_number, cl_opts->opt_serial)) ||
|
|
(cl_opts->opt_position && cl_opts->opt_position == probes_found) ||
|
|
/* Special case for the very first probe found. */
|
|
(probe_identified = false, probes_found == 1)) {
|
|
|
|
strncpy(info->serial, serial_number, sizeof info->serial);
|
|
strncpy(info->manufacturer, "BMP", sizeof info->manufacturer);
|
|
snprintf(info->product, sizeof info->product, "%ls", busReportedDeviceSesc);
|
|
/* Don't bother to parse the version string. It is a part of the
|
|
* product description string. It seems that at the moment it
|
|
* is only being used to print a version string in response
|
|
* to the 'monitor version' command, so it doesn't really matter
|
|
* if the version string is printed as a part of the product string,
|
|
* or as a separate string, the result is pretty much the same. */
|
|
info->version[0] = 0;
|
|
if (probe_identified)
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (is_printing_probes_info)
|
|
return 1;
|
|
if (probes_found == 1)
|
|
/* Exactly one probe found. Its information has already been filled
|
|
* in the detection loop, so use this probe. */
|
|
return 0;
|
|
if (probes_found < 1) {
|
|
DEBUG_WARN("No BMP probe found\n");
|
|
return -1;
|
|
}
|
|
/* Otherwise, if this line is reached, then more than one probe has been found,
|
|
* and no probe was identified as selected by the user.
|
|
* Restart the identification loop, this time printing the probe information,
|
|
* and then return. */
|
|
DEBUG_WARN("%d debuggers found!\nSelect with -P <pos>, or "
|
|
"-s <(partial)serial no.>\n",
|
|
probes_found);
|
|
probes_found = 0;
|
|
is_printing_probes_info = true;
|
|
goto print_probes_info;
|
|
}
|
|
|
|
#else
|
|
/* Old ID: Black_Sphere_Technologies_Black_Magic_Probe_BFE4D6EC-if00
|
|
* Recent: Black_Sphere_Technologies_Black_Magic_Probe_v1.7.1-212-g212292ab_7BAE7AB8-if00
|
|
* usb-Black_Sphere_Technologies_Black_Magic_Probe__SWLINK__v1.7.1-155-gf55ad67b-dirty_DECB8811-if00
|
|
*/
|
|
#define BMP_IDSTRING_BLACKSPHERE "usb-Black_Sphere_Technologies_Black_Magic_Probe"
|
|
#define BMP_IDSTRING_BLACKMAGIC "usb-Black_Magic_Debug_Black_Magic_Probe"
|
|
#define BMP_IDSTRING_1BITSQUARED "usb-1BitSquared_Black_Magic_Probe"
|
|
#define DEVICE_BY_ID "/dev/serial/by-id/"
|
|
|
|
/*
|
|
* Extract type, version and serial from /dev/serial/by_id
|
|
* Return 0 on success
|
|
*
|
|
* Old versions have different strings. Try to cope!
|
|
*/
|
|
static int scan_linux_id(char *name, char *type, char *version, char *serial)
|
|
{
|
|
name += strlen(BMP_IDSTRING_BLACKSPHERE) + 1;
|
|
while (*name == '_')
|
|
name++;
|
|
if (!*name) {
|
|
DEBUG_WARN("Unexpected end\n");
|
|
return -1;
|
|
}
|
|
char *p = name;
|
|
char *delims[4] = {0,0,0,0};
|
|
int underscores = 0;
|
|
while (*p) {
|
|
if (*p == '_') {
|
|
while (p[1] == '_')
|
|
p++; /* remove multiple underscores */
|
|
if (underscores > 2)
|
|
return -1;
|
|
delims[underscores] = p;
|
|
underscores ++;
|
|
}
|
|
p++;
|
|
}
|
|
if (underscores == 0) { /* Old BMP native */
|
|
int res;
|
|
res = sscanf(name, "%8s-if00", serial);
|
|
if (res != 1)
|
|
return -1;
|
|
strcpy(type, "Native");
|
|
strcpy(version, "Unknown");
|
|
} else if (underscores == 2) {
|
|
strncpy(type, name, delims[0] - name - 1);
|
|
strncpy(version, delims[0] + 1, delims[1] - delims[0] - 1);
|
|
int res = sscanf(delims[1] + 1, "%8s-if00", serial);
|
|
if (!res)
|
|
return -1;
|
|
} else {
|
|
int res = sscanf(delims[0] + 1, "%8s-if00", serial);
|
|
if (!res)
|
|
return -1;
|
|
if (name[0] == 'v') {
|
|
strcpy(type, "Unknown");
|
|
strncpy(version, name, delims[0] - name - 1);
|
|
} else {
|
|
strncpy(type, name, delims[0] - name);
|
|
strcpy(type, "Unknown");
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int find_debuggers(BMP_CL_OPTIONS_t *cl_opts, bmp_info_t *info)
|
|
{
|
|
if (cl_opts->opt_device)
|
|
return 1;
|
|
info->bmp_type = BMP_TYPE_BMP;
|
|
DIR *dir = opendir(DEVICE_BY_ID);
|
|
if (!dir) /* No serial device connected!*/
|
|
return 0;
|
|
int found_bmps = 0;
|
|
struct dirent *dp;
|
|
int i = 0;
|
|
while ((dp = readdir(dir)) != NULL) {
|
|
if ((strstr(dp->d_name, BMP_IDSTRING_BLACKMAGIC) ||
|
|
strstr(dp->d_name, BMP_IDSTRING_BLACKSPHERE) ||
|
|
strstr(dp->d_name, BMP_IDSTRING_1BITSQUARED)) &&
|
|
(strstr(dp->d_name, "-if00"))) {
|
|
i++;
|
|
char type[256], version[256], serial[256];
|
|
if (scan_linux_id(dp->d_name, type, version, serial)) {
|
|
DEBUG_WARN("Unexpected device name found \"%s\"\n",
|
|
dp->d_name);
|
|
}
|
|
if ((cl_opts->opt_serial && strstr(serial, cl_opts->opt_serial)) ||
|
|
(cl_opts->opt_position && cl_opts->opt_position == i)) {
|
|
/* With serial number given and partial match, we are done!*/
|
|
strncpy(info->serial, serial, sizeof(info->serial));
|
|
int res = snprintf(info->manufacturer, sizeof(info->manufacturer), "Black Magic Probe (%s)", type);
|
|
if (res)
|
|
DEBUG_WARN("Overflow\n");
|
|
strncpy(info->version, version, sizeof(info->version));
|
|
found_bmps = 1;
|
|
break;
|
|
} else {
|
|
found_bmps++;
|
|
}
|
|
}
|
|
}
|
|
closedir(dir);
|
|
if (found_bmps < 1) {
|
|
DEBUG_WARN("No BMP probe found\n");
|
|
return -1;
|
|
} else if ((found_bmps > 1) || cl_opts->opt_list_only) {
|
|
DEBUG_WARN("Available Probes:\n");
|
|
}
|
|
dir = opendir(DEVICE_BY_ID);
|
|
i = 0;
|
|
while ((dp = readdir(dir)) != NULL) {
|
|
if ((strstr(dp->d_name, BMP_IDSTRING_BLACKMAGIC) ||
|
|
strstr(dp->d_name, BMP_IDSTRING_BLACKSPHERE) ||
|
|
strstr(dp->d_name, BMP_IDSTRING_1BITSQUARED)) &&
|
|
(strstr(dp->d_name, "-if00"))) {
|
|
i++;
|
|
char type[256], version[256], serial[256];
|
|
if (scan_linux_id(dp->d_name, type, version, serial)) {
|
|
DEBUG_WARN("Unexpected device name found \"%s\"\n",
|
|
dp->d_name);
|
|
} else if ((found_bmps == 1) && (!cl_opts->opt_list_only)) {
|
|
strncpy(info->serial, serial, sizeof(info->serial));
|
|
found_bmps = 1;
|
|
strncpy(info->serial, serial, sizeof(info->serial));
|
|
snprintf(info->manufacturer, sizeof(info->manufacturer), "Black Magic Probe (%s)", type);
|
|
strncpy(info->version, version, sizeof(info->version));
|
|
break;
|
|
} else if (found_bmps > 0) {
|
|
DEBUG_WARN("%2d: %s, Black Magic Debug, Black Magic "
|
|
"Probe (%s), %s\n", i, serial, type, version);
|
|
}
|
|
}
|
|
}
|
|
closedir(dir);
|
|
return (found_bmps == 1 && !cl_opts->opt_list_only) ? 0 : 1;
|
|
}
|
|
#endif
|