[core] report detected USB device speed

* Yes, it takes about all of the changes below, to basically add 3 extra characters in the log...
  That's Microsoft Windows for you, baby!
* Closes #314
This commit is contained in:
Pete Batard 2014-05-18 00:37:01 +01:00
parent 4026083da8
commit c85670f7b7
13 changed files with 847 additions and 471 deletions

View file

@ -28,8 +28,6 @@
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <commctrl.h>
#include <setupapi.h>
#include <winioctl.h>
#include <shlobj.h>
#include <process.h>
@ -128,12 +126,12 @@ int dialog_showing = 0;
uint16_t rufus_version[4], embedded_sl_version[2];
char embedded_sl_version_str[2][12] = { "?.??", "?.??" };
RUFUS_UPDATE update = { {0,0,0,0}, {0,0}, NULL, NULL};
StrArray DriveID, DriveLabel;
extern char szStatusMessage[256];
static HANDLE format_thid = NULL;
static HWND hProgress = NULL, hBoot = NULL, hSelectISO = NULL;
static HICON hIconDisc, hIconDown, hIconUp, hIconLang;
static StrArray DriveID, DriveLabel;
static char szTimer[12] = "00:00:00";
static unsigned int timer;
static int64_t last_iso_blocking_status;
@ -609,267 +607,6 @@ static BOOL PopulateProperties(int ComboIndex)
return TRUE;
}
/*
* Refresh the list of USB devices
*/
static BOOL GetUSBDevices(DWORD devnum)
{
// The first two are standard Microsoft drivers (including the Windows 8 UASP one).
// The rest are the vendor UASP drivers I know of so far - list may be incomplete!
const char* storage_name[] = { "USBSTOR", "UASPSTOR", "VUSBSTOR", "ETRONSTOR" };
const char* scsi_name = "SCSI";
const char* vhd_name = "Virtual Disk";
char letter_name[] = " (?:)";
BOOL found = FALSE, is_SCSI, is_UASP, is_VHD;
HDEVINFO dev_info = NULL;
SP_DEVINFO_DATA dev_info_data;
SP_DEVICE_INTERFACE_DATA devint_data;
PSP_DEVICE_INTERFACE_DETAIL_DATA_A devint_detail_data;
DEVINST parent_inst, device_inst;
DWORD size, i, j, k, datatype, drive_index;
ULONG list_size[ARRAYSIZE(storage_name)], full_list_size;
HANDLE hDrive;
LONG maxwidth = 0;
RECT rect;
int s, score, drive_number;
char drive_letters[27], *devid, *devid_list = NULL, entry_msg[128];
char *label, *entry, buffer[MAX_PATH], str[sizeof("0000:0000")+1];
uint16_t vid, pid;
GUID _GUID_DEVINTERFACE_DISK = // only known to some...
{ 0x53f56307L, 0xb6bf, 0x11d0, {0x94, 0xf2, 0x00, 0xa0, 0xc9, 0x1e, 0xfb, 0x8b} };
IGNORE_RETVAL(ComboBox_ResetContent(hDeviceList));
StrArrayClear(&DriveID);
StrArrayClear(&DriveLabel);
GetClientRect(hDeviceList, &rect);
dev_info = SetupDiGetClassDevsA(&_GUID_DEVINTERFACE_DISK, NULL, NULL, DIGCF_PRESENT|DIGCF_DEVICEINTERFACE);
if (dev_info == INVALID_HANDLE_VALUE) {
uprintf("SetupDiGetClassDevs (Interface) failed: %s\n", WindowsErrorString());
return FALSE;
}
full_list_size = 0;
for (s=0; s<ARRAYSIZE(storage_name); s++) {
// Get a list of hardware IDs for all USB storage devices
// This will be used to retrieve the VID:PID of our devices
CM_Get_Device_ID_List_SizeA(&list_size[s], storage_name[s], CM_GETIDLIST_FILTER_SERVICE);
if (list_size[s] != 0)
full_list_size += list_size[s]-1; // remove extra NUL terminator
}
full_list_size += 1; // add extra NUL terminator
if (full_list_size < 2)
return FALSE;
devid_list = (char*)malloc(full_list_size);
if (devid_list == NULL) {
uprintf("Could not allocate Dev ID list\n");
return FALSE;
}
// Build a single list from all the storage enumerators we know of
for (s=0, i=0; s<ARRAYSIZE(storage_name); s++) {
if (list_size[s] > 1) {
CM_Get_Device_ID_ListA(storage_name[s], &devid_list[i], list_size[s], CM_GETIDLIST_FILTER_SERVICE);
// list_size is sometimes larger than required thus we need to find the real end
for (i += list_size[s]; i > 2; i--) {
if ((devid_list[i-2] != '\0') && (devid_list[i-1] == '\0') && (devid_list[i] == '\0'))
break;
}
}
}
dev_info_data.cbSize = sizeof(dev_info_data);
for (i=0; SetupDiEnumDeviceInfo(dev_info, i, &dev_info_data); i++) {
memset(buffer, 0, sizeof(buffer));
if (!SetupDiGetDeviceRegistryPropertyA(dev_info, &dev_info_data, SPDRP_ENUMERATOR_NAME,
&datatype, (LPBYTE)buffer, sizeof(buffer), &size)) {
uprintf("SetupDiGetDeviceRegistryProperty (Enumerator Name) failed: %s\n", WindowsErrorString());
continue;
}
// UASP drives are listed under SCSI (along with regular SYSTEM drives => "DANGER, WILL ROBINSON!!!")
is_SCSI = (safe_stricmp(buffer, scsi_name) == 0);
if ((safe_stricmp(buffer, storage_name[0]) != 0) && (!is_SCSI))
continue;
memset(buffer, 0, sizeof(buffer));
vid = 0; pid = 0;
is_UASP = FALSE, is_VHD = FALSE;
if (!SetupDiGetDeviceRegistryPropertyA(dev_info, &dev_info_data, SPDRP_FRIENDLYNAME,
&datatype, (LPBYTE)buffer, sizeof(buffer), &size)) {
uprintf("SetupDiGetDeviceRegistryProperty (Friendly Name) failed: %s\n", WindowsErrorString());
// We can afford a failure on this call - just replace the name with "USB Storage Device (Generic)"
safe_strcpy(buffer, sizeof(buffer), lmprintf(MSG_045));
} else if (safe_strstr(buffer, vhd_name) != NULL) {
is_VHD = TRUE;
} else {
// Get the VID:PID of the device. We could avoid doing this lookup every time by keeping
// a lookup table, but there shouldn't be that many USB storage devices connected...
for (devid = devid_list; *devid; devid += strlen(devid) + 1) {
if ( (CM_Locate_DevNodeA(&parent_inst, devid, 0) == 0)
&& (CM_Get_Child(&device_inst, parent_inst, 0) == 0)
&& (device_inst == dev_info_data.DevInst) ) {
BOOL post_backslash = FALSE;
// If we're not dealing with the USBSTOR part of our list, then this is an UASP device
is_UASP = ((((uintptr_t)devid)+2) >= ((uintptr_t)devid_list)+list_size[0]);
for (j=0, k=0; (j<strlen(devid))&&(k<2); j++) {
// The ID is in the form USB_VENDOR_BUSID\VID_xxxx&PID_xxxx\...
if (devid[j] == '\\')
post_backslash = TRUE;
if (!post_backslash)
continue;
if (devid[j] == '_') {
pid = (uint16_t)strtoul(&devid[j+1], NULL, 16);
// We could have used a vid_pid[] table, but keeping vid/pid separate is clearer
if (k++==0) vid = pid;
}
}
}
}
}
if (is_VHD) {
uprintf("Found VHD device '%s'\n", buffer);
} else {
if ((vid == 0) && (pid == 0)) {
if (is_SCSI) {
// If we have an SCSI drive and couldn't get a VID:PID, we are most likely
// dealing with a system drive => eliminate it!
continue;
}
safe_strcpy(str, sizeof(str), "????:????"); // Couldn't figure VID:PID
} else {
safe_sprintf(str, sizeof(str), "%04X:%04X", vid, pid);
}
uprintf("Found %s device '%s' (%s)\n", is_UASP?"UAS":"USB", buffer, str);
}
devint_data.cbSize = sizeof(devint_data);
hDrive = INVALID_HANDLE_VALUE;
devint_detail_data = NULL;
for (j=0; ;j++) {
safe_closehandle(hDrive);
safe_free(devint_detail_data);
if (!SetupDiEnumDeviceInterfaces(dev_info, &dev_info_data, &_GUID_DEVINTERFACE_DISK, j, &devint_data)) {
if(GetLastError() != ERROR_NO_MORE_ITEMS) {
uprintf("SetupDiEnumDeviceInterfaces failed: %s\n", WindowsErrorString());
} else {
uprintf("A device was eliminated because it didn't report itself as a disk\n");
}
break;
}
if (!SetupDiGetDeviceInterfaceDetailA(dev_info, &devint_data, NULL, 0, &size, NULL)) {
if(GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
devint_detail_data = (PSP_DEVICE_INTERFACE_DETAIL_DATA_A)calloc(1, size);
if (devint_detail_data == NULL) {
uprintf("Unable to allocate data for SP_DEVICE_INTERFACE_DETAIL_DATA\n");
continue;
}
devint_detail_data->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_A);
} else {
uprintf("SetupDiGetDeviceInterfaceDetail (dummy) failed: %s\n", WindowsErrorString());
continue;
}
}
if (devint_detail_data == NULL) {
uprintf("SetupDiGetDeviceInterfaceDetail (dummy) - no data was allocated\n");
continue;
}
if(!SetupDiGetDeviceInterfaceDetailA(dev_info, &devint_data, devint_detail_data, size, &size, NULL)) {
uprintf("SetupDiGetDeviceInterfaceDetail (actual) failed: %s\n", WindowsErrorString());
continue;
}
hDrive = CreateFileA(devint_detail_data->DevicePath, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
if(hDrive == INVALID_HANDLE_VALUE) {
uprintf("Could not open '%s': %s\n", devint_detail_data->DevicePath, WindowsErrorString());
continue;
}
drive_number = GetDriveNumber(hDrive, devint_detail_data->DevicePath);
if (drive_number < 0)
continue;
drive_index = drive_number + DRIVE_INDEX_MIN;
if (!IsMediaPresent(drive_index)) {
uprintf("Device eliminated because it appears to contain no media\n");
safe_closehandle(hDrive);
safe_free(devint_detail_data);
break;
}
if (GetDriveLabel(drive_index, drive_letters, &label)) {
if ((!enable_HDDs) && (!is_VHD) && ((score = IsHDD(drive_index, vid, pid, buffer)) > 0)) {
uprintf("Device eliminated because it was detected as an USB Hard Drive (score %d > 0)\n", score);
uprintf("If this device is not an USB Hard Drive, please e-mail the author of this application\n");
uprintf("NOTE: You can enable the listing of USB Hard Drives in 'Advanced Options' (after clicking the white triangle)");
safe_closehandle(hDrive);
safe_free(devint_detail_data);
break;
}
// The empty string is returned for drives that don't have any volumes assigned
if (drive_letters[0] == 0) {
entry = lmprintf(MSG_046, label, drive_number,
SizeToHumanReadable(GetDriveSize(drive_index), FALSE, use_fake_units));
} else {
// We have multiple volumes assigned to the same device (multiple partitions)
// If that is the case, use "Multiple Volumes" instead of the label
safe_strcpy(entry_msg, sizeof(entry_msg), ((drive_letters[0] != 0) && (drive_letters[1] != 0))?
lmprintf(MSG_047):label);
for (k=0; drive_letters[k]; k++) {
// Append all the drive letters we detected
letter_name[2] = drive_letters[k];
if (right_to_left_mode)
safe_strcat(entry_msg, sizeof(entry_msg), RIGHT_TO_LEFT_MARK);
safe_strcat(entry_msg, sizeof(entry_msg), letter_name);
if (drive_letters[k] == app_dir[0]) break;
}
// Repeat as we need to break the outside loop
if (drive_letters[k] == app_dir[0]) {
uprintf("Removing %c: from the list: This is the disk from which " APPLICATION_NAME " is running!\n", app_dir[0]);
safe_closehandle(hDrive);
safe_free(devint_detail_data);
break;
}
safe_sprintf(&entry_msg[strlen(entry_msg)], sizeof(entry_msg) - strlen(entry_msg),
"%s [%s]", (right_to_left_mode)?RIGHT_TO_LEFT_MARK:"", SizeToHumanReadable(GetDriveSize(drive_index), FALSE, use_fake_units));
entry = entry_msg;
}
// Must ensure that the combo box is UNSORTED for indexes to be the same
StrArrayAdd(&DriveID, buffer);
StrArrayAdd(&DriveLabel, label);
IGNORE_RETVAL(ComboBox_SetItemData(hDeviceList, ComboBox_AddStringU(hDeviceList, entry), drive_index));
maxwidth = max(maxwidth, GetEntryWidth(hDeviceList, entry));
safe_closehandle(hDrive);
safe_free(devint_detail_data);
break;
}
}
}
SetupDiDestroyDeviceInfoList(dev_info);
// Adjust the Dropdown width to the maximum text size
SendMessage(hDeviceList, CB_SETDROPPEDWIDTH, (WPARAM)maxwidth, 0);
if (devnum >= DRIVE_INDEX_MIN) {
for (i=0; i<ComboBox_GetCount(hDeviceList); i++) {
if ((DWORD)ComboBox_GetItemData(hDeviceList, i) == devnum) {
found = TRUE;
break;
}
}
}
if (!found)
i = 0;
IGNORE_RETVAL(ComboBox_SetCurSel(hDeviceList, i));
SendMessage(hMainDialog, WM_COMMAND, (CBN_SELCHANGE<<16) | IDC_DEVICE, 0);
SendMessage(hMainDialog, WM_COMMAND, (CBN_SELCHANGE<<16) | IDC_FILESYSTEM,
ComboBox_GetCurSel(hFileSystem));
safe_free(devid_list);
return TRUE;
}
/*
* Set up progress bar real estate allocation
*/