1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
// Licensed under the Apache License, Version 2.0 or the MIT License.
// SPDX-License-Identifier: Apache-2.0 OR MIT
// Copyright Tock Contributors 2022.

//! Interface to USB controller hardware

use crate::utilities::cells::VolatileCell;

/// USB controller interface
pub trait UsbController<'a> {
    fn set_client(&self, client: &'a dyn Client<'a>);

    // Should be called before `enable_as_device()`
    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);

    fn attach(&self);

    fn detach(&self);

    fn set_address(&self, addr: u16);

    fn enable_address(&self);

    fn endpoint_in_enable(&self, transfer_type: TransferType, endpoint: usize);

    fn endpoint_out_enable(&self, transfer_type: TransferType, endpoint: usize);

    fn endpoint_in_out_enable(&self, transfer_type: TransferType, endpoint: usize);

    fn endpoint_resume_in(&self, endpoint: usize);

    fn endpoint_resume_out(&self, endpoint: usize);
}

#[derive(Clone, Copy, Debug)]
pub enum TransferType {
    Control = 0,
    Isochronous,
    Bulk,
    Interrupt,
}

#[derive(Clone, Copy, Debug)]
pub enum DeviceSpeed {
    Full,
    Low,
}

/// USB controller client interface
pub trait Client<'a> {
    fn enable(&'a self);
    fn attach(&'a self);
    fn bus_reset(&'a self);

    fn ctrl_setup(&'a self, endpoint: usize) -> CtrlSetupResult;
    fn ctrl_in(&'a self, endpoint: usize) -> CtrlInResult;
    fn ctrl_out(&'a self, endpoint: usize, packet_bytes: u32) -> CtrlOutResult;
    fn ctrl_status(&'a self, endpoint: usize);
    fn ctrl_status_complete(&'a self, endpoint: usize);

    fn packet_in(&'a self, transfer_type: TransferType, endpoint: usize) -> InResult;
    fn packet_out(
        &'a self,
        transfer_type: TransferType,
        endpoint: usize,
        packet_bytes: u32,
    ) -> OutResult;

    fn packet_transmitted(&'a self, endpoint: usize);
}

#[derive(Debug)]
pub enum CtrlSetupResult {
    /// The Setup request was handled successfully
    Ok,
    OkSetAddress,

    // The Setup request cannot be handled; abort this transfer with STALL
    ErrBadLength,
    ErrNoParse,
    ErrNonstandardRequest,
    ErrUnrecognizedDescriptorType,
    ErrUnrecognizedRequestType,
    ErrNoDeviceQualifier,
    ErrInvalidDeviceIndex,
    ErrInvalidConfigurationIndex,
    ErrInvalidInterfaceIndex,
    ErrInvalidStringIndex,

    ErrGeneric,
}

pub enum CtrlInResult {
    /// A packet of the given size was written into the endpoint buffer
    Packet(usize, bool),

    /// The client is not yet able to provide data to the host, but may
    /// be able to in the future.  This result causes the controller
    /// to send a NAK token to the host.
    Delay,

    /// The client does not support the request.  This result causes the
    /// controller to send a STALL token to the host.
    Error,
}

pub enum CtrlOutResult {
    /// Data received (send ACK)
    Ok,

    /// Not ready yet (send NAK)
    Delay,

    /// In halt state (send STALL)
    Halted,
}

/// Result for IN packets sent on bulk or interrupt endpoints.
#[derive(Debug)]
pub enum InResult {
    /// A packet of the given size was written into the endpoint buffer
    Packet(usize),

    /// The client is not yet able to provide data to the host, but may
    /// be able to in the future.  This result causes the controller
    /// to send a NAK token to the host.
    Delay,

    /// The client does not support the request.  This result causes the
    /// controller to send a STALL token to the host.
    Error,
}

/// Result for OUT packets sent on bulk or interrupt endpoints.
#[derive(Debug)]
pub enum OutResult {
    /// The OUT packet was consumed
    Ok,

    /// The client is not yet able to consume data from the host, but may
    /// be able to in the future.  This result causes the controller
    /// to send a NAK token to the host.
    Delay,

    /// The client does not support the request.  This result causes the
    /// controller to send a STALL token to the host.
    Error,
}