É possível reiniciar a conexão de um dispositivo USB, sem desconectar/conectar fisicamente do PC?
Especificamente, o meu aparelho é uma câmara digital. I'estou usando gphoto2
, mas ultimamente eu recebo "erros de leitura do dispositivo" então I'gostaria de tentar fazer uma reinicialização do software da conexão.
Pelo que eu posso dizer, não há módulos do kernel sendo carregados para a câmera. O único que parece relacionado é o usbhid
.
Salvar o seguinte como usbreset.c
/* usbreset -- send a USB port reset to a USB device */
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <linux/usbdevice_fs.h>
int main(int argc, char **argv)
{
const char *filename;
int fd;
int rc;
if (argc != 2) {
fprintf(stderr, "Usage: usbreset device-filename\n");
return 1;
}
filename = argv[1];
fd = open(filename, O_WRONLY);
if (fd < 0) {
perror("Error opening output file");
return 1;
}
printf("Resetting USB device %s\n", filename);
rc = ioctl(fd, USBDEVFS_RESET, 0);
if (rc < 0) {
perror("Error in ioctl");
return 1;
}
printf("Reset successful\n");
close(fd);
return 0;
}
Execute os seguintes comandos no terminal:
Compile o programa:
$ cc usbreset.c -o usbreset
Obtenha o Bus and Device ID do dispositivo USB que você deseja reiniciar:
lsusb
Autocarro 002 Dispositivo 003: ID 0fe9:9010 DVICO
Tornar o nosso programa compilado executável:
$ chmod +x usbreset
Executar o programa com o privilégio sudo; fazer a substituição necessária para <Bus>
e <Device>
ids como encontrado ao executar o comando lsusb
:
$ sudo ./usbreset /dev/bus/usb/002/003
Fonte do programa acima: http://marc.info/?l=linux-usb&m=121459435621262&w=2
Eu já'não me encontrei em suas circunstâncias específicas antes, então eu'não tenho certeza se ele'fará o suficiente, mas a maneira mais simples que eu'encontrei para reiniciar um dispositivo USB é este comando: (Nenhuma aplicação externa é necessária)
sudo sh -c "echo 0 > /sys/bus/usb/devices/1-4.6/authorized"
sudo sh -c "echo 1 > /sys/bus/usb/devices/1-4.6/authorized"
Esse'é o verdadeiro que eu uso para reiniciar meu Kinect, já que o libfreenect parece não ter API para colocá-lo de volta no sono. It's na minha caixa do Gentoo, mas o kernel deve ser novo o suficiente para usar a mesma estrutura de caminho para o sysfs.
O seu obviamente não seria 1-4.6' mas você pode puxar o caminho do dispositivo do seu kernel log (
dmesg') ou você pode usar algo como `lsusb' para obter as IDs do fornecedor e do produto e então usar um comando rápido como este para listar como os caminhos se relacionam com os diferentes pares de IDs de fornecedor/produto:
for X in /sys/bus/usb/devices/*; do
echo "$X"
cat "$X/idVendor" 2>/dev/null
cat "$X/idProduct" 2>/dev/null
echo
done
Isto irá reiniciar todas as portas USB1/2/3 anexadas[1]:
for i in /sys/bus/pci/drivers/[uoex]hci_hcd/*:*; do
[ -e "$i" ] || continue
echo "${i##*/}" > "${i%/*}/unbind"
echo "${i##*/}" > "${i%/*}/bind"
done
Acredito que isto vai resolver o seu problema. Se você não quiser redefinir todos os pontos finais USB, você pode utilizar o ID do dispositivo apropriado de /sys/bus/pci/drivers/ehci_hcd
.
Notas:
[1]: os drivers do kernel *hci_hcd
tipicamente controlam as portas USB. O ohci_hcd
e o uhci_hcd
são para portas USB1.1, o ehci_hcd
é para portas USB2 e o xhci_hcd
é para portas USB3. (veja https://en.wikipedia.org/wiki/Host_controller_interface_(USB,_Firewire))