Nesta dica veremos como reiniciar um dispositivo USB sem a necessidade de desconectar/conectar o cabo do PC. Isso pode ser bem útil em casos onde o dispositivo plugado apresenta instabilidade. Li relatos de que isso ocorre em algumas câmeras digitais.
No meu caso, estou desenvolvendo scripts para teste de UI em dispositivos Android e após algumas horas conectado ao PC, meu celular começava a apresentar comunicação instável com o adb (Android Debugger Bridge). Antes desta solução, minha única saída era desconectar/conectar o cabo, o que inviabilizava a execução do script de forma automática.
Solução 1 - Resetando todos os dispositivos USB
O programa abaixo reinicia todos os dispositivos USB conectados ao PC.
#include <stdio.h>
#include <usb.h>
int main(void)
{
struct usb_bus *busses;
usb_init();
usb_find_busses();
usb_find_devices();
busses = usb_get_busses();
struct usb_bus *bus;
int c, i, a;
/* ... */
for (bus = busses; bus; bus = bus->next) {
struct usb_device *dev;
int val;
usb_dev_handle *junk;
for (dev = bus->devices; dev; dev = dev->next) {
char buf[1024];
junk = usb_open ( dev );
usb_get_string_simple(junk,2,buf,1023);
if ( junk == NULL ){
printf("Can't open %p (%s)\n", dev, buf );
} else {
val = usb_reset(junk);
printf( "reset %p %d (%s)\n", dev, val, buf );
}
usb_close(junk);
}
}
}
Salve o código acima num arquivo e compile-o. Salvei como
usb_reset_all.c:
gcc -o usb_reset_all usb_reset_all.c
Agora basta executar e conferir o resultado nos logs:
./usb_reset_all
$ sudo tail -f /var/log/syslog
Fonte:
Resetting the USB Bus under linux - ClearChain
Solução 2 - Resetando apenas um dispositivo
Se você deseja escolher o dispositivo a ser reiniciado, utilize o código a seguir.
#include <stdio.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <linux/usbdevice_fs.h>
void main(int argc, char **argv)
{
const char *filename;
int fd;
filename = argv[1];
fd = open(filename, O_WRONLY);
ioctl(fd, USBDEVFS_RESET, 0);
close(fd);
return;
}
Salve o código acima num arquivo e compile-o. Salvei como
usb_reset_one.c:
gcc -o usb_reset_one usb_reset_one.c
Antes de executá-lo devemos identificar o dispositivo a ser reiniciado. No meu caso um celular da Samsung:
lsusb
Bus 001 Device 002: ID 046d:c408 Logitech, Inc. Marble Mouse (4-button)
Bus 001 Device 003: ID 045e:009d Microsoft Corp. Wireless Optical Desktop 3.0
Bus
004 Device
110: ID 04e8:6866 Samsung Electronics Co., Ltd
Bus 001 Device 001: ID 1d6b:0001
Linux Foundation 1.1 root hub
Bus 002 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub
Bus 003 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub
Bus 004 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub
Ou seja, dispositivo 110 do barramento 004.
Sendo assim:
./usb_reset_one /dev/bus/usb/004/110
Fonte:
How to reset a USB device without unplugging Linux from the command line | Linux world
Fico por aqui. Sei que trata-se de uma necessidade pouco comum, mas espero que ajude quem por ventura venha a precisar.
Não estava conseguindo compilar o primeiro código.
Só consegui deste jeito:
#include <stdio.h>
#include <usb.h>
int main(void)
{
struct usb_bus *busses;
usb_init();
usb_find_busses();
usb_find_devices();
busses = usb_get_busses();
struct usb_bus *bus;
int c, i, a;
/* ... */
for (bus = busses; bus; bus = bus->next) {
struct usb_device *dev;
int val;
usb_dev_handle *junk;
for (dev = bus->devices; dev; dev = dev->next) {
char buf[1024];
junk = usb_open ( dev );
usb_get_string_simple(junk,2,buf,1023);
if ( junk == NULL ){
printf("Can't open %p (%s)\n", dev, buf );
} else {
val = usb_reset(junk);
printf( "reset %p %d (%s)\n", dev, val, buf );
}
usb_close(junk);
}
}
}
E pra compilar usei o comando:
gcc -o reset_all_usb reset_all_usb.c -lusb