Reset a USB device on Linux
In one of my projects, a USB Bluetooth stick was placed in a place that is not accessible anymore. However, after building it was found out that after changing into power saving mode the stick does not work correctly anymore, which was only solvable by disconnecting and reconnecting it to the port. However we do not have the possibility to do this anymore, so another solution had to be found. The result is a small c program that allows you to reset a USB port, which to the USB stick looks as if it was reconnected.
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <linux/usbdevice_fs.h>
static int reset_device(const char* file) {
int fd = open(file, O_WRONLY);
if (fd < 0) {
perror("Error opening output file");
return 1;
}
printf("Resetting USB device %s: ", file);
int rc = ioctl(fd, USBDEVFS_RESET, 0);
if (rc < 0) {
printf("Failed\n");
close(fd);
return 1;
}
printf("OK\n");
close(fd);
}
int main(int argc, char **argv)
{
if (argc < 2) {
fprintf(stderr, "Usage: usbreset device-filenames\n");
return 1;
}
int failed = 0;
for(int i=1; i<argc; i++) {
failed += reset_device(argv[i]);
}
return failed;
}
First we have to open the device as we would do with any normal file:
int fd = open(file, O_WRONLY);
After we have an active handle to the usb device we can reset it using a special ioctl provided by usbdevfs:
int rc = ioctl(fd, USBDEVFS_RESET, 0);
The rest of the code is related to error handling and argument checking.
Now we just need to compile the program and move it to an accessible place in the filesystem.
gcc -o ~/bin/usbreset usbreset.c
It's now possible to reset any USB device you like:
random@linux:~/Documents$ lsusb
[...]
Bus 001 Device 004: ID 1131:1001 Integrated System Solution Corp. KY-BT100 Bluetooth Adapter
random@linux:~/Documents$ sudo ./usbreset /dev/bus/usb/001/004
Resetting USB device /dev/bus/usb/001/004: OK