usb_descriptor_decoder/descriptors/
desc_endpoint.rs1use 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 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 NotValid = 0,
110 IsochOut = 1,
112 BulkOut = 2,
114 InterruptOut = 3,
116 Control = 4,
118 IsochIn = 5,
120 BulkIn = 6,
122 InterruptIn = 7,
124}