Controlling a USB power supply (on/off) with Linux
Note. The information in this answer is relevant for the older kernels (up to 2.6.32). See tlwhitec's answer for the information on the newer kernels.
# disable external wake-up; do this only once
echo disabled > /sys/bus/usb/devices/usb1/power/wakeup
echo on > /sys/bus/usb/devices/usb1/power/level # turn on
echo suspend > /sys/bus/usb/devices/usb1/power/level # turn off
(You may need to change usb1 to usb n)
Source: Documentation/usb/power-management.txt.gz
Linux USB: turning the power on and off?
Digs through bookmarks
http://blog.andrew.net.au/2009/01/01#usb_power_control
Seems like you need to connect it to a hub and control the hub's power. None of the root hubs I have seen seems to be able to support power control.
How to turn USB port power on and off in Raspberry PI 4
Yes, uhubctl supports RPi4B, I have recently added support for it - you need to use uhubctl version 2.4.0 or later (or build it from master branch). It is also necessary to update USB firmware using sudo rpi-eeprom-update
to make power switching actually work.
Note that you are missing out by using sysfs method to turn USB off on RPi3B+ - using uhubctl you can control either all 4 ports, or 2 of them independently. RPi4B only supports turning off all ports at once.
Turn off power to a USB port
Indeed, that other question did have a technique that worked for what I was trying to do. Note this isn't a generic Linux answer, it will only work on BeagleBone Black and similar devices. (I tested on a BeagleBone Green.) Working backwards from the devmem2
example, this block of C++ code turns the USB power off, then back on:
const size_t page_size_in_bytes = getpagesize();
const size_t address_gpio3_13 = 0x47401c60; // see comment below
const size_t address_start = address_gpio3_13 / page_size_in_bytes * page_size_in_bytes;
const size_t address_offset = address_gpio3_13 - address_start;
int fd = open("/dev/mem", O_RDWR);
void *addr = mmap( 0, page_size_in_bytes, PROT_READ | PROT_WRITE, MAP_SHARED, fd, address_start );
uint8_t *byte_ptr = reinterpret_cast<uint8_t*>(addr);
byte_ptr[address_offset] = 0x00; // turn off USB
std::this_thread::sleep_for( std::chrono::milliseconds(500) );
byte_ptr[address_offset] = 0x01; // turn on USB
munmap( addr, page_size_in_bytes );
close(fd);
(Error handling not included.)
The magic number 0x47401c60
really is a magic number. According to some posts, it looks like a NDA needs to be signed to get access to some of the USB-related documentation. In the ARM335X Technical Reference Manual, the only mention of the 0x47401Cxx address space is the following on page 156:
Block Name Start Address End Address
USB1 Core 0x4740_1C00 0x4740_1FFF
Related Topics
Register Variables in Loop in an Ansible Playbook
Execute Command on Remote Server via Ssh
How to Replace All Lines Between Two Points and Subtitute It with Some Text in Sed
Read a Single Sector from a Disk
Use Perf Inside a Docker Container Without --Privileged
Using 'Find' to Return Filenames Without Extension
Why Does C99 Complain About Storage Sizes
Error: Service "Xxx" Uses an Undefined Network "Xxx"
/Proc/$Pid/Maps Shows Pages with No Rwx Permissions on X86_64 Linux
Add Text Between Two Patterns in File Using Sed Command
Execute Sudo Command on Linux from Plink.Exe on Windows
Use Grep to Find Content in Files and Move Them If They Match
How to Convert ".." in Path Names to Absolute Name in a Bash Script
Why Is Dd with the 'Direct' (O_Direct) Flag So Dramatically Faster
Node Server Crashes After Few Hours
Meaning of Exit Status 1 Returned by Linux Command