1pub use ehci::{descriptors, EndpointDirection};
5use server::{CheckedConn, CheckedPermissions, MessageAllowed};
6use xous::MemoryRange;
7
8use super::messages::SetEnabled;
9pub use super::messages::UsbEvent;
10use super::messages::{BulkIn, BulkOut, Claim, IsConnected, IsEnabled, OpenEndpoint, Subscribe};
11use crate::error::UsbError;
12
13#[macro_export]
14macro_rules! use_host_api {
15 () => {
16 mod usb_host_permissions {
17 use $crate::host::messages::*;
18 #[derive(Clone, Default, server::Permissions)]
19 #[server_name = "os/usb"]
20 pub struct UsbHostPermissions;
21 }
22 type UsbHost = $crate::host::api::UsbHost<usb_host_permissions::UsbHostPermissions>;
23 type ConnectedUsbDevice =
24 $crate::host::api::ConnectedUsbDevice<usb_host_permissions::UsbHostPermissions>;
25 type UsbInEndpoint = $crate::host::api::UsbInEndpoint<usb_host_permissions::UsbHostPermissions>;
26 type UsbOutEndpoint = $crate::host::api::UsbOutEndpoint<usb_host_permissions::UsbHostPermissions>;
27 };
28}
29
30#[derive(Default)]
31pub struct UsbHost<P: CheckedPermissions>(CheckedConn<P>);
32
33pub struct ConnectedUsbDevice<P: CheckedPermissions> {
34 conn: CheckedConn<P>,
35 handle: usize,
36}
37
38pub struct UsbInEndpoint<P: CheckedPermissions> {
39 conn: CheckedConn<P>,
40 handle: usize,
41 endpoint: u8,
42}
43
44pub struct UsbOutEndpoint<P: CheckedPermissions> {
45 conn: CheckedConn<P>,
46 handle: usize,
47 endpoint: u8,
48}
49
50impl<P: CheckedPermissions> UsbHost<P> {
51 pub fn subscribe<S>(&self, context: &mut server::ServerContext<S>)
52 where
53 S: server::Server + server::ArchiveEventHandler<UsbEvent>,
54 P: MessageAllowed<Subscribe>,
55 {
56 self.0.subscribe_archive_infallible(Subscribe, context)
57 }
58
59 pub fn claim(&self, handle: usize) -> Result<ConnectedUsbDevice<P>, UsbError>
60 where
61 P: MessageAllowed<Claim>,
62 {
63 self.0.try_send_blocking_scalar(Claim(handle))??;
64 Ok(ConnectedUsbDevice { conn: self.0.clone(), handle })
65 }
66
67 pub fn set_enabled(&self, enabled: bool) -> Result<(), UsbError>
68 where
69 P: MessageAllowed<SetEnabled>,
70 {
71 self.0.send_scalar_nowait(SetEnabled(enabled))?;
72 Ok(())
73 }
74
75 pub fn is_enabled(&self) -> Result<bool, UsbError>
76 where
77 P: MessageAllowed<IsEnabled>,
78 {
79 Ok(self.0.try_send_blocking_scalar(IsEnabled)?)
80 }
81
82 pub fn is_connected(&self) -> Result<bool, UsbError>
83 where
84 P: MessageAllowed<IsConnected>,
85 {
86 Ok(self.0.try_send_blocking_scalar(IsConnected)?)
87 }
88}
89
90impl<P: CheckedPermissions> ConnectedUsbDevice<P> {
91 pub fn open_in_endpoint(
92 &mut self,
93 endpoint: u8,
94 max_packet_length: u16,
95 ) -> Result<UsbInEndpoint<P>, UsbError>
96 where
97 P: MessageAllowed<OpenEndpoint>,
98 {
99 self.conn.try_send_blocking_scalar(OpenEndpoint {
100 handle: self.handle,
101 endpoint,
102 max_packet_length,
103 direction: EndpointDirection::In,
104 })??;
105 Ok(UsbInEndpoint { conn: self.conn.clone(), handle: self.handle, endpoint })
106 }
107
108 pub fn open_out_endpoint(
109 &mut self,
110 endpoint: u8,
111 max_packet_length: u16,
112 ) -> Result<UsbOutEndpoint<P>, UsbError>
113 where
114 P: MessageAllowed<OpenEndpoint>,
115 {
116 self.conn.try_send_blocking_scalar(OpenEndpoint {
117 handle: self.handle,
118 endpoint,
119 max_packet_length,
120 direction: EndpointDirection::Out,
121 })??;
122 Ok(UsbOutEndpoint { conn: self.conn.clone(), handle: self.handle, endpoint })
123 }
124}
125
126impl<P: CheckedPermissions> UsbInEndpoint<P> {
127 pub fn bulk_in(&mut self, buffer: MemoryRange, length: usize) -> Result<usize, UsbError>
128 where
129 P: MessageAllowed<BulkIn>,
130 {
131 self.conn.lend_mut(BulkIn { handle: self.handle, endpoint: self.endpoint, buffer, length })
132 }
133}
134
135impl<P: CheckedPermissions> UsbOutEndpoint<P> {
136 pub fn bulk_out(&mut self, buffer: MemoryRange, length: usize) -> Result<usize, UsbError>
137 where
138 P: MessageAllowed<BulkOut>,
139 {
140 self.conn.lend_mut(BulkOut { handle: self.handle, endpoint: self.endpoint, buffer, length })
141 }
142}