1#![allow(clippy::declare_interior_mutable_const)] use core::{
4 cell::UnsafeCell,
5 mem::MaybeUninit,
6 sync::atomic::{AtomicU32, Ordering},
7};
8
9use crate::{buffer::Buffer, endpoint::Endpoint, qh::Qh, td::Td};
10use usb_device::{
11 UsbDirection,
12 endpoint::{EndpointAddress, EndpointType},
13};
14
15#[repr(align(32))]
19struct TdList<const COUNT: usize>([UnsafeCell<Td>; COUNT]);
20
21impl<const COUNT: usize> TdList<COUNT> {
22 const fn new() -> Self {
23 const TD: UnsafeCell<Td> = UnsafeCell::new(Td::new());
24 Self([TD; COUNT])
25 }
26}
27
28#[repr(align(4096))]
32struct QhList<const COUNT: usize>([UnsafeCell<Qh>; COUNT]);
33
34impl<const COUNT: usize> QhList<COUNT> {
35 const fn new() -> Self {
36 const QH: UnsafeCell<Qh> = UnsafeCell::new(Qh::new());
37 Self([QH; COUNT])
38 }
39}
40
41struct EpList<const COUNT: usize>([UnsafeCell<MaybeUninit<Endpoint>>; COUNT]);
45
46impl<const COUNT: usize> EpList<COUNT> {
47 const fn new() -> Self {
48 const EP: UnsafeCell<MaybeUninit<Endpoint>> = UnsafeCell::new(MaybeUninit::uninit());
49 Self([EP; COUNT])
50 }
51}
52
53pub const MAX_ENDPOINTS: usize = 8 * 2;
58
59fn index(ep_addr: EndpointAddress) -> usize {
61 (ep_addr.index() * 2) + (UsbDirection::In == ep_addr.direction()) as usize
62}
63
64pub struct EndpointState<const COUNT: usize = MAX_ENDPOINTS> {
98 qh_list: QhList<COUNT>,
99 td_list: TdList<COUNT>,
100 ep_list: EpList<COUNT>,
101 alloc_mask: AtomicU32,
105}
106
107unsafe impl<const COUNT: usize> Sync for EndpointState<COUNT> {}
108
109impl EndpointState<MAX_ENDPOINTS> {
110 pub const fn max_endpoints() -> Self {
115 Self::new()
116 }
117}
118
119impl<const COUNT: usize> Default for EndpointState<COUNT> {
120 fn default() -> Self {
121 Self::new()
122 }
123}
124
125impl<const COUNT: usize> EndpointState<COUNT> {
126 pub const fn new() -> Self {
128 Self {
129 qh_list: QhList::new(),
130 td_list: TdList::new(),
131 ep_list: EpList::new(),
132 alloc_mask: AtomicU32::new(0),
133 }
134 }
135
136 pub(crate) fn allocator(&self) -> Option<EndpointAllocator<'_>> {
140 const ALLOCATOR_TAKEN: u32 = 1 << 31;
141 let alloc_mask = self.alloc_mask.fetch_or(ALLOCATOR_TAKEN, Ordering::SeqCst);
142 (alloc_mask & ALLOCATOR_TAKEN == 0).then(|| EndpointAllocator {
143 qh_list: &self.qh_list.0[..self.qh_list.0.len().min(MAX_ENDPOINTS)],
144 td_list: &self.td_list.0[..self.td_list.0.len().min(MAX_ENDPOINTS)],
145 ep_list: &self.ep_list.0[..self.ep_list.0.len().min(MAX_ENDPOINTS)],
146 alloc_mask: &self.alloc_mask,
147 })
148 }
149}
150
151pub struct EndpointAllocator<'a> {
152 qh_list: &'a [UnsafeCell<Qh>],
153 td_list: &'a [UnsafeCell<Td>],
154 ep_list: &'a [UnsafeCell<MaybeUninit<Endpoint>>],
155 alloc_mask: &'a AtomicU32,
156}
157
158unsafe impl Send for EndpointAllocator<'_> {}
159
160impl EndpointAllocator<'_> {
161 fn try_mask_update(&mut self, mask: u16) -> Option<()> {
164 let mask = mask.into();
165 (mask & self.alloc_mask.fetch_or(mask, Ordering::SeqCst) == 0).then_some(())
166 }
167
168 fn check_allocated(&self, index: usize) -> Option<()> {
170 (index < self.qh_list.len()).then_some(())?;
171 let mask = 1u16 << index;
172 (mask & self.alloc_mask.load(Ordering::SeqCst) as u16 != 0).then_some(())
173 }
174
175 pub fn qh_list_addr(&self) -> *const () {
179 self.qh_list.as_ptr().cast()
180 }
181
182 pub fn endpoint(&self, addr: EndpointAddress) -> Option<&Endpoint> {
186 let index = index(addr);
187 self.check_allocated(index)?;
188
189 let ep = unsafe { &*self.ep_list[index].get() };
194 Some(unsafe { ep.assume_init_ref() })
196 }
197
198 #[expect(clippy::mut_from_ref, reason = "Only called while &mut available")]
205 unsafe fn endpoint_mut_inner(&self, addr: EndpointAddress) -> Option<&mut Endpoint> {
206 let index = index(addr);
207 self.check_allocated(index)?;
208
209 let ep = unsafe { &mut *self.ep_list[index].get() };
213
214 Some(unsafe { ep.assume_init_mut() })
216 }
217
218 pub fn endpoint_mut(&mut self, addr: EndpointAddress) -> Option<&mut Endpoint> {
222 unsafe { self.endpoint_mut_inner(addr) }
224 }
225
226 pub fn endpoints_iter_mut(&mut self) -> impl Iterator<Item = &mut Endpoint> {
228 (0..8)
229 .flat_map(|index| {
230 let ep_out = EndpointAddress::from_parts(index, UsbDirection::Out);
231 let ep_in = EndpointAddress::from_parts(index, UsbDirection::In);
232 [ep_out, ep_in]
233 })
234 .flat_map(|ep| unsafe { self.endpoint_mut_inner(ep) })
236 }
237
238 pub fn nonzero_endpoints_iter_mut(&mut self) -> impl Iterator<Item = &mut Endpoint> {
242 self.endpoints_iter_mut()
243 .filter(|ep| ep.address().index() != 0)
244 }
245
246 pub fn allocate_endpoint(
253 &mut self,
254 addr: EndpointAddress,
255 buffer: Buffer,
256 kind: EndpointType,
257 ) -> Option<&mut Endpoint> {
258 let index = index(addr);
259 (index < self.qh_list.len()).then_some(())?;
260 let mask = 1u16 << index;
261
262 self.try_mask_update(mask)?;
265
266 let qh = unsafe { &mut *self.qh_list[index].get() };
270 let td = unsafe { &mut *self.td_list[index].get() };
271 let ep = unsafe { &mut *self.ep_list[index].get() };
278 ep.write(Endpoint::new(addr, qh, td, buffer, kind));
280 Some(unsafe { ep.assume_init_mut() })
282 }
283}
284
285#[cfg(test)]
286mod tests {
287 use super::{EndpointAddress, EndpointState, EndpointType};
288 use crate::buffer;
289
290 #[test]
291 fn acquire_allocator() {
292 let ep_state = EndpointState::max_endpoints();
293 ep_state.allocator().unwrap();
294 for _ in 0..10 {
295 assert!(ep_state.allocator().is_none());
296 }
297 }
298
299 #[test]
300 fn allocate_endpoint() {
301 let mut buffer = [0; 128];
302 let mut buffer_alloc = unsafe { buffer::Allocator::from_buffer(&mut buffer) };
303 let ep_state = EndpointState::max_endpoints();
304 let mut ep_alloc = ep_state.allocator().unwrap();
305
306 let addr = EndpointAddress::from(0);
308 assert!(ep_alloc.endpoint(addr).is_none());
309 assert!(ep_alloc.endpoint_mut(addr).is_none());
310
311 let ep = ep_alloc
312 .allocate_endpoint(
313 addr,
314 buffer_alloc.allocate(2).unwrap(),
315 EndpointType::Control,
316 )
317 .unwrap();
318 assert_eq!(ep.address(), addr);
319
320 assert!(ep_alloc.endpoint(addr).is_some());
321 assert!(ep_alloc.endpoint_mut(addr).is_some());
322
323 let ep = ep_alloc.allocate_endpoint(
325 addr,
326 buffer_alloc.allocate(2).unwrap(),
327 EndpointType::Control,
328 );
329 assert!(ep.is_none());
330
331 assert!(ep_alloc.endpoint(addr).is_some());
332 assert!(ep_alloc.endpoint_mut(addr).is_some());
333
334 let addr = EndpointAddress::from(1 << 7);
336
337 assert!(ep_alloc.endpoint(addr).is_none());
338 assert!(ep_alloc.endpoint_mut(addr).is_none());
339
340 let ep = ep_alloc
341 .allocate_endpoint(
342 addr,
343 buffer_alloc.allocate(2).unwrap(),
344 EndpointType::Control,
345 )
346 .unwrap();
347 assert_eq!(ep.address(), addr);
348
349 let addr = EndpointAddress::from(3);
352 assert!(ep_alloc.endpoint(addr).is_none());
353 assert!(ep_alloc.endpoint_mut(addr).is_none());
354
355 let ep = ep_alloc
356 .allocate_endpoint(addr, buffer_alloc.allocate(4).unwrap(), EndpointType::Bulk)
357 .unwrap();
358 assert_eq!(ep.address(), addr);
359
360 assert_eq!(ep_alloc.endpoints_iter_mut().count(), 3);
361 assert_eq!(ep_alloc.nonzero_endpoints_iter_mut().count(), 1);
362
363 for (actual, expected) in ep_alloc.endpoints_iter_mut().zip([0usize, 0, 3]) {
364 assert_eq!(actual.address().index(), expected, "{:?}", actual.address());
365 }
366
367 for (actual, expected) in ep_alloc.nonzero_endpoints_iter_mut().zip([3]) {
368 assert_eq!(actual.address().index(), expected, "{:?}", actual.address());
369 }
370
371 let addr = EndpointAddress::from(42);
373 let ep = ep_alloc.allocate_endpoint(
374 addr,
375 buffer_alloc.allocate(4).unwrap(),
376 EndpointType::Interrupt,
377 );
378 assert!(ep.is_none());
379
380 assert_eq!(ep_alloc.endpoints_iter_mut().count(), 3);
381 }
382}