usb/host/
api.rs

1// SPDX-FileCopyrightText: 2023 Foundation Devices, Inc. <hello@foundation.xyz>
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4pub 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}