Adapts libtock drivers for vendor HID (#500)
* adapts libtock drivers for vendor HID * status with timeout
This commit is contained in:
13
patches/tock/11-usb-endpoint-receive.patch
Normal file
13
patches/tock/11-usb-endpoint-receive.patch
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
diff --git a/capsules/src/usb/usb_ctap.rs b/capsules/src/usb/usb_ctap.rs
|
||||||
|
index e8f1a87a4..2c1ecf934 100644
|
||||||
|
--- a/capsules/src/usb/usb_ctap.rs
|
||||||
|
+++ b/capsules/src/usb/usb_ctap.rs
|
||||||
|
@@ -57,7 +57,7 @@ impl<'a, 'b, C: hil::usb::UsbController<'a>> CtapUsbSyscallDriver<'a, 'b, C> {
|
||||||
|
app.waiting = false;
|
||||||
|
// Signal to the app that a packet is ready.
|
||||||
|
app.callback
|
||||||
|
- .map(|mut cb| cb.schedule(CTAP_CALLBACK_RECEIVED, 0, 0));
|
||||||
|
+ .map(|mut cb| cb.schedule(CTAP_CALLBACK_RECEIVED, 1, 0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
18
src/env/tock/mod.rs
vendored
18
src/env/tock/mod.rs
vendored
@@ -118,27 +118,27 @@ fn send_keepalive_up_needed(
|
|||||||
channel: Channel,
|
channel: Channel,
|
||||||
timeout: Duration<isize>,
|
timeout: Duration<isize>,
|
||||||
) -> Result<(), Ctap2StatusCode> {
|
) -> Result<(), Ctap2StatusCode> {
|
||||||
let (interface, cid) = match channel {
|
let (endpoint, cid) = match channel {
|
||||||
Channel::MainHid(cid) => (usb_ctap_hid::UsbInterface::MainHid, cid),
|
Channel::MainHid(cid) => (usb_ctap_hid::UsbEndpoint::MainHid, cid),
|
||||||
#[cfg(feature = "vendor_hid")]
|
#[cfg(feature = "vendor_hid")]
|
||||||
Channel::VendorHid(cid) => (usb_ctap_hid::UsbInterface::VendorHid, cid),
|
Channel::VendorHid(cid) => (usb_ctap_hid::UsbEndpoint::VendorHid, cid),
|
||||||
};
|
};
|
||||||
let keepalive_msg = CtapHid::keepalive(cid, KeepaliveStatus::UpNeeded);
|
let keepalive_msg = CtapHid::keepalive(cid, KeepaliveStatus::UpNeeded);
|
||||||
for mut pkt in keepalive_msg {
|
for mut pkt in keepalive_msg {
|
||||||
let status = usb_ctap_hid::send_or_recv_with_timeout(&mut pkt, timeout, interface);
|
let status =
|
||||||
|
usb_ctap_hid::send_or_recv_with_timeout(&mut pkt, timeout, endpoint).flex_unwrap();
|
||||||
match status {
|
match status {
|
||||||
None => {
|
usb_ctap_hid::SendOrRecvStatus::Timeout => {
|
||||||
debug_ctap!(env, "Sending a KEEPALIVE packet timed out");
|
debug_ctap!(env, "Sending a KEEPALIVE packet timed out");
|
||||||
// TODO: abort user presence test?
|
// TODO: abort user presence test?
|
||||||
}
|
}
|
||||||
Some(usb_ctap_hid::SendOrRecvStatus::Error) => panic!("Error sending KEEPALIVE packet"),
|
usb_ctap_hid::SendOrRecvStatus::Sent => {
|
||||||
Some(usb_ctap_hid::SendOrRecvStatus::Sent) => {
|
|
||||||
debug_ctap!(env, "Sent KEEPALIVE packet");
|
debug_ctap!(env, "Sent KEEPALIVE packet");
|
||||||
}
|
}
|
||||||
Some(usb_ctap_hid::SendOrRecvStatus::Received(received_interface)) => {
|
usb_ctap_hid::SendOrRecvStatus::Received(received_endpoint) => {
|
||||||
// We only parse one packet, because we only care about CANCEL.
|
// We only parse one packet, because we only care about CANCEL.
|
||||||
let (received_cid, processed_packet) = CtapHid::process_single_packet(&pkt);
|
let (received_cid, processed_packet) = CtapHid::process_single_packet(&pkt);
|
||||||
if received_interface != interface || received_cid != &cid {
|
if received_endpoint != endpoint || received_cid != &cid {
|
||||||
debug_ctap!(
|
debug_ctap!(
|
||||||
env,
|
env,
|
||||||
"Received a packet on channel ID {:?} while sending a KEEPALIVE packet",
|
"Received a packet on channel ID {:?} while sending a KEEPALIVE packet",
|
||||||
|
|||||||
40
src/main.rs
40
src/main.rs
@@ -42,7 +42,6 @@ use embedded_time::duration::Milliseconds;
|
|||||||
use libtock_drivers::buttons::{self, ButtonState};
|
use libtock_drivers::buttons::{self, ButtonState};
|
||||||
#[cfg(feature = "debug_ctap")]
|
#[cfg(feature = "debug_ctap")]
|
||||||
use libtock_drivers::console::Console;
|
use libtock_drivers::console::Console;
|
||||||
#[cfg(feature = "with_ctap1")]
|
|
||||||
use libtock_drivers::result::FlexUnwrap;
|
use libtock_drivers::result::FlexUnwrap;
|
||||||
use libtock_drivers::timer::Duration;
|
use libtock_drivers::timer::Duration;
|
||||||
use libtock_drivers::usb_ctap_hid;
|
use libtock_drivers::usb_ctap_hid;
|
||||||
@@ -89,15 +88,19 @@ fn main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let mut pkt_request = [0; 64];
|
let mut pkt_request = [0; 64];
|
||||||
let usb_interface =
|
let usb_endpoint =
|
||||||
match usb_ctap_hid::recv_with_timeout(&mut pkt_request, KEEPALIVE_DELAY_TOCK) {
|
match usb_ctap_hid::recv_with_timeout(&mut pkt_request, KEEPALIVE_DELAY_TOCK)
|
||||||
Some(usb_ctap_hid::SendOrRecvStatus::Received(interface)) => {
|
.flex_unwrap()
|
||||||
|
{
|
||||||
|
usb_ctap_hid::SendOrRecvStatus::Received(endpoint) => {
|
||||||
#[cfg(feature = "debug_ctap")]
|
#[cfg(feature = "debug_ctap")]
|
||||||
print_packet_notice("Received packet", &clock);
|
print_packet_notice("Received packet", &clock);
|
||||||
Some(interface)
|
Some(endpoint)
|
||||||
}
|
}
|
||||||
Some(_) => panic!("Error receiving packet"),
|
usb_ctap_hid::SendOrRecvStatus::Sent => {
|
||||||
None => None,
|
panic!("Returned transmit status on receive")
|
||||||
|
}
|
||||||
|
usb_ctap_hid::SendOrRecvStatus::Timeout => None,
|
||||||
};
|
};
|
||||||
|
|
||||||
let now = clock.try_now().unwrap();
|
let now = clock.try_now().unwrap();
|
||||||
@@ -120,34 +123,31 @@ fn main() {
|
|||||||
// don't cause problems with timers.
|
// don't cause problems with timers.
|
||||||
ctap.update_timeouts(now);
|
ctap.update_timeouts(now);
|
||||||
|
|
||||||
if let Some(interface) = usb_interface {
|
if let Some(endpoint) = usb_endpoint {
|
||||||
let transport = match interface {
|
let transport = match endpoint {
|
||||||
usb_ctap_hid::UsbInterface::MainHid => Transport::MainHid,
|
usb_ctap_hid::UsbEndpoint::MainHid => Transport::MainHid,
|
||||||
#[cfg(feature = "vendor_hid")]
|
#[cfg(feature = "vendor_hid")]
|
||||||
usb_ctap_hid::UsbInterface::VendorHid => Transport::VendorHid,
|
usb_ctap_hid::UsbEndpoint::VendorHid => Transport::VendorHid,
|
||||||
};
|
};
|
||||||
let reply = ctap.process_hid_packet(&pkt_request, transport, now);
|
let reply = ctap.process_hid_packet(&pkt_request, transport, now);
|
||||||
// This block handles sending packets.
|
// This block handles sending packets.
|
||||||
for mut pkt_reply in reply {
|
for mut pkt_reply in reply {
|
||||||
let status = usb_ctap_hid::send_or_recv_with_timeout(
|
let status =
|
||||||
&mut pkt_reply,
|
usb_ctap_hid::send_or_recv_with_timeout(&mut pkt_reply, SEND_TIMEOUT, endpoint)
|
||||||
SEND_TIMEOUT,
|
.flex_unwrap();
|
||||||
interface,
|
|
||||||
);
|
|
||||||
match status {
|
match status {
|
||||||
None => {
|
usb_ctap_hid::SendOrRecvStatus::Timeout => {
|
||||||
#[cfg(feature = "debug_ctap")]
|
#[cfg(feature = "debug_ctap")]
|
||||||
print_packet_notice("Sending packet timed out", &clock);
|
print_packet_notice("Sending packet timed out", &clock);
|
||||||
// TODO: reset the ctap_hid state.
|
// TODO: reset the ctap_hid state.
|
||||||
// Since sending the packet timed out, we cancel this reply.
|
// Since sending the packet timed out, we cancel this reply.
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
Some(usb_ctap_hid::SendOrRecvStatus::Error) => panic!("Error sending packet"),
|
usb_ctap_hid::SendOrRecvStatus::Sent => {
|
||||||
Some(usb_ctap_hid::SendOrRecvStatus::Sent) => {
|
|
||||||
#[cfg(feature = "debug_ctap")]
|
#[cfg(feature = "debug_ctap")]
|
||||||
print_packet_notice("Sent packet", &clock);
|
print_packet_notice("Sent packet", &clock);
|
||||||
}
|
}
|
||||||
Some(usb_ctap_hid::SendOrRecvStatus::Received(_)) => {
|
usb_ctap_hid::SendOrRecvStatus::Received(_) => {
|
||||||
#[cfg(feature = "debug_ctap")]
|
#[cfg(feature = "debug_ctap")]
|
||||||
print_packet_notice("Received an UNEXPECTED packet", &clock);
|
print_packet_notice("Received an UNEXPECTED packet", &clock);
|
||||||
// TODO: handle this unexpected packet.
|
// TODO: handle this unexpected packet.
|
||||||
|
|||||||
158
third_party/libtock-drivers/src/usb_ctap_hid.rs
vendored
158
third_party/libtock-drivers/src/usb_ctap_hid.rs
vendored
@@ -14,10 +14,11 @@
|
|||||||
|
|
||||||
#[cfg(feature = "debug_ctap")]
|
#[cfg(feature = "debug_ctap")]
|
||||||
use crate::console::Console;
|
use crate::console::Console;
|
||||||
use crate::result::TockError;
|
use crate::result::{OutOfRangeError, TockError, TockResult};
|
||||||
use crate::timer::Duration;
|
use crate::timer::Duration;
|
||||||
use crate::{timer, util};
|
use crate::{timer, util};
|
||||||
use core::cell::Cell;
|
use core::cell::Cell;
|
||||||
|
use core::convert::TryFrom;
|
||||||
#[cfg(feature = "debug_ctap")]
|
#[cfg(feature = "debug_ctap")]
|
||||||
use core::fmt::Write;
|
use core::fmt::Write;
|
||||||
use libtock_core::result::{CommandError, EALREADY, EBUSY, SUCCESS};
|
use libtock_core::result::{CommandError, EALREADY, EBUSY, SUCCESS};
|
||||||
@@ -65,17 +66,30 @@ pub fn setup() -> bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, PartialEq, Eq)]
|
#[derive(Clone, Copy, PartialEq, Eq)]
|
||||||
pub enum UsbInterface {
|
pub enum UsbEndpoint {
|
||||||
MainHid = 0,
|
MainHid = 1,
|
||||||
#[cfg(feature = "vendor_hid")]
|
#[cfg(feature = "vendor_hid")]
|
||||||
VendorHid = 1,
|
VendorHid = 2,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryFrom<usize> for UsbEndpoint {
|
||||||
|
type Error = TockError;
|
||||||
|
|
||||||
|
fn try_from(endpoint_num: usize) -> Result<Self, TockError> {
|
||||||
|
match endpoint_num {
|
||||||
|
1 => Ok(UsbEndpoint::MainHid),
|
||||||
|
#[cfg(feature = "vendor_hid")]
|
||||||
|
2 => Ok(UsbEndpoint::VendorHid),
|
||||||
|
_ => Err(OutOfRangeError.into()),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, PartialEq, Eq)]
|
#[derive(Clone, Copy, PartialEq, Eq)]
|
||||||
pub enum SendOrRecvStatus {
|
pub enum SendOrRecvStatus {
|
||||||
Error,
|
Timeout,
|
||||||
Sent,
|
Sent,
|
||||||
Received(UsbInterface),
|
Received(UsbEndpoint),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Waits to receive a packet.
|
/// Waits to receive a packet.
|
||||||
@@ -85,7 +99,7 @@ pub enum SendOrRecvStatus {
|
|||||||
pub fn recv_with_timeout(
|
pub fn recv_with_timeout(
|
||||||
buf: &mut [u8; 64],
|
buf: &mut [u8; 64],
|
||||||
timeout_delay: Duration<isize>,
|
timeout_delay: Duration<isize>,
|
||||||
) -> Option<SendOrRecvStatus> {
|
) -> TockResult<SendOrRecvStatus> {
|
||||||
#[cfg(feature = "verbose_usb")]
|
#[cfg(feature = "verbose_usb")]
|
||||||
writeln!(
|
writeln!(
|
||||||
Console::new(),
|
Console::new(),
|
||||||
@@ -97,12 +111,12 @@ pub fn recv_with_timeout(
|
|||||||
let result = recv_with_timeout_detail(buf, timeout_delay);
|
let result = recv_with_timeout_detail(buf, timeout_delay);
|
||||||
|
|
||||||
#[cfg(feature = "verbose_usb")]
|
#[cfg(feature = "verbose_usb")]
|
||||||
if let Some(SendOrRecvStatus::Received(interface)) = result {
|
if let Ok(SendOrRecvStatus::Received(endpoint)) = result {
|
||||||
writeln!(
|
writeln!(
|
||||||
Console::new(),
|
Console::new(),
|
||||||
"Received packet = {:02x?} on interface {}",
|
"Received packet = {:02x?} on endpoint {}",
|
||||||
buf as &[u8],
|
buf as &[u8],
|
||||||
interface as u8,
|
endpoint as u8,
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
@@ -126,8 +140,8 @@ pub fn recv_with_timeout(
|
|||||||
pub fn send_or_recv_with_timeout(
|
pub fn send_or_recv_with_timeout(
|
||||||
buf: &mut [u8; 64],
|
buf: &mut [u8; 64],
|
||||||
timeout_delay: Duration<isize>,
|
timeout_delay: Duration<isize>,
|
||||||
interface: UsbInterface,
|
endpoint: UsbEndpoint,
|
||||||
) -> Option<SendOrRecvStatus> {
|
) -> TockResult<SendOrRecvStatus> {
|
||||||
#[cfg(feature = "verbose_usb")]
|
#[cfg(feature = "verbose_usb")]
|
||||||
writeln!(
|
writeln!(
|
||||||
Console::new(),
|
Console::new(),
|
||||||
@@ -137,15 +151,15 @@ pub fn send_or_recv_with_timeout(
|
|||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let result = send_or_recv_with_timeout_detail(buf, timeout_delay, interface);
|
let result = send_or_recv_with_timeout_detail(buf, timeout_delay, endpoint);
|
||||||
|
|
||||||
#[cfg(feature = "verbose_usb")]
|
#[cfg(feature = "verbose_usb")]
|
||||||
if let Some(SendOrRecvStatus::Received(received_interface)) = result {
|
if let Ok(SendOrRecvStatus::Received(received_endpoint)) = result {
|
||||||
writeln!(
|
writeln!(
|
||||||
Console::new(),
|
Console::new(),
|
||||||
"Received packet = {:02x?} on interface {}",
|
"Received packet = {:02x?} on endpoint {}",
|
||||||
buf as &[u8],
|
buf as &[u8],
|
||||||
received_interface as u8,
|
received_endpoint as u8,
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
@@ -156,54 +170,38 @@ pub fn send_or_recv_with_timeout(
|
|||||||
fn recv_with_timeout_detail(
|
fn recv_with_timeout_detail(
|
||||||
buf: &mut [u8; 64],
|
buf: &mut [u8; 64],
|
||||||
timeout_delay: Duration<isize>,
|
timeout_delay: Duration<isize>,
|
||||||
) -> Option<SendOrRecvStatus> {
|
) -> TockResult<SendOrRecvStatus> {
|
||||||
let result = syscalls::allow(DRIVER_NUMBER, allow_nr::RECEIVE, buf);
|
let result = syscalls::allow(DRIVER_NUMBER, allow_nr::RECEIVE, buf)?;
|
||||||
if result.is_err() {
|
|
||||||
return Some(SendOrRecvStatus::Error);
|
|
||||||
}
|
|
||||||
|
|
||||||
let status = Cell::new(None);
|
let status = Cell::new(None);
|
||||||
let mut alarm = |direction| {
|
let mut alarm = |direction, endpoint| {
|
||||||
status.set(Some(match direction {
|
status.set(Some(match direction {
|
||||||
subscribe_nr::callback_status::RECEIVED => {
|
subscribe_nr::callback_status::RECEIVED => {
|
||||||
// TODO: set the correct interface
|
UsbEndpoint::try_from(endpoint).map(|i| SendOrRecvStatus::Received(i))
|
||||||
SendOrRecvStatus::Received(UsbInterface::MainHid)
|
|
||||||
}
|
}
|
||||||
// Unknown direction or "transmitted" sent by the kernel.
|
// Unknown direction or "transmitted" sent by the kernel.
|
||||||
_ => SendOrRecvStatus::Error,
|
_ => Err(OutOfRangeError.into()),
|
||||||
}));
|
}));
|
||||||
};
|
};
|
||||||
|
|
||||||
let subscription = syscalls::subscribe::<callback::Identity1Consumer, _>(
|
let subscription = syscalls::subscribe::<callback::Identity2Consumer, _>(
|
||||||
DRIVER_NUMBER,
|
DRIVER_NUMBER,
|
||||||
subscribe_nr::RECEIVE,
|
subscribe_nr::RECEIVE,
|
||||||
&mut alarm,
|
&mut alarm,
|
||||||
);
|
)?;
|
||||||
if subscription.is_err() {
|
|
||||||
return Some(SendOrRecvStatus::Error);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Setup a time-out callback.
|
// Setup a time-out callback.
|
||||||
let timeout_expired = Cell::new(false);
|
|
||||||
let mut timeout_callback = timer::with_callback(|_, _| {
|
let mut timeout_callback = timer::with_callback(|_, _| {
|
||||||
timeout_expired.set(true);
|
status.set(Some(Ok(SendOrRecvStatus::Timeout)));
|
||||||
});
|
});
|
||||||
let mut timeout = match timeout_callback.init() {
|
let mut timeout = timeout_callback.init()?;
|
||||||
Ok(x) => x,
|
let timeout_alarm = timeout.set_alarm(timeout_delay)?;
|
||||||
Err(_) => return Some(SendOrRecvStatus::Error),
|
|
||||||
};
|
|
||||||
let timeout_alarm = match timeout.set_alarm(timeout_delay) {
|
|
||||||
Ok(x) => x,
|
|
||||||
Err(_) => return Some(SendOrRecvStatus::Error),
|
|
||||||
};
|
|
||||||
|
|
||||||
// Trigger USB reception.
|
// Trigger USB reception.
|
||||||
let result_code = syscalls::command(DRIVER_NUMBER, command_nr::RECEIVE, 0, 0);
|
let result_code = syscalls::command(DRIVER_NUMBER, command_nr::RECEIVE, 0, 0)?;
|
||||||
if result_code.is_err() {
|
|
||||||
return Some(SendOrRecvStatus::Error);
|
|
||||||
}
|
|
||||||
|
|
||||||
util::yieldk_for(|| status.get().is_some() || timeout_expired.get());
|
util::yieldk_for(|| status.get().is_some());
|
||||||
|
let status = status.get().unwrap();
|
||||||
|
|
||||||
// Cleanup alarm callback.
|
// Cleanup alarm callback.
|
||||||
match timeout.stop_alarm(timeout_alarm) {
|
match timeout.stop_alarm(timeout_alarm) {
|
||||||
@@ -212,7 +210,7 @@ fn recv_with_timeout_detail(
|
|||||||
return_code: EALREADY,
|
return_code: EALREADY,
|
||||||
..
|
..
|
||||||
})) => {
|
})) => {
|
||||||
if !timeout_expired.get() {
|
if matches!(status, Ok(SendOrRecvStatus::Timeout)) {
|
||||||
#[cfg(feature = "debug_ctap")]
|
#[cfg(feature = "debug_ctap")]
|
||||||
writeln!(
|
writeln!(
|
||||||
Console::new(),
|
Console::new(),
|
||||||
@@ -230,7 +228,7 @@ fn recv_with_timeout_detail(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Cancel USB transaction if necessary.
|
// Cancel USB transaction if necessary.
|
||||||
if status.get().is_none() {
|
if matches!(status, Ok(SendOrRecvStatus::Timeout)) {
|
||||||
#[cfg(feature = "verbose_usb")]
|
#[cfg(feature = "verbose_usb")]
|
||||||
writeln!(Console::new(), "Cancelling USB receive due to timeout").unwrap();
|
writeln!(Console::new(), "Cancelling USB receive due to timeout").unwrap();
|
||||||
let result_code =
|
let result_code =
|
||||||
@@ -253,63 +251,54 @@ fn recv_with_timeout_detail(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
status.get()
|
core::mem::drop(result);
|
||||||
|
core::mem::drop(subscription);
|
||||||
|
core::mem::drop(result_code);
|
||||||
|
status
|
||||||
}
|
}
|
||||||
|
|
||||||
fn send_or_recv_with_timeout_detail(
|
fn send_or_recv_with_timeout_detail(
|
||||||
buf: &mut [u8; 64],
|
buf: &mut [u8; 64],
|
||||||
timeout_delay: Duration<isize>,
|
timeout_delay: Duration<isize>,
|
||||||
// TODO: To be used as part of the syscall.
|
endpoint: UsbEndpoint,
|
||||||
_interface: UsbInterface,
|
) -> TockResult<SendOrRecvStatus> {
|
||||||
) -> Option<SendOrRecvStatus> {
|
let result = syscalls::allow(DRIVER_NUMBER, allow_nr::TRANSMIT_OR_RECEIVE, buf)?;
|
||||||
let result = syscalls::allow(DRIVER_NUMBER, allow_nr::TRANSMIT_OR_RECEIVE, buf);
|
|
||||||
if result.is_err() {
|
|
||||||
return Some(SendOrRecvStatus::Error);
|
|
||||||
}
|
|
||||||
|
|
||||||
let status = Cell::new(None);
|
let status = Cell::new(None);
|
||||||
let mut alarm = |direction| {
|
let mut alarm = |direction, endpoint| {
|
||||||
status.set(Some(match direction {
|
status.set(Some(match direction {
|
||||||
subscribe_nr::callback_status::TRANSMITTED => SendOrRecvStatus::Sent,
|
subscribe_nr::callback_status::TRANSMITTED => Ok(SendOrRecvStatus::Sent),
|
||||||
subscribe_nr::callback_status::RECEIVED => {
|
subscribe_nr::callback_status::RECEIVED => {
|
||||||
// TODO: set the correct interface
|
UsbEndpoint::try_from(endpoint).map(|i| SendOrRecvStatus::Received(i))
|
||||||
SendOrRecvStatus::Received(UsbInterface::MainHid)
|
|
||||||
}
|
}
|
||||||
// Unknown direction sent by the kernel.
|
// Unknown direction sent by the kernel.
|
||||||
_ => SendOrRecvStatus::Error,
|
_ => Err(OutOfRangeError.into()),
|
||||||
}));
|
}));
|
||||||
};
|
};
|
||||||
|
|
||||||
let subscription = syscalls::subscribe::<callback::Identity1Consumer, _>(
|
let subscription = syscalls::subscribe::<callback::Identity2Consumer, _>(
|
||||||
DRIVER_NUMBER,
|
DRIVER_NUMBER,
|
||||||
subscribe_nr::TRANSMIT_OR_RECEIVE,
|
subscribe_nr::TRANSMIT_OR_RECEIVE,
|
||||||
&mut alarm,
|
&mut alarm,
|
||||||
);
|
)?;
|
||||||
if subscription.is_err() {
|
|
||||||
return Some(SendOrRecvStatus::Error);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Setup a time-out callback.
|
// Setup a time-out callback.
|
||||||
let timeout_expired = Cell::new(false);
|
|
||||||
let mut timeout_callback = timer::with_callback(|_, _| {
|
let mut timeout_callback = timer::with_callback(|_, _| {
|
||||||
timeout_expired.set(true);
|
status.set(Some(Ok(SendOrRecvStatus::Timeout)));
|
||||||
});
|
});
|
||||||
let mut timeout = match timeout_callback.init() {
|
let mut timeout = timeout_callback.init()?;
|
||||||
Ok(x) => x,
|
let timeout_alarm = timeout.set_alarm(timeout_delay)?;
|
||||||
Err(_) => return Some(SendOrRecvStatus::Error),
|
|
||||||
};
|
|
||||||
let timeout_alarm = match timeout.set_alarm(timeout_delay) {
|
|
||||||
Ok(x) => x,
|
|
||||||
Err(_) => return Some(SendOrRecvStatus::Error),
|
|
||||||
};
|
|
||||||
|
|
||||||
// Trigger USB transmission.
|
// Trigger USB transmission.
|
||||||
let result_code = syscalls::command(DRIVER_NUMBER, command_nr::TRANSMIT_OR_RECEIVE, 0, 0);
|
let result_code = syscalls::command(
|
||||||
if result_code.is_err() {
|
DRIVER_NUMBER,
|
||||||
return Some(SendOrRecvStatus::Error);
|
command_nr::TRANSMIT_OR_RECEIVE,
|
||||||
}
|
endpoint as usize,
|
||||||
|
0,
|
||||||
|
)?;
|
||||||
|
|
||||||
util::yieldk_for(|| status.get().is_some() || timeout_expired.get());
|
util::yieldk_for(|| status.get().is_some());
|
||||||
|
let status = status.get().unwrap();
|
||||||
|
|
||||||
// Cleanup alarm callback.
|
// Cleanup alarm callback.
|
||||||
match timeout.stop_alarm(timeout_alarm) {
|
match timeout.stop_alarm(timeout_alarm) {
|
||||||
@@ -318,7 +307,7 @@ fn send_or_recv_with_timeout_detail(
|
|||||||
return_code: EALREADY,
|
return_code: EALREADY,
|
||||||
..
|
..
|
||||||
})) => {
|
})) => {
|
||||||
if !timeout_expired.get() {
|
if matches!(status, Ok(SendOrRecvStatus::Timeout)) {
|
||||||
#[cfg(feature = "debug_ctap")]
|
#[cfg(feature = "debug_ctap")]
|
||||||
writeln!(
|
writeln!(
|
||||||
Console::new(),
|
Console::new(),
|
||||||
@@ -336,7 +325,7 @@ fn send_or_recv_with_timeout_detail(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Cancel USB transaction if necessary.
|
// Cancel USB transaction if necessary.
|
||||||
if status.get().is_none() {
|
if matches!(status, Ok(SendOrRecvStatus::Timeout)) {
|
||||||
#[cfg(feature = "verbose_usb")]
|
#[cfg(feature = "verbose_usb")]
|
||||||
writeln!(Console::new(), "Cancelling USB transaction due to timeout").unwrap();
|
writeln!(Console::new(), "Cancelling USB transaction due to timeout").unwrap();
|
||||||
let result_code =
|
let result_code =
|
||||||
@@ -361,5 +350,8 @@ fn send_or_recv_with_timeout_detail(
|
|||||||
writeln!(Console::new(), "Cancelled USB transaction!").unwrap();
|
writeln!(Console::new(), "Cancelled USB transaction!").unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
status.get()
|
core::mem::drop(result);
|
||||||
|
core::mem::drop(subscription);
|
||||||
|
core::mem::drop(result_code);
|
||||||
|
status
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user