SegFault

Reset a USB device on Linux

December 10 , 2017

In one of my projects, a USB Bluetooth stick was placed in a place that is not accessible anymore. However, after building we found out that after changing into power saving mode the stick does not work correctly anymore. Only disconnecting and reconnecting it to the port helped to make the stick usable again. 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;
}

The important part is two lines which open and resets the device.
First, you have to open the device as you would do with a normal file:

int fd = open(file, O_WRONLY);

And then it gets reset using a special ioctl that's only valid for USB devices:

int rc = ioctl(fd, USBDEVFS_RESET, 0);

The rest of the code is related to error handling and argument checking.

Now you just need to compile the program and move it to an accessible place in the filesystem.

gcc -o usbreset usbreset.c
sudo mv ./usbreset /usr/bin/usbreset

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