aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDario Nieuwenhuis <[email protected]>2025-07-15 22:08:08 +0000
committerGitHub <[email protected]>2025-07-15 22:08:08 +0000
commitf525386fca8299791fa81539130576059654d778 (patch)
tree6c995bb777b140ce6c6a6b175d9ca659bb5430ab
parent281a05a99de4df6088ff3333f04428b6198caf4b (diff)
parent93e2fdf51267f112adf0c14ccb7b46eb51edd48c (diff)
Merge pull request #4397 from korbin/allocate-numbered-endpoints
Make USB endpoint allocator methods accept an optional `EndpointAddress`
-rw-r--r--embassy-nrf/src/usb/mod.rs51
-rw-r--r--embassy-rp/src/usb.rs30
-rw-r--r--embassy-stm32/src/usb/otg.rs8
-rw-r--r--embassy-stm32/src/usb/usb.rs68
-rw-r--r--embassy-usb-driver/src/lib.rs2
-rw-r--r--embassy-usb-synopsys-otg/src/lib.rs43
-rw-r--r--embassy-usb/src/builder.rs47
-rw-r--r--embassy-usb/src/class/cdc_acm.rs6
-rw-r--r--embassy-usb/src/class/cdc_ncm/mod.rs6
-rw-r--r--embassy-usb/src/class/cmsis_dap_v2.rs6
-rw-r--r--embassy-usb/src/class/hid.rs4
-rw-r--r--embassy-usb/src/class/midi.rs4
-rw-r--r--embassy-usb/src/class/uac1/speaker.rs3
-rw-r--r--examples/rp/src/bin/usb_raw_bulk.rs4
-rw-r--r--examples/rp/src/bin/usb_webusb.rs4
-rw-r--r--examples/rp235x/src/bin/usb_webusb.rs4
16 files changed, 203 insertions, 87 deletions
diff --git a/embassy-nrf/src/usb/mod.rs b/embassy-nrf/src/usb/mod.rs
index 6cc1b0111..c6970fc0f 100644
--- a/embassy-nrf/src/usb/mod.rs
+++ b/embassy-nrf/src/usb/mod.rs
@@ -121,10 +121,11 @@ impl<'d, T: Instance, V: VbusDetect + 'd> driver::Driver<'d> for Driver<'d, T, V
121 fn alloc_endpoint_in( 121 fn alloc_endpoint_in(
122 &mut self, 122 &mut self,
123 ep_type: EndpointType, 123 ep_type: EndpointType,
124 ep_addr: Option<EndpointAddress>,
124 packet_size: u16, 125 packet_size: u16,
125 interval_ms: u8, 126 interval_ms: u8,
126 ) -> Result<Self::EndpointIn, driver::EndpointAllocError> { 127 ) -> Result<Self::EndpointIn, driver::EndpointAllocError> {
127 let index = self.alloc_in.allocate(ep_type)?; 128 let index = self.alloc_in.allocate(ep_type, ep_addr)?;
128 let ep_addr = EndpointAddress::from_parts(index, Direction::In); 129 let ep_addr = EndpointAddress::from_parts(index, Direction::In);
129 Ok(Endpoint::new(EndpointInfo { 130 Ok(Endpoint::new(EndpointInfo {
130 addr: ep_addr, 131 addr: ep_addr,
@@ -137,10 +138,11 @@ impl<'d, T: Instance, V: VbusDetect + 'd> driver::Driver<'d> for Driver<'d, T, V
137 fn alloc_endpoint_out( 138 fn alloc_endpoint_out(
138 &mut self, 139 &mut self,
139 ep_type: EndpointType, 140 ep_type: EndpointType,
141 ep_addr: Option<EndpointAddress>,
140 packet_size: u16, 142 packet_size: u16,
141 interval_ms: u8, 143 interval_ms: u8,
142 ) -> Result<Self::EndpointOut, driver::EndpointAllocError> { 144 ) -> Result<Self::EndpointOut, driver::EndpointAllocError> {
143 let index = self.alloc_out.allocate(ep_type)?; 145 let index = self.alloc_out.allocate(ep_type, ep_addr)?;
144 let ep_addr = EndpointAddress::from_parts(index, Direction::Out); 146 let ep_addr = EndpointAddress::from_parts(index, Direction::Out);
145 Ok(Endpoint::new(EndpointInfo { 147 Ok(Endpoint::new(EndpointInfo {
146 addr: ep_addr, 148 addr: ep_addr,
@@ -734,7 +736,11 @@ impl Allocator {
734 Self { used: 0 } 736 Self { used: 0 }
735 } 737 }
736 738
737 fn allocate(&mut self, ep_type: EndpointType) -> Result<usize, driver::EndpointAllocError> { 739 fn allocate(
740 &mut self,
741 ep_type: EndpointType,
742 ep_addr: Option<EndpointAddress>,
743 ) -> Result<usize, driver::EndpointAllocError> {
738 // Endpoint addresses are fixed in hardware: 744 // Endpoint addresses are fixed in hardware:
739 // - 0x80 / 0x00 - Control EP0 745 // - 0x80 / 0x00 - Control EP0
740 // - 0x81 / 0x01 - Bulk/Interrupt EP1 746 // - 0x81 / 0x01 - Bulk/Interrupt EP1
@@ -748,16 +754,37 @@ impl Allocator {
748 754
749 // Endpoint directions are allocated individually. 755 // Endpoint directions are allocated individually.
750 756
751 let alloc_index = match ep_type { 757 let alloc_index = if let Some(addr) = ep_addr {
752 EndpointType::Isochronous => 8, 758 // Use the specified endpoint address
753 EndpointType::Control => return Err(driver::EndpointAllocError), 759 let requested_index = addr.index();
754 EndpointType::Interrupt | EndpointType::Bulk => { 760 // Validate the requested index based on endpoint type
755 // Find rightmost zero bit in 1..=7 761 match ep_type {
756 let ones = (self.used >> 1).trailing_ones() as usize; 762 EndpointType::Isochronous => {
757 if ones >= 7 { 763 if requested_index != 8 {
758 return Err(driver::EndpointAllocError); 764 return Err(driver::EndpointAllocError);
765 }
766 }
767 EndpointType::Control => return Err(driver::EndpointAllocError),
768 EndpointType::Interrupt | EndpointType::Bulk => {
769 if requested_index < 1 || requested_index > 7 {
770 return Err(driver::EndpointAllocError);
771 }
772 }
773 }
774 requested_index
775 } else {
776 // Allocate any available endpoint
777 match ep_type {
778 EndpointType::Isochronous => 8,
779 EndpointType::Control => return Err(driver::EndpointAllocError),
780 EndpointType::Interrupt | EndpointType::Bulk => {
781 // Find rightmost zero bit in 1..=7
782 let ones = (self.used >> 1).trailing_ones() as usize;
783 if ones >= 7 {
784 return Err(driver::EndpointAllocError);
785 }
786 ones + 1
759 } 787 }
760 ones + 1
761 } 788 }
762 }; 789 };
763 790
diff --git a/embassy-rp/src/usb.rs b/embassy-rp/src/usb.rs
index 96541ade6..671ecbd32 100644
--- a/embassy-rp/src/usb.rs
+++ b/embassy-rp/src/usb.rs
@@ -153,6 +153,7 @@ impl<'d, T: Instance> Driver<'d, T> {
153 fn alloc_endpoint<D: Dir>( 153 fn alloc_endpoint<D: Dir>(
154 &mut self, 154 &mut self,
155 ep_type: EndpointType, 155 ep_type: EndpointType,
156 ep_addr: Option<EndpointAddress>,
156 max_packet_size: u16, 157 max_packet_size: u16,
157 interval_ms: u8, 158 interval_ms: u8,
158 ) -> Result<Endpoint<'d, T, D>, driver::EndpointAllocError> { 159 ) -> Result<Endpoint<'d, T, D>, driver::EndpointAllocError> {
@@ -169,12 +170,25 @@ impl<'d, T: Instance> Driver<'d, T> {
169 Direction::In => &mut self.ep_in, 170 Direction::In => &mut self.ep_in,
170 }; 171 };
171 172
172 let index = alloc.iter_mut().enumerate().find(|(i, ep)| { 173 let index = if let Some(addr) = ep_addr {
173 if *i == 0 { 174 // Use the specified endpoint address
174 return false; // reserved for control pipe 175 let requested_index = addr.index();
176 if requested_index == 0 || requested_index >= EP_COUNT {
177 return Err(EndpointAllocError);
175 } 178 }
176 !ep.used 179 if alloc[requested_index].used {
177 }); 180 return Err(EndpointAllocError);
181 }
182 Some((requested_index, &mut alloc[requested_index]))
183 } else {
184 // Find any available endpoint
185 alloc.iter_mut().enumerate().find(|(i, ep)| {
186 if *i == 0 {
187 return false; // reserved for control pipe
188 }
189 !ep.used
190 })
191 };
178 192
179 let (index, ep) = index.ok_or(EndpointAllocError)?; 193 let (index, ep) = index.ok_or(EndpointAllocError)?;
180 assert!(!ep.used); 194 assert!(!ep.used);
@@ -299,19 +313,21 @@ impl<'d, T: Instance> driver::Driver<'d> for Driver<'d, T> {
299 fn alloc_endpoint_in( 313 fn alloc_endpoint_in(
300 &mut self, 314 &mut self,
301 ep_type: EndpointType, 315 ep_type: EndpointType,
316 ep_addr: Option<EndpointAddress>,
302 max_packet_size: u16, 317 max_packet_size: u16,
303 interval_ms: u8, 318 interval_ms: u8,
304 ) -> Result<Self::EndpointIn, driver::EndpointAllocError> { 319 ) -> Result<Self::EndpointIn, driver::EndpointAllocError> {
305 self.alloc_endpoint(ep_type, max_packet_size, interval_ms) 320 self.alloc_endpoint(ep_type, ep_addr, max_packet_size, interval_ms)
306 } 321 }
307 322
308 fn alloc_endpoint_out( 323 fn alloc_endpoint_out(
309 &mut self, 324 &mut self,
310 ep_type: EndpointType, 325 ep_type: EndpointType,
326 ep_addr: Option<EndpointAddress>,
311 max_packet_size: u16, 327 max_packet_size: u16,
312 interval_ms: u8, 328 interval_ms: u8,
313 ) -> Result<Self::EndpointOut, driver::EndpointAllocError> { 329 ) -> Result<Self::EndpointOut, driver::EndpointAllocError> {
314 self.alloc_endpoint(ep_type, max_packet_size, interval_ms) 330 self.alloc_endpoint(ep_type, ep_addr, max_packet_size, interval_ms)
315 } 331 }
316 332
317 fn start(self, control_max_packet_size: u16) -> (Self::Bus, Self::ControlPipe) { 333 fn start(self, control_max_packet_size: u16) -> (Self::Bus, Self::ControlPipe) {
diff --git a/embassy-stm32/src/usb/otg.rs b/embassy-stm32/src/usb/otg.rs
index 590d1a427..3547ded00 100644
--- a/embassy-stm32/src/usb/otg.rs
+++ b/embassy-stm32/src/usb/otg.rs
@@ -231,19 +231,23 @@ impl<'d, T: Instance> embassy_usb_driver::Driver<'d> for Driver<'d, T> {
231 fn alloc_endpoint_in( 231 fn alloc_endpoint_in(
232 &mut self, 232 &mut self,
233 ep_type: EndpointType, 233 ep_type: EndpointType,
234 ep_addr: Option<EndpointAddress>,
234 max_packet_size: u16, 235 max_packet_size: u16,
235 interval_ms: u8, 236 interval_ms: u8,
236 ) -> Result<Self::EndpointIn, EndpointAllocError> { 237 ) -> Result<Self::EndpointIn, EndpointAllocError> {
237 self.inner.alloc_endpoint_in(ep_type, max_packet_size, interval_ms) 238 self.inner
239 .alloc_endpoint_in(ep_type, ep_addr, max_packet_size, interval_ms)
238 } 240 }
239 241
240 fn alloc_endpoint_out( 242 fn alloc_endpoint_out(
241 &mut self, 243 &mut self,
242 ep_type: EndpointType, 244 ep_type: EndpointType,
245 ep_addr: Option<EndpointAddress>,
243 max_packet_size: u16, 246 max_packet_size: u16,
244 interval_ms: u8, 247 interval_ms: u8,
245 ) -> Result<Self::EndpointOut, EndpointAllocError> { 248 ) -> Result<Self::EndpointOut, EndpointAllocError> {
246 self.inner.alloc_endpoint_out(ep_type, max_packet_size, interval_ms) 249 self.inner
250 .alloc_endpoint_out(ep_type, ep_addr, max_packet_size, interval_ms)
247 } 251 }
248 252
249 fn start(self, control_max_packet_size: u16) -> (Self::Bus, Self::ControlPipe) { 253 fn start(self, control_max_packet_size: u16) -> (Self::Bus, Self::ControlPipe) {
diff --git a/embassy-stm32/src/usb/usb.rs b/embassy-stm32/src/usb/usb.rs
index 3e8e74a1f..92c1601cc 100644
--- a/embassy-stm32/src/usb/usb.rs
+++ b/embassy-stm32/src/usb/usb.rs
@@ -359,9 +359,38 @@ impl<'d, T: Instance> Driver<'d, T> {
359 addr 359 addr
360 } 360 }
361 361
362 fn is_endpoint_available<D: Dir>(&self, index: usize, ep_type: EndpointType) -> bool {
363 if index == 0 && ep_type != EndpointType::Control {
364 return false; // EP0 is reserved for control
365 }
366
367 let ep = match self.alloc.get(index) {
368 Some(ep) => ep,
369 None => return false,
370 };
371
372 let used = ep.used_out || ep.used_in;
373
374 if used && ep.ep_type == EndpointType::Isochronous {
375 // Isochronous endpoints are always double-buffered.
376 // Their corresponding endpoint/channel registers are forced to be unidirectional.
377 // Do not reuse this index.
378 // FIXME: Bulk endpoints can be double buffered, but are not in the current implementation.
379 return false;
380 }
381
382 let used_dir = match D::dir() {
383 Direction::Out => ep.used_out,
384 Direction::In => ep.used_in,
385 };
386
387 !used || (ep.ep_type == ep_type && !used_dir)
388 }
389
362 fn alloc_endpoint<D: Dir>( 390 fn alloc_endpoint<D: Dir>(
363 &mut self, 391 &mut self,
364 ep_type: EndpointType, 392 ep_type: EndpointType,
393 ep_addr: Option<EndpointAddress>,
365 max_packet_size: u16, 394 max_packet_size: u16,
366 interval_ms: u8, 395 interval_ms: u8,
367 ) -> Result<Endpoint<'d, T, D>, driver::EndpointAllocError> { 396 ) -> Result<Endpoint<'d, T, D>, driver::EndpointAllocError> {
@@ -373,28 +402,17 @@ impl<'d, T: Instance> Driver<'d, T> {
373 D::dir() 402 D::dir()
374 ); 403 );
375 404
376 let index = self.alloc.iter_mut().enumerate().find(|(i, ep)| { 405 let index = if let Some(addr) = ep_addr {
377 if *i == 0 && ep_type != EndpointType::Control { 406 // Use the specified endpoint address
378 return false; // reserved for control pipe 407 self.is_endpoint_available::<D>(addr.index(), ep_type)
379 } 408 .then_some(addr.index())
380 let used = ep.used_out || ep.used_in; 409 } else {
381 if used && (ep.ep_type == EndpointType::Isochronous) { 410 // Find any available endpoint
382 // Isochronous endpoints are always double-buffered. 411 (0..self.alloc.len()).find(|&i| self.is_endpoint_available::<D>(i, ep_type))
383 // Their corresponding endpoint/channel registers are forced to be unidirectional. 412 };
384 // Do not reuse this index.
385 // FIXME: Bulk endpoints can be double buffered, but are not in the current implementation.
386 return false;
387 }
388
389 let used_dir = match D::dir() {
390 Direction::Out => ep.used_out,
391 Direction::In => ep.used_in,
392 };
393 !used || (ep.ep_type == ep_type && !used_dir)
394 });
395 413
396 let (index, ep) = match index { 414 let (index, ep) = match index {
397 Some(x) => x, 415 Some(i) => (i, &mut self.alloc[i]),
398 None => return Err(EndpointAllocError), 416 None => return Err(EndpointAllocError),
399 }; 417 };
400 418
@@ -479,27 +497,29 @@ impl<'d, T: Instance> driver::Driver<'d> for Driver<'d, T> {
479 fn alloc_endpoint_in( 497 fn alloc_endpoint_in(
480 &mut self, 498 &mut self,
481 ep_type: EndpointType, 499 ep_type: EndpointType,
500 ep_addr: Option<EndpointAddress>,
482 max_packet_size: u16, 501 max_packet_size: u16,
483 interval_ms: u8, 502 interval_ms: u8,
484 ) -> Result<Self::EndpointIn, driver::EndpointAllocError> { 503 ) -> Result<Self::EndpointIn, driver::EndpointAllocError> {
485 self.alloc_endpoint(ep_type, max_packet_size, interval_ms) 504 self.alloc_endpoint(ep_type, ep_addr, max_packet_size, interval_ms)
486 } 505 }
487 506
488 fn alloc_endpoint_out( 507 fn alloc_endpoint_out(
489 &mut self, 508 &mut self,
490 ep_type: EndpointType, 509 ep_type: EndpointType,
510 ep_addr: Option<EndpointAddress>,
491 max_packet_size: u16, 511 max_packet_size: u16,
492 interval_ms: u8, 512 interval_ms: u8,
493 ) -> Result<Self::EndpointOut, driver::EndpointAllocError> { 513 ) -> Result<Self::EndpointOut, driver::EndpointAllocError> {
494 self.alloc_endpoint(ep_type, max_packet_size, interval_ms) 514 self.alloc_endpoint(ep_type, ep_addr, max_packet_size, interval_ms)
495 } 515 }
496 516
497 fn start(mut self, control_max_packet_size: u16) -> (Self::Bus, Self::ControlPipe) { 517 fn start(mut self, control_max_packet_size: u16) -> (Self::Bus, Self::ControlPipe) {
498 let ep_out = self 518 let ep_out = self
499 .alloc_endpoint(EndpointType::Control, control_max_packet_size, 0) 519 .alloc_endpoint(EndpointType::Control, None, control_max_packet_size, 0)
500 .unwrap(); 520 .unwrap();
501 let ep_in = self 521 let ep_in = self
502 .alloc_endpoint(EndpointType::Control, control_max_packet_size, 0) 522 .alloc_endpoint(EndpointType::Control, None, control_max_packet_size, 0)
503 .unwrap(); 523 .unwrap();
504 assert_eq!(ep_out.info.addr.index(), 0); 524 assert_eq!(ep_out.info.addr.index(), 0);
505 assert_eq!(ep_in.info.addr.index(), 0); 525 assert_eq!(ep_in.info.addr.index(), 0);
diff --git a/embassy-usb-driver/src/lib.rs b/embassy-usb-driver/src/lib.rs
index d204e4d85..99616f1ec 100644
--- a/embassy-usb-driver/src/lib.rs
+++ b/embassy-usb-driver/src/lib.rs
@@ -136,6 +136,7 @@ pub trait Driver<'a> {
136 fn alloc_endpoint_out( 136 fn alloc_endpoint_out(
137 &mut self, 137 &mut self,
138 ep_type: EndpointType, 138 ep_type: EndpointType,
139 ep_addr: Option<EndpointAddress>,
139 max_packet_size: u16, 140 max_packet_size: u16,
140 interval_ms: u8, 141 interval_ms: u8,
141 ) -> Result<Self::EndpointOut, EndpointAllocError>; 142 ) -> Result<Self::EndpointOut, EndpointAllocError>;
@@ -153,6 +154,7 @@ pub trait Driver<'a> {
153 fn alloc_endpoint_in( 154 fn alloc_endpoint_in(
154 &mut self, 155 &mut self,
155 ep_type: EndpointType, 156 ep_type: EndpointType,
157 ep_addr: Option<EndpointAddress>,
156 max_packet_size: u16, 158 max_packet_size: u16,
157 interval_ms: u8, 159 interval_ms: u8,
158 ) -> Result<Self::EndpointIn, EndpointAllocError>; 160 ) -> Result<Self::EndpointIn, EndpointAllocError>;
diff --git a/embassy-usb-synopsys-otg/src/lib.rs b/embassy-usb-synopsys-otg/src/lib.rs
index 3f6531813..9d74c046d 100644
--- a/embassy-usb-synopsys-otg/src/lib.rs
+++ b/embassy-usb-synopsys-otg/src/lib.rs
@@ -345,6 +345,7 @@ impl<'d, const MAX_EP_COUNT: usize> Driver<'d, MAX_EP_COUNT> {
345 fn alloc_endpoint<D: Dir>( 345 fn alloc_endpoint<D: Dir>(
346 &mut self, 346 &mut self,
347 ep_type: EndpointType, 347 ep_type: EndpointType,
348 ep_addr: Option<EndpointAddress>,
348 max_packet_size: u16, 349 max_packet_size: u16,
349 interval_ms: u8, 350 interval_ms: u8,
350 ) -> Result<Endpoint<'d, D>, EndpointAllocError> { 351 ) -> Result<Endpoint<'d, D>, EndpointAllocError> {
@@ -379,15 +380,31 @@ impl<'d, const MAX_EP_COUNT: usize> Driver<'d, MAX_EP_COUNT> {
379 Direction::In => &mut self.ep_in[..self.instance.endpoint_count], 380 Direction::In => &mut self.ep_in[..self.instance.endpoint_count],
380 }; 381 };
381 382
382 // Find free endpoint slot 383 // Find endpoint slot
383 let slot = eps.iter_mut().enumerate().find(|(i, ep)| { 384 let slot = if let Some(addr) = ep_addr {
384 if *i == 0 && ep_type != EndpointType::Control { 385 // Use the specified endpoint address
385 // reserved for control pipe 386 let requested_index = addr.index();
386 false 387 if requested_index >= self.instance.endpoint_count {
387 } else { 388 return Err(EndpointAllocError);
388 ep.is_none()
389 } 389 }
390 }); 390 if requested_index == 0 && ep_type != EndpointType::Control {
391 return Err(EndpointAllocError); // EP0 is reserved for control
392 }
393 if eps[requested_index].is_some() {
394 return Err(EndpointAllocError); // Already allocated
395 }
396 Some((requested_index, &mut eps[requested_index]))
397 } else {
398 // Find any free endpoint slot
399 eps.iter_mut().enumerate().find(|(i, ep)| {
400 if *i == 0 && ep_type != EndpointType::Control {
401 // reserved for control pipe
402 false
403 } else {
404 ep.is_none()
405 }
406 })
407 };
391 408
392 let index = match slot { 409 let index = match slot {
393 Some((index, ep)) => { 410 Some((index, ep)) => {
@@ -438,27 +455,29 @@ impl<'d, const MAX_EP_COUNT: usize> embassy_usb_driver::Driver<'d> for Driver<'d
438 fn alloc_endpoint_in( 455 fn alloc_endpoint_in(
439 &mut self, 456 &mut self,
440 ep_type: EndpointType, 457 ep_type: EndpointType,
458 ep_addr: Option<EndpointAddress>,
441 max_packet_size: u16, 459 max_packet_size: u16,
442 interval_ms: u8, 460 interval_ms: u8,
443 ) -> Result<Self::EndpointIn, EndpointAllocError> { 461 ) -> Result<Self::EndpointIn, EndpointAllocError> {
444 self.alloc_endpoint(ep_type, max_packet_size, interval_ms) 462 self.alloc_endpoint(ep_type, ep_addr, max_packet_size, interval_ms)
445 } 463 }
446 464
447 fn alloc_endpoint_out( 465 fn alloc_endpoint_out(
448 &mut self, 466 &mut self,
449 ep_type: EndpointType, 467 ep_type: EndpointType,
468 ep_addr: Option<EndpointAddress>,
450 max_packet_size: u16, 469 max_packet_size: u16,
451 interval_ms: u8, 470 interval_ms: u8,
452 ) -> Result<Self::EndpointOut, EndpointAllocError> { 471 ) -> Result<Self::EndpointOut, EndpointAllocError> {
453 self.alloc_endpoint(ep_type, max_packet_size, interval_ms) 472 self.alloc_endpoint(ep_type, ep_addr, max_packet_size, interval_ms)
454 } 473 }
455 474
456 fn start(mut self, control_max_packet_size: u16) -> (Self::Bus, Self::ControlPipe) { 475 fn start(mut self, control_max_packet_size: u16) -> (Self::Bus, Self::ControlPipe) {
457 let ep_out = self 476 let ep_out = self
458 .alloc_endpoint(EndpointType::Control, control_max_packet_size, 0) 477 .alloc_endpoint(EndpointType::Control, None, control_max_packet_size, 0)
459 .unwrap(); 478 .unwrap();
460 let ep_in = self 479 let ep_in = self
461 .alloc_endpoint(EndpointType::Control, control_max_packet_size, 0) 480 .alloc_endpoint(EndpointType::Control, None, control_max_packet_size, 0)
462 .unwrap(); 481 .unwrap();
463 assert_eq!(ep_out.info.addr.index(), 0); 482 assert_eq!(ep_out.info.addr.index(), 0);
464 assert_eq!(ep_in.info.addr.index(), 0); 483 assert_eq!(ep_in.info.addr.index(), 0);
diff --git a/embassy-usb/src/builder.rs b/embassy-usb/src/builder.rs
index 6c4b3f9a4..8d7abe46c 100644
--- a/embassy-usb/src/builder.rs
+++ b/embassy-usb/src/builder.rs
@@ -2,7 +2,7 @@ use heapless::Vec;
2 2
3use crate::config::MAX_HANDLER_COUNT; 3use crate::config::MAX_HANDLER_COUNT;
4use crate::descriptor::{BosWriter, DescriptorWriter, SynchronizationType, UsageType}; 4use crate::descriptor::{BosWriter, DescriptorWriter, SynchronizationType, UsageType};
5use crate::driver::{Driver, Endpoint, EndpointInfo, EndpointType}; 5use crate::driver::{Driver, Endpoint, EndpointAddress, EndpointInfo, EndpointType};
6use crate::msos::{DeviceLevelDescriptor, FunctionLevelDescriptor, MsOsDescriptorWriter}; 6use crate::msos::{DeviceLevelDescriptor, FunctionLevelDescriptor, MsOsDescriptorWriter};
7use crate::types::{InterfaceNumber, StringIndex}; 7use crate::types::{InterfaceNumber, StringIndex};
8use crate::{Handler, Interface, UsbDevice, MAX_INTERFACE_COUNT, STRING_INDEX_CUSTOM_START}; 8use crate::{Handler, Interface, UsbDevice, MAX_INTERFACE_COUNT, STRING_INDEX_CUSTOM_START};
@@ -465,11 +465,17 @@ impl<'a, 'd, D: Driver<'d>> InterfaceAltBuilder<'a, 'd, D> {
465 /// Allocate an IN endpoint, without writing its descriptor. 465 /// Allocate an IN endpoint, without writing its descriptor.
466 /// 466 ///
467 /// Used for granular control over the order of endpoint and descriptor creation. 467 /// Used for granular control over the order of endpoint and descriptor creation.
468 pub fn alloc_endpoint_in(&mut self, ep_type: EndpointType, max_packet_size: u16, interval_ms: u8) -> D::EndpointIn { 468 pub fn alloc_endpoint_in(
469 &mut self,
470 ep_type: EndpointType,
471 ep_addr: Option<EndpointAddress>,
472 max_packet_size: u16,
473 interval_ms: u8,
474 ) -> D::EndpointIn {
469 let ep = self 475 let ep = self
470 .builder 476 .builder
471 .driver 477 .driver
472 .alloc_endpoint_in(ep_type, max_packet_size, interval_ms) 478 .alloc_endpoint_in(ep_type, ep_addr, max_packet_size, interval_ms)
473 .expect("alloc_endpoint_in failed"); 479 .expect("alloc_endpoint_in failed");
474 480
475 ep 481 ep
@@ -478,13 +484,14 @@ impl<'a, 'd, D: Driver<'d>> InterfaceAltBuilder<'a, 'd, D> {
478 fn endpoint_in( 484 fn endpoint_in(
479 &mut self, 485 &mut self,
480 ep_type: EndpointType, 486 ep_type: EndpointType,
487 ep_addr: Option<EndpointAddress>,
481 max_packet_size: u16, 488 max_packet_size: u16,
482 interval_ms: u8, 489 interval_ms: u8,
483 synchronization_type: SynchronizationType, 490 synchronization_type: SynchronizationType,
484 usage_type: UsageType, 491 usage_type: UsageType,
485 extra_fields: &[u8], 492 extra_fields: &[u8],
486 ) -> D::EndpointIn { 493 ) -> D::EndpointIn {
487 let ep = self.alloc_endpoint_in(ep_type, max_packet_size, interval_ms); 494 let ep = self.alloc_endpoint_in(ep_type, ep_addr, max_packet_size, interval_ms);
488 self.endpoint_descriptor(ep.info(), synchronization_type, usage_type, extra_fields); 495 self.endpoint_descriptor(ep.info(), synchronization_type, usage_type, extra_fields);
489 496
490 ep 497 ep
@@ -496,13 +503,14 @@ impl<'a, 'd, D: Driver<'d>> InterfaceAltBuilder<'a, 'd, D> {
496 pub fn alloc_endpoint_out( 503 pub fn alloc_endpoint_out(
497 &mut self, 504 &mut self,
498 ep_type: EndpointType, 505 ep_type: EndpointType,
506 ep_addr: Option<EndpointAddress>,
499 max_packet_size: u16, 507 max_packet_size: u16,
500 interval_ms: u8, 508 interval_ms: u8,
501 ) -> D::EndpointOut { 509 ) -> D::EndpointOut {
502 let ep = self 510 let ep = self
503 .builder 511 .builder
504 .driver 512 .driver
505 .alloc_endpoint_out(ep_type, max_packet_size, interval_ms) 513 .alloc_endpoint_out(ep_type, ep_addr, max_packet_size, interval_ms)
506 .expect("alloc_endpoint_out failed"); 514 .expect("alloc_endpoint_out failed");
507 515
508 ep 516 ep
@@ -511,13 +519,14 @@ impl<'a, 'd, D: Driver<'d>> InterfaceAltBuilder<'a, 'd, D> {
511 fn endpoint_out( 519 fn endpoint_out(
512 &mut self, 520 &mut self,
513 ep_type: EndpointType, 521 ep_type: EndpointType,
522 ep_addr: Option<EndpointAddress>,
514 max_packet_size: u16, 523 max_packet_size: u16,
515 interval_ms: u8, 524 interval_ms: u8,
516 synchronization_type: SynchronizationType, 525 synchronization_type: SynchronizationType,
517 usage_type: UsageType, 526 usage_type: UsageType,
518 extra_fields: &[u8], 527 extra_fields: &[u8],
519 ) -> D::EndpointOut { 528 ) -> D::EndpointOut {
520 let ep = self.alloc_endpoint_out(ep_type, max_packet_size, interval_ms); 529 let ep = self.alloc_endpoint_out(ep_type, ep_addr, max_packet_size, interval_ms);
521 self.endpoint_descriptor(ep.info(), synchronization_type, usage_type, extra_fields); 530 self.endpoint_descriptor(ep.info(), synchronization_type, usage_type, extra_fields);
522 531
523 ep 532 ep
@@ -527,9 +536,10 @@ impl<'a, 'd, D: Driver<'d>> InterfaceAltBuilder<'a, 'd, D> {
527 /// 536 ///
528 /// Descriptors are written in the order builder functions are called. Note that some 537 /// Descriptors are written in the order builder functions are called. Note that some
529 /// classes care about the order. 538 /// classes care about the order.
530 pub fn endpoint_bulk_in(&mut self, max_packet_size: u16) -> D::EndpointIn { 539 pub fn endpoint_bulk_in(&mut self, ep_addr: Option<EndpointAddress>, max_packet_size: u16) -> D::EndpointIn {
531 self.endpoint_in( 540 self.endpoint_in(
532 EndpointType::Bulk, 541 EndpointType::Bulk,
542 ep_addr,
533 max_packet_size, 543 max_packet_size,
534 0, 544 0,
535 SynchronizationType::NoSynchronization, 545 SynchronizationType::NoSynchronization,
@@ -542,9 +552,10 @@ impl<'a, 'd, D: Driver<'d>> InterfaceAltBuilder<'a, 'd, D> {
542 /// 552 ///
543 /// Descriptors are written in the order builder functions are called. Note that some 553 /// Descriptors are written in the order builder functions are called. Note that some
544 /// classes care about the order. 554 /// classes care about the order.
545 pub fn endpoint_bulk_out(&mut self, max_packet_size: u16) -> D::EndpointOut { 555 pub fn endpoint_bulk_out(&mut self, ep_addr: Option<EndpointAddress>, max_packet_size: u16) -> D::EndpointOut {
546 self.endpoint_out( 556 self.endpoint_out(
547 EndpointType::Bulk, 557 EndpointType::Bulk,
558 ep_addr,
548 max_packet_size, 559 max_packet_size,
549 0, 560 0,
550 SynchronizationType::NoSynchronization, 561 SynchronizationType::NoSynchronization,
@@ -557,9 +568,15 @@ impl<'a, 'd, D: Driver<'d>> InterfaceAltBuilder<'a, 'd, D> {
557 /// 568 ///
558 /// Descriptors are written in the order builder functions are called. Note that some 569 /// Descriptors are written in the order builder functions are called. Note that some
559 /// classes care about the order. 570 /// classes care about the order.
560 pub fn endpoint_interrupt_in(&mut self, max_packet_size: u16, interval_ms: u8) -> D::EndpointIn { 571 pub fn endpoint_interrupt_in(
572 &mut self,
573 ep_addr: Option<EndpointAddress>,
574 max_packet_size: u16,
575 interval_ms: u8,
576 ) -> D::EndpointIn {
561 self.endpoint_in( 577 self.endpoint_in(
562 EndpointType::Interrupt, 578 EndpointType::Interrupt,
579 ep_addr,
563 max_packet_size, 580 max_packet_size,
564 interval_ms, 581 interval_ms,
565 SynchronizationType::NoSynchronization, 582 SynchronizationType::NoSynchronization,
@@ -569,9 +586,15 @@ impl<'a, 'd, D: Driver<'d>> InterfaceAltBuilder<'a, 'd, D> {
569 } 586 }
570 587
571 /// Allocate a INTERRUPT OUT endpoint and write its descriptor. 588 /// Allocate a INTERRUPT OUT endpoint and write its descriptor.
572 pub fn endpoint_interrupt_out(&mut self, max_packet_size: u16, interval_ms: u8) -> D::EndpointOut { 589 pub fn endpoint_interrupt_out(
590 &mut self,
591 ep_addr: Option<EndpointAddress>,
592 max_packet_size: u16,
593 interval_ms: u8,
594 ) -> D::EndpointOut {
573 self.endpoint_out( 595 self.endpoint_out(
574 EndpointType::Interrupt, 596 EndpointType::Interrupt,
597 ep_addr,
575 max_packet_size, 598 max_packet_size,
576 interval_ms, 599 interval_ms,
577 SynchronizationType::NoSynchronization, 600 SynchronizationType::NoSynchronization,
@@ -586,6 +609,7 @@ impl<'a, 'd, D: Driver<'d>> InterfaceAltBuilder<'a, 'd, D> {
586 /// classes care about the order. 609 /// classes care about the order.
587 pub fn endpoint_isochronous_in( 610 pub fn endpoint_isochronous_in(
588 &mut self, 611 &mut self,
612 ep_addr: Option<EndpointAddress>,
589 max_packet_size: u16, 613 max_packet_size: u16,
590 interval_ms: u8, 614 interval_ms: u8,
591 synchronization_type: SynchronizationType, 615 synchronization_type: SynchronizationType,
@@ -594,6 +618,7 @@ impl<'a, 'd, D: Driver<'d>> InterfaceAltBuilder<'a, 'd, D> {
594 ) -> D::EndpointIn { 618 ) -> D::EndpointIn {
595 self.endpoint_in( 619 self.endpoint_in(
596 EndpointType::Isochronous, 620 EndpointType::Isochronous,
621 ep_addr,
597 max_packet_size, 622 max_packet_size,
598 interval_ms, 623 interval_ms,
599 synchronization_type, 624 synchronization_type,
@@ -605,6 +630,7 @@ impl<'a, 'd, D: Driver<'d>> InterfaceAltBuilder<'a, 'd, D> {
605 /// Allocate a ISOCHRONOUS OUT endpoint and write its descriptor. 630 /// Allocate a ISOCHRONOUS OUT endpoint and write its descriptor.
606 pub fn endpoint_isochronous_out( 631 pub fn endpoint_isochronous_out(
607 &mut self, 632 &mut self,
633 ep_addr: Option<EndpointAddress>,
608 max_packet_size: u16, 634 max_packet_size: u16,
609 interval_ms: u8, 635 interval_ms: u8,
610 synchronization_type: SynchronizationType, 636 synchronization_type: SynchronizationType,
@@ -613,6 +639,7 @@ impl<'a, 'd, D: Driver<'d>> InterfaceAltBuilder<'a, 'd, D> {
613 ) -> D::EndpointOut { 639 ) -> D::EndpointOut {
614 self.endpoint_out( 640 self.endpoint_out(
615 EndpointType::Isochronous, 641 EndpointType::Isochronous,
642 ep_addr,
616 max_packet_size, 643 max_packet_size,
617 interval_ms, 644 interval_ms,
618 synchronization_type, 645 synchronization_type,
diff --git a/embassy-usb/src/class/cdc_acm.rs b/embassy-usb/src/class/cdc_acm.rs
index 732a433f8..a1144ce05 100644
--- a/embassy-usb/src/class/cdc_acm.rs
+++ b/embassy-usb/src/class/cdc_acm.rs
@@ -254,14 +254,14 @@ impl<'d, D: Driver<'d>> CdcAcmClass<'d, D> {
254 ], 254 ],
255 ); 255 );
256 256
257 let comm_ep = alt.endpoint_interrupt_in(8, 255); 257 let comm_ep = alt.endpoint_interrupt_in(None, 8, 255);
258 258
259 // Data interface 259 // Data interface
260 let mut iface = func.interface(); 260 let mut iface = func.interface();
261 let data_if = iface.interface_number(); 261 let data_if = iface.interface_number();
262 let mut alt = iface.alt_setting(USB_CLASS_CDC_DATA, 0x00, CDC_PROTOCOL_NONE, None); 262 let mut alt = iface.alt_setting(USB_CLASS_CDC_DATA, 0x00, CDC_PROTOCOL_NONE, None);
263 let read_ep = alt.endpoint_bulk_out(max_packet_size); 263 let read_ep = alt.endpoint_bulk_out(None, max_packet_size);
264 let write_ep = alt.endpoint_bulk_in(max_packet_size); 264 let write_ep = alt.endpoint_bulk_in(None, max_packet_size);
265 265
266 drop(func); 266 drop(func);
267 267
diff --git a/embassy-usb/src/class/cdc_ncm/mod.rs b/embassy-usb/src/class/cdc_ncm/mod.rs
index 09d923d2a..3af853091 100644
--- a/embassy-usb/src/class/cdc_ncm/mod.rs
+++ b/embassy-usb/src/class/cdc_ncm/mod.rs
@@ -313,15 +313,15 @@ impl<'d, D: Driver<'d>> CdcNcmClass<'d, D> {
313 ], 313 ],
314 ); 314 );
315 315
316 let comm_ep = alt.endpoint_interrupt_in(8, 255); 316 let comm_ep = alt.endpoint_interrupt_in(None, 8, 255);
317 317
318 // Data interface 318 // Data interface
319 let mut iface = func.interface(); 319 let mut iface = func.interface();
320 let data_if = iface.interface_number(); 320 let data_if = iface.interface_number();
321 let _alt = iface.alt_setting(USB_CLASS_CDC_DATA, 0x00, CDC_PROTOCOL_NTB, None); 321 let _alt = iface.alt_setting(USB_CLASS_CDC_DATA, 0x00, CDC_PROTOCOL_NTB, None);
322 let mut alt = iface.alt_setting(USB_CLASS_CDC_DATA, 0x00, CDC_PROTOCOL_NTB, None); 322 let mut alt = iface.alt_setting(USB_CLASS_CDC_DATA, 0x00, CDC_PROTOCOL_NTB, None);
323 let read_ep = alt.endpoint_bulk_out(max_packet_size); 323 let read_ep = alt.endpoint_bulk_out(None, max_packet_size);
324 let write_ep = alt.endpoint_bulk_in(max_packet_size); 324 let write_ep = alt.endpoint_bulk_in(None, max_packet_size);
325 325
326 drop(func); 326 drop(func);
327 327
diff --git a/embassy-usb/src/class/cmsis_dap_v2.rs b/embassy-usb/src/class/cmsis_dap_v2.rs
index a94e3ddb7..a9fd9cdf0 100644
--- a/embassy-usb/src/class/cmsis_dap_v2.rs
+++ b/embassy-usb/src/class/cmsis_dap_v2.rs
@@ -61,10 +61,10 @@ impl<'d, D: Driver<'d>> CmsisDapV2Class<'d, D> {
61 )); 61 ));
62 let mut interface = function.interface(); 62 let mut interface = function.interface();
63 let mut alt = interface.alt_setting(0xFF, 0, 0, Some(iface_string)); 63 let mut alt = interface.alt_setting(0xFF, 0, 0, Some(iface_string));
64 let read_ep = alt.endpoint_bulk_out(max_packet_size); 64 let read_ep = alt.endpoint_bulk_out(None, max_packet_size);
65 let write_ep = alt.endpoint_bulk_in(max_packet_size); 65 let write_ep = alt.endpoint_bulk_in(None, max_packet_size);
66 let trace_ep = if trace { 66 let trace_ep = if trace {
67 Some(alt.endpoint_bulk_in(max_packet_size)) 67 Some(alt.endpoint_bulk_in(None, max_packet_size))
68 } else { 68 } else {
69 None 69 None
70 }; 70 };
diff --git a/embassy-usb/src/class/hid.rs b/embassy-usb/src/class/hid.rs
index 6d9e0aced..182e1f83f 100644
--- a/embassy-usb/src/class/hid.rs
+++ b/embassy-usb/src/class/hid.rs
@@ -133,9 +133,9 @@ fn build<'d, D: Driver<'d>>(
133 ], 133 ],
134 ); 134 );
135 135
136 let ep_in = alt.endpoint_interrupt_in(config.max_packet_size, config.poll_ms); 136 let ep_in = alt.endpoint_interrupt_in(None, config.max_packet_size, config.poll_ms);
137 let ep_out = if with_out_endpoint { 137 let ep_out = if with_out_endpoint {
138 Some(alt.endpoint_interrupt_out(config.max_packet_size, config.poll_ms)) 138 Some(alt.endpoint_interrupt_out(None, config.max_packet_size, config.poll_ms))
139 } else { 139 } else {
140 None 140 None
141 }; 141 };
diff --git a/embassy-usb/src/class/midi.rs b/embassy-usb/src/class/midi.rs
index 52a96f278..1d152ca44 100644
--- a/embassy-usb/src/class/midi.rs
+++ b/embassy-usb/src/class/midi.rs
@@ -129,14 +129,14 @@ impl<'d, D: Driver<'d>> MidiClass<'d, D> {
129 for i in 0..n_out_jacks { 129 for i in 0..n_out_jacks {
130 endpoint_data[2 + i as usize] = in_jack_id_emb(i); 130 endpoint_data[2 + i as usize] = in_jack_id_emb(i);
131 } 131 }
132 let read_ep = alt.endpoint_bulk_out(max_packet_size); 132 let read_ep = alt.endpoint_bulk_out(None, max_packet_size);
133 alt.descriptor(CS_ENDPOINT, &endpoint_data[0..2 + n_out_jacks as usize]); 133 alt.descriptor(CS_ENDPOINT, &endpoint_data[0..2 + n_out_jacks as usize]);
134 134
135 endpoint_data[1] = n_in_jacks; 135 endpoint_data[1] = n_in_jacks;
136 for i in 0..n_in_jacks { 136 for i in 0..n_in_jacks {
137 endpoint_data[2 + i as usize] = out_jack_id_emb(i); 137 endpoint_data[2 + i as usize] = out_jack_id_emb(i);
138 } 138 }
139 let write_ep = alt.endpoint_bulk_in(max_packet_size); 139 let write_ep = alt.endpoint_bulk_in(None, max_packet_size);
140 alt.descriptor(CS_ENDPOINT, &endpoint_data[0..2 + n_in_jacks as usize]); 140 alt.descriptor(CS_ENDPOINT, &endpoint_data[0..2 + n_in_jacks as usize]);
141 141
142 MidiClass { read_ep, write_ep } 142 MidiClass { read_ep, write_ep }
diff --git a/embassy-usb/src/class/uac1/speaker.rs b/embassy-usb/src/class/uac1/speaker.rs
index 1ff29088c..9565e2a25 100644
--- a/embassy-usb/src/class/uac1/speaker.rs
+++ b/embassy-usb/src/class/uac1/speaker.rs
@@ -268,9 +268,10 @@ impl<'d, D: Driver<'d>> Speaker<'d, D> {
268 268
269 alt.descriptor(CS_INTERFACE, &format_descriptor); 269 alt.descriptor(CS_INTERFACE, &format_descriptor);
270 270
271 let streaming_endpoint = alt.alloc_endpoint_out(EndpointType::Isochronous, max_packet_size, 1); 271 let streaming_endpoint = alt.alloc_endpoint_out(EndpointType::Isochronous, None, max_packet_size, 1);
272 let feedback_endpoint = alt.alloc_endpoint_in( 272 let feedback_endpoint = alt.alloc_endpoint_in(
273 EndpointType::Isochronous, 273 EndpointType::Isochronous,
274 None,
274 4, // Feedback packets are 24 bit (10.14 format). 275 4, // Feedback packets are 24 bit (10.14 format).
275 1, 276 1,
276 ); 277 );
diff --git a/examples/rp/src/bin/usb_raw_bulk.rs b/examples/rp/src/bin/usb_raw_bulk.rs
index 103269791..0747901d1 100644
--- a/examples/rp/src/bin/usb_raw_bulk.rs
+++ b/examples/rp/src/bin/usb_raw_bulk.rs
@@ -96,8 +96,8 @@ async fn main(_spawner: Spawner) {
96 let mut function = builder.function(0xFF, 0, 0); 96 let mut function = builder.function(0xFF, 0, 0);
97 let mut interface = function.interface(); 97 let mut interface = function.interface();
98 let mut alt = interface.alt_setting(0xFF, 0, 0, None); 98 let mut alt = interface.alt_setting(0xFF, 0, 0, None);
99 let mut read_ep = alt.endpoint_bulk_out(64); 99 let mut read_ep = alt.endpoint_bulk_out(None, 64);
100 let mut write_ep = alt.endpoint_bulk_in(64); 100 let mut write_ep = alt.endpoint_bulk_in(None, 64);
101 drop(function); 101 drop(function);
102 102
103 // Build the builder. 103 // Build the builder.
diff --git a/examples/rp/src/bin/usb_webusb.rs b/examples/rp/src/bin/usb_webusb.rs
index a5dc94d5b..5cecb92f0 100644
--- a/examples/rp/src/bin/usb_webusb.rs
+++ b/examples/rp/src/bin/usb_webusb.rs
@@ -125,8 +125,8 @@ impl<'d, D: Driver<'d>> WebEndpoints<'d, D> {
125 let mut iface = func.interface(); 125 let mut iface = func.interface();
126 let mut alt = iface.alt_setting(0xff, 0x00, 0x00, None); 126 let mut alt = iface.alt_setting(0xff, 0x00, 0x00, None);
127 127
128 let write_ep = alt.endpoint_bulk_in(config.max_packet_size); 128 let write_ep = alt.endpoint_bulk_in(None, config.max_packet_size);
129 let read_ep = alt.endpoint_bulk_out(config.max_packet_size); 129 let read_ep = alt.endpoint_bulk_out(None, config.max_packet_size);
130 130
131 WebEndpoints { write_ep, read_ep } 131 WebEndpoints { write_ep, read_ep }
132 } 132 }
diff --git a/examples/rp235x/src/bin/usb_webusb.rs b/examples/rp235x/src/bin/usb_webusb.rs
index 75d28c853..a68163b61 100644
--- a/examples/rp235x/src/bin/usb_webusb.rs
+++ b/examples/rp235x/src/bin/usb_webusb.rs
@@ -125,8 +125,8 @@ impl<'d, D: Driver<'d>> WebEndpoints<'d, D> {
125 let mut iface = func.interface(); 125 let mut iface = func.interface();
126 let mut alt = iface.alt_setting(0xff, 0x00, 0x00, None); 126 let mut alt = iface.alt_setting(0xff, 0x00, 0x00, None);
127 127
128 let write_ep = alt.endpoint_bulk_in(config.max_packet_size); 128 let write_ep = alt.endpoint_bulk_in(None, config.max_packet_size);
129 let read_ep = alt.endpoint_bulk_out(config.max_packet_size); 129 let read_ep = alt.endpoint_bulk_out(None, config.max_packet_size);
130 130
131 WebEndpoints { write_ep, read_ep } 131 WebEndpoints { write_ep, read_ep }
132 } 132 }