PC ile fiziksel olarak bağlantısı kesilmeden/bağlanmadan bir USB cihazının bağlantısını sıfırlamak mümkün müdür?
Özellikle, cihazım dijital bir kamera. gphoto2
kullanıyorum, ancak son zamanlarda "aygıt okuma hatası" alıyorum, bu yüzden bağlantının yazılımını sıfırlamayı denemek istiyorum.
Söyleyebileceğim kadarıyla, kamera için yüklü çekirdek modülü yok. İlişkili görünen tek kişi usbhid
.
Aşağıdakileri usbreset.c
olarak kaydedin
/* 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;
}
Çalıştır terminalde aşağıdaki komutları:
Programı derleyin:
$ cc usbreset.c -o usbreset
Sıfırlamak istediğiniz USB cihazının Veri Yolu ve Cihaz Kimliğini alın:
$ lsusb
Bus 002 Device 003: ID 0fe9:9010 DVICO
Derlenmiş programımızın çalıştırılabilir olmasını sağlayın:
$ chmod +x usbreset
Sudo ayrıcalığı ile programı yürütün; lsusb
komutunu çalıştırarak bulunan <Bus>
ve <Device>
id için gerekli değişimi yapın:
$ Sudo ./usbreset /dev/bus/usb/002/003
Yukarıdaki programın kaynağı: http://marc.info/?l=linux-usb&m=121459435621262&w=2
Kendimi daha önce sizin kendi şartlarınızda bulamadım, bu yüzden yeterli olup olmadığından emin değilim, ancak bir USB cihazını sıfırlamak için bulduğum en basit yöntem şudur: (Harici uygulama gerekmez)
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"
Bu benim Kinect'imi sıfırlamak için kullandığım gerçek. Çünkü libfreenect, tekrar uyku moduna geçirecek API yok. Gentoo kutumda, ancak çekirdek, sysfs için aynı yol yapısını kullanacak kadar yeni olmalıdır.
Açıkçası 1-4.6
olmazdı ancak bu aygıt yolunu çekirdek günlüğünüzden (dmesg
) çekebilir ya da satıcı ve ürün kimliklerini almak için lsusb
gibi bir şey kullanabilirsiniz ve sonra yolların farklı satıcı/ürün kimliği çiftleriyle nasıl ilişkili olduğunu listelemek için böyle hızlı bir komut kullanın:
for X in /sys/bus/usb/devices/*; do
echo "$X"
cat "$X/idVendor" 2>/dev/null
cat "$X/idProduct" 2>/dev/null
echo
done
Bu, USB1/2/3 ekli bağlantı noktalarının tümünü [1] sıfırlar:
for i in /sys/bus/pci/drivers/[uoex]hci_hcd/*:*; do
[ -e "$i" ] || continue
echo "${i##*/}" > "${i%/*}/unbind"
echo "${i##*/}" > "${i%/*}/bind"
done
Bunun senin problemini çözeceğine inanıyorum. Tüm USB uç noktalarını sıfırlamak istemiyorsanız, uygun cihaz kimliğini /sys/bus/pci/drivers/ehci_hcd
Notlar: [1]: *hci_hcd
çekirdek sürücüleri genellikle USB bağlantı noktalarını kontrol eder. ohci_hcd
ve uhci_hcd
, USB1.1 bağlantı noktaları içindir, ehci_hcd
, USB2 bağlantı noktaları içindir ve xhci_hcd
, USB3 bağlantı noktaları içindir. (bkz https://en.wikipedia.org/wiki/Host_controller_interface_ (USB, _Firewire) )
Bunu bir python betiğinde otomatikleştirmem gerekiyordu, bu yüzden LiLo'nun son derece yararlı cevabını aşağıdakilere uyarladım:
#!/usr/bin/env python
import os
import sys
from subprocess import Popen, PIPE
import fcntl
driver = sys.argv[-1]
print "resetting driver:", driver
USBDEVFS_RESET= 21780
try:
lsusb_out = Popen("lsusb | grep -i %s"%driver, Shell=True, bufsize=64, stdin=PIPE, stdout=PIPE, close_fds=True).stdout.read().strip().split()
bus = lsusb_out[1]
device = lsusb_out[3][:-1]
f = open("/dev/bus/usb/%s/%s"%(bus, device), 'w', os.O_WRONLY)
fcntl.ioctl(f, USBDEVFS_RESET, 0)
except Exception, msg:
print "failed to reset device:", msg
Benim durumumda cp210x sürücüsü (lsmod | grep usbserial
öğesinden söyleyebilirim), bu yüzden yukarıdaki kod parçasını reset_usb.py olarak kaydedebilir ve sonra bunu yapabilirsiniz:
Sudo python reset_usb.py cp210x
Sisteminizde zaten bir c derleyici kurulumu yoksa, ancak pythonunuz varsa da bu yardımcı olabilir.
Buradaki cevaplara dayanarak tüm süreci basitleştiren bir Python betiği oluşturdum.
Aşağıdaki betiği reset_usb.py ya da klon bu repo olarak kaydedin.
Kullanımı:
python reset_usb.py help # Show this help
Sudo python reset_usb.py list # List all USB devices
Sudo python reset_usb.py path /dev/bus/usb/XXX/YYY # Reset USB device using path /dev/bus/usb/XXX/YYY
Sudo python reset_usb.py search "search terms" # Search for USB device using the search terms within the search string returned by list and reset matching device
Sudo python reset_usb.py listpci # List all PCI USB devices
Sudo python reset_usb.py pathpci /sys/bus/pci/drivers/.../XXXX:XX:XX.X # Reset PCI USB device using path /sys/bus/pci/drivers/.../XXXX:XX:XX.X
Sudo python reset_usb.py searchpci "search terms" # Search for PCI USB device using the search terms within the search string returned by listpci and reset matching device
Senaryo:
#!/usr/bin/env python
import os
import sys
from subprocess import Popen, PIPE
import fcntl
instructions = '''
Usage: python reset_usb.py help : Show this help
Sudo python reset_usb.py list : List all USB devices
Sudo python reset_usb.py path /dev/bus/usb/XXX/YYY : Reset USB device using path /dev/bus/usb/XXX/YYY
Sudo python reset_usb.py search "search terms" : Search for USB device using the search terms within the search string returned by list and reset matching device
Sudo python reset_usb.py listpci : List all PCI USB devices
Sudo python reset_usb.py pathpci /sys/bus/pci/drivers/.../XXXX:XX:XX.X : Reset PCI USB device using path
Sudo python reset_usb.py searchpci "search terms" : Search for PCI USB device using the search terms within the search string returned by listpci and reset matching device
'''
if len(sys.argv) < 2:
print(instructions)
sys.exit(0)
option = sys.argv[1].lower()
if 'help' in option:
print(instructions)
sys.exit(0)
def create_pci_list():
pci_usb_list = list()
try:
lspci_out = Popen('lspci -Dvmm', Shell=True, bufsize=64, stdin=PIPE, stdout=PIPE, close_fds=True).stdout.read().strip().decode('utf-8')
pci_devices = lspci_out.split('%s%s' % (os.linesep, os.linesep))
for pci_device in pci_devices:
device_dict = dict()
categories = pci_device.split(os.linesep)
for category in categories:
key, value = category.split('\t')
device_dict[key[:-1]] = value.strip()
if 'USB' not in device_dict['Class']:
continue
for root, dirs, files in os.walk('/sys/bus/pci/drivers/'):
slot = device_dict['Slot']
if slot in dirs:
device_dict['path'] = os.path.join(root, slot)
break
pci_usb_list.append(device_dict)
except Exception as ex:
print('Failed to list pci devices! Error: %s' % ex)
sys.exit(-1)
return pci_usb_list
def create_usb_list():
device_list = list()
try:
lsusb_out = Popen('lsusb -v', Shell=True, bufsize=64, stdin=PIPE, stdout=PIPE, close_fds=True).stdout.read().strip().decode('utf-8')
usb_devices = lsusb_out.split('%s%s' % (os.linesep, os.linesep))
for device_categories in usb_devices:
if not device_categories:
continue
categories = device_categories.split(os.linesep)
device_stuff = categories[0].strip().split()
bus = device_stuff[1]
device = device_stuff[3][:-1]
device_dict = {'bus': bus, 'device': device}
device_info = ' '.join(device_stuff[6:])
device_dict['description'] = device_info
for category in categories:
if not category:
continue
categoryinfo = category.strip().split()
if categoryinfo[0] == 'iManufacturer':
manufacturer_info = ' '.join(categoryinfo[2:])
device_dict['manufacturer'] = manufacturer_info
if categoryinfo[0] == 'iProduct':
device_info = ' '.join(categoryinfo[2:])
device_dict['device'] = device_info
path = '/dev/bus/usb/%s/%s' % (bus, device)
device_dict['path'] = path
device_list.append(device_dict)
except Exception as ex:
print('Failed to list usb devices! Error: %s' % ex)
sys.exit(-1)
return device_list
if 'listpci' in option:
pci_usb_list = create_pci_list()
for device in pci_usb_list:
print('path=%s' % device['path'])
print(' manufacturer=%s' % device['SVendor'])
print(' device=%s' % device['SDevice'])
print(' search string=%s %s' % (device['SVendor'], device['SDevice']))
sys.exit(0)
if 'list' in option:
usb_list = create_usb_list()
for device in usb_list:
print('path=%s' % device['path'])
print(' description=%s' % device['description'])
print(' manufacturer=%s' % device['manufacturer'])
print(' device=%s' % device['device'])
print(' search string=%s %s %s' % (device['description'], device['manufacturer'], device['device']))
sys.exit(0)
if len(sys.argv) < 3:
print(instructions)
sys.exit(0)
option2 = sys.argv[2]
print('Resetting device: %s' % option2)
# echo -n "0000:39:00.0" | tee /sys/bus/pci/drivers/xhci_hcd/unbind;echo -n "0000:39:00.0" | tee /sys/bus/pci/drivers/xhci_hcd/bind
def reset_pci_usb_device(dev_path):
folder, slot = os.path.split(dev_path)
try:
fp = open(os.path.join(folder, 'unbind'), 'wt')
fp.write(slot)
fp.close()
fp = open(os.path.join(folder, 'bind'), 'wt')
fp.write(slot)
fp.close()
print('Successfully reset %s' % dev_path)
sys.exit(0)
except Exception as ex:
print('Failed to reset device! Error: %s' % ex)
sys.exit(-1)
if 'pathpci' in option:
reset_pci_usb_device(option2)
if 'searchpci' in option:
pci_usb_list = create_pci_list()
for device in pci_usb_list:
text = '%s %s' % (device['SVendor'], device['SDevice'])
if option2 in text:
reset_pci_usb_device(device['path'])
print('Failed to find device!')
sys.exit(-1)
def reset_usb_device(dev_path):
USBDEVFS_RESET = 21780
try:
f = open(dev_path, 'w', os.O_WRONLY)
fcntl.ioctl(f, USBDEVFS_RESET, 0)
print('Successfully reset %s' % dev_path)
sys.exit(0)
except Exception as ex:
print('Failed to reset device! Error: %s' % ex)
sys.exit(-1)
if 'path' in option:
reset_usb_device(option2)
if 'search' in option:
usb_list = create_usb_list()
for device in usb_list:
text = '%s %s %s' % (device['description'], device['manufacturer'], device['device'])
if option2 in text:
reset_usb_device(device['path'])
print('Failed to find device!')
sys.exit(-1)
Sorunun özel durumu gphoto2'nin USB üzerindeki bir kamerayla iletişim problemi olması nedeniyle, gphoto2'de USB bağlantısını sıfırlamak için bir seçenek var:
gphoto2 --reset
Belki de soru sorulduğunda 2010'da bu seçenek yoktu.
Aygıt numarasına göre belirli bir USB aygıtını sıfırlayacak python komut dosyası yaptım. Cihaz numarasını lsusb komutundan öğrenebilirsiniz.
örneğin:
$ lsusb
Bus 002 Device 004: ID 046d:c312 Logitech, Inc. DeLuxe 250 Keyboard
Bu dizgede 004 cihaz numarasıdır
import os
import argparse
import subprocess
path='/sys/bus/usb/devices/'
def runbash(cmd):
p = subprocess.Popen(cmd, Shell=True, stdout=subprocess.PIPE)
out = p.stdout.read().strip()
return out
def reset_device(dev_num):
sub_dirs = []
for root, dirs, files in os.walk(path):
for name in dirs:
sub_dirs.append(os.path.join(root, name))
dev_found = 0
for sub_dir in sub_dirs:
if True == os.path.isfile(sub_dir+'/devnum'):
fd = open(sub_dir+'/devnum','r')
line = fd.readline()
if int(dev_num) == int(line):
print ('Your device is at: '+sub_dir)
dev_found = 1
break
fd.close()
if dev_found == 1:
reset_file = sub_dir+'/authorized'
runbash('echo 0 > '+reset_file)
runbash('echo 1 > '+reset_file)
print ('Device reset successful')
else:
print ("No such device")
def main():
parser = argparse.ArgumentParser()
parser.add_argument('-d', '--devnum', dest='devnum')
args = parser.parse_args()
if args.devnum is None:
print('Usage:usb_reset.py -d <device_number> \nThe device number can be obtained from lsusb command result')
return
reset_device(args.devnum)
if __name__=='__main__':
main()
Sıfırlamanın en hızlı yolu, USB denetleyicisinin kendisini sıfırlamak olacaktır. Bunu yapmak, udev'i cihazın bağlantı kesilmesinde kaydını silmeye zorlar ve etkinleştirdikten sonra kayıt işlemi geri döner.
echo -n "0000:00:1a.0" | tee /sys/bus/pci/drivers/ehci_hcd/unbind
echo -n "0000:00:1d.0" | tee /sys/bus/pci/drivers/ehci_hcd/unbind
echo -n "0000:00:1a.0" | tee /sys/bus/pci/drivers/ehci_hcd/bind
echo -n "0000:00:1d.0" | tee /sys/bus/pci/drivers/ehci_hcd/bind
Bu, çoğu PC ortamı için çalışmalıdır. Bununla birlikte, bazı özel donanımlar kullanıyorsanız, cihaz adlarını basitçe yineleyebilirsiniz. Bu yöntemle cihazın ismini lsusb ile bulmanız gerekmez. Ayrıca otomatik bir betiğe dahil edebilirsiniz.
Modülleri yeniden yükleyerek bir tür balyoz kullanıyorum. Bu benim usb_reset.sh betiğim:
#!/bin/bash
# USB drivers
rmmod xhci_pci
rmmod ehci_pci
# uncomment if you have firewire
#rmmod ohci_pci
modprobe xhci_pci
modprobe ehci_pci
# uncomment if you have firewire
#modprobe ohci_pci
Ve bu, benim sistem yöneticim olan /usr/lib/systemd/system/usbreset.service 'dir.
[Unit]
Description=usbreset Service
After=gdm.service
Wants=gdm.service
[Service]
Type=oneshot
ExecStart=/path/to/usb_reset.sh
İşte yalnızca eşleşen bir ürün/satıcı kimliğini sıfırlayacak komut dosyası.
#!/bin/bash
set -euo pipefail
IFS=$'\n\t'
VENDOR="045e"
PRODUCT="0719"
for DIR in $(find /sys/bus/usb/devices/ -maxdepth 1 -type l); do
if [[ -f $DIR/idVendor && -f $DIR/idProduct &&
$(cat $DIR/idVendor) == $VENDOR && $(cat $DIR/idProduct) == $PRODUCT ]]; then
echo 0 > $DIR/authorized
sleep 0.5
echo 1 > $DIR/authorized
fi
done
belirli bir USB cihazını sıfırlamak için basit bir bash betiği yaptım.
#!/bin/bash
#type lsusb to find "vendor" and "product" ID in terminal
set -euo pipefail
IFS=$'\n\t'
#edit the below two lines of vendor and product values using lsusb result
dev=$(lsusb -t | grep usbdevicename | grep 'If 1' | cut -d' ' -f13|cut -d"," -f1)
#VENDOR=05a3
#PRODUCT=9230
VENDOR=$(lsusb -s $dev | cut -d' ' -f6 | cut -d: -f1)
PRODUCT=$(lsusb -s $dev | cut -d' ' -f6 | cut -d: -f2)
for DIR in $(find /sys/bus/usb/devices/ -maxdepth 1 -type l); do
if [[ -f $DIR/idVendor && -f $DIR/idProduct &&
$(cat $DIR/idVendor) == $VENDOR && $(cat $DIR/idProduct) == $PRODUCT ]]; then
echo 0 > $DIR/authorized
sleep 0.5
echo 1 > $DIR/authorized
fi
done
Bazen bu işlemi VID (satıcı kimliği) ve PID (ürün kimliği) ile tanımlanan belirli bir cihazda yapmak istiyorum. Bu, güzel libusb kütüphanesini kullanan, bu amaç için faydalı bulduğum bir betik.
İlk çalıştırma:
Sudo apt-get install libusb-dev
Daha sonra, bu c ++ dosyasının resetDeviceConnection cihazı, vid ve pid ile tanımlandığı şekilde bir cihaz bağlantısını sıfırlamak için bu görevi gerçekleştirmelidir.
#include <libusb-1.0/libusb.h>
int resetDeviceConnection(UINT_16 vid, UINT_16 pid){
/*Open libusb*/
int resetStatus = 0;
libusb_context * context;
libusb_init(&context);
libusb_device_handle * dev_handle = libusb_open_device_with_vid_pid(context,vid,pid);
if (dev_handle == NULL){
printf("usb resetting unsuccessful! No matching device found, or error encountered!\n");
resetStatus = 1;
}
else{
/*reset the device, if one was found*/
resetStatus = libusb_reset_device(dev_handle);
}
/*exit libusb*/
libusb_exit(context);
return resetStatus;
}
(kişisel TIL kataloğumdan çalındı: https://github.com/Marviel/TIL/blob/master/unix_tools/Reset_specific_USB_Device.md )
Biri bir balyoz istedi mi? Bu, burada diğer çeşitli cevaplardan bir araya getirilmiştir.
#!/bin/bash
# Root required
if (( UID )); then
exec Sudo "$0" "[email protected]"
fi
cd /sys/bus/pci/drivers
function reinit {(
local d="$1"
test -e "$d" || return
rmmod "$d"
cd "$d"
for i in $(ls | grep :); do
echo "$i" > unbind
done
sleep 1
for i in $(ls | grep :); do
echo "$i" > bind
done
modprobe "$d"
)}
for d in ?hci_???; do
echo " - $d"
reinit "$d"
done
Bunu dene, bu bir yazılım fişi.
Bazen bazı aygıtlar için aygıtın bağlantısını kolayca kaldırmaz.
Örnek:
"Genius NetScroll 120" yazılımımı kaldırmak veya çıkarmak istiyorum.
Sonra ilk takılı usb cihazımı kontrol ediyorum
$ lsusb
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 002 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 001 Device 002: ID 8087:0020 Intel Corp. Integrated Rate Matching Hub
Bus 002 Device 002: ID 8087:0020 Intel Corp. Integrated Rate Matching Hub
Bus 001 Device 003: ID 03f0:231d Hewlett-Packard
Bus 001 Device 004: ID 138a:0007 Validity Sensors, Inc. VFS451 Fingerprint Reader
Bus 001 Device 005: ID 04f2:b163 Chicony Electronics Co., Ltd
Bus 002 Device 009: ID 0458:003a KYE Systems Corp. (Mouse Systems) NetScroll+ Mini Traveler / Genius NetScroll 120 **<----This my Mouse! XDDD**
Tamam, faremi buldum, bir Bus 002, Cihaz 009, idVendor 0458 ve idProduct 003a'ya sahip, yani bu fare hakkında bir referans cihazı bilgisi.
Bu önemlidir, Veriyolu numarası cihaza başlangıç adı yoludur ve çıkarılacak doğru cihazın olduğundan emin olmak için ürün kimliğini ve Satıcısını kontrol edeceğim.
$ ls /sys/bus/usb/drivers/usb/
1-1/ 1-1.1/ 1-1.3/ 1-1.5/ 2-1/ 2-1.3/ bind uevent unbind usb1/ usb2/
Klasörlere dikkat edin, 2 numaralı klasörün başlangıcını kontrol edin, bunu kontrol edeceğim, çünkü veriyolum 002, ve birer birer birer birer fare bilgim hakkında doğru idVendor ve idProduct içeren her klasörü kontrol ettim.
Bu durumda, bu komutu kullanarak bilgiyi alacağım:
cat /sys/bus/usb/drivers/usb/2-1.3/idVendor
0458
cat /sys/bus/usb/drivers/usb/2-1.3/idProduct
003a
Tamam, /sys/bus/usb/drivers/usb/2-1.3/ yolu bilgi faremle eşleşiyor! XDDD.
Cihazı çıkarmanın zamanı geldi!
su -c "echo 1 > /sys/bus/usb/drivers/usb/2-1.3/remove"
USB cihazını tekrar takın ve tekrar çalışın!
Cihaz adınızı biliyorsanız, bu python betiği çalışacaktır:
#!/usr/bin/python
"""
USB Reset
Call as "usbreset.py <device_file_path>"
With device_file_path like "/dev/bus/usb/bus_number/device_number"
"""
import fcntl, sys, os
USBDEVFS_RESET = ord('U') << (4*2) | 20
def main():
fd = os.open(sys.argv[1], os.O_WRONLY)
if fd < 0: sys.exit(1)
fcntl.ioctl(fd, USBDEVFS_RESET, 0)
os.close(fd)
sys.exit(0)
# end main
if __== '__main__':
main()
Belki bu da bir kamera için çalışır:
Ardından açlıktan kurtulmuş bir USB 3.0
HDD benim tarafımda 3.4.42
(kernel.org) Linux. dmesg
, 360'lardan sonra komutların zaman aşımına uğradığını söyledi (üzgünüm, syslog'u buraya kopyalayamıyorum, bağlı ağları değil) ve sürücü tamamen askıya alındı. Aygıta erişen işlemler çekirdek içinde engelleniyordu, okunamıyordu. NFS
hung, ZFS
hung, dd
hung.
Bunu yaptıktan sonra her şey tekrar çalıştı. dmesg
, USB
cihazının bulunduğu hakkında yalnızca tek bir satır söyledi.
Aşağıdakilerin ayrıntılı olarak ne yaptığı hakkında hiçbir fikrim yok. Ama işe yaradı.
Aşağıdaki örnek çıktı, 2.6.32-5-686
kernel ile Debian Squeeze'den geliyor, bu yüzden 2.6 ve üzeri için çalıştığını düşünüyorum:
$ ls -al /dev/sdb
brw-rw---T 1 root floppy 8, 16 Jun 3 20:24 /dev/sdb
$ ls -al /sys/dev/block/8:16/device/rescan
--w------- 1 root root 4096 Jun 6 01:46 /sys/dev/block/8:16/device/rescan
$ echo 1 > /sys/dev/block/8:16/device/rescan
Bu işe yaramazsa, belki de başka biri cihaza nasıl gerçek bir sıfırlama gönderileceğini bulabilir.