mirror of
https://github.com/pbatard/rufus.git
synced 2026-10-22 22:34:26 +00:00
Compare commits
2 commits
875f221d5b
...
714e3ad901
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
714e3ad901 |
||
|
|
f7e714f7b4 |
5 changed files with 212 additions and 27 deletions
3
.github/workflows/mingw.yml
vendored
3
.github/workflows/mingw.yml
vendored
|
|
@ -35,6 +35,7 @@ jobs:
|
|||
include:
|
||||
- { sys: mingw64, env: x86_64, exe: rufus.exe }
|
||||
- { sys: mingw32, env: i686, exe: rufus_x86.exe }
|
||||
- { sys: ucrt64, env: ucrt-x86_64, exe: rufus_ucrt.exe }
|
||||
|
||||
defaults:
|
||||
run:
|
||||
|
|
@ -80,7 +81,7 @@ jobs:
|
|||
- name: Build
|
||||
run: |
|
||||
./configure --disable-debug ${{ steps.set_alpha.outputs.option }} ${{ steps.set_beta.outputs.option }}
|
||||
make -j4
|
||||
make -j4 ACLOCAL=: AUTOMAKE=: AUTOCONF=: AUTOHEADER=:
|
||||
mv ./src/rufus.exe ./${{ matrix.exe }}
|
||||
strip ./${{ matrix.exe }}
|
||||
upx --lzma --best ./${{ matrix.exe }}
|
||||
|
|
|
|||
161
src/dev.c
161
src/dev.c
|
|
@ -49,18 +49,83 @@ extern RUFUS_DRIVE rufus_drive[MAX_DRIVES];
|
|||
extern BOOL enable_HDDs, enable_VHDs, use_fake_units, enable_vmdk, usb_debug;
|
||||
extern BOOL list_non_usb_removable_drives, its_a_me_mario;
|
||||
|
||||
static inline uint64_t ssp_to_bps(uint32_t v)
|
||||
{
|
||||
static const uint64_t scale[4] = { 1ULL, 1000ULL, 1000000ULL, 1000000000ULL };
|
||||
return (uint64_t)(v >> 16) * scale[(v >> 4) & 0x3];
|
||||
}
|
||||
|
||||
static uint64_t get_max_bps(const uint8_t* bos, uint32_t len)
|
||||
{
|
||||
uint8_t l, min_rx_lanes, min_tx_lanes;
|
||||
uint32_t i, n, ssp, offset, attr, avail;
|
||||
uint64_t bps, max_bps = 0;
|
||||
|
||||
if (len < 5 || bos[0] < 5 || bos[1] != 0x0F)
|
||||
return 0;
|
||||
offset = bos[0]; // skip the BOS header
|
||||
|
||||
while (offset + 3 <= len) {
|
||||
l = bos[offset];
|
||||
if (l < 3 || offset + l > len)
|
||||
break;
|
||||
// Look for the SUPERSPEED_PLUS (0x0A) Device Capability descriptor (0x10)
|
||||
if (bos[offset + 1] == 0x10 && bos[offset + 2] == 0x0A && l >= 12) {
|
||||
// Get the bmAttributes field
|
||||
memcpy(&attr, &bos[offset + 4], sizeof(attr));
|
||||
// Get the min lanes from the wFunctionalitySupport field
|
||||
min_rx_lanes = bos[offset + 9] & 0x0F;
|
||||
min_tx_lanes = bos[offset + 9] >> 4;
|
||||
n = (attr & 0x1F) + 1; // Number of Sublink Speed Attributes
|
||||
avail = (l - 12) / 4;
|
||||
if (n > avail)
|
||||
n = avail;
|
||||
for (i = 0; i < n; i++) {
|
||||
memcpy(&ssp, &bos[offset + 12 + 4 * i], sizeof(ssp));
|
||||
bps = ssp_to_bps(ssp) * ((ssp & 0x80) ? min_tx_lanes : min_rx_lanes);
|
||||
if (bps > max_bps)
|
||||
max_bps = bps;
|
||||
}
|
||||
}
|
||||
// Next descriptor
|
||||
offset += l;
|
||||
}
|
||||
return max_bps;
|
||||
}
|
||||
|
||||
static uint32_t version_to_speed(uint16_t usb_version) {
|
||||
switch (usb_version) {
|
||||
case 0x0100: return USB_SPEED_LOW_1_5M;
|
||||
case 0x0110: return USB_SPEED_FULL_12M;
|
||||
case 0x0200:
|
||||
case 0x0201:
|
||||
case 0x0210: return USB_SPEED_HIGH_480M;
|
||||
case 0x0300: return USB_SPEED_SUPER_5G;
|
||||
case 0x0310: return USB_SPEED_SUPER_10G;
|
||||
case 0x0320: return USB_SPEED_SUPER_20G;
|
||||
case 0x0400: return USB_SPEED_SUPER_40G;
|
||||
case 0x0410: return USB_SPEED_SUPER_80G;
|
||||
default: return USB_SPEED_UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the VID, PID and current device speed
|
||||
*/
|
||||
static BOOL GetUSBProperties(char* parent_path, char* device_id, usb_device_props* props)
|
||||
{
|
||||
int pass;
|
||||
BOOL r = FALSE;
|
||||
CONFIGRET cr;
|
||||
HANDLE handle = INVALID_HANDLE_VALUE;
|
||||
DWORD size;
|
||||
DEVINST device_inst;
|
||||
USB_NODE_CONNECTION_INFORMATION_EX conn_info;
|
||||
USB_NODE_CONNECTION_INFORMATION_EX_V2 conn_info_v2;
|
||||
MY_USB_NODE_CONNECTION_SUPERSPEEDPLUS_INFORMATION ssp;
|
||||
uint8_t buf[sizeof(USB_DESCRIPTOR_REQUEST) + 512] = { 0 };
|
||||
uint8_t* bos = &buf[sizeof(USB_DESCRIPTOR_REQUEST)];
|
||||
USB_DESCRIPTOR_REQUEST* req = (USB_DESCRIPTOR_REQUEST*)buf;
|
||||
DWORD size, header_size = offsetof(USB_DESCRIPTOR_REQUEST, Data);
|
||||
|
||||
if ((parent_path == NULL) || (device_id == NULL) || (props == NULL))
|
||||
goto out;
|
||||
|
|
@ -99,26 +164,92 @@ static BOOL GetUSBProperties(char* parent_path, char* device_id, usb_device_prop
|
|||
if ((conn_info.DeviceDescriptor.idVendor != 0) || (conn_info.DeviceDescriptor.idProduct != 0)) {
|
||||
props->vid = conn_info.DeviceDescriptor.idVendor;
|
||||
props->pid = conn_info.DeviceDescriptor.idProduct;
|
||||
props->speed = conn_info.Speed + 1;
|
||||
// Not exactly accurate since a USB 3.x device connected to a USB 2.0 port will use the
|
||||
// 2.0 lanes and report a 2.0 device descriptor there, which means that, despite being
|
||||
// able to operate at 3.0 speeds, we only see a max speed of 2.0. Our additional checks
|
||||
// below should however be able to take care of detecting the max speed.
|
||||
props->max_speed = version_to_speed(conn_info.DeviceDescriptor.bcdUSB);
|
||||
props->current_speed = conn_info.Speed + 1;
|
||||
r = TRUE;
|
||||
}
|
||||
|
||||
// The USB speed report of modern Windows is a complete mess
|
||||
size = sizeof(ssp);
|
||||
memset(&ssp, 0, size);
|
||||
ssp.ConnectionIndex = (ULONG)props->port;
|
||||
ssp.Length = size;
|
||||
size = sizeof(conn_info_v2);
|
||||
memset(&conn_info_v2, 0, size);
|
||||
conn_info_v2.ConnectionIndex = (ULONG)props->port;
|
||||
conn_info_v2.Length = size;
|
||||
conn_info_v2.SupportedUsbProtocols.Usb300 = 1;
|
||||
// Requires Windows 11 24H2 or later
|
||||
if (DeviceIoControl(handle, IOCTL_USB_GET_NODE_CONNECTION_SUPERSPEEDPLUS_INFORMATION, &ssp, sizeof(ssp), &ssp, sizeof(ssp), &size, NULL)) {
|
||||
uint64_t cur_bps = max(ssp_to_bps(ssp.RxSuperSpeedPlus) * (ssp.RxLaneCount + 1), ssp_to_bps(ssp.TxSuperSpeedPlus) * (ssp.TxLaneCount + 1));
|
||||
if (cur_bps >= 80000000000ULL)
|
||||
props->current_speed = USB_SPEED_SUPER_80G;
|
||||
else if (cur_bps >= 40000000000ULL)
|
||||
props->current_speed = USB_SPEED_SUPER_40G;
|
||||
else if (cur_bps >= 20000000000ULL)
|
||||
props->current_speed = USB_SPEED_SUPER_20G;
|
||||
else if (cur_bps >= 10000000000ULL)
|
||||
props->current_speed = USB_SPEED_SUPER_10G;
|
||||
else if (cur_bps >= 5000000000ULL)
|
||||
props->current_speed = USB_SPEED_SUPER_5G;
|
||||
else
|
||||
goto next;
|
||||
props->max_speed = props->current_speed;
|
||||
|
||||
// Read the BOS to compare with the advertised speed
|
||||
size = 5;
|
||||
for (pass = 0; pass < 2; pass++) {
|
||||
req->ConnectionIndex = (ULONG)props->port;
|
||||
req->SetupPacket.bmRequest = 0x80;
|
||||
req->SetupPacket.bRequest = 0x06;
|
||||
req->SetupPacket.wValue = (0x0F << 8);
|
||||
req->SetupPacket.wIndex = 0;
|
||||
req->SetupPacket.wLength = (USHORT)size;
|
||||
if (!DeviceIoControl(handle, IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION, req, header_size + size, req, header_size + size, &size, NULL) ||
|
||||
size < header_size + 5)
|
||||
break;
|
||||
if (pass == 0) {
|
||||
size = req->Data[2] | (req->Data[3] << 8);
|
||||
if (size < 5 || size > 512)
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (pass == 2) {
|
||||
// Now the problem is that the max bps from the BOS is for *single* lane only, and the
|
||||
// USB Forum *STUPIDLY* defined a minimum amount of lanes in the BOS but NOT a maximum
|
||||
// or a preferred, which means we can not actually get the max speed of a USB 3.2 (2 x
|
||||
// 10G lanes) if it's operating at USB 3.1 speed (1 x 10G lane). Somebody *REALLY*
|
||||
// doesn't want users to find out if they are being screwed on USB speeds...
|
||||
uint64_t max_bps = get_max_bps(bos, size);
|
||||
if (max_bps >= 80000000000ULL)
|
||||
props->max_speed = USB_SPEED_SUPER_80G;
|
||||
else if (max_bps >= 40000000000ULL)
|
||||
props->max_speed = USB_SPEED_SUPER_40G;
|
||||
else if (max_bps >= 20000000000ULL)
|
||||
props->max_speed = USB_SPEED_SUPER_20G;
|
||||
else if (max_bps >= 10000000000ULL)
|
||||
props->max_speed = USB_SPEED_SUPER_10G;
|
||||
else if (max_bps >= 5000000000ULL)
|
||||
props->max_speed = USB_SPEED_SUPER_5G;
|
||||
}
|
||||
goto out;
|
||||
}
|
||||
|
||||
next:
|
||||
if (!DeviceIoControl(handle, IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX_V2, &conn_info_v2, size, &conn_info_v2, size, &size, NULL)) {
|
||||
uprintf("Could not get node connection information (V2) for device '%s': %s", device_id, WindowsErrorString());
|
||||
} else if (conn_info_v2.Flags.DeviceIsOperatingAtSuperSpeedPlusOrHigher) {
|
||||
props->speed = USB_SPEED_SUPER_PLUS;
|
||||
props->current_speed = USB_SPEED_SUPER_10G;
|
||||
} else if (conn_info_v2.Flags.DeviceIsOperatingAtSuperSpeedOrHigher) {
|
||||
props->speed = USB_SPEED_SUPER;
|
||||
props->current_speed = USB_SPEED_SUPER_5G;
|
||||
} else if (conn_info_v2.Flags.DeviceIsSuperSpeedPlusCapableOrHigher) {
|
||||
props->lower_speed = 2;
|
||||
props->max_speed = USB_SPEED_SUPER_10G;
|
||||
} else if (conn_info_v2.Flags.DeviceIsSuperSpeedCapableOrHigher) {
|
||||
props->lower_speed = 1;
|
||||
props->max_speed = USB_SPEED_SUPER_5G;
|
||||
}
|
||||
|
||||
out:
|
||||
|
|
@ -471,7 +602,12 @@ BOOL GetDevices(DWORD devnum)
|
|||
const char* scsi_card_name[] = {
|
||||
"_SD_", "_SDHC_", "_SDXC_", "_MMC_", "_MS_", "_MSPro_", "_xDPicture_", "_O2Media_"
|
||||
};
|
||||
const char* usb_speed_name[USB_SPEED_MAX] = { "USB", "USB 1.0", "USB 1.1", "USB 2.0", "USB 3.0", "USB 3.1" };
|
||||
const char* usb_version[USB_SPEED_MAX] = {
|
||||
"USB", "USB 1.0", "USB 1.1", "USB 2.1", "USB 3.0", "USB 3.1", "USB 3.2", "USB 4.0", "USB 4.1"
|
||||
}; // See, USB Forum, it *REALLY* isn't that hard!!!
|
||||
const char* usb_speed[USB_SPEED_MAX] = {
|
||||
"???", "1.5 Mbps", "12 Mbps", "480 Mbps", "5 Gbps", "10 Gbps", "20 Gbps", "40 Gbps", "80 Gbps"
|
||||
};
|
||||
const char* windows_sandbox_vhd_label = "PortableBaseLayer";
|
||||
// Hash table and String Array used to match a Device ID with the parent hub's Device Interface Path
|
||||
htab_table htab_devid = HTAB_EMPTY;
|
||||
|
|
@ -847,12 +983,13 @@ BOOL GetDevices(DWORD devnum)
|
|||
if (s < ARRAYSIZE(ignore_vid_pid))
|
||||
continue;
|
||||
}
|
||||
if (props.speed >= USB_SPEED_MAX)
|
||||
props.speed = 0;
|
||||
if (props.current_speed >= USB_SPEED_MAX)
|
||||
props.current_speed = 0;
|
||||
uprintf("Found %s%s%s device '%s' (%s) %s", props.is_UASP ? "UAS (" : "",
|
||||
usb_speed_name[props.speed], props.is_UASP ? ")" : "", buffer, str, method_str);
|
||||
if (props.lower_speed)
|
||||
uprintf("NOTE: This device is a USB 3.%c device operating at lower speed...", '0' + props.lower_speed - 1);
|
||||
usb_version[props.current_speed], props.is_UASP ? ")" : "", buffer, str, method_str);
|
||||
if (props.max_speed > props.current_speed)
|
||||
uprintf("NOTE: This a %s (%s) device operating at %s speed (%s)...", usb_version[props.max_speed],
|
||||
usb_speed[props.max_speed], usb_version[props.current_speed], usb_speed[props.current_speed]);
|
||||
}
|
||||
devint_data.cbSize = sizeof(devint_data);
|
||||
devint_detail_data = NULL;
|
||||
|
|
|
|||
63
src/dev.h
63
src/dev.h
|
|
@ -21,19 +21,22 @@
|
|||
#include <cfgmgr32.h>
|
||||
|
||||
#define USB_SPEED_UNKNOWN 0
|
||||
#define USB_SPEED_LOW 1
|
||||
#define USB_SPEED_FULL 2
|
||||
#define USB_SPEED_HIGH 3
|
||||
#define USB_SPEED_SUPER 4
|
||||
#define USB_SPEED_SUPER_PLUS 5
|
||||
#define USB_SPEED_MAX 6
|
||||
#define USB_SPEED_LOW_1_5M 1 // USB 1.0
|
||||
#define USB_SPEED_FULL_12M 2 // USB 1.1
|
||||
#define USB_SPEED_HIGH_480M 3 // USB 2.0
|
||||
#define USB_SPEED_SUPER_5G 4 // USB 3.0
|
||||
#define USB_SPEED_SUPER_10G 5 // USB 3.1
|
||||
#define USB_SPEED_SUPER_20G 6 // USB 3.2
|
||||
#define USB_SPEED_SUPER_40G 7 // USB 4.0
|
||||
#define USB_SPEED_SUPER_80G 8 // USB 4.1
|
||||
#define USB_SPEED_MAX 9
|
||||
|
||||
/* List of the properties we are interested in */
|
||||
typedef struct usb_device_props {
|
||||
int32_t vid;
|
||||
int32_t pid;
|
||||
uint32_t speed;
|
||||
uint32_t lower_speed;
|
||||
uint32_t current_speed;
|
||||
uint32_t max_speed;
|
||||
uint32_t port;
|
||||
BOOLEAN is_USB;
|
||||
BOOLEAN is_SCSI;
|
||||
|
|
@ -145,3 +148,47 @@ const GUID GUID_DEVINTERFACE_USB_HUB =
|
|||
{ 0xf18a0e88L, 0xc30c, 0x11d0, {0x88, 0x15, 0x00, 0xa0, 0xc9, 0x06, 0xbe, 0xd8} };
|
||||
|
||||
#define DEVID_HTAB_SIZE 257
|
||||
|
||||
#ifndef FILE_DEVICE_USB
|
||||
#define FILE_DEVICE_USB FILE_DEVICE_UNKNOWN
|
||||
#endif
|
||||
|
||||
typedef struct _USB_DESCRIPTOR_REQUEST {
|
||||
ULONG ConnectionIndex;
|
||||
struct {
|
||||
UCHAR bmRequest;
|
||||
UCHAR bRequest;
|
||||
USHORT wValue;
|
||||
USHORT wIndex;
|
||||
USHORT wLength;
|
||||
} SetupPacket;
|
||||
UCHAR Data[0];
|
||||
} USB_DESCRIPTOR_REQUEST, * PUSB_DESCRIPTOR_REQUEST;
|
||||
|
||||
#ifndef USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION
|
||||
#define USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION 260
|
||||
#endif
|
||||
|
||||
#ifndef IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION
|
||||
#define IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION CTL_CODE \
|
||||
(FILE_DEVICE_USB, USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||
#endif
|
||||
|
||||
#ifndef USB_GET_NODE_CONNECTION_SUPERSPEEDPLUS_INFORMATION
|
||||
#define USB_GET_NODE_CONNECTION_SUPERSPEEDPLUS_INFORMATION 289
|
||||
#endif
|
||||
|
||||
#ifndef IOCTL_USB_GET_NODE_CONNECTION_SUPERSPEEDPLUS_INFORMATION
|
||||
#define IOCTL_USB_GET_NODE_CONNECTION_SUPERSPEEDPLUS_INFORMATION CTL_CODE\
|
||||
(FILE_DEVICE_USB, USB_GET_NODE_CONNECTION_SUPERSPEEDPLUS_INFORMATION, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
ULONG ConnectionIndex;
|
||||
ULONG Length;
|
||||
ULONG RxSuperSpeedPlus;
|
||||
ULONG RxLaneCount;
|
||||
ULONG TxSuperSpeedPlus;
|
||||
ULONG TxLaneCount;
|
||||
} MY_USB_NODE_CONNECTION_SUPERSPEEDPLUS_INFORMATION;
|
||||
|
||||
|
|
|
|||
|
|
@ -277,7 +277,7 @@ static PCSTR _NormalizeDeviceName(IN PCSTR Device, IN PSTR NormalizedDeviceNameB
|
|||
return Device;
|
||||
// Handle custom paths of the form "<Physical> <Offset> <Size>" used by Rufus to
|
||||
// enable multi-partition access on removable devices, for pre 1703 platforms.
|
||||
if (sscanf(Device, "%s %I64u %I64u", NormalizedDeviceNameBuffer, Offset, Size) < 1)
|
||||
if (sscanf(Device, "%s %llu %llu", NormalizedDeviceNameBuffer, Offset, Size) < 1)
|
||||
return NULL;
|
||||
if ((NormalizedDeviceNameBuffer[1] == '\\') || (NormalizedDeviceNameBuffer[1] == '.'))
|
||||
NormalizedDeviceNameBuffer[1] = '?';
|
||||
|
|
|
|||
10
src/rufus.rc
10
src/rufus.rc
|
|
@ -33,7 +33,7 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
|
|||
IDD_DIALOG DIALOGEX 12, 12, 232, 326
|
||||
STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU
|
||||
EXSTYLE WS_EX_ACCEPTFILES
|
||||
CAPTION "Rufus 4.15.2409"
|
||||
CAPTION "Rufus 4.15.2411"
|
||||
FONT 9, "Segoe UI Symbol", 400, 0, 0x0
|
||||
BEGIN
|
||||
LTEXT "Drive Properties",IDS_DRIVE_PROPERTIES_TXT,8,6,53,12,NOT WS_GROUP
|
||||
|
|
@ -409,8 +409,8 @@ END
|
|||
//
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 4,15,2409,0
|
||||
PRODUCTVERSION 4,15,2409,0
|
||||
FILEVERSION 4,15,2411,0
|
||||
PRODUCTVERSION 4,15,2411,0
|
||||
FILEFLAGSMASK 0x3fL
|
||||
#ifdef _DEBUG
|
||||
FILEFLAGS 0x1L
|
||||
|
|
@ -428,13 +428,13 @@ BEGIN
|
|||
VALUE "Comments", "https://rufus.ie"
|
||||
VALUE "CompanyName", "Akeo Consulting"
|
||||
VALUE "FileDescription", "Rufus"
|
||||
VALUE "FileVersion", "4.15.2409"
|
||||
VALUE "FileVersion", "4.15.2411"
|
||||
VALUE "InternalName", "Rufus"
|
||||
VALUE "LegalCopyright", "© 2011-2026 Pete Batard (GPL v3)"
|
||||
VALUE "LegalTrademarks", "https://www.gnu.org/licenses/gpl-3.0.html"
|
||||
VALUE "OriginalFilename", "rufus-4.15.exe"
|
||||
VALUE "ProductName", "Rufus"
|
||||
VALUE "ProductVersion", "4.15.2409"
|
||||
VALUE "ProductVersion", "4.15.2411"
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue