USB in Linux
Introduction
USB device
A USB device can:
- provide a piece of hardware for USB communication
- implement the USB protocol
- implement some useful protocol
- additional hardware/software for providing desired functionality
A device can be self powered, bus powered or both.
Whenever a USB device is attached to the bus:
- it will be enumerated by the USB subsystem An unique device number (1-127) is assigned
- the device descriptor is read The desciptor is a data structure which contains information about the device and its properties.
USB endpoint
We can think the USB endpoint as the networking port, different endpoint is used for different service.
Device may have up to 31 endpoints (including ep0):
- Each of them gets a unique Endpoint address
- Endpoint 0 may transfer data in both directions
- All other endpoints may transfer data in one direction
- IN Transfer data from device to host
- OUT Transfer data from host to device
- Control
- Bi-directional endpoint
- Used for enumeration
- Can be used for application
- Interrupt
- Transfers a small amount of low-latency data
- Reserves bandwidth on the bus
- Used for time-sensitive data (HID)
- Bulk
- Used for large data transfers
- Used for large, time-insensitive data(Network packets, Mass Storage, etc).
- Does not reserve bandwidth on bus, uses whatever time is left over
- Isochronous
- Transfers a large amount of time-sensitive data
- Delivery is not guaranteed (no ACKs are sent)
- Used for Audio and Video streams
- Late data is as good as no data
- Better to drop a frame than to delay and force a re-transmission
USB host Controllers
USB host controllers are compatible with either the Open Host Controller Interface (OHCI, by Compaq) or the Universal Host Controller Interface (UHCI, by Intel) standard.
Both types have the same capabilities and USB devices work with both host controller types.
Basically the hardware of UHCI is simpler and therefore it is cheaper, but needs a more complex device driver, which could cause slightly more CPU load.
USB Complete Fifth Edition, Chapter4 Enumeration: How the Host Learns about Devices
One of a hub’s duties is to detect attachment and removal of devices on its downstream-facing ports.Each hub has an interrupt IN endpoint for reporting these events to the host.
On system boot-up, hubs inform the host if any devices are attached including additional downstream hubs and any devices attached to those hubs.
After boot-up, a host continues to poll periodically (USB 2.0) or receives ERDY TPs (Enhanced SuperSpeed) that request communications to learn of any newly attached or removed devices.
On learning of a new device,
- the host sends requests to the device’s hub to cause the hub to establish a communications path between the host and device.
- the host then attempts to enumerate the device by issuing control transfers containing standard USB requests to the device. All USB devices must support control transfers, standard requests, and endpoint zero.
Getting to the Configured state
Device removal
Tips for successful enumeration
USB Debugging
# lsusb -t /: Bus 04.Port 1: Dev 1, Class=root_hub, Driver=xhci_hcd/4p, 10000M /: Bus 03.Port 1: Dev 1, Class=root_hub, Driver=xhci_hcd/12p, 480M |__ Port 1: Dev 2, If 0, Class=Hub, Driver=hub/4p, 480M |__ Port 5: Dev 3, If 0, Class=Human Interface Device, Driver=usbhid, 1.5M |__ Port 5: Dev 3, If 1, Class=Human Interface Device, Driver=usbhid, 1.5M |__ Port 6: Dev 4, If 0, Class=Human Interface Device, Driver=usbhid, 1.5M |__ Port 10: Dev 5, If 0, Class=Wireless, Driver=btusb, 12M |__ Port 10: Dev 5, If 1, Class=Wireless, Driver=btusb, 12M /: Bus 02.Port 1: Dev 1, Class=root_hub, Driver=xhci_hcd/4p, 10000M /: Bus 01.Port 1: Dev 1, Class=root_hub, Driver=xhci_hcd/1p, 480M # lsusb Bus 004 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub Bus 003 Device 004: ID 046d:c05a Logitech, Inc. M90/M100 Optical Mouse Bus 003 Device 003: ID 046d:c31c Logitech, Inc. Keyboard K120 Bus 003 Device 005: ID 8087:0025 Intel Corp. Bus 003 Device 002: ID 1a40:0101 Terminus Technology Inc. Hub Bus 003 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub Bus 002 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub # lsusb -v -s 3:1 Bus 003 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub Device Descriptor: bLength 18 bDescriptorType 1 bcdUSB 2.00 bDeviceClass 9 Hub bDeviceSubClass 0 bDeviceProtocol 1 Single TT bMaxPacketSize0 64 idVendor 0x1d6b Linux Foundation idProduct 0x0002 2.0 root hub bcdDevice 5.13 iManufacturer 3 Linux 5.13.0-1008-intel xhci-hcd iProduct 2 xHCI Host Controller iSerial 1 0000:00:14.0 bNumConfigurations 1 Configuration Descriptor: bLength 9 bDescriptorType 2 wTotalLength 0x0019 bNumInterfaces 1 bConfigurationValue 1 iConfiguration 0 bmAttributes 0xe0 Self Powered Remote Wakeup MaxPower 0mA Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 0 bAlternateSetting 0 bNumEndpoints 1 bInterfaceClass 9 Hub bInterfaceSubClass 0 bInterfaceProtocol 0 Full speed (or root) hub iInterface 0 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x81 EP 1 IN bmAttributes 3 Transfer Type Interrupt Synch Type None Usage Type Data wMaxPacketSize 0x0004 1x 4 bytes bInterval 12 Hub Descriptor: bLength 11 bDescriptorType 41 nNbrPorts 12 wHubCharacteristic 0x000a No power switching (usb 1.0) Per-port overcurrent protection TT think time 8 FS bits bPwrOn2PwrGood 10 * 2 milli seconds bHubContrCurrent 0 milli Ampere DeviceRemovable 0x00 0x00 PortPwrCtrlMask 0xff 0xff Hub Port Status: Port 1: 0000.0303 lowspeed power enable connect Port 2: 0000.0100 power Port 3: 0000.0100 power Port 4: 0000.0100 power Port 5: 0000.0303 lowspeed power enable connect Port 6: 0000.0507 highspeed power suspend enable connect Port 7: 0000.0100 power Port 8: 0000.0100 power Port 9: 0000.0100 power Port 10: 0000.0107 power suspend enable connect Port 11: 0000.0100 power Port 12: 0000.0100 power can't get device qualifier: Resource temporarily unavailable can't get debug descriptor: Resource temporarily unavailable Device Status: 0x0001 Self Powered # lspci | grep USB 00:0d.0 USB controller: Intel Corporation Device 9a13 (rev 01) 00:0d.2 USB controller: Intel Corporation Device 9a1b (rev 01) 00:14.0 USB controller: Intel Corporation Device a0ed (rev 20) 00:14.1 USB controller: Intel Corporation Device a0ee (rev 20)All USB information can be found under /sys/bus/usb/devices/ :
$ ls /sys/bus/usb/devices/ 1-0:1.0 1-1.1 1-1.2 1-1.2:1.1 1-1.2:1.3 1-10:1.0 1-1:1.0 1-2:1.0 2-0:1.0 4-0:1.0 usb2 usb4 1-1 1-1.1:1.0 1-1.2:1.0 1-1.2:1.2 1-10 1-10:1.1 1-2 1-2:1.1 3-0:1.0 usb1 usb3
- usbX
- X ID of host controller on your machine.
- X-A.B.C Device path.
- X HCD ID.
- A.B.C Physical path to port where your USB device is connected.
- X-A.B.C:Y.Z
- X-A.B.C Device path
- Y Active configuration
- Z bInterfaceNumber
Basic Information
To get a list of currently attached USB devices (including hubs);$ sudo lsusb -v
/sys/bus/usb
The USB is a polled bus, the host polls each device, devices cannot initiate any communication.- /sys/bus/usb/drivers/.../new_id Writing a device ID to this file will attempt to dynamically add a new device ID to a USB device driver. This may allow the driver to support more hardware than was included in the driver's static device ID support table at compile time. The format for the device ID is: idVendor idProduct bInterfaceClass RefIdVendor RefIdProduct The vendor ID and device ID fields are required, the rest is optional. The `Ref*` tuple can be used to tell the driver to use the same driver_data for the new device as it is used for the reference device.
Fixing USB Autosuspend
The Linux kernel automatically suspends USB devices when there is driver support and the devices are not in use.This saves quite a bit of power.However, some USB devices are not compatible with USB autosuspend and will misbehave at some point. Affected devices are most commonly USB mice and keyboards.
In essence, this is not really a USB hardware problem, but perhaps more a Linux problem.
The actual fault lies with a misinterpretation of the eXtensible Host Controller Interface (xHCI) specification.
This issue previously did not exist with the older Enhanced Host Controller Interface (EHCI) specification.
Identify the device
To identify the affected USB device by its vendor and product ID:$ lsusb -v ... Bus 001 Device 002: ID 046d:c31c Logitech, Inc. Keyboard K120 Couldn't open device, some information will be missing Device Descriptor: bLength 18 bDescriptorType 1 bcdUSB 1.10 bDeviceClass 0 bDeviceSubClass 0 bDeviceProtocol 0 bMaxPacketSize0 8 idVendor 0x046d Logitech, Inc. idProduct 0xc31c Keyboard K120 bcdDevice 64.00 iManufacturer 1 iProduct 2 iSerial 0 bNumConfigurations 1 ...Wite down the numbers:
- Bus
- Device
- idVendor
- idProduct
Test
A simple test suffices to know whether the suspect USB device is really affected by autosuspend.$ grep 046d /sys/bus/usb/devices/usb*/*/idVendor /sys/bus/usb/devices/usb1/1-7/idVendor:046d $ grep c31c /sys/bus/usb/devices/usb*/*/idProduct /sys/bus/usb/devices/usb1/1-7/idProduct:c31cIf the device driver supports it, the USB power/control attribute will default to auto. The auto state is the normal state in which the kernel is allowed to autosuspend and autoresume the device.
$ cat /sys/bus/usb/devices/usb1/1-7/power/control onThe on state means device autosuspend is not allowed, system suspends are still allowed.
If your device now works in the on state correctly, USB autosuspend is the problem at hand.
Solution
A permanent solution can only be achieved by creating a device-specific rules file for udev./etc/udev/rules.d/usb-power.rules:
# Logic Inc. Keyboard ACTION=="add", SUBSYSTEM=="usb", ATTR{idVendor}=="046d", ATTR{idProduct}=="c31c", TEST=="power/control", ATTR{power/control}="auto"
Power Management for USB
What is Power Management?
Power Management (PM) is the practice of saving energy by suspending parts of a computer system when they aren't being used.A suspended component can be "resumed" (returned to a functional full-power state) when the kernel needs to use it.
What is Remote Wakeup?
When a device has been suspended, it generally doesn't resume until the computer tells it to.When a device is enabled for remote wakeup and it is suspended, it may resume itself (or send a request to be resumed) in response to some external event.
Examples include a suspended keyboard resuming when a key is pressed, or a suspended USB hub resuming when a device is plugged in.
When is a USB device idle?
A device is idle whenever the kernel thinks it's not busy doing anything important and thus is a candidate for being suspended.Drivers are allowed to declare that a device isn't idle even when there's no actual communication taking place.
If a USB device has no driver, its usbfs file isn't open, and it isn't being accessed through sysfs, then it definitely is idle.
autosuspend
Dynamic suspends occur when the kernel decides to suspend an idle device.This is called "autosuspend" for short.
In general, a device won't be autosuspended unless it has been idle for some minimum period of time, the so-called idle-delay time.
If a
device has been autosuspended and a program tries to use it, the kernel will automatically resume the device (autoresume).
It is worth mentioning that many USB drivers don't support autosuspend.
If a non-supporting driver is bound to a device, the device won't be autosuspended. In effect, the kernel pretends the device is never idle.
The user interface for autosuspend
The user interface for controlling dynamic PM is located in the power/ subdirectory of each USB device's sysfs directory, that is,/sys/bus/usb/devices/.../power/The relevant attribute files are:
- power/wakeup This file is empty if the device does not support remote wakeup.
- power/control This file contains one of two words:
- on means that the device should be resumed and autosuspend is not allowed. (Of course, system suspends are still allowed.)
- auto is the normal state in which the kernel is allowed to autosuspend and autoresume the device.
- power/autosuspend_delay_ms This file contains the number of milliseconds the device should remain idle before the kernel will autosuspend it (the idle-delay time).
- The default is 2000
- 0 means to autosuspend as soon as the device becomes idle,
- negative values mean never to autosuspend
Otherwise the file contains either the word "enabled" or the word "disabled"
the default idle-delay time
The default autosuspend idle-delay time (in seconds) is controlled by a module parameter in usbcore.You can specify the value when usbcore is loaded. For example, to set it to 5 seconds instead of 2 you would do:
$ sudo modprobe usbcore autosuspend=5If usbcore is compiled into the kernel rather than built as a loadable module, you can add this to the kernel's boot command line.
usbcore.autosuspend=5Setting the initial default idle-delay to -1 will prevent any autosuspend of any USB device. This has the benefit of allowing you then to enable autosuspend for selected devices.
Warnings
Many devices do not support power management very well.You can suspend them, but when you try to resume them they disconnect themselves from the USB bus or they stop working entirely.
For this reason, by default the kernel disables autosuspend (the power/control attribute is initialized to "on") for all devices other than hubs.
Hubs, at least, appear to be reasonably well-behaved in this regard.
This means that non-hub devices won't be autosuspended unless the user or a program explicitly enables it.
USB Network Protocol
Past, present and future of USB Network Protocol
Most of 3G/LTE modems communicate by USB bus.
Kind of USB network drivers
USB network device driver can be classified by various protocols offered from communication module manufacturer or OS developer.USB communications device class (or USB CDC class) is a composite USB device class.
The communications device class provides an interface for transmitting Ethernet or ATM frames onto some physical media.
CDC(Communications Device Class) includes all protocols for modem and Ethernet devices as device class according to USB-IF for communication device.
USB-IF defines CDC ECM (Ethernet Networking Control Model) and CDC EEM (Ethernet Emulation Devices) for USB network device and CDC NCM (Network Control Model) to improve packet handling mode for large size of data.
- CDC ACM Early USB modem offered CDC ACM (Abstract Control Model) .
- CDC ECM ECM protocol is used to Tx/Rx frames between host and device.
- CDC NCM NCM protocol is used to Tx/Rx frames between host and device to Tx/Rx high data in high throughput.
- RNDIS(Remote NDIS) Microsoft produced RNDIS that is a variant of CDC ECM.
- host To build rndis_host.ko:
Most OS following CDC ACM, the USB-IF standard, include CDC ACM support driver, so USB modem manufacturers didn’t need to develop special USB device driver.
ACM driver thinks UDB devices as a virtual modem or COM port.
Device drivers Tx/Rx data and AT commands via AM driver (different channels)
ECM devices are usually LAN/WAN adaptors which can be assigned with MAC and IP.
NCM devices are usually 3.5G/4G celluar adaptor.
Different kernel config is used to enable RNDIS for host and device:
Device Drivers ---> Network Device Support ---> Usb Network Adapters ---> Multi-purpose USB Networking Framework ---> CDC Ethernet Support Host For RDNIS and ActiveSync Devices
Device Drivers ---> USB support ---> USB Gadget Support ---> USB Gadget Driver ---> Ethernet Gadget (with CDC Ethernet Support) RNDIS supportQualcomm produced and used QMI/RmNet for communication and control on their chips.
Every CDC USB sub class is composed of a control and data interface.
No matter CDC-ECM or RNDIS, the USB networking model looks like:
The Linux USB Input Subsystem
Input subsystem is a collection of drivers that is designed to support all input devices under Linux.Most of the drivers reside in drivers/input, although quite a few live in drivers/hid and drivers/platform.
The core of the input subsystem is the input module, which must be loaded before any other of the input modules - it serves as a way of communication between two groups of modules:
- Device drivers These modules talk to the hardware (for example via USB), and provide events (keystrokes, mouse movements) to the input module.
- Event handlers Event handlers get events from input core and distribute the events to userspace and in-kernel consumers, as needed.
$ ls -l /dev/input total 0 drwxr-xr-x 2 root root 140 Nov 19 01:13 by-id drwxr-xr-x 2 root root 140 Nov 19 01:13 by-path crw-rw---- 1 root input 13, 64 Nov 19 01:13 event0 crw-rw---- 1 root input 13, 65 Nov 19 01:13 event1 crw-rw---- 1 root input 13, 74 Nov 19 01:13 event10 crw-rw---- 1 root input 13, 75 Nov 19 01:13 event11 crw-rw---- 1 root input 13, 76 Nov 19 01:13 event12 crw-rw---- 1 root input 13, 77 Nov 19 01:13 event13 crw-rw---- 1 root input 13, 66 Nov 19 01:13 event2 crw-rw---- 1 root input 13, 67 Nov 19 01:13 event3 crw-rw---- 1 root input 13, 68 Nov 19 01:13 event4 crw-rw---- 1 root input 13, 69 Nov 19 01:13 event5 crw-rw---- 1 root input 13, 70 Nov 19 01:13 event6 crw-rw---- 1 root input 13, 71 Nov 19 01:13 event7 crw-rw---- 1 root input 13, 72 Nov 19 01:13 event8 crw-rw---- 1 root input 13, 73 Nov 19 01:13 event9 crw-rw---- 1 root input 13, 63 Nov 19 01:13 mice crw-rw---- 1 root input 13, 32 Nov 19 01:13 mouse0For ex., the USB mouse will be available as a character device on major 13, minor 63.
XFree can use it :
Section "Pointer" Protocol "ImPS/2" Device "/dev/input/mice" ZAxisMapping 4 5 EndSectionYou can use blocking and nonblocking reads on the /dev/input/eventX devices to get a number of input events.
The data structure of the input event:
struct input_event { struct timeval time; unsigned short type; unsigned short code; unsigned int value; };For ex., read the mouse input
$ sudo cat /dev/input/mouse0characters should appear when you move the mouse.
- Initially, the USB mouse used /sys/class/input/input3
$ cat /sys/class/input/input3/name Logitech USB Optical Mouse
$ cat /sys/class/input/input14/name Logitech USB Optical Mouse
Part I
The three elements of the input subsystem are :- the input core
- drivers
- event handlers
struct input_dev { void *private; char *name; char *phys; char *uniq; struct input_id id; unsigned long evbit[NBITS(EV_MAX)]; unsigned long keybit[NBITS(KEY_MAX)]; unsigned long relbit[NBITS(REL_MAX)]; unsigned long absbit[NBITS(ABS_MAX)]; unsigned long mscbit[NBITS(MSC_MAX)]; unsigned long ledbit[NBITS(LED_MAX)]; unsigned long sndbit[NBITS(SND_MAX)]; unsigned long ffbit[NBITS(FF_MAX)]; int ff_effects_max; unsigned int keycodemax; unsigned int keycodesize; void *keycode; unsigned int repeat_key; struct timer_list timer; struct pm_dev *pm_dev; int state; int sync; int abs[ABS_MAX + 1]; int rep[REP_MAX + 1]; unsigned long key[NBITS(KEY_MAX)]; unsigned long led[NBITS(LED_MAX)]; unsigned long snd[NBITS(SND_MAX)]; int absmax[ABS_MAX + 1]; int absmin[ABS_MAX + 1]; int absfuzz[ABS_MAX + 1]; int absflat[ABS_MAX + 1]; int (*open)(struct input_dev *dev); void (*close)(struct input_dev *dev); int (*accept)(struct input_dev *dev, struct file *file); int (*flush)(struct input_dev *dev, struct file *file); int (*event)(struct input_dev *dev, unsigned int type, unsigned int code, int value); int (*upload_effect)(struct input_dev *dev, struct ff_effect *effect); int (*erase_effect)(struct input_dev *dev, int effect_id); struct list_head h_list; struct list_head node; };Event handlers provide the interface to user space, converting the standard event format into the format required by a particular API.
Handlers usually take care of the device nodes (/dev entries) too.
The most common handler is the keyboard handler, which is the “standard input” that most programmers (especially C programmers) are familiar with.
Drivers usually interface with low-level hardware, such as USB, PCI memory or I/O regions, or serial port I/O regions.
They convert the low-level hardware version of the user input into the standard event format before sending it to the input core.
The input core uses a standard kernel plugin design, with input_register_device() used to add each device and input_unregister_device() used to remove it.
In addition to managing drivers and handlers, the input core also exports a useful /proc filesystem interface, which can be used to see what devices and handlers are currently active.
$ cat /proc/bus/input/devices ... I: Bus=0003 Vendor=046d Product=c31c Version=0110 N: Name="Logitech USB Keyboard" P: Phys=usb-0000:00:15.0-2.2/input0 S: Sysfs=/devices/pci0000:00/0000:00:15.0/usb1/1-2/1-2.2/1-2.2:1.0/0003:046D:C31C.0002/input/input6 U: Uniq= H: Handlers=sysrq kbd event3 leds B: PROP=0 B: EV=120013 B: KEY=1000000000007 ff9f207ac14057ff febeffdfffefffff fffffffffffffffe B: MSC=10 B: LED=1f ...
- I: The identity information - showing bus type 3 (which is USB) and the vendor, product and version information from the USB descriptors in the keyboard.
- N: The name - showing a string provided by the USB descriptors.
- P: The physical device information - a structure information comprised of the PCI address for the USB controller, the USB tree and the input interface.
- H: The handler drivers associated with this device
- B: The various B: lines show the bitfields that identify the devices' capabilities
The input0 part indicates this is the first logical input device for the physical device.
The logical input device is an abstraction of one or more physical devices that delivers logical input values to an application.
Some devices, such as multimedia keyboards, can map part of the physical device to one logical input device and map another part to a second logical input device.
Resetting the USB Subsystem
There are four basic USB standards. Each standard has a specific Interface type as follows:- 1.x – Open Host Controller Interface (OHCI)
- 1.x – Universal Host Controller Interface (UHCI)
- 2.0 – Enhanced Host Controller Interface (EHCI)
- 3.0 – eXtensible Host Controller Interface (xHCI)
$ lsusb -t /: Bus 04.Port 1: Dev 1, Class=root_hub, Driver=xhci_hcd/2p, 10000M /: Bus 03.Port 1: Dev 1, Class=root_hub, Driver=xhci_hcd/2p, 480M /: Bus 02.Port 1: Dev 1, Class=root_hub, Driver=xhci_hcd/6p, 10000M /: Bus 01.Port 1: Dev 1, Class=root_hub, Driver=xhci_hcd/12p, 480M |__ Port 1: Dev 2, If 0, Class=Hub, Driver=hub/4p, 480M |__ Port 1: Dev 4, If 0, Class=Human Interface Device, Driver=usbhid, 1.5M |__ Port 2: Dev 6, If 3, Class=Human Interface Device, Driver=usbhid, 12M |__ Port 2: Dev 6, If 1, Class=Audio, Driver=snd-usb-audio, 12M |__ Port 2: Dev 6, If 2, Class=Audio, Driver=snd-usb-audio, 12M |__ Port 2: Dev 6, If 0, Class=Audio, Driver=snd-usb-audio, 12M |__ Port 2: Dev 3, If 0, Class=Human Interface Device, Driver=usbhid, 1.5M |__ Port 2: Dev 3, If 1, Class=Human Interface Device, Driver=usbhid, 1.5M |__ Port 10: Dev 5, If 0, Class=Wireless, Driver=btusb, 12M |__ Port 10: Dev 5, If 1, Class=Wireless, Driver=btusb, 12M
- There are four USB buses. These are labeled Bus 1 to Bus 4.
- Each bus has a root hub All of these main devices are listed as “root_hubs” on Port 1.
- Audio
- Video
- Network
- Chipsets
- Card readers
- Optical devices
- Internally mounted Mass Storage Device
- Bluetooth
Root hubs are always Port 1 and devices attached are listed on the following ports, starting at 2, as they are attached.
The driver specifies the Linux driver and designates the USB Standard (OHCI, UHCI, EHCI or xHCI), the number following the “/” designates how many ports are located on the root hub device.
Be aware that the number of ports may not be external ports.
An internal USB port can be used to add external ports or add an internal device.
Some internal devices, which may be part of the ports:
$ lsusb Bus 004 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub Bus 003 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub Bus 002 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub Bus 001 Device 003: ID 045e:0750 Microsoft Corp. Wired Keyboard 600 Bus 001 Device 005: ID 8087:0026 Intel Corp. Bus 001 Device 006: ID 047f:c009 Plantronics, Inc. Wired Keyboard 600 Bus 001 Device 004: ID 046d:c077 Logitech, Inc. M105 Optical Mouse Bus 001 Device 002: ID 214b:7250 USB2.0 HUB Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
- Bus 1 has 6 devies attached
- Linux Foundation 2.0 root hub
- USB2.0 HUB
- Microsoft Corp. Wired Keyboard 600
- Logitech, Inc. M105 Optical Mouse
- Intel Corp. Bluetooth
- Plantronics, Inc. Wired Keyboard 600
- Each USB device has a built-in Device ID which is in two parts separated by a colon The first part is the manufacturer (Vendor ID) and the second part is the device (Product ID). A list of Vendor IDs can be found on the Internet or at https://usb-ids.gowdy.us/read/UD/
Domain:Bus:Slot.Function
- Domain
- Bus The "bus" refers to a PCI/PCI-X/PCI express bus from the motherboard's chipset, to which devices are attached.
- Slot The "slot" refers to a space on the PCI bus to which a single physical device is attached, which is electrically distinct from other "slots" on that bus.
- Function The "function" refers to a subset of a physical device which provides distinct functionality.
For instance, two distinct USB controllers occupying two different slots.
$ lspci | grep USB 00:14.0 USB controller: Intel Corporation Comet Lake PCH-LP USB 3.1 xHCI Host Controller 39:00.0 USB controller: Intel Corporation JHL7540 Thunderbolt 3 USB Controller [Titan Ridge 2C 2018] (rev 06)It is only missing the Domain portion which is: 0000.
We know the PCI address for the USB controller, need to find which PCI address is used for which USB bus.
To reset a USB Root Hub, you need to know its address.
To show only devices with specified device and/or bus numbers (in decimal)
lsusb -s [[bus]:][devnum]For example, if I wanted the address for the 1st device(root hub) on Bus 1,
$ lsusb -s 1:1 Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hubBoth /sys/bus/pci/drivers/*/ and /sys/bus/usb/drivers/usb/ has the folllowing interfaces to enable/disable devices:
- bind – enable the device
- unbind – disable device
echo -n "0000:00:13.0" | tee /sys/bus/pci/drivers/ohci_hcd/unbind echo -n "0000:00:13.0" | tee /sys/bus/pci/drivers/ohci_hcd/bindFor the USB interface:
# echo 2-1.4 > /sys/bus/usb/drivers/usb/unbind # echo 2-1.4 > /sys/bus/usb/drivers/usb/bind
PCIe Hot Reset on Linux
- A 'cold reset' is a fundamental reset that takes place after power is applied to a PCIe device.
# tree /sys/bus/pci/slots /sys/bus/pci/slots |-- 1 | |-- adapter | |-- address | |-- cur_bus_speed | |-- max_bus_speed | |-- module -> ../../../../module/pciehp | `-- power `-- 8 |-- adapter |-- address |-- cur_bus_speed |-- max_bus_speed |-- module -> ../../../../module/pciehp `-- power
Software can initiate a hot reset by setting and then clearing the secondary bus reset bit in the bridge control register in the PCI configuration space of the bridge port upstream of the device.
It must not reset the entire PCIe device.
Implementing function-level resets is not required by the PCIe specification.
A function-level reset is initiated by setting the initiate function-level reset bit in the function's device control register in the PCI express capability structure in the PCI configuration space. Linux exposes the function-level reset functionality in the form of /sys/bus/pci/devices/$dev/reset.
Writing a 1 to this file will initiate a function-level reset on the corresponding function.
# ls /sys/bus/pci/devices/*/reset /sys/bus/pci/devices/0000:00:02.0/reset /sys/bus/pci/devices/0000:00:1c.5/reset /sys/bus/pci/devices/0000:2d:00.0/reset /sys/bus/pci/devices/0000:00:06.0/reset /sys/bus/pci/devices/0000:00:1c.6/reset /sys/bus/pci/devices/0000:2e:00.0/reset /sys/bus/pci/devices/0000:00:07.0/reset /sys/bus/pci/devices/0000:00:1c.7/reset /sys/bus/pci/devices/0000:2f:00.0/reset /sys/bus/pci/devices/0000:00:1c.0/reset /sys/bus/pci/devices/0000:01:00.0/reset /sys/bus/pci/devices/0000:30:00.0/resetNote that this only affects that specific function of the device, not the whole device, and devices are not required to implement function-level resets as per the PCIe specification.
The following script will attempt to:
- remove the PCIe device
- command the upstream switch port to issue a hot reset
- rescan the PCIe bus.
#!/bin/bash dev=$1 if [ -z "$dev" ]; then echo "Error: no device specified" exit 1 fi if [ ! -e "/sys/bus/pci/devices/$dev" ]; then dev="0000:$dev" fi if [ ! -e "/sys/bus/pci/devices/$dev" ]; then echo "Error: device $dev not found" exit 1 fi port=$(basename $(dirname $(readlink "/sys/bus/pci/devices/$dev"))) if [ ! -e "/sys/bus/pci/devices/$port" ]; then echo "Error: device $port not found" exit 1 fi echo "Removing $dev..." echo 1 > "/sys/bus/pci/devices/$dev/remove" echo "Performing hot reset of port $port..." bc=$(setpci -s $port BRIDGE_CONTROL) echo "Bridge control:" $bc setpci -s $port BRIDGE_CONTROL=$(printf "%04x" $(("0x$bc" | 0x40))) sleep 0.01 setpci -s $port BRIDGE_CONTROL=$bc sleep 0.5 echo "Rescanning bus..." echo 1 > "/sys/bus/pci/devices/$port/rescan"
Linux tip: How to reset device connected to USB port
use a SystemD Timer
Create a script file in /home/myuser/bin/myscript.sh :#!/bin/bash x=1 while [ $x -le 5 ] do logger "Welcome $x times" x=$(( $x + 1 )) sleep 60 doneCreate a Systemd service unit file /etc/systemd/system/myscript.service
[Unit] Description=Hello: just say hi [Service] Type=simple ExecStart=/home/jerry-lee-tpe/bin/myscript.sh [Install] WantedBy=default.targetEnable a unit to be started on bootup and Start immediately:
chmod 644 /etc/systemd/system/myscript.service systemctl enable myscript.service
留言