diff --git a/README.md b/README.md
index 03b01aa..ea3d583 100644
--- a/README.md
+++ b/README.md
@@ -36,6 +36,10 @@ From my testing so far I've found that games don't really like to have two contr
 
 On Steam Deck, once you have the driver working from Desktop mode, it should also work automatically from Game Mode.
 
+### Uninstalling
+
+If you wish to completely remove the installation, run the following script as root: `~/bin/xreal_driver_uninstall`
+
 ## Development
 
 ### Dependencies
@@ -61,4 +65,4 @@ make
 
 ### Deployment
 
-To create the deployment gzip file, run `bin/package.sh`. Upload the resulting gzip file and the `bin/xreal_driver_setup` file to a new Release.
+To create the deployment gzip file, run `bin/package`. Upload the resulting gzip file and the `bin/xreal_driver_setup` file to a new Release.
diff --git a/bin/package.sh b/bin/package
similarity index 94%
rename from bin/package.sh
rename to bin/package
index 9bb5df3..5aae83e 100755
--- a/bin/package.sh
+++ b/bin/package
@@ -27,6 +27,7 @@ mv xrealAirLinuxDriver $PACKAGE_DIR
 
 # copy user-relevant scripts
 cp ../bin/xreal_driver_config $PACKAGE_DIR
+cp ../bin/xreal_driver_uninstall $PACKAGE_DIR
 
 # copy the udev rule that's needed for the USB integration
 cp -r ../udev $PACKAGE_DIR
diff --git a/bin/xreal_driver_setup b/bin/xreal_driver_setup
index 16f9e7c..f3b3860 100755
--- a/bin/xreal_driver_setup
+++ b/bin/xreal_driver_setup
@@ -10,15 +10,23 @@ if [ "$(id -u)" != "0" ]; then
 fi
 
 # If we're on Steam Deck, check if the file system is readonly, if so, disable readonly and store the state to re-enable later
-steam_deck_readonly_fs=false
-if command -v steamos-readonly &> /dev/null; then
+steam_deck_readonly_fs=0
+if [ $(command -v steamos-readonly) ]; then
   if steamos-readonly status | grep -q "enabled"; then
-    steam_deck_readonly_fs=true
+    steam_deck_readonly_fs=1
     echo "Disabling readonly SteamOS partition"
     steamos-readonly disable
   fi
 fi
 
+USER=${SUDO_USER:-$USER}
+USER_HOME=$(getent passwd $USER | cut -d: -f6)
+if [ -e "$USER_HOME/bin/xreal_driver_uninstall" ]; then
+  echo "Cleaning up the previous installation"
+
+  # ` || true` will ensure that this can't cause a failure, even with `set -e`
+  $USER_HOME/bin/xreal_driver_uninstall --for-install || true
+fi
 
 if ! lsmod | grep -q uinput; then
   echo "Setting up uinput kernel module"
@@ -49,9 +57,6 @@ if test -f "$UDEV_FILE"; then
 fi
 
 echo "Copying udev file to ${UDEV_FILE}"
-USER=${SUDO_USER:-$USER}
-USER_HOME=$(getent passwd $USER | cut -d: -f6)
-
 # escaping sed replace: https://stackoverflow.com/questions/407523/escape-a-string-for-a-sed-replace-pattern
 ESCAPED_USER_HOME=$(printf '%s\n' "$USER_HOME" | sed -e 's/[\/&]/\\&/g')
 sed -i -e "s/{user_home}/$ESCAPED_USER_HOME/g" -e "s/{user}/$USER/g" udev/60-xreal-air.rules
@@ -61,10 +66,11 @@ udevadm control --reload
 udevadm trigger
 
 echo "Copying scripts to ${USER_HOME}/bin"
-if test ! -d "$USER_HOME/bin"; then
+if [ ! -d "$USER_HOME/bin" ]; then
   mkdir $USER_HOME/bin
 fi
 cp xreal_driver_config $USER_HOME/bin
+cp xreal_driver_uninstall $USER_HOME/bin
 
 echo "Setting up the systemd service"
 # check if the systemd service is already running from a previous install
@@ -95,7 +101,7 @@ rm -rf $tmp_dir
 cd "$(dirs -l -0)" && dirs -c
 
 # If we disabled the Steam Deck readonly file system, re-enable it
-if $steam_deck_readonly_fs; then
+if [ "$steam_deck_readonly_fs" -eq 1 ]; then
   echo "Re-enabling readonly SteamOS partition"
   steamos-readonly enable
 fi
diff --git a/bin/xreal_driver_uninstall b/bin/xreal_driver_uninstall
new file mode 100755
index 0000000..643d17c
--- /dev/null
+++ b/bin/xreal_driver_uninstall
@@ -0,0 +1,56 @@
+#!/usr/bin/env bash
+
+for_install=0
+if [[ -n "$1" ]] && [[ "$1" == "--for-install" ]]; then
+    for_install=1
+fi
+
+# we don't want the uninstall script to be able to cause a failure if being triggered by the setup script
+[ "$for_install" -eq 0 ] && set -e
+
+# Make sure only root can run our script
+if [ "$(id -u)" != "0" ]; then
+   echo "This script must be run as root" 1>&2
+   exit 1
+fi
+
+# If we're on Steam Deck, check if the file system is readonly, if so, disable readonly and store the state to re-enable later
+steam_deck_readonly_fs=0
+if [ "$for_install" -eq 0 ] && [ $(command -v steamos-readonly) ]; then
+  if steamos-readonly status | grep -q "enabled"; then
+    steam_deck_readonly_fs=1
+    echo "Disabling readonly SteamOS partition"
+    steamos-readonly disable
+  fi
+fi
+
+[ "$for_install" -eq 0 ] && echo "Removing the udev rule"
+rm -f /etc/udev/rules.d/60-xreal-air.rules
+udevadm control --reload
+
+[ "$for_install" -eq 0 ] && echo "Removing the systemd service"
+if systemctl is-active --quiet xreal-air-driver; then
+    systemctl stop xreal-air-driver
+fi
+rm -f /etc/systemd/system/xreal-air-driver.service
+rm -f /usr/bin/xrealAirLinuxDriver
+
+# If we disabled the Steam Deck readonly file system, re-enable it
+if [ "$steam_deck_readonly_fs" -eq 1 ]; then
+  echo "Re-enabling readonly SteamOS partition"
+  steamos-readonly enable
+fi
+
+[ "$for_install" -eq 0 ] && echo "Removing installed files from ~/ and ~/bin/"
+USER=${SUDO_USER:-$USER}
+USER_HOME=$(getent passwd $USER | cut -d: -f6)
+if [ "$for_install" -eq 0 ]; then
+    rm -f $USER_HOME/.xreal_driver_config
+    rm -f $USER_HOME/.xreal_driver_log
+fi
+rm -f $USER_HOME/.xreal_joystick_debug
+rm -f $USER_HOME/.xreal_driver_lock
+rm -f $USER_HOME/bin/xreal_driver_config
+
+# this script is self-deleting, leave this as the last command
+rm -f $USER_HOME/bin/xreal_driver_uninstall
\ No newline at end of file