Ocean
system/usb/Device.h
Go to the documentation of this file.
1 /*
2  * Copyright (c) Meta Platforms, Inc. and affiliates.
3  *
4  * This source code is licensed under the MIT license found in the
5  * LICENSE file in the root directory of this source tree.
6  */
7 
8 #ifndef META_OCEAN_SYSTEM_USB_DEVICE_H
9 #define META_OCEAN_SYSTEM_USB_DEVICE_H
10 
11 #include "ocean/system/usb/USB.h"
13 
14 #include "ocean/base/Lock.h"
16 
17 namespace Ocean
18 {
19 
20 namespace System
21 {
22 
23 namespace USB
24 {
25 
26 // Forward declaration.
27 class Device;
28 
29 /**
30  * Definition of a shared pointer holding a device.
31  * @see Device.
32  * @ingroup systemusb
33  */
34 using SharedDevice = std::shared_ptr<Device>;
35 
36 /**
37  * Definition of a vector holding SharedDevice objects.
38  * @see SharedDevice.
39  * @ingroup systemusb
40  */
41 using SharedDevices = std::vector<SharedDevice>;
42 
43 /**
44  * This class wraps a libusb device.
45  * The class holds a reference to the libusb device as long as the object exists.
46  * @ingroup systemusb
47  */
48 class OCEAN_SYSTEM_USB_EXPORT Device
49 {
50  public:
51 
52  /**
53  * Definition of a scoped subscription object.
54  */
56 
57  protected:
58 
59  /**
60  * Definition of an unordered map mapping interface indices to usages.
61  */
62  using UsageMap = std::unordered_map<int, unsigned int>;
63 
64  /**
65  * Definition of a pair combining a pointer to a buffer and the size of this buffer.
66  */
67  using BufferPointer = std::pair<const void*, size_t>;
68 
69  /**
70  * Definition of a vector holding buffer pointers.
71  */
72  using BufferPointers = std::vector<BufferPointer>;
73 
74  public:
75 
76  /**
77  * Default constructor creating an invalid device.
78  */
79  Device() = default;
80 
81  /**
82  * Move constructor.
83  * @param device The device to be moved
84  */
85  inline Device(Device&& device);
86 
87  /**
88  * Creates a new device object based on a given (not yet opened) libusb device.
89  * @param context The USB context to be used, invalid to use the default context
90  * @param usbDevice The libusb device to be wrapped, the device is not yet open (otherwise a handle would exist), must be valid
91  */
92  Device(SharedContext context, libusb_device* usbDevice);
93 
94  /**
95  * Creates a new device object based on a given libusb device handle (which means that the devices is already opened).
96  * @param context The USB context to be used, invalid to use the default context
97  * @param usbDeviceHandle The handle of the device, must be valid
98  */
99  Device(SharedContext context, libusb_device_handle* usbDeviceHandle);
100 
101  /**
102  * Creates a new device object based on a given (already opened) libusb device and its device handle.
103  * @param context The USB context to be used, invalid to use the default context
104  * @param usbDevice The libusb device to be wrapped, the device has been opened already (because a device handle exists), must be valid
105  * @param usbDeviceHandle The handle of the device, must be valid
106  */
107  Device(SharedContext context, libusb_device* usbDevice, libusb_device_handle* usbDeviceHandle);
108 
109  /**
110  * Creates a new device object (for an already opened device) based on a given system handle.
111  * On some platforms like e.g., Android, the device must be opened on the Java side (resulting in a file descriptor), this file descriptor can then be used as a system handle.
112  * @param context The USB context to be used, invalid to use the default context
113  * @param systemDeviceHandle The system specific handle to the device (e.g., a file descriptor received from Java on Android platforms), must be valid
114  */
115  Device(SharedContext context, const int64_t systemDeviceHandle);
116 
117  /**
118  * Destructs the device and releases all resources.
119  */
120  virtual ~Device();
121 
122  /**
123  * Returns the vendor id of the device.
124  * @return The device's vendor id
125  */
126  uint16_t vendorId() const;
127 
128  /**
129  * Returns the product id of the device.
130  * @return The device's product id
131  */
132  uint16_t productId() const;
133 
134  /**
135  * Returns the name of the device (not the product name).
136  * @return The device's name
137  */
138  std::string name() const;
139 
140  /**
141  * Returns the product name of the device.
142  * The device needs to be open before the product name can be queried.<br>
143  * In case the name of the product is not available, a lookup table is used based on the vendor id and product id.
144  * @return The device's product name, empty if not available
145  * @see isOpen().
146  */
147  std::string productName() const;
148 
149  /**
150  * Returns the manufacturer name of this device.
151  * The device needs to be open before the manufacturer name can be queried.<br>
152  * In case the name of the manufacturer is not available, a lookup table is used based on the vendor id.
153  * @return The device's manufacturer name, empty if not available
154  * @see isOpen().
155  */
156  std::string manufacturerName() const;
157 
158  /**
159  * Returns the serial number of this device.
160  * The device needs to be open before the serial number can be queried.
161  * @return The device's serial number, empty if not available
162  * @see isOpen().
163  */
164  std::string serialNumber() const;
165 
166  /**
167  * Opens the device.
168  * @return True, if succeeded
169  * @see isOpen().
170  */
171  bool open();
172 
173  /**
174  * Closes an opened device.
175  * In case the device was opened via a system device handle (e.g., a file descriptor on Android platforms, calling this function does have no effect).
176  * @return True, if succeeded
177  * @see isOpen().
178  */
179  bool close();
180 
181  /**
182  * Detaches the kernel driver for the device.
183  * @param interfaceIndex The index of the interface for which the kernel driver will be detached
184  * @param driverWasNotActive Optional resulting information why the resulting subscription object may be invalid; True, in case no kernel driver was active (may indicate that there was no need to detach the driver)
185  * @return The scoped subscription object which will keep the driver detached as long as the subscription object exists, an invalid subscription in case of an error
186  */
187  [[nodiscard]] ScopedSubscription detachKernelDriver(const int interfaceIndex, bool* driverWasNotActive = nullptr);
188 
189  /**
190  * Claims an interface of the device.
191  * @param interfaceIndex The index of the interface to claim
192  * @return The scoped subscription object which will keep the interface claimed as long as the subscription object exists, an invalid subscription in case of an error
193  */
194  [[nodiscard]] ScopedSubscription claimInterface(const int interfaceIndex);
195 
196  /**
197  * Returns the wrapped libusb device.
198  * @return The libusb device, nullptr if now device is wrapped
199  * @see isValid().
200  */
201  inline libusb_device* usbDevice();
202 
203  /**
204  * Returns the handle to the wrapped libusb device.
205  * @return The libusb device handle, nullptr if the device is not yet opened
206  * @see isValid().
207  */
208  inline libusb_device_handle* usbDeviceHandle();
209 
210  /**
211  * Explicitly releases the device.
212  * In case the device is opened, the device will be closed.
213  * Further, all claimed interfaces will be released and detached kernel drivers will re-attached.
214  */
215  void release();
216 
217  /**
218  * The context which is associated with this device.
219  * @return The device's context, nullptr if the device is associated with the default context
220  */
221  inline SharedContext context() const;
222 
223  /**
224  * Returns whether this device is valid.
225  * A valid device does not need to be open.
226  * @return True, of so
227  * @see isOpen().
228  */
229  inline bool isValid() const;
230 
231  /**
232  * Returns whether this device is open.
233  * A device is open if a corresponding device handle exists.
234  * @return True, if so
235  * @see isValid().
236  */
237  inline bool isOpen() const;
238 
239  /**
240  * Returns whether this device is wrapping a device based on a given system device handle.
241  * @return True, if so
242  */
243  inline bool isWrapped() const;
244 
245  /**
246  * Returns the class code of this device.
247  * The device needs to be valid.
248  * @return The device's class code
249  */
250  inline libusb_class_code classCode() const;
251 
252  /**
253  * Move operator.
254  * @param device The device to be moved
255  * @return The reference to this device
256  */
257  Device& operator=(Device&& device);
258 
259  /**
260  * Returns a string descriptor of an opened device.
261  * @param usbDeviceHandle The handle of the device for which the string descriptor will be returned
262  * @param index The index of the string descriptor to return
263  * @return The resulting string descriptor, empty in case of an error
264  */
265  static std::string stringDescriptor(libusb_device_handle* usbDeviceHandle, const uint8_t index);
266 
267  protected:
268 
269  /**
270  * Initializes this device with a given opened libusb device.
271  * @param context The context which is associated with the device, nullptr to use the default context
272  * @param usbDevice The opened libusb device, must be valid
273  * @param usbDeviceHandle The handle to the opened libusb device, must be valid
274  * @return True, if succeeded
275  */
276  bool initialize(SharedContext context, libusb_device* usbDevice, libusb_device_handle* usbDeviceHandle);
277 
278  /**
279  * Re-attaches a detached kernel driver for a specified interface.
280  * @param interfaceIndex The index of the interface
281  */
282  void reattachKernelDriver(const int interfaceIndex);
283 
284  /**
285  * Releases a claimed interface.
286  * @param interfaceIndex The index of the interface
287  */
288  void releaseInterface(const int interfaceIndex);
289 
290  /**
291  * Disabled copy constructor.
292  */
293  Device(const Device&) = delete;
294 
295  /**
296  * Disabled copy operator.
297  * @return Reference to this object
298  */
299  Device& operator=(const Device&) = delete;
300 
301  /**
302  * Extracts the payload buffers from a given USB transfer object.
303  * The transfer can be an isochronous transfer or a bulk transfer.<br>
304  * The memory is not copied, only pointers and size are extracted from the transfer.<br>
305  * Thus, the resulting buffers are only valid as long the transfer object is not released.<br>
306  * @param usbTransfer The transfer object from which the payload buffers will be extracted, must have status LIBUSB_TRANSFER_COMPLETED
307  * @param bufferPointers The resulting payload buffers, one in case of bulk mode, multiple buffers in case of isochronous mode
308  * @return True, if succeeded
309  */
310  static bool extractPayload(struct libusb_transfer& usbTransfer, BufferPointers& bufferPointers);
311 
312  /**
313  * Determines the layout of an isochronous transfer.
314  * @param usbContext The context to be used, nullptr to use the default context
315  * @param interface The interface on which the transfer will happen
316  * @param endpointAddress The address of the endpoint on which the transfer will happen
317  * @param maxVideoFrameSize The maximal size of a video frame, in bytes, with range [1, infinity)
318  * @param maxPayloadTransferSize The maximal transfer size of payload, in bytes, with range [1, infinity)
319  * @param transferSize The resulting size of an entire transfer, in bytes
320  * @param packetsPerTransfer The resulting number of packets per transfer
321  * @param bytesPerPacket The resulting number of bytes per packet
322  * @return The index of the altsetting which supports the specified maximal video frame size and payload size, -1 if no matching altsetting could be found
323  */
324  static int determineIsochronousTransferLayout(libusb_context* usbContext, const libusb_interface& interface, const uint8_t endpointAddress, const uint32_t maxVideoFrameSize, const uint32_t maxPayloadTransferSize, size_t& transferSize, size_t& packetsPerTransfer, size_t& bytesPerPacket);
325 
326  protected:
327 
328  /// The context which is associated with this device, nullptr if the default context is used.
330 
331  /// Optional system device handle in case this object is wrapped (e.g., on Android platforms).
332  int64_t systemDeviceHandle_ = 0;
333 
334  /// The actual libusb device.
335  libusb_device* usbDevice_ = nullptr;
336 
337  /// The handle to the opened libusb device.
338  libusb_device_handle* usbDeviceHandle_ = nullptr;
339 
340  /// The device descriptor of this device.
341  libusb_device_descriptor usbDeviceDescriptor_ = {};
342 
343  /// The usage counter for detached kernel drivers.
345 
346  /// The usage counter for claimed interfaces.
348 
349  /// The device's lock.
350  mutable Lock lock_;
351 };
352 
353 inline Device::Device(Device&& device)
354 {
355  *this = std::move(device);
356 }
357 
358 inline libusb_device* Device::usbDevice()
359 {
360  const ScopedLock scopedLock(lock_);
361 
362  return usbDevice_;
363 }
364 
365 inline libusb_device_handle* Device::usbDeviceHandle()
366 {
367  const ScopedLock scopedLock(lock_);
368 
369  return usbDeviceHandle_;
370 }
371 
373 {
374  return context_;
375 }
376 
377 inline bool Device::isValid() const
378 {
379  const ScopedLock scopedLock(lock_);
380 
381  return usbDevice_ != nullptr;
382 }
383 
384 inline bool Device::isOpen() const
385 {
386  const ScopedLock scopedLock(lock_);
387 
388  return usbDeviceHandle_ != nullptr;
389 }
390 
391 inline bool Device::isWrapped() const
392 {
393  const ScopedLock scopedLock(lock_);
394 
395  ocean_assert(systemDeviceHandle_ == 0 || isValid());
396 
397  return systemDeviceHandle_ != 0;
398 }
399 
400 inline libusb_class_code Device::classCode() const
401 {
402  const ScopedLock scopedLock(lock_);
403 
404  ocean_assert(isValid());
405 
406  return libusb_class_code(usbDeviceDescriptor_.bDeviceClass);
407 }
408 
409 }
410 
411 }
412 
413 }
414 
415 #endif // META_OCEAN_SYSTEM_USB_DEVICE_H
This class implements a recursive lock object.
Definition: Lock.h:31
This class implements a scoped lock object for recursive lock objects.
Definition: Lock.h:135
This class implements a subscription object which can be used unique subscriptions to e....
Definition: ScopedSubscription.h:28
This class wraps a libusb device.
Definition: system/usb/Device.h:49
SharedContext context() const
The context which is associated with this device.
Definition: system/usb/Device.h:372
Device & operator=(Device &&device)
Move operator.
bool isValid() const
Returns whether this device is valid.
Definition: system/usb/Device.h:377
int64_t systemDeviceHandle_
Optional system device handle in case this object is wrapped (e.g., on Android platforms).
Definition: system/usb/Device.h:332
void releaseInterface(const int interfaceIndex)
Releases a claimed interface.
Device & operator=(const Device &)=delete
Disabled copy operator.
SharedContext context_
The context which is associated with this device, nullptr if the default context is used.
Definition: system/usb/Device.h:329
UsageMap detachedInterfaceUsageMap_
The usage counter for detached kernel drivers.
Definition: system/usb/Device.h:344
uint16_t vendorId() const
Returns the vendor id of the device.
std::string serialNumber() const
Returns the serial number of this device.
Device(const Device &)=delete
Disabled copy constructor.
static std::string stringDescriptor(libusb_device_handle *usbDeviceHandle, const uint8_t index)
Returns a string descriptor of an opened device.
Device(SharedContext context, const int64_t systemDeviceHandle)
Creates a new device object (for an already opened device) based on a given system handle.
bool isOpen() const
Returns whether this device is open.
Definition: system/usb/Device.h:384
std::string manufacturerName() const
Returns the manufacturer name of this device.
std::string productName() const
Returns the product name of the device.
std::string name() const
Returns the name of the device (not the product name).
static bool extractPayload(struct libusb_transfer &usbTransfer, BufferPointers &bufferPointers)
Extracts the payload buffers from a given USB transfer object.
static int determineIsochronousTransferLayout(libusb_context *usbContext, const libusb_interface &interface, const uint8_t endpointAddress, const uint32_t maxVideoFrameSize, const uint32_t maxPayloadTransferSize, size_t &transferSize, size_t &packetsPerTransfer, size_t &bytesPerPacket)
Determines the layout of an isochronous transfer.
void reattachKernelDriver(const int interfaceIndex)
Re-attaches a detached kernel driver for a specified interface.
ScopedSubscription claimInterface(const int interfaceIndex)
Claims an interface of the device.
bool isWrapped() const
Returns whether this device is wrapping a device based on a given system device handle.
Definition: system/usb/Device.h:391
std::unordered_map< int, unsigned int > UsageMap
Definition of an unordered map mapping interface indices to usages.
Definition: system/usb/Device.h:62
ScopedSubscription detachKernelDriver(const int interfaceIndex, bool *driverWasNotActive=nullptr)
Detaches the kernel driver for the device.
std::pair< const void *, size_t > BufferPointer
Definition of a pair combining a pointer to a buffer and the size of this buffer.
Definition: system/usb/Device.h:67
libusb_device * usbDevice_
The actual libusb device.
Definition: system/usb/Device.h:335
UsageMap claimedInterfaceUsageMap_
The usage counter for claimed interfaces.
Definition: system/usb/Device.h:347
libusb_device_handle * usbDeviceHandle()
Returns the handle to the wrapped libusb device.
Definition: system/usb/Device.h:365
virtual ~Device()
Destructs the device and releases all resources.
Device()=default
Default constructor creating an invalid device.
bool close()
Closes an opened device.
Lock lock_
The device's lock.
Definition: system/usb/Device.h:350
Device(SharedContext context, libusb_device *usbDevice, libusb_device_handle *usbDeviceHandle)
Creates a new device object based on a given (already opened) libusb device and its device handle.
libusb_class_code classCode() const
Returns the class code of this device.
Definition: system/usb/Device.h:400
Device(SharedContext context, libusb_device_handle *usbDeviceHandle)
Creates a new device object based on a given libusb device handle (which means that the devices is al...
libusb_device_handle * usbDeviceHandle_
The handle to the opened libusb device.
Definition: system/usb/Device.h:338
void release()
Explicitly releases the device.
Device(SharedContext context, libusb_device *usbDevice)
Creates a new device object based on a given (not yet opened) libusb device.
libusb_device_descriptor usbDeviceDescriptor_
The device descriptor of this device.
Definition: system/usb/Device.h:341
std::vector< BufferPointer > BufferPointers
Definition of a vector holding buffer pointers.
Definition: system/usb/Device.h:72
bool initialize(SharedContext context, libusb_device *usbDevice, libusb_device_handle *usbDeviceHandle)
Initializes this device with a given opened libusb device.
libusb_device * usbDevice()
Returns the wrapped libusb device.
Definition: system/usb/Device.h:358
uint16_t productId() const
Returns the product id of the device.
bool open()
Opens the device.
std::shared_ptr< Device > SharedDevice
Definition of a shared pointer holding a device.
Definition: system/usb/Device.h:34
std::vector< SharedDevice > SharedDevices
Definition of a vector holding SharedDevice objects.
Definition: system/usb/Device.h:41
std::shared_ptr< Context > SharedContext
Definition of a shared pointer holding a context.
Definition: system/usb/Context.h:32
The namespace covering the entire Ocean framework.
Definition: Accessor.h:15