Skip to content

Commit 9ffb9d2

Browse files
committed
Add rp2040 workaround to allow forced reboots, and improve behaviour with no vid/pid filtering
1 parent 1b6272d commit 9ffb9d2

2 files changed

Lines changed: 23 additions & 12 deletions

File tree

main.cpp

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -481,6 +481,7 @@ struct _settings {
481481
int vid=-1;
482482
int pid=-1;
483483
string ser;
484+
bool force_rp2040 = false;
484485
uint32_t offset = 0;
485486
uint32_t from = 0;
486487
uint32_t to = 0;
@@ -610,6 +611,7 @@ auto device_selection =
610611
(option("--vid") & integer("vid").set(settings.vid).if_missing([] { return "missing vid"; })) % "Filter by vendor id" +
611612
(option("--pid") & integer("pid").set(settings.pid)) % "Filter by product id" +
612613
(option("--ser") & value("ser").set(settings.ser)) % "Filter by serial number"
614+
+ option("--rp2040").set(settings.force_rp2040) % "Use RP2040 workarounds on Windows when using custom vid/pid (ignored on other platforms)"
613615
+ option('f', "--force").set(settings.force) % "Force a device not in BOOTSEL mode but running compatible code to reset so the command can be executed. After executing the command (unless the command itself is a 'reboot') the device will be rebooted back to application mode" +
614616
option('F', "--force-no-reboot").set(settings.force_no_reboot) % "Force a device not in BOOTSEL mode but running compatible code to reset so the command can be executed. After executing the command (unless the command itself is a 'reboot') the device will be left connected and accessible to picotool, but without the USB drive mounted"
615617
).min(0).doc_non_optional(true).collapse_synopsys("device-selection");
@@ -8703,6 +8705,13 @@ int main(int argc, char **argv) {
87038705
if (result != dr_error) {
87048706
devices[result].emplace_back(std::make_tuple(chip, *dev, handle));
87058707
}
8708+
8709+
if (settings.vid == 0 && !settings.ser.empty() && !devices[dr_vidpid_bootrom_ok].empty()) {
8710+
// Searching with no vid/pid filtering (ie opening all devices) can cause issues, so stop
8711+
// searching when we have a serial number, as we know we have the correct device
8712+
DEBUG_LOG("Found bootrom device with serial number, so stopping search");
8713+
break;
8714+
}
87068715
}
87078716
}
87088717
auto supported = selected_cmd->get_device_support();
@@ -8797,13 +8806,13 @@ int main(int argc, char **argv) {
87978806
// we reboot into BOOTSEL mode and disable MSC interface (the 1 here)
87988807
auto &to_reboot = std::get<1>(devices[dr_vidpid_stdio_usb][0]);
87998808
auto &to_reboot_handle = std::get<2>(devices[dr_vidpid_stdio_usb][0]);
8809+
unsigned int disable_mask = 1; // disable MSC interface
88008810
#if defined(_WIN32)
88018811
{
88028812
struct libusb_device_descriptor desc;
88038813
libusb_get_device_descriptor(to_reboot, &desc);
8804-
if (desc.idProduct == PRODUCT_ID_RP2040_STDIO_USB) {
8805-
fail(ERROR_NOT_POSSIBLE,
8806-
"Forced commands do not work with RP2040 on Windows - you can force reboot into BOOTSEL mode via 'picotool reboot -f -u' instead.");
8814+
if (desc.idProduct == PRODUCT_ID_RP2040_STDIO_USB || settings.force_rp2040) {
8815+
disable_mask = 0; // enable MSC interface so Zadig works correctly
88078816
}
88088817
}
88098818
#endif
@@ -8820,7 +8829,7 @@ int main(int argc, char **argv) {
88208829
}
88218830
}
88228831

8823-
reboot_device(to_reboot, to_reboot_handle, true, 1);
8832+
reboot_device(to_reboot, to_reboot_handle, true, disable_mask);
88248833
fos << "The device was asked to reboot into BOOTSEL mode so the command can be executed.";
88258834
} else if (tries == 1) {
88268835
fos << "\nWaiting for device to reboot";
@@ -8841,11 +8850,13 @@ int main(int argc, char **argv) {
88418850
// again is to assume it has the same serial number.
88428851
settings.address = -1;
88438852
settings.bus = -1;
8844-
// also skip vid/pid filtering, as that will typically change in BOOTSEL mode, and could be white-labelled on RP2350
8845-
settings.pid = -1;
8846-
// still filter for rpi vid/pid if we don't have a serial number, as that is an RP2040 running a no_flash binary, so will
8847-
// have a standard rpi vid/pid in BOOTSEL mode
8848-
settings.vid = settings.ser.empty() ? -1 : 0; // 0 means skip vid/pid filtering entirely, -1 means filter for rpi vid/pid
8853+
if (settings.pid != -1 || settings.vid != -1) {
8854+
// also skip vid/pid filtering, as that should change in BOOTSEL mode, and could be white-labelled on RP2350
8855+
settings.pid = -1;
8856+
// still filter for rpi vid/pid if we don't have a serial number, as that is an RP2040 running a no_flash binary, so will
8857+
// have a standard rpi vid/pid in BOOTSEL mode
8858+
settings.vid = settings.ser.empty() ? -1 : 0; // 0 means skip vid/pid filtering entirely, -1 means filter for rpi vid/pid
8859+
}
88498860
continue;
88508861
}
88518862
}

picoboot_connection/picoboot_connection.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -184,15 +184,15 @@ enum picoboot_device_result picoboot_open_device(libusb_device *device, libusb_d
184184
// Set model based on bootrom vid/pid for RP2040, as it cannot be white-labelled
185185
*chip = rp2040;
186186
} else {
187-
// Otherwise check the chip info
187+
// Otherwise check the chip info command exists
188188
struct picoboot_get_info_cmd info_cmd;
189189
info_cmd.bType = PICOBOOT_GET_INFO_SYS,
190190
info_cmd.dParams[0] = (uint32_t) (SYS_INFO_CHIP_INFO);
191191
uint32_t word_buf[64];
192-
// RP2040 doesn't have this function, so returns non-zero
192+
// Other devices don't have this function, so will return errors
193193
int info_ret = picoboot_get_info(*dev_handle, &info_cmd, (uint8_t*)word_buf, sizeof(word_buf));
194194
if (info_ret) {
195-
*chip = rp2040;
195+
return dr_vidpid_unknown;
196196
} else {
197197
*chip = rp2350;
198198
}

0 commit comments

Comments
 (0)