aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDario Nieuwenhuis <[email protected]>2024-09-16 19:51:52 +0000
committerGitHub <[email protected]>2024-09-16 19:51:52 +0000
commitae8caf3f55d91579234f199458c369536fd39bb1 (patch)
tree43e2180b0292cece5d4f590f06f4717cc97c9b09
parente90b3bc4494682ae23d5839328ab950e34ca7cfe (diff)
parenta8ca6713e6e9b7ad5dd53f9b46bcf5e893adda1e (diff)
Merge pull request #3314 from elagil/add_iso_endpoint_support
Add ISO endpoint support
-rw-r--r--embassy-stm32/src/usb/usb.rs211
-rw-r--r--embassy-usb-synopsys-otg/src/lib.rs30
-rw-r--r--embassy-usb-synopsys-otg/src/otg_v1.rs16
-rw-r--r--embassy-usb/src/builder.rs140
-rw-r--r--embassy-usb/src/descriptor.rs91
5 files changed, 430 insertions, 58 deletions
diff --git a/embassy-stm32/src/usb/usb.rs b/embassy-stm32/src/usb/usb.rs
index 9384c8688..0ab2306c8 100644
--- a/embassy-stm32/src/usb/usb.rs
+++ b/embassy-stm32/src/usb/usb.rs
@@ -80,6 +80,8 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandl
80 80
81 if istr.ctr() { 81 if istr.ctr() {
82 let index = istr.ep_id() as usize; 82 let index = istr.ep_id() as usize;
83 CTR_TRIGGERED[index].store(true, Ordering::Relaxed);
84
83 let mut epr = regs.epr(index).read(); 85 let mut epr = regs.epr(index).read();
84 if epr.ctr_rx() { 86 if epr.ctr_rx() {
85 if index == 0 && epr.setup() { 87 if index == 0 && epr.setup() {
@@ -120,6 +122,10 @@ const USBRAM_ALIGN: usize = 4;
120const NEW_AW: AtomicWaker = AtomicWaker::new(); 122const NEW_AW: AtomicWaker = AtomicWaker::new();
121static BUS_WAKER: AtomicWaker = NEW_AW; 123static BUS_WAKER: AtomicWaker = NEW_AW;
122static EP0_SETUP: AtomicBool = AtomicBool::new(false); 124static EP0_SETUP: AtomicBool = AtomicBool::new(false);
125
126const NEW_CTR_TRIGGERED: AtomicBool = AtomicBool::new(false);
127static CTR_TRIGGERED: [AtomicBool; EP_COUNT] = [NEW_CTR_TRIGGERED; EP_COUNT];
128
123static EP_IN_WAKERS: [AtomicWaker; EP_COUNT] = [NEW_AW; EP_COUNT]; 129static EP_IN_WAKERS: [AtomicWaker; EP_COUNT] = [NEW_AW; EP_COUNT];
124static EP_OUT_WAKERS: [AtomicWaker; EP_COUNT] = [NEW_AW; EP_COUNT]; 130static EP_OUT_WAKERS: [AtomicWaker; EP_COUNT] = [NEW_AW; EP_COUNT];
125static IRQ_RESET: AtomicBool = AtomicBool::new(false); 131static IRQ_RESET: AtomicBool = AtomicBool::new(false);
@@ -163,20 +169,37 @@ fn calc_out_len(len: u16) -> (u16, u16) {
163mod btable { 169mod btable {
164 use super::*; 170 use super::*;
165 171
166 pub(super) fn write_in<T: Instance>(index: usize, addr: u16) { 172 pub(super) fn write_in_tx<T: Instance>(index: usize, addr: u16) {
167 USBRAM.mem(index * 4 + 0).write_value(addr); 173 USBRAM.mem(index * 4 + 0).write_value(addr);
168 } 174 }
169 175
170 pub(super) fn write_in_len<T: Instance>(index: usize, _addr: u16, len: u16) { 176 pub(super) fn write_in_rx<T: Instance>(index: usize, addr: u16) {
177 USBRAM.mem(index * 4 + 2).write_value(addr);
178 }
179
180 pub(super) fn write_in_len_rx<T: Instance>(index: usize, _addr: u16, len: u16) {
181 USBRAM.mem(index * 4 + 3).write_value(len);
182 }
183
184 pub(super) fn write_in_len_tx<T: Instance>(index: usize, _addr: u16, len: u16) {
171 USBRAM.mem(index * 4 + 1).write_value(len); 185 USBRAM.mem(index * 4 + 1).write_value(len);
172 } 186 }
173 187
174 pub(super) fn write_out<T: Instance>(index: usize, addr: u16, max_len_bits: u16) { 188 pub(super) fn write_out_rx<T: Instance>(index: usize, addr: u16, max_len_bits: u16) {
175 USBRAM.mem(index * 4 + 2).write_value(addr); 189 USBRAM.mem(index * 4 + 2).write_value(addr);
176 USBRAM.mem(index * 4 + 3).write_value(max_len_bits); 190 USBRAM.mem(index * 4 + 3).write_value(max_len_bits);
177 } 191 }
178 192
179 pub(super) fn read_out_len<T: Instance>(index: usize) -> u16 { 193 pub(super) fn write_out_tx<T: Instance>(index: usize, addr: u16, max_len_bits: u16) {
194 USBRAM.mem(index * 4 + 0).write_value(addr);
195 USBRAM.mem(index * 4 + 1).write_value(max_len_bits);
196 }
197
198 pub(super) fn read_out_len_tx<T: Instance>(index: usize) -> u16 {
199 USBRAM.mem(index * 4 + 1).read()
200 }
201
202 pub(super) fn read_out_len_rx<T: Instance>(index: usize) -> u16 {
180 USBRAM.mem(index * 4 + 3).read() 203 USBRAM.mem(index * 4 + 3).read()
181 } 204 }
182} 205}
@@ -184,19 +207,37 @@ mod btable {
184mod btable { 207mod btable {
185 use super::*; 208 use super::*;
186 209
187 pub(super) fn write_in<T: Instance>(_index: usize, _addr: u16) {} 210 pub(super) fn write_in_tx<T: Instance>(_index: usize, _addr: u16) {}
188 211
189 pub(super) fn write_in_len<T: Instance>(index: usize, addr: u16, len: u16) { 212 pub(super) fn write_in_rx<T: Instance>(_index: usize, _addr: u16) {}
213
214 pub(super) fn write_in_len_tx<T: Instance>(index: usize, addr: u16, len: u16) {
190 USBRAM.mem(index * 2).write_value((addr as u32) | ((len as u32) << 16)); 215 USBRAM.mem(index * 2).write_value((addr as u32) | ((len as u32) << 16));
191 } 216 }
192 217
193 pub(super) fn write_out<T: Instance>(index: usize, addr: u16, max_len_bits: u16) { 218 pub(super) fn write_in_len_rx<T: Instance>(index: usize, addr: u16, len: u16) {
219 USBRAM
220 .mem(index * 2 + 1)
221 .write_value((addr as u32) | ((len as u32) << 16));
222 }
223
224 pub(super) fn write_out_tx<T: Instance>(index: usize, addr: u16, max_len_bits: u16) {
225 USBRAM
226 .mem(index * 2)
227 .write_value((addr as u32) | ((max_len_bits as u32) << 16));
228 }
229
230 pub(super) fn write_out_rx<T: Instance>(index: usize, addr: u16, max_len_bits: u16) {
194 USBRAM 231 USBRAM
195 .mem(index * 2 + 1) 232 .mem(index * 2 + 1)
196 .write_value((addr as u32) | ((max_len_bits as u32) << 16)); 233 .write_value((addr as u32) | ((max_len_bits as u32) << 16));
197 } 234 }
198 235
199 pub(super) fn read_out_len<T: Instance>(index: usize) -> u16 { 236 pub(super) fn read_out_len_tx<T: Instance>(index: usize) -> u16 {
237 (USBRAM.mem(index * 2).read() >> 16) as u16
238 }
239
240 pub(super) fn read_out_len_rx<T: Instance>(index: usize) -> u16 {
200 (USBRAM.mem(index * 2 + 1).read() >> 16) as u16 241 (USBRAM.mem(index * 2 + 1).read() >> 16) as u16
201 } 242 }
202} 243}
@@ -327,6 +368,13 @@ impl<'d, T: Instance> Driver<'d, T> {
327 return false; // reserved for control pipe 368 return false; // reserved for control pipe
328 } 369 }
329 let used = ep.used_out || ep.used_in; 370 let used = ep.used_out || ep.used_in;
371 if used && (ep.ep_type == EndpointType::Isochronous || ep.ep_type == EndpointType::Bulk) {
372 // Isochronous and bulk endpoints are double-buffered.
373 // Their corresponding endpoint/channel registers are forced to be unidirectional.
374 // Do not reuse this index.
375 return false;
376 }
377
330 let used_dir = match D::dir() { 378 let used_dir = match D::dir() {
331 Direction::Out => ep.used_out, 379 Direction::Out => ep.used_out,
332 Direction::In => ep.used_in, 380 Direction::In => ep.used_in,
@@ -350,7 +398,11 @@ impl<'d, T: Instance> Driver<'d, T> {
350 let addr = self.alloc_ep_mem(len); 398 let addr = self.alloc_ep_mem(len);
351 399
352 trace!(" len_bits = {:04x}", len_bits); 400 trace!(" len_bits = {:04x}", len_bits);
353 btable::write_out::<T>(index, addr, len_bits); 401 btable::write_out_rx::<T>(index, addr, len_bits);
402
403 if ep_type == EndpointType::Isochronous {
404 btable::write_out_tx::<T>(index, addr, len_bits);
405 }
354 406
355 EndpointBuffer { 407 EndpointBuffer {
356 addr, 408 addr,
@@ -366,7 +418,11 @@ impl<'d, T: Instance> Driver<'d, T> {
366 let addr = self.alloc_ep_mem(len); 418 let addr = self.alloc_ep_mem(len);
367 419
368 // ep_in_len is written when actually TXing packets. 420 // ep_in_len is written when actually TXing packets.
369 btable::write_in::<T>(index, addr); 421 btable::write_in_tx::<T>(index, addr);
422
423 if ep_type == EndpointType::Isochronous {
424 btable::write_in_rx::<T>(index, addr);
425 }
370 426
371 EndpointBuffer { 427 EndpointBuffer {
372 addr, 428 addr,
@@ -656,6 +712,18 @@ impl Dir for Out {
656 } 712 }
657} 713}
658 714
715/// Selects the packet buffer.
716///
717/// For double-buffered endpoints, both the `Rx` and `Tx` buffer from a channel are used for the same
718/// direction of transfer. This is opposed to single-buffered endpoints, where one channel can serve
719/// two directions at the same time.
720enum PacketBuffer {
721 /// The RX buffer - must be used for single-buffered OUT endpoints
722 Rx,
723 /// The TX buffer - must be used for single-buffered IN endpoints
724 Tx,
725}
726
659/// USB endpoint. 727/// USB endpoint.
660pub struct Endpoint<'d, T: Instance, D> { 728pub struct Endpoint<'d, T: Instance, D> {
661 _phantom: PhantomData<(&'d mut T, D)>, 729 _phantom: PhantomData<(&'d mut T, D)>,
@@ -664,15 +732,46 @@ pub struct Endpoint<'d, T: Instance, D> {
664} 732}
665 733
666impl<'d, T: Instance, D> Endpoint<'d, T, D> { 734impl<'d, T: Instance, D> Endpoint<'d, T, D> {
667 fn write_data(&mut self, buf: &[u8]) { 735 /// Write to a double-buffered endpoint.
736 ///
737 /// For double-buffered endpoints, the data buffers overlap, but we still need to write to the right counter field.
738 /// The DTOG_TX bit indicates the buffer that is currently in use by the USB peripheral, that is, the buffer in
739 /// which the next transmit packet will be stored, so we need to write the counter of the OTHER buffer, which is
740 /// where the last transmitted packet was stored.
741 fn write_data_double_buffered(&mut self, buf: &[u8], packet_buffer: PacketBuffer) {
668 let index = self.info.addr.index(); 742 let index = self.info.addr.index();
669 self.buf.write(buf); 743 self.buf.write(buf);
670 btable::write_in_len::<T>(index, self.buf.addr, buf.len() as _); 744
745 match packet_buffer {
746 PacketBuffer::Rx => btable::write_in_len_rx::<T>(index, self.buf.addr, buf.len() as _),
747 PacketBuffer::Tx => btable::write_in_len_tx::<T>(index, self.buf.addr, buf.len() as _),
748 }
671 } 749 }
672 750
673 fn read_data(&mut self, buf: &mut [u8]) -> Result<usize, EndpointError> { 751 /// Write to a single-buffered endpoint.
752 fn write_data(&mut self, buf: &[u8]) {
753 self.write_data_double_buffered(buf, PacketBuffer::Tx);
754 }
755
756 /// Read from a double-buffered endpoint.
757 ///
758 /// For double-buffered endpoints, the data buffers overlap, but we still need to read from the right counter field.
759 /// The DTOG_RX bit indicates the buffer that is currently in use by the USB peripheral, that is, the buffer in
760 /// which the next received packet will be stored, so we need to read the counter of the OTHER buffer, which is
761 /// where the last received packet was stored.
762 fn read_data_double_buffered(
763 &mut self,
764 buf: &mut [u8],
765 packet_buffer: PacketBuffer,
766 ) -> Result<usize, EndpointError> {
674 let index = self.info.addr.index(); 767 let index = self.info.addr.index();
675 let rx_len = btable::read_out_len::<T>(index) as usize & 0x3FF; 768
769 let rx_len = match packet_buffer {
770 PacketBuffer::Rx => btable::read_out_len_rx::<T>(index),
771 PacketBuffer::Tx => btable::read_out_len_tx::<T>(index),
772 } as usize
773 & 0x3FF;
774
676 trace!("READ DONE, rx_len = {}", rx_len); 775 trace!("READ DONE, rx_len = {}", rx_len);
677 if rx_len > buf.len() { 776 if rx_len > buf.len() {
678 return Err(EndpointError::BufferOverflow); 777 return Err(EndpointError::BufferOverflow);
@@ -680,6 +779,11 @@ impl<'d, T: Instance, D> Endpoint<'d, T, D> {
680 self.buf.read(&mut buf[..rx_len]); 779 self.buf.read(&mut buf[..rx_len]);
681 Ok(rx_len) 780 Ok(rx_len)
682 } 781 }
782
783 /// Read from a single-buffered endpoint.
784 fn read_data(&mut self, buf: &mut [u8]) -> Result<usize, EndpointError> {
785 self.read_data_double_buffered(buf, PacketBuffer::Rx)
786 }
683} 787}
684 788
685impl<'d, T: Instance> driver::Endpoint for Endpoint<'d, T, In> { 789impl<'d, T: Instance> driver::Endpoint for Endpoint<'d, T, In> {
@@ -734,25 +838,53 @@ impl<'d, T: Instance> driver::EndpointOut for Endpoint<'d, T, Out> {
734 EP_OUT_WAKERS[index].register(cx.waker()); 838 EP_OUT_WAKERS[index].register(cx.waker());
735 let regs = T::regs(); 839 let regs = T::regs();
736 let stat = regs.epr(index).read().stat_rx(); 840 let stat = regs.epr(index).read().stat_rx();
737 if matches!(stat, Stat::NAK | Stat::DISABLED) { 841 if self.info.ep_type == EndpointType::Isochronous {
738 Poll::Ready(stat) 842 // The isochronous endpoint does not change its `STAT_RX` field to `NAK` when receiving a packet.
843 // Therefore, this instead waits until the `CTR` interrupt was triggered.
844 if matches!(stat, Stat::DISABLED) || CTR_TRIGGERED[index].load(Ordering::Relaxed) {
845 Poll::Ready(stat)
846 } else {
847 Poll::Pending
848 }
739 } else { 849 } else {
740 Poll::Pending 850 if matches!(stat, Stat::NAK | Stat::DISABLED) {
851 Poll::Ready(stat)
852 } else {
853 Poll::Pending
854 }
741 } 855 }
742 }) 856 })
743 .await; 857 .await;
744 858
859 CTR_TRIGGERED[index].store(false, Ordering::Relaxed);
860
745 if stat == Stat::DISABLED { 861 if stat == Stat::DISABLED {
746 return Err(EndpointError::Disabled); 862 return Err(EndpointError::Disabled);
747 } 863 }
748 864
749 let rx_len = self.read_data(buf)?;
750
751 let regs = T::regs(); 865 let regs = T::regs();
866
867 let packet_buffer = if self.info.ep_type == EndpointType::Isochronous {
868 // Find the buffer, which is currently in use. Read from the OTHER buffer.
869 if regs.epr(index).read().dtog_rx() {
870 PacketBuffer::Rx
871 } else {
872 PacketBuffer::Tx
873 }
874 } else {
875 PacketBuffer::Rx
876 };
877
878 let rx_len = self.read_data_double_buffered(buf, packet_buffer)?;
879
752 regs.epr(index).write(|w| { 880 regs.epr(index).write(|w| {
753 w.set_ep_type(convert_type(self.info.ep_type)); 881 w.set_ep_type(convert_type(self.info.ep_type));
754 w.set_ea(self.info.addr.index() as _); 882 w.set_ea(self.info.addr.index() as _);
755 w.set_stat_rx(Stat::from_bits(Stat::NAK.to_bits() ^ Stat::VALID.to_bits())); 883 if self.info.ep_type == EndpointType::Isochronous {
884 w.set_stat_rx(Stat::from_bits(0)); // STAT_RX remains `VALID`.
885 } else {
886 w.set_stat_rx(Stat::from_bits(Stat::NAK.to_bits() ^ Stat::VALID.to_bits()));
887 }
756 w.set_stat_tx(Stat::from_bits(0)); 888 w.set_stat_tx(Stat::from_bits(0));
757 w.set_ctr_rx(true); // don't clear 889 w.set_ctr_rx(true); // don't clear
758 w.set_ctr_tx(true); // don't clear 890 w.set_ctr_tx(true); // don't clear
@@ -776,25 +908,54 @@ impl<'d, T: Instance> driver::EndpointIn for Endpoint<'d, T, In> {
776 EP_IN_WAKERS[index].register(cx.waker()); 908 EP_IN_WAKERS[index].register(cx.waker());
777 let regs = T::regs(); 909 let regs = T::regs();
778 let stat = regs.epr(index).read().stat_tx(); 910 let stat = regs.epr(index).read().stat_tx();
779 if matches!(stat, Stat::NAK | Stat::DISABLED) { 911 if self.info.ep_type == EndpointType::Isochronous {
780 Poll::Ready(stat) 912 // The isochronous endpoint does not change its `STAT_RX` field to `NAK` when receiving a packet.
913 // Therefore, this instead waits until the `CTR` interrupt was triggered.
914 if matches!(stat, Stat::DISABLED) || CTR_TRIGGERED[index].load(Ordering::Relaxed) {
915 Poll::Ready(stat)
916 } else {
917 Poll::Pending
918 }
781 } else { 919 } else {
782 Poll::Pending 920 if matches!(stat, Stat::NAK | Stat::DISABLED) {
921 Poll::Ready(stat)
922 } else {
923 Poll::Pending
924 }
783 } 925 }
784 }) 926 })
785 .await; 927 .await;
786 928
929 CTR_TRIGGERED[index].store(false, Ordering::Relaxed);
930
787 if stat == Stat::DISABLED { 931 if stat == Stat::DISABLED {
788 return Err(EndpointError::Disabled); 932 return Err(EndpointError::Disabled);
789 } 933 }
790 934
791 self.write_data(buf); 935 let regs = T::regs();
936
937 let packet_buffer = if self.info.ep_type == EndpointType::Isochronous {
938 // Find the buffer, which is currently in use. Write to the OTHER buffer.
939 if regs.epr(index).read().dtog_tx() {
940 PacketBuffer::Tx
941 } else {
942 PacketBuffer::Rx
943 }
944 } else {
945 PacketBuffer::Tx
946 };
947
948 self.write_data_double_buffered(buf, packet_buffer);
792 949
793 let regs = T::regs(); 950 let regs = T::regs();
794 regs.epr(index).write(|w| { 951 regs.epr(index).write(|w| {
795 w.set_ep_type(convert_type(self.info.ep_type)); 952 w.set_ep_type(convert_type(self.info.ep_type));
796 w.set_ea(self.info.addr.index() as _); 953 w.set_ea(self.info.addr.index() as _);
797 w.set_stat_tx(Stat::from_bits(Stat::NAK.to_bits() ^ Stat::VALID.to_bits())); 954 if self.info.ep_type == EndpointType::Isochronous {
955 w.set_stat_tx(Stat::from_bits(0)); // STAT_TX remains `VALID`.
956 } else {
957 w.set_stat_tx(Stat::from_bits(Stat::NAK.to_bits() ^ Stat::VALID.to_bits()));
958 }
798 w.set_stat_rx(Stat::from_bits(0)); 959 w.set_stat_rx(Stat::from_bits(0));
799 w.set_ctr_rx(true); // don't clear 960 w.set_ctr_rx(true); // don't clear
800 w.set_ctr_tx(true); // don't clear 961 w.set_ctr_tx(true); // don't clear
diff --git a/embassy-usb-synopsys-otg/src/lib.rs b/embassy-usb-synopsys-otg/src/lib.rs
index 5fb82db42..b145f4aa8 100644
--- a/embassy-usb-synopsys-otg/src/lib.rs
+++ b/embassy-usb-synopsys-otg/src/lib.rs
@@ -1071,6 +1071,21 @@ impl<'d> embassy_usb_driver::EndpointOut for Endpoint<'d, Out> {
1071 w.set_pktcnt(1); 1071 w.set_pktcnt(1);
1072 }); 1072 });
1073 1073
1074 if self.info.ep_type == EndpointType::Isochronous {
1075 // Isochronous endpoints must set the correct even/odd frame bit to
1076 // correspond with the next frame's number.
1077 let frame_number = self.regs.dsts().read().fnsof();
1078 let frame_is_odd = frame_number & 0x01 == 1;
1079
1080 self.regs.doepctl(index).modify(|r| {
1081 if frame_is_odd {
1082 r.set_sd0pid_sevnfrm(true);
1083 } else {
1084 r.set_sd1pid_soddfrm(true);
1085 }
1086 });
1087 }
1088
1074 // Clear NAK to indicate we are ready to receive more data 1089 // Clear NAK to indicate we are ready to receive more data
1075 self.regs.doepctl(index).modify(|w| { 1090 self.regs.doepctl(index).modify(|w| {
1076 w.set_cnak(true); 1091 w.set_cnak(true);
@@ -1158,6 +1173,21 @@ impl<'d> embassy_usb_driver::EndpointIn for Endpoint<'d, In> {
1158 w.set_xfrsiz(buf.len() as _); 1173 w.set_xfrsiz(buf.len() as _);
1159 }); 1174 });
1160 1175
1176 if self.info.ep_type == EndpointType::Isochronous {
1177 // Isochronous endpoints must set the correct even/odd frame bit to
1178 // correspond with the next frame's number.
1179 let frame_number = self.regs.dsts().read().fnsof();
1180 let frame_is_odd = frame_number & 0x01 == 1;
1181
1182 self.regs.diepctl(index).modify(|r| {
1183 if frame_is_odd {
1184 r.set_sd0pid_sevnfrm(true);
1185 } else {
1186 r.set_sd1pid_soddfrm(true);
1187 }
1188 });
1189 }
1190
1161 // Enable endpoint 1191 // Enable endpoint
1162 self.regs.diepctl(index).modify(|w| { 1192 self.regs.diepctl(index).modify(|w| {
1163 w.set_cnak(true); 1193 w.set_cnak(true);
diff --git a/embassy-usb-synopsys-otg/src/otg_v1.rs b/embassy-usb-synopsys-otg/src/otg_v1.rs
index a8530980c..d3abc328d 100644
--- a/embassy-usb-synopsys-otg/src/otg_v1.rs
+++ b/embassy-usb-synopsys-otg/src/otg_v1.rs
@@ -795,15 +795,15 @@ pub mod regs {
795 pub fn set_sd0pid_sevnfrm(&mut self, val: bool) { 795 pub fn set_sd0pid_sevnfrm(&mut self, val: bool) {
796 self.0 = (self.0 & !(0x01 << 28usize)) | (((val as u32) & 0x01) << 28usize); 796 self.0 = (self.0 & !(0x01 << 28usize)) | (((val as u32) & 0x01) << 28usize);
797 } 797 }
798 #[doc = "SODDFRM/SD1PID"] 798 #[doc = "SD1PID/SODDFRM"]
799 #[inline(always)] 799 #[inline(always)]
800 pub const fn soddfrm_sd1pid(&self) -> bool { 800 pub const fn sd1pid_soddfrm(&self) -> bool {
801 let val = (self.0 >> 29usize) & 0x01; 801 let val = (self.0 >> 29usize) & 0x01;
802 val != 0 802 val != 0
803 } 803 }
804 #[doc = "SODDFRM/SD1PID"] 804 #[doc = "SD1PID/SODDFRM"]
805 #[inline(always)] 805 #[inline(always)]
806 pub fn set_soddfrm_sd1pid(&mut self, val: bool) { 806 pub fn set_sd1pid_soddfrm(&mut self, val: bool) {
807 self.0 = (self.0 & !(0x01 << 29usize)) | (((val as u32) & 0x01) << 29usize); 807 self.0 = (self.0 & !(0x01 << 29usize)) | (((val as u32) & 0x01) << 29usize);
808 } 808 }
809 #[doc = "EPDIS"] 809 #[doc = "EPDIS"]
@@ -1174,15 +1174,15 @@ pub mod regs {
1174 pub fn set_sd0pid_sevnfrm(&mut self, val: bool) { 1174 pub fn set_sd0pid_sevnfrm(&mut self, val: bool) {
1175 self.0 = (self.0 & !(0x01 << 28usize)) | (((val as u32) & 0x01) << 28usize); 1175 self.0 = (self.0 & !(0x01 << 28usize)) | (((val as u32) & 0x01) << 28usize);
1176 } 1176 }
1177 #[doc = "SODDFRM"] 1177 #[doc = "SD1PID/SODDFRM"]
1178 #[inline(always)] 1178 #[inline(always)]
1179 pub const fn soddfrm(&self) -> bool { 1179 pub const fn sd1pid_soddfrm(&self) -> bool {
1180 let val = (self.0 >> 29usize) & 0x01; 1180 let val = (self.0 >> 29usize) & 0x01;
1181 val != 0 1181 val != 0
1182 } 1182 }
1183 #[doc = "SODDFRM"] 1183 #[doc = "SD1PID/SODDFRM"]
1184 #[inline(always)] 1184 #[inline(always)]
1185 pub fn set_soddfrm(&mut self, val: bool) { 1185 pub fn set_sd1pid_soddfrm(&mut self, val: bool) {
1186 self.0 = (self.0 & !(0x01 << 29usize)) | (((val as u32) & 0x01) << 29usize); 1186 self.0 = (self.0 & !(0x01 << 29usize)) | (((val as u32) & 0x01) << 29usize);
1187 } 1187 }
1188 #[doc = "EPDIS"] 1188 #[doc = "EPDIS"]
diff --git a/embassy-usb/src/builder.rs b/embassy-usb/src/builder.rs
index 7168e077c..e1bf8041f 100644
--- a/embassy-usb/src/builder.rs
+++ b/embassy-usb/src/builder.rs
@@ -1,8 +1,8 @@
1use heapless::Vec; 1use heapless::Vec;
2 2
3use crate::config::MAX_HANDLER_COUNT; 3use crate::config::MAX_HANDLER_COUNT;
4use crate::descriptor::{BosWriter, DescriptorWriter}; 4use crate::descriptor::{BosWriter, DescriptorWriter, SynchronizationType, UsageType};
5use crate::driver::{Driver, Endpoint, EndpointType}; 5use crate::driver::{Driver, Endpoint, 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};
@@ -414,7 +414,7 @@ impl<'a, 'd, D: Driver<'d>> InterfaceAltBuilder<'a, 'd, D> {
414 /// Descriptors are written in the order builder functions are called. Note that some 414 /// Descriptors are written in the order builder functions are called. Note that some
415 /// classes care about the order. 415 /// classes care about the order.
416 pub fn descriptor(&mut self, descriptor_type: u8, descriptor: &[u8]) { 416 pub fn descriptor(&mut self, descriptor_type: u8, descriptor: &[u8]) {
417 self.builder.config_descriptor.write(descriptor_type, descriptor); 417 self.builder.config_descriptor.write(descriptor_type, descriptor, &[]);
418 } 418 }
419 419
420 /// Add a custom Binary Object Store (BOS) descriptor to this alternate setting. 420 /// Add a custom Binary Object Store (BOS) descriptor to this alternate setting.
@@ -422,26 +422,80 @@ impl<'a, 'd, D: Driver<'d>> InterfaceAltBuilder<'a, 'd, D> {
422 self.builder.bos_descriptor.capability(capability_type, capability); 422 self.builder.bos_descriptor.capability(capability_type, capability);
423 } 423 }
424 424
425 fn endpoint_in(&mut self, ep_type: EndpointType, max_packet_size: u16, interval_ms: u8) -> D::EndpointIn { 425 /// Write a custom endpoint descriptor for a certain endpoint.
426 ///
427 /// This can be necessary, if the endpoint descriptors can only be written
428 /// after the endpoint was created. As an example, an endpoint descriptor
429 /// may contain the address of an endpoint that was allocated earlier.
430 pub fn endpoint_descriptor(
431 &mut self,
432 endpoint: &EndpointInfo,
433 synchronization_type: SynchronizationType,
434 usage_type: UsageType,
435 extra_fields: &[u8],
436 ) {
437 self.builder
438 .config_descriptor
439 .endpoint(endpoint, synchronization_type, usage_type, extra_fields);
440 }
441
442 /// Allocate an IN endpoint, without writing its descriptor.
443 ///
444 /// Used for granular control over the order of endpoint and descriptor creation.
445 pub fn alloc_endpoint_in(&mut self, ep_type: EndpointType, max_packet_size: u16, interval_ms: u8) -> D::EndpointIn {
426 let ep = self 446 let ep = self
427 .builder 447 .builder
428 .driver 448 .driver
429 .alloc_endpoint_in(ep_type, max_packet_size, interval_ms) 449 .alloc_endpoint_in(ep_type, max_packet_size, interval_ms)
430 .expect("alloc_endpoint_in failed"); 450 .expect("alloc_endpoint_in failed");
431 451
432 self.builder.config_descriptor.endpoint(ep.info()); 452 ep
453 }
454
455 fn endpoint_in(
456 &mut self,
457 ep_type: EndpointType,
458 max_packet_size: u16,
459 interval_ms: u8,
460 synchronization_type: SynchronizationType,
461 usage_type: UsageType,
462 extra_fields: &[u8],
463 ) -> D::EndpointIn {
464 let ep = self.alloc_endpoint_in(ep_type, max_packet_size, interval_ms);
465 self.endpoint_descriptor(ep.info(), synchronization_type, usage_type, extra_fields);
433 466
434 ep 467 ep
435 } 468 }
436 469
437 fn endpoint_out(&mut self, ep_type: EndpointType, max_packet_size: u16, interval_ms: u8) -> D::EndpointOut { 470 /// Allocate an OUT endpoint, without writing its descriptor.
471 ///
472 /// Use for granular control over the order of endpoint and descriptor creation.
473 pub fn alloc_endpoint_out(
474 &mut self,
475 ep_type: EndpointType,
476 max_packet_size: u16,
477 interval_ms: u8,
478 ) -> D::EndpointOut {
438 let ep = self 479 let ep = self
439 .builder 480 .builder
440 .driver 481 .driver
441 .alloc_endpoint_out(ep_type, max_packet_size, interval_ms) 482 .alloc_endpoint_out(ep_type, max_packet_size, interval_ms)
442 .expect("alloc_endpoint_out failed"); 483 .expect("alloc_endpoint_out failed");
443 484
444 self.builder.config_descriptor.endpoint(ep.info()); 485 ep
486 }
487
488 fn endpoint_out(
489 &mut self,
490 ep_type: EndpointType,
491 max_packet_size: u16,
492 interval_ms: u8,
493 synchronization_type: SynchronizationType,
494 usage_type: UsageType,
495 extra_fields: &[u8],
496 ) -> D::EndpointOut {
497 let ep = self.alloc_endpoint_out(ep_type, max_packet_size, interval_ms);
498 self.endpoint_descriptor(ep.info(), synchronization_type, usage_type, extra_fields);
445 499
446 ep 500 ep
447 } 501 }
@@ -451,7 +505,14 @@ impl<'a, 'd, D: Driver<'d>> InterfaceAltBuilder<'a, 'd, D> {
451 /// Descriptors are written in the order builder functions are called. Note that some 505 /// Descriptors are written in the order builder functions are called. Note that some
452 /// classes care about the order. 506 /// classes care about the order.
453 pub fn endpoint_bulk_in(&mut self, max_packet_size: u16) -> D::EndpointIn { 507 pub fn endpoint_bulk_in(&mut self, max_packet_size: u16) -> D::EndpointIn {
454 self.endpoint_in(EndpointType::Bulk, max_packet_size, 0) 508 self.endpoint_in(
509 EndpointType::Bulk,
510 max_packet_size,
511 0,
512 SynchronizationType::NoSynchronization,
513 UsageType::DataEndpoint,
514 &[],
515 )
455 } 516 }
456 517
457 /// Allocate a BULK OUT endpoint and write its descriptor. 518 /// Allocate a BULK OUT endpoint and write its descriptor.
@@ -459,7 +520,14 @@ impl<'a, 'd, D: Driver<'d>> InterfaceAltBuilder<'a, 'd, D> {
459 /// Descriptors are written in the order builder functions are called. Note that some 520 /// Descriptors are written in the order builder functions are called. Note that some
460 /// classes care about the order. 521 /// classes care about the order.
461 pub fn endpoint_bulk_out(&mut self, max_packet_size: u16) -> D::EndpointOut { 522 pub fn endpoint_bulk_out(&mut self, max_packet_size: u16) -> D::EndpointOut {
462 self.endpoint_out(EndpointType::Bulk, max_packet_size, 0) 523 self.endpoint_out(
524 EndpointType::Bulk,
525 max_packet_size,
526 0,
527 SynchronizationType::NoSynchronization,
528 UsageType::DataEndpoint,
529 &[],
530 )
463 } 531 }
464 532
465 /// Allocate a INTERRUPT IN endpoint and write its descriptor. 533 /// Allocate a INTERRUPT IN endpoint and write its descriptor.
@@ -467,24 +535,66 @@ impl<'a, 'd, D: Driver<'d>> InterfaceAltBuilder<'a, 'd, D> {
467 /// Descriptors are written in the order builder functions are called. Note that some 535 /// Descriptors are written in the order builder functions are called. Note that some
468 /// classes care about the order. 536 /// classes care about the order.
469 pub fn endpoint_interrupt_in(&mut self, max_packet_size: u16, interval_ms: u8) -> D::EndpointIn { 537 pub fn endpoint_interrupt_in(&mut self, max_packet_size: u16, interval_ms: u8) -> D::EndpointIn {
470 self.endpoint_in(EndpointType::Interrupt, max_packet_size, interval_ms) 538 self.endpoint_in(
539 EndpointType::Interrupt,
540 max_packet_size,
541 interval_ms,
542 SynchronizationType::NoSynchronization,
543 UsageType::DataEndpoint,
544 &[],
545 )
471 } 546 }
472 547
473 /// Allocate a INTERRUPT OUT endpoint and write its descriptor. 548 /// Allocate a INTERRUPT OUT endpoint and write its descriptor.
474 pub fn endpoint_interrupt_out(&mut self, max_packet_size: u16, interval_ms: u8) -> D::EndpointOut { 549 pub fn endpoint_interrupt_out(&mut self, max_packet_size: u16, interval_ms: u8) -> D::EndpointOut {
475 self.endpoint_out(EndpointType::Interrupt, max_packet_size, interval_ms) 550 self.endpoint_out(
551 EndpointType::Interrupt,
552 max_packet_size,
553 interval_ms,
554 SynchronizationType::NoSynchronization,
555 UsageType::DataEndpoint,
556 &[],
557 )
476 } 558 }
477 559
478 /// Allocate a ISOCHRONOUS IN endpoint and write its descriptor. 560 /// Allocate a ISOCHRONOUS IN endpoint and write its descriptor.
479 /// 561 ///
480 /// Descriptors are written in the order builder functions are called. Note that some 562 /// Descriptors are written in the order builder functions are called. Note that some
481 /// classes care about the order. 563 /// classes care about the order.
482 pub fn endpoint_isochronous_in(&mut self, max_packet_size: u16, interval_ms: u8) -> D::EndpointIn { 564 pub fn endpoint_isochronous_in(
483 self.endpoint_in(EndpointType::Isochronous, max_packet_size, interval_ms) 565 &mut self,
566 max_packet_size: u16,
567 interval_ms: u8,
568 synchronization_type: SynchronizationType,
569 usage_type: UsageType,
570 extra_fields: &[u8],
571 ) -> D::EndpointIn {
572 self.endpoint_in(
573 EndpointType::Isochronous,
574 max_packet_size,
575 interval_ms,
576 synchronization_type,
577 usage_type,
578 extra_fields,
579 )
484 } 580 }
485 581
486 /// Allocate a ISOCHRONOUS OUT endpoint and write its descriptor. 582 /// Allocate a ISOCHRONOUS OUT endpoint and write its descriptor.
487 pub fn endpoint_isochronous_out(&mut self, max_packet_size: u16, interval_ms: u8) -> D::EndpointOut { 583 pub fn endpoint_isochronous_out(
488 self.endpoint_out(EndpointType::Isochronous, max_packet_size, interval_ms) 584 &mut self,
585 max_packet_size: u16,
586 interval_ms: u8,
587 synchronization_type: SynchronizationType,
588 usage_type: UsageType,
589 extra_fields: &[u8],
590 ) -> D::EndpointOut {
591 self.endpoint_out(
592 EndpointType::Isochronous,
593 max_packet_size,
594 interval_ms,
595 synchronization_type,
596 usage_type,
597 extra_fields,
598 )
489 } 599 }
490} 600}
diff --git a/embassy-usb/src/descriptor.rs b/embassy-usb/src/descriptor.rs
index c4d79e39f..06ebe0481 100644
--- a/embassy-usb/src/descriptor.rs
+++ b/embassy-usb/src/descriptor.rs
@@ -1,4 +1,5 @@
1//! Utilities for writing USB descriptors. 1//! Utilities for writing USB descriptors.
2use embassy_usb_driver::EndpointType;
2 3
3use crate::builder::Config; 4use crate::builder::Config;
4use crate::driver::EndpointInfo; 5use crate::driver::EndpointInfo;
@@ -38,6 +39,40 @@ pub mod capability_type {
38 pub const PLATFORM: u8 = 5; 39 pub const PLATFORM: u8 = 5;
39} 40}
40 41
42/// USB endpoint synchronization type. The values of this enum can be directly
43/// cast into `u8` to get the bmAttributes synchronization type bits.
44/// Values other than `NoSynchronization` are only allowed on isochronous endpoints.
45#[repr(u8)]
46#[derive(Copy, Clone, Eq, PartialEq, Debug)]
47#[cfg_attr(feature = "defmt", derive(defmt::Format))]
48pub enum SynchronizationType {
49 /// No synchronization is used.
50 NoSynchronization = 0b00,
51 /// Unsynchronized, although sinks provide data rate feedback.
52 Asynchronous = 0b01,
53 /// Synchronized using feedback or feedforward data rate information.
54 Adaptive = 0b10,
55 /// Synchronized to the USB’s SOF.
56 Synchronous = 0b11,
57}
58
59/// USB endpoint usage type. The values of this enum can be directly cast into
60/// `u8` to get the bmAttributes usage type bits.
61/// Values other than `DataEndpoint` are only allowed on isochronous endpoints.
62#[repr(u8)]
63#[derive(Copy, Clone, Eq, PartialEq, Debug)]
64#[cfg_attr(feature = "defmt", derive(defmt::Format))]
65pub enum UsageType {
66 /// Use the endpoint for regular data transfer.
67 DataEndpoint = 0b00,
68 /// Endpoint conveys explicit feedback information for one or more data endpoints.
69 FeedbackEndpoint = 0b01,
70 /// A data endpoint that also serves as an implicit feedback endpoint for one or more data endpoints.
71 ImplicitFeedbackDataEndpoint = 0b10,
72 /// Reserved usage type.
73 Reserved = 0b11,
74}
75
41/// A writer for USB descriptors. 76/// A writer for USB descriptors.
42pub(crate) struct DescriptorWriter<'a> { 77pub(crate) struct DescriptorWriter<'a> {
43 pub buf: &'a mut [u8], 78 pub buf: &'a mut [u8],
@@ -65,23 +100,26 @@ impl<'a> DescriptorWriter<'a> {
65 self.position 100 self.position
66 } 101 }
67 102
68 /// Writes an arbitrary (usually class-specific) descriptor. 103 /// Writes an arbitrary (usually class-specific) descriptor with optional extra fields.
69 pub fn write(&mut self, descriptor_type: u8, descriptor: &[u8]) { 104 pub fn write(&mut self, descriptor_type: u8, descriptor: &[u8], extra_fields: &[u8]) {
70 let length = descriptor.len(); 105 let descriptor_length = descriptor.len();
106 let extra_fields_length = extra_fields.len();
107 let total_length = descriptor_length + extra_fields_length;
71 108
72 assert!( 109 assert!(
73 (self.position + 2 + length) <= self.buf.len() && (length + 2) <= 255, 110 (self.position + 2 + total_length) <= self.buf.len() && (total_length + 2) <= 255,
74 "Descriptor buffer full" 111 "Descriptor buffer full"
75 ); 112 );
76 113
77 self.buf[self.position] = (length + 2) as u8; 114 self.buf[self.position] = (total_length + 2) as u8;
78 self.buf[self.position + 1] = descriptor_type; 115 self.buf[self.position + 1] = descriptor_type;
79 116
80 let start = self.position + 2; 117 let start = self.position + 2;
81 118
82 self.buf[start..start + length].copy_from_slice(descriptor); 119 self.buf[start..start + descriptor_length].copy_from_slice(descriptor);
120 self.buf[start + descriptor_length..start + total_length].copy_from_slice(extra_fields);
83 121
84 self.position = start + length; 122 self.position = start + total_length;
85 } 123 }
86 124
87 pub(crate) fn configuration(&mut self, config: &Config) { 125 pub(crate) fn configuration(&mut self, config: &Config) {
@@ -99,6 +137,7 @@ impl<'a> DescriptorWriter<'a> {
99 | if config.supports_remote_wakeup { 0x20 } else { 0x00 }, // bmAttributes 137 | if config.supports_remote_wakeup { 0x20 } else { 0x00 }, // bmAttributes
100 (config.max_power / 2) as u8, // bMaxPower 138 (config.max_power / 2) as u8, // bMaxPower
101 ], 139 ],
140 &[],
102 ); 141 );
103 } 142 }
104 143
@@ -145,6 +184,7 @@ impl<'a> DescriptorWriter<'a> {
145 function_protocol, 184 function_protocol,
146 0, 185 0,
147 ], 186 ],
187 &[],
148 ); 188 );
149 } 189 }
150 190
@@ -195,6 +235,7 @@ impl<'a> DescriptorWriter<'a> {
195 interface_protocol, // bInterfaceProtocol 235 interface_protocol, // bInterfaceProtocol
196 str_index, // iInterface 236 str_index, // iInterface
197 ], 237 ],
238 &[],
198 ); 239 );
199 } 240 }
200 241
@@ -204,21 +245,50 @@ impl<'a> DescriptorWriter<'a> {
204 /// 245 ///
205 /// * `endpoint` - Endpoint previously allocated with 246 /// * `endpoint` - Endpoint previously allocated with
206 /// [`UsbDeviceBuilder`](crate::bus::UsbDeviceBuilder). 247 /// [`UsbDeviceBuilder`](crate::bus::UsbDeviceBuilder).
207 pub fn endpoint(&mut self, endpoint: &EndpointInfo) { 248 /// * `synchronization_type` - The synchronization type of the endpoint.
249 /// * `usage_type` - The usage type of the endpoint.
250 /// * `extra_fields` - Additional, class-specific entries at the end of the endpoint descriptor.
251 pub fn endpoint(
252 &mut self,
253 endpoint: &EndpointInfo,
254 synchronization_type: SynchronizationType,
255 usage_type: UsageType,
256 extra_fields: &[u8],
257 ) {
208 match self.num_endpoints_mark { 258 match self.num_endpoints_mark {
209 Some(mark) => self.buf[mark] += 1, 259 Some(mark) => self.buf[mark] += 1,
210 None => panic!("you can only call `endpoint` after `interface/interface_alt`."), 260 None => panic!("you can only call `endpoint` after `interface/interface_alt`."),
211 }; 261 };
212 262
263 let mut bm_attributes = endpoint.ep_type as u8;
264
265 // Synchronization types other than `NoSynchronization`,
266 // and usage types other than `DataEndpoint`
267 // are only allowed for isochronous endpoints.
268 if endpoint.ep_type != EndpointType::Isochronous {
269 assert_eq!(synchronization_type, SynchronizationType::NoSynchronization);
270 assert_eq!(usage_type, UsageType::DataEndpoint);
271 } else {
272 if usage_type == UsageType::FeedbackEndpoint {
273 assert_eq!(synchronization_type, SynchronizationType::NoSynchronization)
274 }
275
276 let synchronization_bm_attibutes: u8 = (synchronization_type as u8) << 2;
277 let usage_bm_attibutes: u8 = (usage_type as u8) << 4;
278
279 bm_attributes |= usage_bm_attibutes | synchronization_bm_attibutes;
280 }
281
213 self.write( 282 self.write(
214 descriptor_type::ENDPOINT, 283 descriptor_type::ENDPOINT,
215 &[ 284 &[
216 endpoint.addr.into(), // bEndpointAddress 285 endpoint.addr.into(), // bEndpointAddress
217 endpoint.ep_type as u8, // bmAttributes 286 bm_attributes, // bmAttributes
218 endpoint.max_packet_size as u8, 287 endpoint.max_packet_size as u8,
219 (endpoint.max_packet_size >> 8) as u8, // wMaxPacketSize 288 (endpoint.max_packet_size >> 8) as u8, // wMaxPacketSize
220 endpoint.interval_ms, // bInterval 289 endpoint.interval_ms, // bInterval
221 ], 290 ],
291 extra_fields,
222 ); 292 );
223 } 293 }
224 294
@@ -318,6 +388,7 @@ impl<'a> BosWriter<'a> {
318 0x00, 0x00, // wTotalLength 388 0x00, 0x00, // wTotalLength
319 0x00, // bNumDeviceCaps 389 0x00, // bNumDeviceCaps
320 ], 390 ],
391 &[],
321 ); 392 );
322 393
323 self.capability(capability_type::USB_2_0_EXTENSION, &[0; 4]); 394 self.capability(capability_type::USB_2_0_EXTENSION, &[0; 4]);