Stop USB Wake from Suspend

I've just invested some hours struggling to get my PC not to Wake from Suspend. My hope in writing this, is that it may help others wanting the same thing to easily achieve it too. I've searched the web extensively to find this fix, and was happy to find it right here in the Mate Community, thanks to a post by karnemelk. By the time you read this, I hope the amazing Ubuntu & Mate teams will have created a simple point and click solution sparing you from even these three simple steps.

There are two reasons I'm writing this, rather than just link to that post. First, some newbies might appreciate the more basic 3-Step copy & paste process I'll outline. Secondly, I'll only briefly mention the other more complex main approach I found online and tried unsuccessfully as described in more detail with these posts.

The Problem:
I use Suspend on a PC to save the state of my work, and don't want the USB keyboard or USB Bluetooth mouse to wake the PC if they're bumped during Suspend. Instead I use the Power Button to wake the PC. I had set this with a Disable USB Wakeup setting in the PC BIOS and it worked fine until a couple of weeks ago when Software Updater (perhaps for security reasons) apparently did something that made Mate start ignoring my BIOS setting. While trying to get it working again, I updated my BIOS but it made no difference to this problem.

What Didn't Work:
Countless websites (and some posts here in the Mate Community) suggest using an echo command to send the USB device name(s) to a file named
/proc/acpi/wakeup
but no variation of that worked. PCs differ, so those approaches might work for you if this one doesn't. I'll outline my PC details below in case that's helpful.

Three Simple Steps to Success:
Step 1. Create a /etc/systemd/system/acpi-wake.service file and copy several lines of specific variables and a command line into it.
*NOTE: You'll need to input your Password for each of these three steps, so be sure you have it handy before starting.

A. Open the Mate Teminal app. In my Ubuntu Mate 20.04.1 it's in the Panel Menu under System Tools.

B. Launch the Nano command line app by highlighting and copying the line below, then pulling down Edit at the top of the Terminal window and clicking Paste. Once the line in the Terminal window matches the one below, tap the Enter key and then input your Password at the prompt, to run it. Here then, is the command to copy/paste into the Terminal:
sudo nano /etc/systemd/system/acpi-wake.service

C. Highlight, Copy, and Paste all of the text in the box below, into the Nano window that's now running in your Terminal app:


[Unit]
Description=ACPI Wake Service

[Service]
Type=oneshot
ExecStart=/bin/sh -c "for i in $(cat /proc/acpi/wakeup|grep enabled|awk '{print $1}'|xargs); do [ $i != PBTN ] && echo $i|tee /proc/acpi/wakeup;done"

[Install]
WantedBy=multi-user.target

Note that the command line in the middle of the box is long and may extend beyond the edge of the box above, and of the Nano window when you paste it in. You may have scrollbars at the side, bottom or top of your web browser, Terminal and/or Nano window(s) that enable you to see the whole thing during copy and paste if you're curious. But if you start your mouse inside the top-left of the box above and drag to the bottom inside of the box, all of the text will be highlighted even if it extends beyond the right margin. Here's how it looks after pasting into Nano on my PC:

D. Save the file and Exit the Nano app. To do that, first hold down the Ctrl key and tap the letter "O" key (lower or UPPER case works fine) to "Write Out" (Save) the file. It's already named by the "sudo..." command line you pasted into the Terminal app to launch Nano in Step 1.B above. Now you can Exit the Nano app by holding down the Ctrl key and tapping the letter "x" key.

Step 2. Launch the file with the Start command. Copy the line in the box below, and paste it into the Terminal window, tap the Enter key, and input your Password at the prompt.

systemctl start acpi-wake.service

Step 3. Activate the file with the Enable command. Copy the line in the box below, and paste it into the Terminal window, tap the Enter key, and input your Password at the prompt.

systemctl enable acpi-wake.service

You're done. Now to test whether this method works on your PC, just Suspend it using your normal method and then try tapping keys and mouse buttons. If it doesn't work, you could try the methods that didn't work for me or post a Help request to see if someone can come up with a way to do it.

If you want to only disable one or more specific input devices from waking your PC, it's more complex because you'll need to find the code(s) for such device(s) and either change the long command you put into the
/etc/systemd/system/acpi-wake.service
file with Nano above, or do that using one of the more complex methods that didn't work for me. If that's your goal, post a followup question and maybe someone can help. Good luck! :slightly_smiling_face:

System Details:
I strongly suspect this will work on most if not all PCs running Ubuntu Mate 20.04.1 with all Updates applied. As mentioned above, simply setting the BIOS to disable USB from waking the PC used to work fine with this Mate version and the Mate wizards may already be working on an easy way to do it somewhere in the System Settings apps or elsewhere. Here then are my system details:
Kernel Linux 5.4.0-56-generic x86_64
MATE 1.24.0
Dell Desktop
BIOS version 2.13.0
Mfg. 11/2019
RAM 12GB
CPI Core i5-9400 2.9GHz

2 Likes

Hi,

You asked for an explanation, here its is :innocent:

ExecStart=/bin/sh -c "for i in $(cat /proc/acpi/wakeup|grep enabled|awk '{print $1}'|xargs); do [ $i != PBTN ] && echo $i|tee /proc/acpi/wakeup;done"

  1. This starts a posix shell (/bin/sh) to executes a command (-c)
  2. Then it greps all enabled devices from the wakeup event list (cat not needed)
  3. Awk prints the first column from the wakeup eventlist (grep not needed)
  4. Xargs puts then in a row instead of a list. (not needed)
  5. The list of enabled device names is then fed back to the wakeup eventlist to disable that device.
  6. Its skips PBTN, as you need at least one event to trigger a wakeup.

