opentitanlib/io/usb/
mod.rs

1// Copyright lowRISC contributors (OpenTitan project).
2// Licensed under the Apache License, Version 2.0, see LICENSE for details.
3// SPDX-License-Identifier: Apache-2.0
4
5pub mod desc;
6
7use anyhow::Result;
8use serde::{Deserialize, Serialize};
9use std::time::Duration;
10use thiserror::Error;
11
12use crate::impl_serializable_error;
13
14/// Errors related to the GPIO interface.
15#[derive(Debug, Error, Serialize, Deserialize)]
16pub enum UsbError {
17    #[error("Generic error: {0}")]
18    Generic(String),
19}
20impl_serializable_error!(UsbError);
21
22/// A trait which represents a USB device.
23pub trait UsbDevice {
24    /// Return the VID of the device.
25    fn get_vendor_id(&self) -> u16;
26
27    /// Return the PID of the device.
28    fn get_product_id(&self) -> u16;
29
30    /// Gets the serial number of the device.
31    fn get_serial_number(&self) -> Option<&str>;
32
33    /// Try to get the parent of this device (or None if root).
34    fn get_parent(&self) -> Result<Box<dyn UsbDevice>>;
35
36    /// Set the active configuration.
37    fn set_active_configuration(&self, config: u8) -> Result<()>;
38
39    /// Claim an interface for use with the kernel.
40    fn claim_interface(&self, iface: u8) -> Result<()>;
41
42    /// Release a previously claimed interface to the kernel.
43    fn release_interface(&self, iface: u8) -> Result<()>;
44
45    /// Set an interface alternate setting.
46    fn set_alternate_setting(&self, iface: u8, setting: u8) -> Result<()>;
47
48    /// Check whether a kernel driver currentl controls the device.
49    fn kernel_driver_active(&self, iface: u8) -> Result<bool>;
50
51    /// Detach the kernel driver from the device.
52    fn detach_kernel_driver(&self, iface: u8) -> Result<()>;
53
54    /// Attach the kernel driver to the device.
55    fn attach_kernel_driver(&self, iface: u8) -> Result<()>;
56
57    /// Return the device's descriptor.
58    fn device_descriptor(&self) -> desc::Device<'_>;
59
60    /// Return the currently active configuration's descriptor.
61    fn active_configuration(&self) -> Result<desc::Configuration<'_>>;
62
63    /// Return the device's bus number.
64    fn bus_number(&self) -> u8;
65
66    /// Return the device's address.
67    fn address(&self) -> u8;
68
69    /// Return the sequence of port numbers from the root down to the device.
70    fn port_numbers(&self) -> Result<Vec<u8>>;
71
72    /// Return a string descriptor in ASCII.
73    fn read_string_descriptor_ascii(&self, idx: u8) -> Result<String>;
74
75    /// Reset the device.
76    ///
77    /// Note that this UsbDevice handle will most likely become invalid
78    /// after resetting the device and a new one has to be obtained.
79    fn reset(&self) -> Result<()>;
80
81    /// Get the default timeout for operations.
82    fn get_timeout(&self) -> Duration;
83
84    /// Issue a USB control request with optional host-to-device data.
85    fn write_control_timeout(
86        &self,
87        request_type: u8,
88        request: u8,
89        value: u16,
90        index: u16,
91        buf: &[u8],
92        timeout: Duration,
93    ) -> Result<usize>;
94
95    /// Issue a USB control request with optional host-to-device data.
96    ///
97    /// This function uses the default timeout set up by the context.
98    fn write_control(
99        &self,
100        request_type: u8,
101        request: u8,
102        value: u16,
103        index: u16,
104        buf: &[u8],
105    ) -> Result<usize> {
106        self.write_control_timeout(request_type, request, value, index, buf, self.get_timeout())
107    }
108
109    /// Issue a USB control request with optional device-to-host data.
110    fn read_control_timeout(
111        &self,
112        request_type: u8,
113        request: u8,
114        value: u16,
115        index: u16,
116        buf: &mut [u8],
117        timeout: Duration,
118    ) -> Result<usize>;
119
120    /// Issue a USB control request with optional device-to-host data.
121    ///
122    /// This function uses the default timeout set up by the context.
123    fn read_control(
124        &self,
125        request_type: u8,
126        request: u8,
127        value: u16,
128        index: u16,
129        buf: &mut [u8],
130    ) -> Result<usize> {
131        self.read_control_timeout(request_type, request, value, index, buf, self.get_timeout())
132    }
133
134    /// Read bulk data bytes to given USB endpoint.
135    fn read_bulk_timeout(&self, endpoint: u8, data: &mut [u8], timeout: Duration) -> Result<usize>;
136
137    /// Read bulk data bytes to given USB endpoint.
138    ///
139    /// This function uses the default timeout set up by the context.
140    fn read_bulk(&self, endpoint: u8, data: &mut [u8]) -> Result<usize> {
141        self.read_bulk_timeout(endpoint, data, self.get_timeout())
142    }
143
144    /// Write bulk data bytes to given USB endpoint.
145    fn write_bulk_timeout(&self, endpoint: u8, data: &[u8], timeout: Duration) -> Result<usize>;
146
147    /// Write bulk data bytes to given USB endpoint.
148    ///
149    /// This function uses the default timeout set up by the context.
150    fn write_bulk(&self, endpoint: u8, data: &[u8]) -> Result<usize> {
151        self.write_bulk_timeout(endpoint, data, self.get_timeout())
152    }
153}
154
155/// A trait which represents a USB context.
156pub trait UsbContext {
157    /// Find a device by VID:PID, and optionally disambiguate by serial number.
158    ///
159    /// If no device matches, this function returns immediately and does not wait.
160    fn device_by_id(
161        &self,
162        usb_vid: u16,
163        usb_pid: u16,
164        usb_serial: Option<&str>,
165    ) -> Result<Box<dyn UsbDevice>> {
166        self.device_by_id_with_timeout(usb_vid, usb_pid, usb_serial, Duration::ZERO)
167    }
168
169    /// Find a device by VID:PID, and optionally disambiguate by serial number.
170    fn device_by_id_with_timeout(
171        &self,
172        usb_vid: u16,
173        usb_pid: u16,
174        usb_serial: Option<&str>,
175        timeout: Duration,
176    ) -> Result<Box<dyn UsbDevice>>;
177
178    /// Find a device with a specific interface, and optionally disambiguate by serial number.
179    ///
180    /// If no device matches, this function returns immediately and does not wait.
181    fn device_by_interface(
182        &self,
183        class: u8,
184        subclass: u8,
185        protocol: u8,
186        usb_serial: Option<&str>,
187    ) -> Result<Box<dyn UsbDevice>> {
188        self.device_by_interface_with_timeout(class, subclass, protocol, usb_serial, Duration::ZERO)
189    }
190
191    fn device_by_interface_with_timeout(
192        &self,
193        class: u8,
194        subclass: u8,
195        protocol: u8,
196        usb_serial: Option<&str>,
197        timeout: Duration,
198    ) -> Result<Box<dyn UsbDevice>>;
199}