748 lines
30 KiB
Diff
748 lines
30 KiB
Diff
diff --git a/capsules/src/usb/usbc_client.rs b/capsules/src/usb/usbc_client.rs
|
|
index b0678c23..9fb43781 100644
|
|
--- a/capsules/src/usb/usbc_client.rs
|
|
+++ b/capsules/src/usb/usbc_client.rs
|
|
@@ -115,11 +115,11 @@ impl<'a, C: hil::usb::UsbController<'a>> hil::usb::Client<'a> for Client<'a, C>
|
|
self.client_ctrl.enable();
|
|
|
|
// Set up a bulk-in endpoint for debugging
|
|
- self.controller().endpoint_set_buffer(1, self.buffer(1));
|
|
+ self.controller().endpoint_set_in_buffer(1, self.buffer(1));
|
|
self.controller().endpoint_in_enable(TransferType::Bulk, 1);
|
|
|
|
// Set up a bulk-out endpoint for debugging
|
|
- self.controller().endpoint_set_buffer(2, self.buffer(2));
|
|
+ self.controller().endpoint_set_out_buffer(2, self.buffer(2));
|
|
self.controller().endpoint_out_enable(TransferType::Bulk, 2);
|
|
}
|
|
|
|
diff --git a/capsules/src/usb/usbc_client_ctrl.rs b/capsules/src/usb/usbc_client_ctrl.rs
|
|
index 2aaca0cc..5f9b253c 100644
|
|
--- a/capsules/src/usb/usbc_client_ctrl.rs
|
|
+++ b/capsules/src/usb/usbc_client_ctrl.rs
|
|
@@ -201,7 +201,7 @@ impl<'a, 'b, C: hil::usb::UsbController<'a>> ClientCtrl<'a, 'b, C> {
|
|
pub fn enable(&'a self) {
|
|
// Set up the default control endpoint
|
|
self.controller
|
|
- .endpoint_set_buffer(0, &self.ctrl_buffer.buf);
|
|
+ .endpoint_set_ctrl_buffer(&self.ctrl_buffer.buf);
|
|
self.controller
|
|
.enable_as_device(hil::usb::DeviceSpeed::Full); // must be Full for Bulk transfers
|
|
self.controller
|
|
diff --git a/capsules/src/usb/usbc_ctap_hid.rs b/capsules/src/usb/usbc_ctap_hid.rs
|
|
index fdf7263a..4b1916cf 100644
|
|
--- a/capsules/src/usb/usbc_ctap_hid.rs
|
|
+++ b/capsules/src/usb/usbc_ctap_hid.rs
|
|
@@ -88,8 +88,9 @@ static HID: HIDDescriptor<'static> = HIDDescriptor {
|
|
pub struct ClientCtapHID<'a, 'b, C: 'a> {
|
|
client_ctrl: ClientCtrl<'a, 'static, C>,
|
|
|
|
- // A 64-byte buffer for the endpoint
|
|
- buffer: Buffer64,
|
|
+ // 64-byte buffers for the endpoint
|
|
+ in_buffer: Buffer64,
|
|
+ out_buffer: Buffer64,
|
|
|
|
// Interaction with the client
|
|
client: OptionalCell<&'b dyn CtapUsbClient>,
|
|
@@ -133,7 +134,8 @@ impl<'a, 'b, C: hil::usb::UsbController<'a>> ClientCtapHID<'a, 'b, C> {
|
|
LANGUAGES,
|
|
STRINGS,
|
|
),
|
|
- buffer: Default::default(),
|
|
+ in_buffer: Default::default(),
|
|
+ out_buffer: Default::default(),
|
|
client: OptionalCell::empty(),
|
|
tx_packet: OptionalCell::empty(),
|
|
pending_in: Cell::new(false),
|
|
@@ -187,7 +189,7 @@ impl<'a, 'b, C: hil::usb::UsbController<'a>> ClientCtapHID<'a, 'b, C> {
|
|
fn send_packet_to_client(&'a self) -> bool {
|
|
// Copy the packet into a buffer to send to the client.
|
|
let mut buf: [u8; 64] = [0; 64];
|
|
- for (i, x) in self.buffer.buf.iter().enumerate() {
|
|
+ for (i, x) in self.out_buffer.buf.iter().enumerate() {
|
|
buf[i] = x.get();
|
|
}
|
|
|
|
@@ -220,11 +222,7 @@ impl<'a, 'b, C: hil::usb::UsbController<'a>> ClientCtapHID<'a, 'b, C> {
|
|
|
|
fn cancel_in_transaction(&'a self) -> bool {
|
|
self.tx_packet.take();
|
|
- let result = self.pending_in.take();
|
|
- if result {
|
|
- self.controller().endpoint_cancel_in(1);
|
|
- }
|
|
- result
|
|
+ self.pending_in.take()
|
|
}
|
|
|
|
fn cancel_out_transaction(&'a self) -> bool {
|
|
@@ -243,7 +241,10 @@ impl<'a, 'b, C: hil::usb::UsbController<'a>> hil::usb::Client<'a> for ClientCtap
|
|
self.client_ctrl.enable();
|
|
|
|
// Set up the interrupt in-out endpoint
|
|
- self.controller().endpoint_set_buffer(1, &self.buffer.buf);
|
|
+ self.controller()
|
|
+ .endpoint_set_in_buffer(1, &self.in_buffer.buf);
|
|
+ self.controller()
|
|
+ .endpoint_set_out_buffer(1, &self.out_buffer.buf);
|
|
self.controller()
|
|
.endpoint_in_out_enable(TransferType::Interrupt, 1);
|
|
}
|
|
@@ -293,7 +294,7 @@ impl<'a, 'b, C: hil::usb::UsbController<'a>> hil::usb::Client<'a> for ClientCtap
|
|
}
|
|
|
|
if let Some(packet) = self.tx_packet.take() {
|
|
- let buf = &self.buffer.buf;
|
|
+ let buf = &self.in_buffer.buf;
|
|
for i in 0..64 {
|
|
buf[i].set(packet[i]);
|
|
}
|
|
@@ -346,6 +347,12 @@ impl<'a, 'b, C: hil::usb::UsbController<'a>> hil::usb::Client<'a> for ClientCtap
|
|
panic!("Unexpected tx_packet while a packet was being transmitted.");
|
|
}
|
|
self.pending_in.set(false);
|
|
+
|
|
+ // Clear any pending packet on the receiving side.
|
|
+ // It's up to the client to handle the transmitted packet and decide if they want to
|
|
+ // receive another packet.
|
|
+ self.cancel_out_transaction();
|
|
+
|
|
// Notify the client
|
|
self.client.map(|client| client.packet_transmitted());
|
|
}
|
|
diff --git a/chips/nrf52/src/usbd.rs b/chips/nrf52/src/usbd.rs
|
|
index 8c1992cc..972871d0 100644
|
|
--- a/chips/nrf52/src/usbd.rs
|
|
+++ b/chips/nrf52/src/usbd.rs
|
|
@@ -623,7 +623,7 @@ pub enum UsbState {
|
|
pub enum EndpointState {
|
|
Disabled,
|
|
Ctrl(CtrlState),
|
|
- Bulk(TransferType, EndpointDirection, BulkState),
|
|
+ Bulk(TransferType, Option<BulkInState>, Option<BulkOutState>),
|
|
}
|
|
|
|
impl EndpointState {
|
|
@@ -634,10 +634,10 @@ impl EndpointState {
|
|
}
|
|
}
|
|
|
|
- fn bulk_state(self) -> (TransferType, EndpointDirection, BulkState) {
|
|
+ fn bulk_state(self) -> (TransferType, Option<BulkInState>, Option<BulkOutState>) {
|
|
match self {
|
|
- EndpointState::Bulk(transfer_type, direction, state) => {
|
|
- (transfer_type, direction, state)
|
|
+ EndpointState::Bulk(transfer_type, in_state, out_state) => {
|
|
+ (transfer_type, in_state, out_state)
|
|
}
|
|
_ => panic!("Expected EndpointState::Bulk"),
|
|
}
|
|
@@ -651,31 +651,18 @@ pub enum CtrlState {
|
|
ReadStatus,
|
|
}
|
|
|
|
-#[derive(Copy, Clone, Debug)]
|
|
-pub enum EndpointDirection {
|
|
- In,
|
|
- Out,
|
|
- InOut,
|
|
-}
|
|
-
|
|
-impl EndpointDirection {
|
|
- fn has_in(&self) -> bool {
|
|
- match self {
|
|
- EndpointDirection::In | EndpointDirection::InOut => true,
|
|
- EndpointDirection::Out => false,
|
|
- }
|
|
- }
|
|
-
|
|
- fn has_out(&self) -> bool {
|
|
- match self {
|
|
- EndpointDirection::Out | EndpointDirection::InOut => true,
|
|
- EndpointDirection::In => false,
|
|
- }
|
|
- }
|
|
+#[derive(Copy, Clone, PartialEq, Debug)]
|
|
+pub enum BulkInState {
|
|
+ // The endpoint is ready to perform transactions.
|
|
+ Init,
|
|
+ // There is a pending DMA transfer on this IN endpoint.
|
|
+ InDma,
|
|
+ // There is a pending IN packet transfer on this endpoint.
|
|
+ InData,
|
|
}
|
|
|
|
#[derive(Copy, Clone, PartialEq, Debug)]
|
|
-pub enum BulkState {
|
|
+pub enum BulkOutState {
|
|
// The endpoint is ready to perform transactions.
|
|
Init,
|
|
// There is a pending OUT packet in this endpoint's buffer, to be read by
|
|
@@ -685,14 +672,11 @@ pub enum BulkState {
|
|
OutData,
|
|
// There is a pending DMA transfer on this OUT endpoint.
|
|
OutDma,
|
|
- // There is a pending DMA transfer on this IN endpoint.
|
|
- InDma,
|
|
- // There is a pending IN packet transfer on this endpoint.
|
|
- InData,
|
|
}
|
|
|
|
pub struct Endpoint<'a> {
|
|
- slice: OptionalCell<&'a [VolatileCell<u8>]>,
|
|
+ slice_in: OptionalCell<&'a [VolatileCell<u8>]>,
|
|
+ slice_out: OptionalCell<&'a [VolatileCell<u8>]>,
|
|
state: Cell<EndpointState>,
|
|
// The USB controller can only process one DMA transfer at a time (over all endpoints). The
|
|
// request_transmit_* bits allow to queue transfers until the DMA becomes available again.
|
|
@@ -705,7 +689,8 @@ pub struct Endpoint<'a> {
|
|
impl Endpoint<'_> {
|
|
const fn new() -> Self {
|
|
Endpoint {
|
|
- slice: OptionalCell::empty(),
|
|
+ slice_in: OptionalCell::empty(),
|
|
+ slice_out: OptionalCell::empty(),
|
|
state: Cell::new(EndpointState::Disabled),
|
|
request_transmit_in: Cell::new(false),
|
|
request_transmit_out: Cell::new(false),
|
|
@@ -914,18 +899,12 @@ impl<'a> Usbd<'a> {
|
|
chip_revision.get()
|
|
);
|
|
}
|
|
- Some(ChipRevision::REV::Value::REVC) => {
|
|
+ Some(ChipRevision::REV::Value::REVC) | Some(ChipRevision::REV::Value::REVD) => {
|
|
debug_info!(
|
|
"Your chip is NRF52840 revision {}. The USB stack was tested on your chip :)",
|
|
chip_revision.get()
|
|
);
|
|
}
|
|
- Some(ChipRevision::REV::Value::REVD) => {
|
|
- internal_warn!(
|
|
- "Your chip is NRF52840 revision {}. Although this USB implementation should be compatible, your chip hasn't been tested.",
|
|
- chip_revision.get()
|
|
- );
|
|
- }
|
|
None => {
|
|
internal_warn!(
|
|
"Your chip is NRF52840 revision {} (unknown revision). Although this USB implementation should be compatible, your chip hasn't been tested.",
|
|
@@ -1026,7 +1005,7 @@ impl<'a> Usbd<'a> {
|
|
});
|
|
self.descriptors[endpoint].state.set(match endpoint {
|
|
0 => EndpointState::Ctrl(CtrlState::Init),
|
|
- 1..=7 => EndpointState::Bulk(transfer_type, EndpointDirection::In, BulkState::Init),
|
|
+ 1..=7 => EndpointState::Bulk(transfer_type, Some(BulkInState::Init), None),
|
|
8 => unimplemented!("isochronous endpoint"),
|
|
_ => unreachable!("unexisting endpoint"),
|
|
});
|
|
@@ -1064,7 +1043,7 @@ impl<'a> Usbd<'a> {
|
|
});
|
|
self.descriptors[endpoint].state.set(match endpoint {
|
|
0 => EndpointState::Ctrl(CtrlState::Init),
|
|
- 1..=7 => EndpointState::Bulk(transfer_type, EndpointDirection::Out, BulkState::Init),
|
|
+ 1..=7 => EndpointState::Bulk(transfer_type, None, Some(BulkOutState::Init)),
|
|
8 => unimplemented!("isochronous endpoint"),
|
|
_ => unreachable!("unexisting endpoint"),
|
|
});
|
|
@@ -1114,7 +1093,11 @@ impl<'a> Usbd<'a> {
|
|
});
|
|
self.descriptors[endpoint].state.set(match endpoint {
|
|
0 => EndpointState::Ctrl(CtrlState::Init),
|
|
- 1..=7 => EndpointState::Bulk(transfer_type, EndpointDirection::InOut, BulkState::Init),
|
|
+ 1..=7 => EndpointState::Bulk(
|
|
+ transfer_type,
|
|
+ Some(BulkInState::Init),
|
|
+ Some(BulkOutState::Init),
|
|
+ ),
|
|
8 => unimplemented!("isochronous endpoint"),
|
|
_ => unreachable!("unexisting endpoint"),
|
|
});
|
|
@@ -1304,13 +1287,13 @@ impl<'a> Usbd<'a> {
|
|
match desc.state.get() {
|
|
EndpointState::Disabled => {}
|
|
EndpointState::Ctrl(_) => desc.state.set(EndpointState::Ctrl(CtrlState::Init)),
|
|
- EndpointState::Bulk(transfer_type, direction, _) => {
|
|
+ EndpointState::Bulk(transfer_type, in_state, out_state) => {
|
|
desc.state.set(EndpointState::Bulk(
|
|
transfer_type,
|
|
- direction,
|
|
- BulkState::Init,
|
|
+ in_state.map(|_| BulkInState::Init),
|
|
+ out_state.map(|_| BulkOutState::Init),
|
|
));
|
|
- if direction.has_out() {
|
|
+ if out_state.is_some() {
|
|
// Accept incoming OUT packets.
|
|
regs.size_epout[ep].set(0);
|
|
}
|
|
@@ -1347,13 +1330,13 @@ impl<'a> Usbd<'a> {
|
|
match endpoint {
|
|
0 => {}
|
|
1..=7 => {
|
|
- let (transfer_type, direction, state) =
|
|
+ let (transfer_type, in_state, out_state) =
|
|
self.descriptors[endpoint].state.get().bulk_state();
|
|
- assert_eq!(state, BulkState::InDma);
|
|
+ assert_eq!(in_state, Some(BulkInState::InDma));
|
|
self.descriptors[endpoint].state.set(EndpointState::Bulk(
|
|
transfer_type,
|
|
- direction,
|
|
- BulkState::InData,
|
|
+ Some(BulkInState::InData),
|
|
+ out_state,
|
|
));
|
|
}
|
|
8 => unimplemented!("isochronous endpoint"),
|
|
@@ -1405,25 +1388,25 @@ impl<'a> Usbd<'a> {
|
|
1..=7 => {
|
|
// Notify the client about the new packet.
|
|
let packet_bytes = regs.size_epout[endpoint].get();
|
|
- let (transfer_type, direction, state) =
|
|
+ let (transfer_type, in_state, out_state) =
|
|
self.descriptors[endpoint].state.get().bulk_state();
|
|
- assert_eq!(state, BulkState::OutDma);
|
|
+ assert_eq!(out_state, Some(BulkOutState::OutDma));
|
|
|
|
- self.debug_packet("out", packet_bytes as usize, endpoint);
|
|
+ self.debug_out_packet(packet_bytes as usize, endpoint);
|
|
|
|
self.client.map(|client| {
|
|
let result = client.packet_out(transfer_type, endpoint, packet_bytes);
|
|
debug_packets!("packet_out => {:?}", result);
|
|
- let newstate = match result {
|
|
+ let new_out_state = match result {
|
|
hil::usb::OutResult::Ok => {
|
|
// Indicate that the endpoint is ready to receive data again.
|
|
regs.size_epout[endpoint].set(0);
|
|
- BulkState::Init
|
|
+ BulkOutState::Init
|
|
}
|
|
|
|
hil::usb::OutResult::Delay => {
|
|
// We can't send the packet now. Wait for a resume_out call from the client.
|
|
- BulkState::OutDelay
|
|
+ BulkOutState::OutDelay
|
|
}
|
|
|
|
hil::usb::OutResult::Error => {
|
|
@@ -1432,13 +1415,13 @@ impl<'a> Usbd<'a> {
|
|
+ EndpointStall::IO::Out
|
|
+ EndpointStall::STALL::Stall,
|
|
);
|
|
- BulkState::Init
|
|
+ BulkOutState::Init
|
|
}
|
|
};
|
|
self.descriptors[endpoint].state.set(EndpointState::Bulk(
|
|
transfer_type,
|
|
- direction,
|
|
- newstate,
|
|
+ in_state,
|
|
+ Some(new_out_state),
|
|
));
|
|
});
|
|
}
|
|
@@ -1497,29 +1480,27 @@ impl<'a> Usbd<'a> {
|
|
// Endpoint 8 (isochronous) doesn't receive any EPDATA event.
|
|
for endpoint in 1..NUM_ENDPOINTS {
|
|
if epdatastatus.is_set(status_epin(endpoint)) {
|
|
- let (transfer_type, direction, state) =
|
|
+ let (transfer_type, in_state, out_state) =
|
|
self.descriptors[endpoint].state.get().bulk_state();
|
|
- match state {
|
|
- BulkState::InData => {
|
|
+ assert!(in_state.is_some());
|
|
+ match in_state.unwrap() {
|
|
+ BulkInState::InData => {
|
|
// Totally expected state. Nothing to do.
|
|
}
|
|
- BulkState::Init => {
|
|
+ BulkInState::Init => {
|
|
internal_warn!(
|
|
"Received a stale epdata IN in an unexpected state: {:?}",
|
|
- state
|
|
+ in_state
|
|
);
|
|
}
|
|
- BulkState::OutDelay
|
|
- | BulkState::OutData
|
|
- | BulkState::OutDma
|
|
- | BulkState::InDma => {
|
|
- internal_err!("Unexpected state: {:?}", state);
|
|
+ BulkInState::InDma => {
|
|
+ internal_err!("Unexpected state: {:?}", in_state);
|
|
}
|
|
}
|
|
self.descriptors[endpoint].state.set(EndpointState::Bulk(
|
|
transfer_type,
|
|
- direction,
|
|
- BulkState::Init,
|
|
+ Some(BulkInState::Init),
|
|
+ out_state,
|
|
));
|
|
self.client
|
|
.map(|client| client.packet_transmitted(endpoint));
|
|
@@ -1530,28 +1511,26 @@ impl<'a> Usbd<'a> {
|
|
// Endpoint 8 (isochronous) doesn't receive any EPDATA event.
|
|
for ep in 1..NUM_ENDPOINTS {
|
|
if epdatastatus.is_set(status_epout(ep)) {
|
|
- let (transfer_type, direction, state) =
|
|
+ let (transfer_type, in_state, out_state) =
|
|
self.descriptors[ep].state.get().bulk_state();
|
|
- match state {
|
|
- BulkState::Init => {
|
|
+ assert!(out_state.is_some());
|
|
+ match out_state.unwrap() {
|
|
+ BulkOutState::Init => {
|
|
// The endpoint is ready to receive data. Request a transmit_out.
|
|
self.descriptors[ep].request_transmit_out.set(true);
|
|
}
|
|
- BulkState::OutDelay => {
|
|
+ BulkOutState::OutDelay => {
|
|
// The endpoint will be resumed later by the client application with transmit_out().
|
|
}
|
|
- BulkState::OutData
|
|
- | BulkState::OutDma
|
|
- | BulkState::InDma
|
|
- | BulkState::InData => {
|
|
- internal_err!("Unexpected state: {:?}", state);
|
|
+ BulkOutState::OutData | BulkOutState::OutDma => {
|
|
+ internal_err!("Unexpected state: {:?}", out_state);
|
|
}
|
|
}
|
|
// Indicate that the endpoint now has data available.
|
|
self.descriptors[ep].state.set(EndpointState::Bulk(
|
|
transfer_type,
|
|
- direction,
|
|
- BulkState::OutData,
|
|
+ in_state,
|
|
+ Some(BulkOutState::OutData),
|
|
));
|
|
}
|
|
}
|
|
@@ -1564,8 +1543,8 @@ impl<'a> Usbd<'a> {
|
|
let state = self.descriptors[endpoint].state.get().ctrl_state();
|
|
match state {
|
|
CtrlState::Init => {
|
|
- let ep_buf = &self.descriptors[endpoint].slice;
|
|
- let ep_buf = ep_buf.expect("No slice set for this descriptor");
|
|
+ let ep_buf = &self.descriptors[endpoint].slice_out;
|
|
+ let ep_buf = ep_buf.expect("No OUT slice set for this descriptor");
|
|
if ep_buf.len() < 8 {
|
|
panic!("EP0 DMA buffer length < 8");
|
|
}
|
|
@@ -1697,21 +1676,21 @@ impl<'a> Usbd<'a> {
|
|
let regs = &*self.registers;
|
|
|
|
self.client.map(|client| {
|
|
- let (transfer_type, direction, state) =
|
|
+ let (transfer_type, in_state, out_state) =
|
|
self.descriptors[endpoint].state.get().bulk_state();
|
|
- assert_eq!(state, BulkState::Init);
|
|
+ assert_eq!(in_state, Some(BulkInState::Init));
|
|
|
|
let result = client.packet_in(transfer_type, endpoint);
|
|
debug_packets!("packet_in => {:?}", result);
|
|
- let newstate = match result {
|
|
+ let new_in_state = match result {
|
|
hil::usb::InResult::Packet(size) => {
|
|
self.start_dma_in(endpoint, size);
|
|
- BulkState::InDma
|
|
+ BulkInState::InDma
|
|
}
|
|
|
|
hil::usb::InResult::Delay => {
|
|
// No packet to send now. Wait for a resume call from the client.
|
|
- BulkState::Init
|
|
+ BulkInState::Init
|
|
}
|
|
|
|
hil::usb::InResult::Error => {
|
|
@@ -1720,14 +1699,14 @@ impl<'a> Usbd<'a> {
|
|
+ EndpointStall::IO::In
|
|
+ EndpointStall::STALL::Stall,
|
|
);
|
|
- BulkState::Init
|
|
+ BulkInState::Init
|
|
}
|
|
};
|
|
|
|
self.descriptors[endpoint].state.set(EndpointState::Bulk(
|
|
transfer_type,
|
|
- direction,
|
|
- newstate,
|
|
+ Some(new_in_state),
|
|
+ out_state,
|
|
));
|
|
});
|
|
}
|
|
@@ -1735,15 +1714,16 @@ impl<'a> Usbd<'a> {
|
|
fn transmit_out(&self, endpoint: usize) {
|
|
debug_events!("transmit_out({})", endpoint);
|
|
|
|
- let (transfer_type, direction, state) = self.descriptors[endpoint].state.get().bulk_state();
|
|
+ let (transfer_type, in_state, out_state) =
|
|
+ self.descriptors[endpoint].state.get().bulk_state();
|
|
// Starting the DMA can only happen in the OutData state, i.e. after an EPDATA event.
|
|
- assert_eq!(state, BulkState::OutData);
|
|
+ assert_eq!(out_state, Some(BulkOutState::OutData));
|
|
self.start_dma_out(endpoint);
|
|
|
|
self.descriptors[endpoint].state.set(EndpointState::Bulk(
|
|
transfer_type,
|
|
- direction,
|
|
- BulkState::OutDma,
|
|
+ in_state,
|
|
+ Some(BulkOutState::OutDma),
|
|
));
|
|
}
|
|
|
|
@@ -1751,9 +1731,9 @@ impl<'a> Usbd<'a> {
|
|
let regs = &*self.registers;
|
|
|
|
let slice = self.descriptors[endpoint]
|
|
- .slice
|
|
- .expect("No slice set for this descriptor");
|
|
- self.debug_packet("in", size, endpoint);
|
|
+ .slice_in
|
|
+ .expect("No IN slice set for this descriptor");
|
|
+ self.debug_in_packet(size, endpoint);
|
|
|
|
// Start DMA transfer
|
|
self.set_pending_dma();
|
|
@@ -1766,8 +1746,8 @@ impl<'a> Usbd<'a> {
|
|
let regs = &*self.registers;
|
|
|
|
let slice = self.descriptors[endpoint]
|
|
- .slice
|
|
- .expect("No slice set for this descriptor");
|
|
+ .slice_out
|
|
+ .expect("No OUT slice set for this descriptor");
|
|
|
|
// Start DMA transfer
|
|
self.set_pending_dma();
|
|
@@ -1777,10 +1757,27 @@ impl<'a> Usbd<'a> {
|
|
}
|
|
|
|
// Debug-only function
|
|
- fn debug_packet(&self, _title: &str, size: usize, endpoint: usize) {
|
|
+ fn debug_in_packet(&self, size: usize, endpoint: usize) {
|
|
+ let slice = self.descriptors[endpoint]
|
|
+ .slice_in
|
|
+ .expect("No IN slice set for this descriptor");
|
|
+ if size > slice.len() {
|
|
+ panic!("Packet is too large: {}", size);
|
|
+ }
|
|
+
|
|
+ let mut packet_hex = [0; 128];
|
|
+ packet_to_hex(slice, &mut packet_hex);
|
|
+ debug_packets!(
|
|
+ "in={}",
|
|
+ core::str::from_utf8(&packet_hex[..(2 * size)]).unwrap()
|
|
+ );
|
|
+ }
|
|
+
|
|
+ // Debug-only function
|
|
+ fn debug_out_packet(&self, size: usize, endpoint: usize) {
|
|
let slice = self.descriptors[endpoint]
|
|
- .slice
|
|
- .expect("No slice set for this descriptor");
|
|
+ .slice_out
|
|
+ .expect("No OUT slice set for this descriptor");
|
|
if size > slice.len() {
|
|
panic!("Packet is too large: {}", size);
|
|
}
|
|
@@ -1788,8 +1785,7 @@ impl<'a> Usbd<'a> {
|
|
let mut packet_hex = [0; 128];
|
|
packet_to_hex(slice, &mut packet_hex);
|
|
debug_packets!(
|
|
- "{}={}",
|
|
- _title,
|
|
+ "out={}",
|
|
core::str::from_utf8(&packet_hex[..(2 * size)]).unwrap()
|
|
);
|
|
}
|
|
@@ -1807,17 +1803,41 @@ impl<'a> power::PowerClient for Usbd<'a> {
|
|
}
|
|
|
|
impl<'a> hil::usb::UsbController<'a> for Usbd<'a> {
|
|
- fn endpoint_set_buffer(&self, endpoint: usize, buf: &'a [VolatileCell<u8>]) {
|
|
+ fn endpoint_set_ctrl_buffer(&self, buf: &'a [VolatileCell<u8>]) {
|
|
+ if buf.len() < 8 {
|
|
+ panic!("Endpoint buffer must be at least 8 bytes");
|
|
+ }
|
|
+ if !buf.len().is_power_of_two() {
|
|
+ panic!("Buffer size must be a power of 2");
|
|
+ }
|
|
+ self.descriptors[0].slice_in.set(buf);
|
|
+ self.descriptors[0].slice_out.set(buf);
|
|
+ }
|
|
+
|
|
+ fn endpoint_set_in_buffer(&self, endpoint: usize, buf: &'a [VolatileCell<u8>]) {
|
|
+ if buf.len() < 8 {
|
|
+ panic!("Endpoint buffer must be at least 8 bytes");
|
|
+ }
|
|
+ if !buf.len().is_power_of_two() {
|
|
+ panic!("Buffer size must be a power of 2");
|
|
+ }
|
|
+ if endpoint == 0 || endpoint >= NUM_ENDPOINTS {
|
|
+ panic!("Endpoint number is invalid");
|
|
+ }
|
|
+ self.descriptors[endpoint].slice_in.set(buf);
|
|
+ }
|
|
+
|
|
+ fn endpoint_set_out_buffer(&self, endpoint: usize, buf: &'a [VolatileCell<u8>]) {
|
|
if buf.len() < 8 {
|
|
panic!("Endpoint buffer must be at least 8 bytes");
|
|
}
|
|
if !buf.len().is_power_of_two() {
|
|
panic!("Buffer size must be a power of 2");
|
|
}
|
|
- if endpoint >= NUM_ENDPOINTS {
|
|
- panic!("Endpoint number is too high");
|
|
+ if endpoint == 0 || endpoint >= NUM_ENDPOINTS {
|
|
+ panic!("Endpoint number is invalid");
|
|
}
|
|
- self.descriptors[endpoint].slice.set(buf);
|
|
+ self.descriptors[endpoint].slice_out.set(buf);
|
|
}
|
|
|
|
fn enable_as_device(&self, speed: hil::usb::DeviceSpeed) {
|
|
@@ -1900,8 +1920,8 @@ impl<'a> hil::usb::UsbController<'a> for Usbd<'a> {
|
|
fn endpoint_resume_in(&self, endpoint: usize) {
|
|
debug_events!("endpoint_resume_in({})", endpoint);
|
|
|
|
- let (_, direction, _) = self.descriptors[endpoint].state.get().bulk_state();
|
|
- assert!(direction.has_in());
|
|
+ let (_, in_state, _) = self.descriptors[endpoint].state.get().bulk_state();
|
|
+ assert!(in_state.is_some());
|
|
|
|
if self.dma_pending.get() {
|
|
debug_events!("requesting resume_in[{}]", endpoint);
|
|
@@ -1916,20 +1936,21 @@ impl<'a> hil::usb::UsbController<'a> for Usbd<'a> {
|
|
fn endpoint_resume_out(&self, endpoint: usize) {
|
|
debug_events!("endpoint_resume_out({})", endpoint);
|
|
|
|
- let (transfer_type, direction, state) = self.descriptors[endpoint].state.get().bulk_state();
|
|
- assert!(direction.has_out());
|
|
+ let (transfer_type, in_state, out_state) =
|
|
+ self.descriptors[endpoint].state.get().bulk_state();
|
|
+ assert!(out_state.is_some());
|
|
|
|
- match state {
|
|
- BulkState::OutDelay => {
|
|
+ match out_state.unwrap() {
|
|
+ BulkOutState::OutDelay => {
|
|
// The endpoint has now finished processing the last ENDEPOUT. No EPDATA event
|
|
// happened in the meantime, so the state is now back to Init.
|
|
self.descriptors[endpoint].state.set(EndpointState::Bulk(
|
|
transfer_type,
|
|
- direction,
|
|
- BulkState::Init,
|
|
+ in_state,
|
|
+ Some(BulkOutState::Init),
|
|
));
|
|
}
|
|
- BulkState::OutData => {
|
|
+ BulkOutState::OutData => {
|
|
// Although the client reported a delay before, an EPDATA event has
|
|
// happened in the meantime. This pending transaction will now
|
|
// continue in transmit_out().
|
|
@@ -1942,25 +1963,11 @@ impl<'a> hil::usb::UsbController<'a> for Usbd<'a> {
|
|
self.transmit_out(endpoint);
|
|
}
|
|
}
|
|
- BulkState::Init | BulkState::OutDma | BulkState::InDma | BulkState::InData => {
|
|
- internal_err!("Unexpected state: {:?}", state);
|
|
+ BulkOutState::Init | BulkOutState::OutDma => {
|
|
+ internal_err!("Unexpected state: {:?}", out_state);
|
|
}
|
|
}
|
|
}
|
|
-
|
|
- fn endpoint_cancel_in(&self, endpoint: usize) {
|
|
- debug_events!("endpoint_cancel_in({})", endpoint);
|
|
-
|
|
- let (transfer_type, direction, state) = self.descriptors[endpoint].state.get().bulk_state();
|
|
- assert!(direction.has_in());
|
|
- assert_eq!(state, BulkState::InData);
|
|
-
|
|
- self.descriptors[endpoint].state.set(EndpointState::Bulk(
|
|
- transfer_type,
|
|
- direction,
|
|
- BulkState::Init,
|
|
- ));
|
|
- }
|
|
}
|
|
|
|
fn status_epin(ep: usize) -> Field<u32, EndpointStatus::Register> {
|
|
diff --git a/chips/sam4l/src/usbc/mod.rs b/chips/sam4l/src/usbc/mod.rs
|
|
index 28a0b9f9..ab5b636f 100644
|
|
--- a/chips/sam4l/src/usbc/mod.rs
|
|
+++ b/chips/sam4l/src/usbc/mod.rs
|
|
@@ -1438,11 +1438,28 @@ fn endpoint_enable_interrupts(endpoint: usize, mask: FieldValue<u32, EndpointCon
|
|
}
|
|
|
|
impl hil::usb::UsbController<'a> for Usbc<'a> {
|
|
- fn endpoint_set_buffer(&self, endpoint: usize, buf: &'a [VolatileCell<u8>]) {
|
|
+ fn endpoint_set_ctrl_buffer(&self, buf: &'a [VolatileCell<u8>]) {
|
|
if buf.len() != 8 {
|
|
client_err!("Bad endpoint buffer size");
|
|
}
|
|
|
|
+ self._endpoint_bank_set_buffer(EndpointIndex::new(0), BankIndex::Bank0, buf);
|
|
+ }
|
|
+
|
|
+ fn endpoint_set_in_buffer(&self, endpoint: usize, buf: &'a [VolatileCell<u8>]) {
|
|
+ if buf.len() != 8 {
|
|
+ client_err!("Bad endpoint buffer size");
|
|
+ }
|
|
+
|
|
+ self._endpoint_bank_set_buffer(EndpointIndex::new(endpoint), BankIndex::Bank0, buf);
|
|
+ }
|
|
+
|
|
+ fn endpoint_set_out_buffer(&self, endpoint: usize, buf: &'a [VolatileCell<u8>]) {
|
|
+ if buf.len() != 8 {
|
|
+ client_err!("Bad endpoint buffer size");
|
|
+ }
|
|
+
|
|
+ // XXX: when implementing in_out endpoints, this should probably set a different slice than endpoint_set_in_buffer.
|
|
self._endpoint_bank_set_buffer(EndpointIndex::new(endpoint), BankIndex::Bank0, buf);
|
|
}
|
|
|
|
@@ -1547,10 +1564,6 @@ impl hil::usb::UsbController<'a> for Usbc<'a> {
|
|
requests.resume_out = true;
|
|
self.requests[endpoint].set(requests);
|
|
}
|
|
-
|
|
- fn endpoint_cancel_in(&self, _endpoint: usize) {
|
|
- unimplemented!()
|
|
- }
|
|
}
|
|
|
|
/// Static state to manage the USBC
|
|
diff --git a/kernel/src/hil/usb.rs b/kernel/src/hil/usb.rs
|
|
index 64610fa5..a114b30d 100644
|
|
--- a/kernel/src/hil/usb.rs
|
|
+++ b/kernel/src/hil/usb.rs
|
|
@@ -5,7 +5,9 @@ use crate::common::cells::VolatileCell;
|
|
/// USB controller interface
|
|
pub trait UsbController<'a> {
|
|
// Should be called before `enable_as_device()`
|
|
- fn endpoint_set_buffer(&self, endpoint: usize, buf: &'a [VolatileCell<u8>]);
|
|
+ fn endpoint_set_ctrl_buffer(&self, buf: &'a [VolatileCell<u8>]);
|
|
+ fn endpoint_set_in_buffer(&self, endpoint: usize, buf: &'a [VolatileCell<u8>]);
|
|
+ fn endpoint_set_out_buffer(&self, endpoint: usize, buf: &'a [VolatileCell<u8>]);
|
|
|
|
// Must be called before `attach()`
|
|
fn enable_as_device(&self, speed: DeviceSpeed);
|
|
@@ -27,8 +29,6 @@ pub trait UsbController<'a> {
|
|
fn endpoint_resume_in(&self, endpoint: usize);
|
|
|
|
fn endpoint_resume_out(&self, endpoint: usize);
|
|
-
|
|
- fn endpoint_cancel_in(&self, endpoint: usize);
|
|
}
|
|
|
|
#[derive(Clone, Copy, Debug)]
|