Skip to content

Commit 720adc9

Browse files
committed
Add rp2040 workaround to allow forced reboots, and improve behaviour with no vid/pid filtering
1 parent ed78403 commit 720adc9

File tree

2 files changed

+23
-12
lines changed

2 files changed

+23
-12
lines changed

main.cpp

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -465,6 +465,7 @@ struct _settings {
465465
int vid=-1;
466466
int pid=-1;
467467
string ser;
468+
bool force_rp2040 = false;
468469
uint32_t offset = 0;
469470
uint32_t from = 0;
470471
uint32_t to = 0;
@@ -593,6 +594,7 @@ auto device_selection =
593594
(option("--vid") & integer("vid").set(settings.vid).if_missing([] { return "missing vid"; })) % "Filter by vendor id" +
594595
(option("--pid") & integer("pid").set(settings.pid)) % "Filter by product id" +
595596
(option("--ser") & value("ser").set(settings.ser)) % "Filter by serial number"
597+
+ option("--rp2040").set(settings.force_rp2040) % "Use RP2040 workarounds on Windows when using custom vid/pid (ignored on other platforms)"
596598
+ 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" +
597599
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"
598600
).min(0).doc_non_optional(true).collapse_synopsys("device-selection");
@@ -8624,6 +8626,13 @@ int main(int argc, char **argv) {
86248626
if (result != dr_error) {
86258627
devices[result].emplace_back(std::make_tuple(model, *dev, handle));
86268628
}
8629+
8630+
if (settings.vid == 0 && !settings.ser.empty() && !devices[dr_vidpid_bootrom_ok].empty()) {
8631+
// Searching with no vid/pid filtering (ie opening all devices) can cause issues, so stop
8632+
// searching when we have a serial number, as we know we have the correct device
8633+
DEBUG_LOG("Found bootrom device with serial number, so stopping search");
8634+
break;
8635+
}
86278636
}
86288637
}
86298638
auto supported = selected_cmd->get_device_support();
@@ -8718,13 +8727,13 @@ int main(int argc, char **argv) {
87188727
// we reboot into BOOTSEL mode and disable MSC interface (the 1 here)
87198728
auto &to_reboot = std::get<1>(devices[dr_vidpid_stdio_usb][0]);
87208729
auto &to_reboot_handle = std::get<2>(devices[dr_vidpid_stdio_usb][0]);
8730+
unsigned int disable_mask = 1; // disable MSC interface
87218731
#if defined(_WIN32)
87228732
{
87238733
struct libusb_device_descriptor desc;
87248734
libusb_get_device_descriptor(to_reboot, &desc);
8725-
if (desc.idProduct == PRODUCT_ID_RP2040_STDIO_USB) {
8726-
fail(ERROR_NOT_POSSIBLE,
8727-
"Forced commands do not work with RP2040 on Windows - you can force reboot into BOOTSEL mode via 'picotool reboot -f -u' instead.");
8735+
if (desc.idProduct == PRODUCT_ID_RP2040_STDIO_USB || settings.force_rp2040) {
8736+
disable_mask = 0; // enable MSC interface so Zadig works correctly
87288737
}
87298738
}
87308739
#endif
@@ -8741,7 +8750,7 @@ int main(int argc, char **argv) {
87418750
}
87428751
}
87438752

8744-
reboot_device(to_reboot, to_reboot_handle, true, 1);
8753+
reboot_device(to_reboot, to_reboot_handle, true, disable_mask);
87458754
fos << "The device was asked to reboot into BOOTSEL mode so the command can be executed.";
87468755
} else if (tries == 1) {
87478756
fos << "\nWaiting for device to reboot";
@@ -8762,11 +8771,13 @@ int main(int argc, char **argv) {
87628771
// again is to assume it has the same serial number.
87638772
settings.address = -1;
87648773
settings.bus = -1;
8765-
// also skip vid/pid filtering, as that will typically change in BOOTSEL mode, and could be white-labelled on RP2350
8766-
settings.pid = -1;
8767-
// 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
8768-
// have a standard rpi vid/pid in BOOTSEL mode
8769-
settings.vid = settings.ser.empty() ? -1 : 0; // 0 means skip vid/pid filtering entirely, -1 means filter for rpi vid/pid
8774+
if (settings.pid != -1 || settings.vid != -1) {
8775+
// also skip vid/pid filtering, as that should change in BOOTSEL mode, and could be white-labelled on RP2350
8776+
settings.pid = -1;
8777+
// 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
8778+
// have a standard rpi vid/pid in BOOTSEL mode
8779+
settings.vid = settings.ser.empty() ? -1 : 0; // 0 means skip vid/pid filtering entirely, -1 means filter for rpi vid/pid
8780+
}
87708781
continue;
87718782
}
87728783
}

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
*model = 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-
*model = rp2040;
195+
return dr_vidpid_unknown;
196196
} else {
197197
*model = rp2350;
198198
}

0 commit comments

Comments
 (0)