'tee' is used to echo this to

  1. the terminal
  2. to /proc/acpi/wakeup, thereby disabling that device.

The reason you need sudo is because you don't have write access to /proc/acpi/wakeup.

This semi script is then put as a one-liner into a systemd script, that needs proper rights to execute the above.
Then you need sudo to create/enable/disable the script.
This is smart thing, because you can easily disable the script and then reboot to return to normal.

However, a simpler way of doing this, use this line:

ExecStart=/bin/sh -c "for i in $(awk '{ if ($3=="*enabled") print $1}' /proc/acpi/wakeup);do case $i in PBTN|PWRB) continue;;*) echo $i|tee /proc/acpi/wakeup;;esac;done"

  1. This starts a posix shell (/bin/sh) to executes a command (-c)
  2. Then uses awk to get all enabled devices from the wakeup event list and only print the first column
  3. Then iterates over the items to disable by echoing them to /proc/acpi/wakeup
  4. Its skips PBTN and PWRB in my case, as you need at least one event to trigger a wakeup.

In conclusion: you need to add another step to make sure your powerbutton acronym is supported. Lets say yours is 1234 and not in the list. Then you need to add it to the case statement like this: PBTN|PWRB|1234)

:smiley:

1 Like

Excellent explanation! Thanks, Guy. :smiley:

Regards the power button, how would I find out the code for it? As described in my writeup, the power button still works even though everything is disabled by karnemelk's script. After running it, if I run this line in Terminal:
cat /proc/acpi/wakeup | sort
every device listed is disabled. So I guess either the power button isn't listed there, or the disabled setting doesn't disable it (BIOS over-ride?).

Clearly this could be a very important item to check on, if karnemelk's script disables Power Button Wake from Suspend on some PCs. Hopefully the power button would show up with some obvious code in a
cat /proc/acpi/wakeup | sort
list on any PC where disabling it could mean a hard boot to Wake from Suspend.

Yes, sometimes its not that clear and you have to go through the /proc/acpi/wakeup manually.

What I would do in a situation like that:

  1. grep enabled /proc/acpi/wakeup
  2. start disabling them one by one until the powerbutton stops responding.

Therefor keep one of them enabled that is not the powerbutton :wink:

1 Like

Thanks for the followup, Guy. It will probably be very helpful for most users working on this. In my case, the power button code is apparently listed and possibly deactivated somewhere else. As I mentioned above, cat /proc/acpi/wakeup | sort shows everything disabled. So I guess that's also why your suggestion of grep enabled /proc/acpi/wakeup silently returns no output. Wish I could recall where in my system there was an entirely different listing of device codes, and whether one of those gave some indication of relating to the power button. Anyway, the bottom line for me is that with everything disabled in /proc/acpi/wakeup the keyboard and mouse no longer wake from Suspend but happily the power button does. :slightly_smiling_face:

Thanks again for your code clarification, and especially for offering an improved version for others seeking a solution.

Looks like you're trying to use a for loop in a systemd service file to modify the /proc/acpi/wakeup file. The issue here is with the command substitution $(...) inside double quotes. When you use double quotes, the command substitution runs immediately, and the result is inserted into the command. However, in this case, you probably want the for loop to be executed dynamically when the service starts.

To achieve this, you should use single quotes to delay the command substitution until runtime. Also, it's a good practice to include the complete path for commands and avoid unnecessary cat and grep combinations. Here's an updated version of your ExecStart line:

ExecStart=/bin/sh -c 'for i in $(awk "/enabled/{print \$1}" /proc/acpi/wakeup); do [ "$i" != "PBTN" ] && [ "$i" != "PWRB" ] && echo "$i" | tee /proc/acpi/wakeup; done || true'

In this version, I replaced $(cat ... | grep ... | awk ... | xargs) with a more streamlined awk command. Also, I corrected the [ "$i" != "PBTN" ] condition to use proper syntax for string comparison. The whole command is enclosed in single quotes to prevent premature command substitution.


Add || true to the end of command, otherwise it throws an error

systemd[1]: Starting ACPI Wake Service...
systemd[1]: acpi-wake.service: Main process exited, code=exited, s>
systemd[1]: acpi-wake.service: Failed with result 'exit-code'.
systemd[1]: Failed to start ACPI Wake Service.

Ansible

An Ansible role might look like this

---
- name: Copy acpi-wake.service
  copy:
    src: acpi-wake.service
    dest: /etc/systemd/system/

- name: Reload systemd
  ansible.builtin.systemd:
    name: acpi-wake.service
    state: restarted
    enabled: true
2 Likes

Welcome @obopeqe to the community!

1 Like

Thanks :grinning:
I haven't logged in for a while, so just now saw your helpful suggestion. For whatever reason(s), the solution I found is still working flawlessly so I'm unlikely to mess with it for now. Also, as you've noted, my comprehension of scripting is less than minimal so I have little clue how your proposed solution works. Clearly if my current kludge stops working I'll be back to take a crack at figuring it out. Meanwhile I'm savoring the discovery of another helpful option.
Thanks :grinning:

1 Like