1
2
3
4
5 package oshi.hardware.platform.linux;
6
7 import static oshi.software.os.linux.LinuxOperatingSystem.HAS_UDEV;
8
9 import java.util.ArrayList;
10 import java.util.Collections;
11 import java.util.HashMap;
12 import java.util.List;
13 import java.util.Map;
14
15 import org.slf4j.Logger;
16 import org.slf4j.LoggerFactory;
17
18 import com.sun.jna.platform.linux.Udev;
19 import com.sun.jna.platform.linux.Udev.UdevDevice;
20 import com.sun.jna.platform.linux.Udev.UdevEnumerate;
21 import com.sun.jna.platform.linux.Udev.UdevListEntry;
22
23 import oshi.annotation.concurrent.Immutable;
24 import oshi.hardware.UsbDevice;
25 import oshi.hardware.common.AbstractUsbDevice;
26
27
28
29
30 @Immutable
31 public class LinuxUsbDevice extends AbstractUsbDevice {
32
33 private static final Logger LOG = LoggerFactory.getLogger(LinuxUsbDevice.class);
34
35 private static final String SUBSYSTEM_USB = "usb";
36 private static final String DEVTYPE_USB_DEVICE = "usb_device";
37 private static final String ATTR_PRODUCT = "product";
38 private static final String ATTR_MANUFACTURER = "manufacturer";
39 private static final String ATTR_VENDOR_ID = "idVendor";
40 private static final String ATTR_PRODUCT_ID = "idProduct";
41 private static final String ATTR_SERIAL = "serial";
42
43 public LinuxUsbDevice(String name, String vendor, String vendorId, String productId, String serialNumber,
44 String uniqueDeviceId, List<UsbDevice> connectedDevices) {
45 super(name, vendor, vendorId, productId, serialNumber, uniqueDeviceId, connectedDevices);
46 }
47
48
49
50
51
52
53
54
55
56
57
58
59
60 public static List<UsbDevice> getUsbDevices(boolean tree) {
61 List<UsbDevice> devices = getUsbDevices();
62 if (tree) {
63 return devices;
64 }
65 List<UsbDevice> deviceList = new ArrayList<>();
66
67
68 for (UsbDevice device : devices) {
69 deviceList.add(new LinuxUsbDevice(device.getName(), device.getVendor(), device.getVendorId(),
70 device.getProductId(), device.getSerialNumber(), device.getUniqueDeviceId(),
71 Collections.emptyList()));
72 addDevicesToList(deviceList, device.getConnectedDevices());
73 }
74 return deviceList;
75 }
76
77 private static List<UsbDevice> getUsbDevices() {
78 if (!HAS_UDEV) {
79 LOG.warn("USB Device information requires libudev, which is not present.");
80 return Collections.emptyList();
81 }
82
83 List<String> usbControllers = new ArrayList<>();
84
85
86 Map<String, String> nameMap = new HashMap<>();
87 Map<String, String> vendorMap = new HashMap<>();
88 Map<String, String> vendorIdMap = new HashMap<>();
89 Map<String, String> productIdMap = new HashMap<>();
90 Map<String, String> serialMap = new HashMap<>();
91 Map<String, List<String>> hubMap = new HashMap<>();
92
93
94 Udev.UdevContext udev = Udev.INSTANCE.udev_new();
95 try {
96 UdevEnumerate enumerate = udev.enumerateNew();
97 try {
98 enumerate.addMatchSubsystem(SUBSYSTEM_USB);
99 enumerate.scanDevices();
100
101
102 for (UdevListEntry entry = enumerate.getListEntry(); entry != null; entry = entry.getNext()) {
103 String syspath = entry.getName();
104 UdevDevice device = udev.deviceNewFromSyspath(syspath);
105 if (device != null) {
106 try {
107
108 if (DEVTYPE_USB_DEVICE.equals(device.getDevtype())) {
109 String value = device.getSysattrValue(ATTR_PRODUCT);
110 if (value != null) {
111 nameMap.put(syspath, value);
112 }
113 value = device.getSysattrValue(ATTR_MANUFACTURER);
114 if (value != null) {
115 vendorMap.put(syspath, value);
116 }
117 value = device.getSysattrValue(ATTR_VENDOR_ID);
118 if (value != null) {
119 vendorIdMap.put(syspath, value);
120 }
121 value = device.getSysattrValue(ATTR_PRODUCT_ID);
122 if (value != null) {
123 productIdMap.put(syspath, value);
124 }
125 value = device.getSysattrValue(ATTR_SERIAL);
126 if (value != null) {
127 serialMap.put(syspath, value);
128 }
129
130 UdevDevice parent = device.getParentWithSubsystemDevtype(SUBSYSTEM_USB,
131 DEVTYPE_USB_DEVICE);
132 if (parent == null) {
133
134 usbControllers.add(syspath);
135 } else {
136
137 String parentPath = parent.getSyspath();
138 hubMap.computeIfAbsent(parentPath, x -> new ArrayList<>()).add(syspath);
139 }
140 }
141 } finally {
142 device.unref();
143 }
144 }
145 }
146 } finally {
147 enumerate.unref();
148 }
149 } finally {
150 udev.unref();
151 }
152
153
154 List<UsbDevice> controllerDevices = new ArrayList<>();
155 for (String controller : usbControllers) {
156 controllerDevices.add(getDeviceAndChildren(controller, "0000", "0000", nameMap, vendorMap, vendorIdMap,
157 productIdMap, serialMap, hubMap));
158 }
159 return controllerDevices;
160 }
161
162 private static void addDevicesToList(List<UsbDevice> deviceList, List<UsbDevice> list) {
163 for (UsbDevice device : list) {
164 deviceList.add(device);
165 addDevicesToList(deviceList, device.getConnectedDevices());
166 }
167 }
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183 private static LinuxUsbDevice getDeviceAndChildren(String devPath, String vid, String pid,
184 Map<String, String> nameMap, Map<String, String> vendorMap, Map<String, String> vendorIdMap,
185 Map<String, String> productIdMap, Map<String, String> serialMap, Map<String, List<String>> hubMap) {
186 String vendorId = vendorIdMap.getOrDefault(devPath, vid);
187 String productId = productIdMap.getOrDefault(devPath, pid);
188 List<String> childPaths = hubMap.getOrDefault(devPath, new ArrayList<>());
189 List<UsbDevice> usbDevices = new ArrayList<>();
190 for (String path : childPaths) {
191 usbDevices.add(getDeviceAndChildren(path, vendorId, productId, nameMap, vendorMap, vendorIdMap,
192 productIdMap, serialMap, hubMap));
193 }
194 Collections.sort(usbDevices);
195 return new LinuxUsbDevice(nameMap.getOrDefault(devPath, vendorId + ":" + productId),
196 vendorMap.getOrDefault(devPath, ""), vendorId, productId, serialMap.getOrDefault(devPath, ""), devPath,
197 usbDevices);
198 }
199 }