usb_descriptor_decoder/descriptors/
desc_endpoint.rs

1use bit_field::BitField;
2use num_derive::FromPrimitive;
3use num_traits::FromPrimitive;
4
5use super::PortSpeed;
6
7#[derive(Copy, Clone, Default, Debug)]
8#[repr(C, packed)]
9pub struct Endpoint {
10    len: u8,
11    descriptor_type: u8,
12    pub endpoint_address: u8,
13    pub attributes: u8,
14    pub max_packet_size: u16,
15    pub interval: u8,
16    pub ssc: Option<SuperSpeedCmp>,
17}
18
19#[derive(Clone, Copy, Debug)]
20#[repr(C, packed)]
21pub struct SuperSpeedCmp {
22    pub kind: u8,
23    pub max_burst: u8,
24    pub attributes: u8,
25    pub bytes_per_interval: u16,
26}
27
28impl Endpoint {
29    pub fn endpoint_type(&self) -> EndpointType {
30        EndpointType::from_u8(if self.attributes == 0 {
31            4
32        } else {
33            self.attributes.get_bits(0..=1)
34                + if self.endpoint_address.get_bit(7) {
35                    4
36                } else {
37                    0
38                }
39        })
40        .expect("EndpointType must be convertible from `attributes` and `endpoint_address`.")
41    }
42
43    pub fn calc_actual_interval(&self, port_speed: PortSpeed) -> u8 {
44        if let PortSpeed::FullSpeed | PortSpeed::LowSpeed = port_speed {
45            if let EndpointType::IsochOut | EndpointType::IsochIn = self.endpoint_type() {
46                self.interval + 2
47            } else {
48                self.interval + 3
49            }
50        } else {
51            self.interval - 1
52        }
53    }
54
55    pub fn max_streams(&self) -> Option<u8> {
56        //TODO: complete me
57        if self.is_bulk_out() {
58            Some(self.calculate_max_streams())
59        } else {
60            None
61        }
62    }
63
64    pub fn is_bulk_out(&self) -> bool {
65        self.endpoint_type() == EndpointType::BulkOut
66    }
67
68    pub fn calculate_max_streams(&self) -> u8 {
69        self.ssc
70            .as_ref()
71            .map(|ssc| {
72                if self.is_bulk_out() {
73                    
74                    ssc.attributes & 0x1F
75                } else {
76                    0
77                }
78            })
79            .unwrap()
80    }
81
82    pub fn is_superspeedplus(&self) -> bool {
83        false
84    }
85
86    pub fn mult(&self, lec: bool) -> u8 {
87        if !lec && self.endpoint_type() == EndpointType::IsochOut {
88            if self.is_superspeedplus() {
89                return 0;
90            }
91            self.ssc
92                .as_ref()
93                .map(|ssc| ssc.attributes & 0x3)
94                .unwrap_or(0)
95        } else {
96            0
97        }
98    }
99
100    pub fn doorbell_value_aka_dci(&self) -> u32 {
101        2 * u32::from(self.endpoint_address.get_bits(0..=3))
102            + self.endpoint_address.get_bit(7) as u32
103    }
104}
105
106#[derive(Copy, Clone, Debug, Ord, PartialOrd, Eq, PartialEq, Hash, FromPrimitive)]
107pub enum EndpointType {
108    /// Not Valid.
109    NotValid = 0,
110    /// Isoch Out.
111    IsochOut = 1,
112    /// Bulk Out.
113    BulkOut = 2,
114    /// Interrupt Out.
115    InterruptOut = 3,
116    /// Control Bidirectional.
117    Control = 4,
118    /// Isoch In.
119    IsochIn = 5,
120    /// Bulk In.
121    BulkIn = 6,
122    /// Interrupt In.
123    InterruptIn = 7,
124}