diff --git a/Cargo.lock b/Cargo.lock
index 50a4c9f4..c1fca899 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1647,6 +1647,7 @@ dependencies = [
  "smart-leds",
  "usb-device",
  "usbd-hid",
+ "usbd-picotool-reset",
  "usbd-serial",
  "ws2812-pio",
 ]
@@ -2362,6 +2363,15 @@ dependencies = [
  "usbd-hid-descriptors",
 ]
 
+[[package]]
+name = "usbd-picotool-reset"
+version = "0.3.0"
+source = "git+https://github.com/JohnAZoidberg/usbd-picotool-reset?branch=rp-2040-hal-0.8#46cbb075a39031cd0fb8c4539aa9ed20dabff76d"
+dependencies = [
+ "rp2040-hal",
+ "usb-device",
+]
+
 [[package]]
 name = "usbd-serial"
 version = "0.1.1"
diff --git a/Cargo.toml b/Cargo.toml
index a8e11c48..8fbc51e7 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -35,6 +35,9 @@ usb-device = "0.2.9"
 heapless = "0.7.16"
 usbd-serial = "0.1.1"
 usbd-hid = "0.6.1"
+# Can't use right now, depends on embedded-hal 1.0.0
+# usbd-picotool-reset = "0.3.0"
+usbd-picotool-reset = { git = "https://github.com/JohnAZoidberg/usbd-picotool-reset", branch = "rp-2040-hal-0.8" }
 fugit = "0.3.7"
 # LED Matrix
 is31fl3741 = "0.3.0"
diff --git a/fwupd/.gitignore b/fwupd/.gitignore
new file mode 100644
index 00000000..c2498874
--- /dev/null
+++ b/fwupd/.gitignore
@@ -0,0 +1 @@
+*.cab
diff --git a/fwupd/Makefile b/fwupd/Makefile
new file mode 100644
index 00000000..dfc882d4
--- /dev/null
+++ b/fwupd/Makefile
@@ -0,0 +1,3 @@
+qtpy.cab: firmware.metainfo.xml
+	cp ../target/thumbv6m-none-eabi/release/qtpy.uf2 .
+	gcab -c -v $@ qtpy.uf2 firmware.metainfo.xml
diff --git a/fwupd/firmware.metainfo.xml b/fwupd/firmware.metainfo.xml
new file mode 100644
index 00000000..c511a7ca
--- /dev/null
+++ b/fwupd/firmware.metainfo.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<component type="firmware">
+  <id>work.frame.inputmodule.qtpy</id>
+  <name>Framework QT Py</name>
+  <summary>Firmware for the Framework QT Py</summary>
+  <description>
+    <p>
+      Updating the firmware on your Framework QT Py improves performance and
+      adds new features.
+    </p>
+  </description>
+  <provides>
+    <!-- 32ac:0012 -->
+    <firmware type="flashed">5a5b58d0-9cb4-5f8b-a449-e7b7c820b0cb</firmware>
+  </provides>
+  <url type="homepage">https://github.com/FrameworkComputer/inputmodule-rs</url>
+  <metadata_license>CC0-1.0</metadata_license>
+  <project_license>proprietary</project_license>
+  <categories>
+    <category>X-Device</category>
+  </categories>
+  <releases>
+    <release urgency="normal" version="0.20" date="2024-11-17" install_duration="40">
+      <checksum filename="qtpy.uf2" target="content"/>
+      <description>
+        New firmware!
+      </description>
+    </release>
+  </releases>
+  <requires>{{ min_ver }}
+    <id compare="ge" version="1.9.2">org.freedesktop.fwupd</id>
+  </requires>
+  <custom>
+    <!--<value key="LVFS::VersionFormat">{{ version_format }}</value>-->
+    <value key="LVFS::UpdateProtocol">com.microsoft.uf2</value>
+  </custom>
+  <!--
+  <keywords>
+    <keyword>{{ keyword }}</keyword>
+    <keyword>{{ id }}</keyword>
+  </keywords>
+  -->
+</component>
diff --git a/qtpy/Cargo.toml b/qtpy/Cargo.toml
index 39e128f9..412b5e61 100644
--- a/qtpy/Cargo.toml
+++ b/qtpy/Cargo.toml
@@ -23,6 +23,7 @@ usb-device.workspace = true
 heapless.workspace = true
 usbd-serial.workspace = true
 usbd-hid.workspace = true
+usbd-picotool-reset.workspace = true
 fugit.workspace = true
 
 # C1 Minimal
diff --git a/qtpy/src/main.rs b/qtpy/src/main.rs
index 1ba7cd1a..b659da22 100644
--- a/qtpy/src/main.rs
+++ b/qtpy/src/main.rs
@@ -34,11 +34,13 @@ use bsp::hal::{
 };
 
 // USB Device support
-use usb_device::{class_prelude::*, prelude::*};
+use usb_device::{class_prelude::*, prelude::*, descriptor::lang_id};
 
 // USB Communications Class Device support
 use usbd_serial::{SerialPort, USB_CLASS_CDC};
 
+use usbd_picotool_reset::PicoToolReset;
+
 // Used to demonstrate writing formatted strings
 // use core::fmt::Write;
 // use heapless::String;
@@ -95,10 +97,16 @@ fn main() -> ! {
         &mut pac.RESETS,
     ));
 
+    let mut picotool: PicoToolReset<_> = PicoToolReset::new(&usb_bus);
+
     // Set up the USB Communications Class Device driver
     let mut serial = SerialPort::new(&usb_bus);
 
     let mut usb_dev = UsbDeviceBuilder::new(&usb_bus, UsbVidPid(FRAMEWORK_VID, COMMUNITY_PID))
+        //.strings(&[StringDescriptors::new(lang_id::ENGLISH_US)
+        //    .manufacturer("Adafruit")
+        //    .product("QT PY - Framework 16 Inputmodule FW")])
+        //.expect("Failed to set strings")
         .manufacturer("Adafruit")
         .product("QT PY - Framework 16 Inputmodule FW")
         .max_power(500)
@@ -141,7 +149,8 @@ fn main() -> ! {
         }
 
         // Check for new data
-        if usb_dev.poll(&mut [&mut serial]) {
+        // usb_dev.poll(&mut [&mut picotool, &mut serial]);
+        if usb_dev.poll(&mut [&mut picotool, &mut serial]) {
             let mut buf = [0u8; 64];
             match serial.read(&mut buf) {
                 Err(_e) => {
diff --git a/rust-toolchain.toml b/rust-toolchain.toml
index 460b3c4b..264c9503 100644
--- a/rust-toolchain.toml
+++ b/rust-toolchain.toml
@@ -1,4 +1,6 @@
 [toolchain]
+# Needed for embeded-hal 1.0.0
+# channel = "1.75.0"
 channel = "1.74.0"
 targets = ["thumbv6m-none-eabi"]
 components = ["clippy", "rustfmt"]