components/
usb.rs

1// Licensed under the Apache License, Version 2.0 or the MIT License.
2// SPDX-License-Identifier: Apache-2.0 OR MIT
3// Copyright Tock Contributors 2022.
4
5//! Generic component for initializing a USB device given a USBController.
6//!
7//! This provides one Component, UsbComponent, which implements
8//! A userspace syscall interface to a USB peripheral.
9//!
10//! Usage
11//! -----
12//! ```rust
13//! let usb_driver = components::usb::UsbComponent::new(
14//!     board_kernel,
15//!     capsules_extra::usb::usb_user::DRIVER_NUM,
16//!     &peripherals.usbc,
17//! )
18//! .finalize(components::usb_component_static!(sam4l::usbc::Usbc));
19//! ```
20
21use core::mem::MaybeUninit;
22use kernel::capabilities;
23use kernel::component::Component;
24use kernel::create_capability;
25use kernel::hil::usb::UsbController;
26
27#[macro_export]
28macro_rules! usb_component_static {
29    ($U:ty $(,)?) => {{
30        let usb_client = kernel::static_buf!(capsules_extra::usb::usbc_client::Client<'static, $U>);
31        let usb_driver = kernel::static_buf!(
32            capsules_extra::usb::usb_user::UsbSyscallDriver<
33                'static,
34                capsules_extra::usb::usbc_client::Client<'static, $U>,
35            >
36        );
37        (usb_client, usb_driver)
38    }};
39}
40
41pub struct UsbComponent<U: UsbController<'static> + 'static> {
42    board_kernel: &'static kernel::Kernel,
43    driver_num: usize,
44    usbc: &'static U,
45}
46
47impl<U: UsbController<'static> + 'static> UsbComponent<U> {
48    pub fn new(board_kernel: &'static kernel::Kernel, driver_num: usize, usbc: &'static U) -> Self {
49        Self {
50            board_kernel,
51            driver_num,
52            usbc,
53        }
54    }
55}
56
57impl<U: UsbController<'static> + 'static> Component for UsbComponent<U> {
58    type StaticInput = (
59        &'static mut MaybeUninit<capsules_extra::usb::usbc_client::Client<'static, U>>,
60        &'static mut MaybeUninit<
61            capsules_extra::usb::usb_user::UsbSyscallDriver<
62                'static,
63                capsules_extra::usb::usbc_client::Client<'static, U>,
64            >,
65        >,
66    );
67    type Output = &'static capsules_extra::usb::usb_user::UsbSyscallDriver<
68        'static,
69        capsules_extra::usb::usbc_client::Client<'static, U>,
70    >;
71
72    fn finalize(self, s: Self::StaticInput) -> Self::Output {
73        let grant_cap = create_capability!(capabilities::MemoryAllocationCapability);
74
75        // Configure the USB controller
76        let usb_client = s.0.write(capsules_extra::usb::usbc_client::Client::new(
77            self.usbc,
78            capsules_extra::usb::usbc_client::MAX_CTRL_PACKET_SIZE_SAM4L,
79        ));
80        self.usbc.set_client(usb_client);
81
82        // Configure the USB userspace driver
83        let usb_driver =
84            s.1.write(capsules_extra::usb::usb_user::UsbSyscallDriver::new(
85                usb_client,
86                self.board_kernel.create_grant(self.driver_num, &grant_cap),
87            ));
88
89        usb_driver
90    }
91}