synopsys_usb_otg/
endpoint.rs

1use crate::endpoint_memory::{EndpointBuffer, EndpointBufferState};
2use crate::ral::{endpoint0_out, endpoint_in, endpoint_out, modify_reg, read_reg, write_reg};
3use crate::target::{fifo_write, UsbRegisters};
4use crate::transition::EndpointDescriptor;
5use crate::UsbPeripheral;
6use core::cell::RefCell;
7use core::ops::{Deref, DerefMut};
8use critical_section::{CriticalSection, Mutex};
9use usb_device::endpoint::EndpointAddress;
10use usb_device::{Result, UsbDirection, UsbError};
11
12pub fn set_stalled(usb: UsbRegisters, address: EndpointAddress, stalled: bool) {
13    critical_section::with(|_| match address.direction() {
14        UsbDirection::Out => {
15            let ep = usb.endpoint_out(address.index() as usize);
16            modify_reg!(endpoint_out, ep, DOEPCTL, STALL: stalled as u32);
17        }
18        UsbDirection::In => {
19            let ep = usb.endpoint_in(address.index() as usize);
20            modify_reg!(endpoint_in, ep, DIEPCTL, STALL: stalled as u32);
21        }
22    })
23}
24
25pub fn is_stalled(usb: UsbRegisters, address: EndpointAddress) -> bool {
26    let stall = match address.direction() {
27        UsbDirection::Out => {
28            let ep = usb.endpoint_out(address.index());
29            read_reg!(endpoint_out, ep, DOEPCTL, STALL)
30        }
31        UsbDirection::In => {
32            let ep = usb.endpoint_in(address.index());
33            read_reg!(endpoint_in, ep, DIEPCTL, STALL)
34        }
35    };
36    stall != 0
37}
38
39/// Arbitrates access to the endpoint-specific registers and packet buffer memory.
40pub struct Endpoint {
41    descriptor: EndpointDescriptor,
42    usb: UsbRegisters,
43}
44
45impl Endpoint {
46    pub fn new<USB: UsbPeripheral>(descriptor: EndpointDescriptor) -> Endpoint {
47        Endpoint {
48            descriptor,
49            usb: UsbRegisters::new::<USB>(),
50        }
51    }
52
53    pub fn address(&self) -> EndpointAddress {
54        self.descriptor.address
55    }
56
57    #[inline(always)]
58    fn index(&self) -> u8 {
59        self.descriptor.address.index() as u8
60    }
61}
62
63pub struct EndpointIn {
64    common: Endpoint,
65}
66
67impl EndpointIn {
68    pub fn new<USB: UsbPeripheral>(descriptor: EndpointDescriptor) -> EndpointIn {
69        EndpointIn {
70            common: Endpoint::new::<USB>(descriptor),
71        }
72    }
73
74    pub fn configure(&self, _cs: CriticalSection<'_>) {
75        if self.index() == 0 {
76            let mpsiz = match self.descriptor.max_packet_size {
77                8 => 0b11,
78                16 => 0b10,
79                32 => 0b01,
80                64 => 0b00,
81                other => panic!("Unsupported EP0 size: {}", other),
82            };
83
84            let regs = self.usb.endpoint_in(self.index() as usize);
85            write_reg!(endpoint_in, regs, DIEPCTL, MPSIZ: mpsiz as u32, SNAK: 1);
86            write_reg!(endpoint_in, regs, DIEPTSIZ, PKTCNT: 0, XFRSIZ: self.descriptor.max_packet_size as u32);
87        } else {
88            let regs = self.usb.endpoint_in(self.index() as usize);
89            write_reg!(endpoint_in, regs, DIEPCTL,
90                SNAK: 1,
91                USBAEP: 1,
92                EPTYP: self.descriptor.ep_type.to_bm_attributes() as u32,
93                SD0PID_SEVNFRM: 1,
94                TXFNUM: self.index() as u32,
95                MPSIZ: self.descriptor.max_packet_size as u32
96            );
97        }
98    }
99
100    pub fn deconfigure(&self, _cs: CriticalSection<'_>) {
101        let regs = self.usb.endpoint_in(self.index() as usize);
102
103        // deactivating endpoint
104        modify_reg!(endpoint_in, regs, DIEPCTL, USBAEP: 0);
105
106        // TODO: flushing FIFO
107
108        // disabling endpoint
109        if read_reg!(endpoint_in, regs, DIEPCTL, EPENA) != 0 && self.index() != 0 {
110            modify_reg!(endpoint_in, regs, DIEPCTL, EPDIS: 1)
111        }
112
113        // clean EP interrupts
114        write_reg!(endpoint_in, regs, DIEPINT, 0xff);
115
116        // TODO: deconfiguring TX FIFO
117    }
118
119    pub fn write(&self, buf: &[u8]) -> Result<()> {
120        let ep = self.usb.endpoint_in(self.index() as usize);
121        if self.index() != 0 && read_reg!(endpoint_in, ep, DIEPCTL, EPENA) != 0 {
122            return Err(UsbError::WouldBlock);
123        }
124
125        if buf.len() > self.descriptor.max_packet_size as usize {
126            return Err(UsbError::BufferOverflow);
127        }
128
129        if !buf.is_empty() {
130            // Check for FIFO free space
131            let size_words = (buf.len() + 3) / 4;
132            if size_words > read_reg!(endpoint_in, ep, DTXFSTS, INEPTFSAV) as usize {
133                return Err(UsbError::WouldBlock);
134            }
135        }
136
137        #[cfg(feature = "fs")]
138        write_reg!(endpoint_in, ep, DIEPTSIZ, PKTCNT: 1, XFRSIZ: buf.len() as u32);
139        #[cfg(feature = "hs")]
140        write_reg!(endpoint_in, ep, DIEPTSIZ, MCNT: 1, PKTCNT: 1, XFRSIZ: buf.len() as u32);
141
142        modify_reg!(endpoint_in, ep, DIEPCTL, CNAK: 1, EPENA: 1);
143
144        fifo_write(self.usb, self.index(), buf);
145
146        Ok(())
147    }
148}
149
150pub struct EndpointOut {
151    common: Endpoint,
152    pub(crate) buffer: Mutex<RefCell<EndpointBuffer>>,
153}
154
155impl EndpointOut {
156    pub fn new<USB: UsbPeripheral>(
157        descriptor: EndpointDescriptor,
158        buffer: EndpointBuffer,
159    ) -> EndpointOut {
160        EndpointOut {
161            common: Endpoint::new::<USB>(descriptor),
162            buffer: Mutex::new(RefCell::new(buffer)),
163        }
164    }
165
166    pub fn configure(&self, _cs: CriticalSection<'_>) {
167        if self.index() == 0 {
168            let mpsiz = match self.descriptor.max_packet_size {
169                8 => 0b11,
170                16 => 0b10,
171                32 => 0b01,
172                64 => 0b00,
173                other => panic!("Unsupported EP0 size: {}", other),
174            };
175
176            let regs = self.usb.endpoint0_out();
177            write_reg!(endpoint0_out, regs, DOEPTSIZ0, STUPCNT: 1, PKTCNT: 1, XFRSIZ: self.descriptor.max_packet_size as u32);
178            modify_reg!(endpoint0_out, regs, DOEPCTL0, MPSIZ: mpsiz as u32, EPENA: 1, CNAK: 1);
179        } else {
180            let regs = self.usb.endpoint_out(self.index() as usize);
181            write_reg!(endpoint_out, regs, DOEPCTL,
182                SD0PID_SEVNFRM: 1,
183                CNAK: 1,
184                EPENA: 1,
185                USBAEP: 1,
186                EPTYP: self.descriptor.ep_type.to_bm_attributes() as u32,
187                MPSIZ: self.descriptor.max_packet_size as u32
188            );
189        }
190    }
191
192    pub fn deconfigure(&self, _cs: CriticalSection<'_>, core_id: u32) {
193        let regs = self.usb.endpoint_out(self.index() as usize);
194
195        // GD32VF103 doesn't support endpoint deactivation after reset, so skip this.
196        if core_id > 0x0000_1000 {
197            // deactivating endpoint
198            modify_reg!(endpoint_out, regs, DOEPCTL, USBAEP: 0);
199
200            // disabling endpoint
201            if read_reg!(endpoint_out, regs, DOEPCTL, EPENA) != 0 && self.index() != 0 {
202                modify_reg!(endpoint_out, regs, DOEPCTL, EPDIS: 1)
203            }
204        }
205
206        // clean EP interrupts
207        write_reg!(endpoint_out, regs, DOEPINT, 0xff);
208    }
209
210    pub fn read(&self, buf: &mut [u8]) -> Result<usize> {
211        critical_section::with(|cs| self.buffer.borrow_ref_mut(cs).read_packet(buf))
212    }
213
214    pub fn buffer_state(&self) -> EndpointBufferState {
215        critical_section::with(|cs| self.buffer.borrow_ref(cs).state())
216    }
217}
218
219impl Deref for EndpointIn {
220    type Target = Endpoint;
221
222    fn deref(&self) -> &Self::Target {
223        &self.common
224    }
225}
226
227impl DerefMut for EndpointIn {
228    fn deref_mut(&mut self) -> &mut Self::Target {
229        &mut self.common
230    }
231}
232
233impl Deref for EndpointOut {
234    type Target = Endpoint;
235
236    fn deref(&self) -> &Self::Target {
237        &self.common
238    }
239}
240
241impl DerefMut for EndpointOut {
242    fn deref_mut(&mut self) -> &mut Self::Target {
243        &mut self.common
244    }
245}