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
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
//! Event TRBs.

use bit_field::BitField;
use core::convert::{TryFrom, TryInto};
use num_derive::FromPrimitive;
use num_traits::FromPrimitive;

allowed! {
    /// TRBs which are allowed to be pushed to the Event Ring.
    enum {
        /// Transfer Event TRB.
        TransferEvent,
        /// Command Completion Event TRB.
        CommandCompletion,
        /// Port Status Change Event TRB.
        PortStatusChange,
        /// Bandwidth Request Event TRB.
        BandwidthRequest,
        /// Doorbell Event TRB.
        Doorbell,
        /// Host Controller Event TRB.
        HostController,
        /// Device Notification Event TRB.
        DeviceNotification,
        /// MFINDEX Wrap Event TRB.
        MfindexWrap
    }
}
impl TryFrom<[u32; 4]> for Allowed {
    type Error = [u32; 4];

    fn try_from(raw: [u32; 4]) -> Result<Self, Self::Error> {
        macro_rules! try_from {
            ($name:ident) => {
                if let Ok(t) = $name::try_from(raw) {
                    return Ok(Self::$name(t));
                }
            };
        }

        try_from!(TransferEvent);
        try_from!(CommandCompletion);
        try_from!(PortStatusChange);
        try_from!(BandwidthRequest);
        try_from!(Doorbell);
        try_from!(HostController);
        try_from!(DeviceNotification);
        try_from!(MfindexWrap);

        Err(raw)
    }
}

macro_rules! completion_code {
    ($name:ident) => {
        impl $name {
            /// Returns the Completion Code.
            ///
            /// # Errors
            ///
            /// This method may return an [`Err`] value with the Completion Code that is either reserved or
            /// not implemented by this crate.
            pub fn completion_code(&self) -> Result<CompletionCode, u8> {
                let c: u8 = self.0[2].get_bits(24..=31).try_into().unwrap();
                CompletionCode::from_u8(c).ok_or(c)
            }
        }
    };
}
macro_rules! event {
    ($name:ident,$full:expr,$ty:expr) => {
        add_trb_with_default!($name, $full, $ty);
        completion_code!($name);
    };
}
macro_rules! impl_debug_for_event_trb{
    ($name:ident{})=>{
        impl_debug_for_trb!($name{
            completion_code
        });
    };
    ($name:ident {
        $($method:ident),*
    })=>{
        impl_debug_for_trb!($name{
            completion_code,
            $($method),*
        });
    }
}

event!(
    PortStatusChange,
    "Port Status Change Event TRB",
    Type::PortStatusChange
);
reserved!(PortStatusChange(Type::PortStatusChange){
    [0]0..=23;
    [1]0..=31;
    [2]0..=23;
    [3]1..=9;
    [3]16..=31
});
impl PortStatusChange {
    /// Returns the value of the Port ID field.
    #[must_use]
    pub fn port_id(&self) -> u8 {
        self.0[0].get_bits(24..=31).try_into().unwrap()
    }
}
impl_debug_for_event_trb!(PortStatusChange { port_id });

event!(TransferEvent, "Transfer Event TRB", Type::TransferEvent);
reserved!(TransferEvent(Type::TransferEvent){
    [3]1..=1;
    [3]3..=9;
    [3]21..=23
});
impl TransferEvent {
    /// Returns the value of the TRB Pointer field.
    #[must_use]
    pub fn trb_pointer(&self) -> u64 {
        let l: u64 = self.0[0].into();
        let u: u64 = self.0[1].into();

        (u << 32) | l
    }

    /// Returns the value of the TRB Transfer Length field.
    #[must_use]
    pub fn trb_transfer_length(&self) -> u32 {
        self.0[2].get_bits(0..=23)
    }

    /// Returns the value of the Event Data field.
    #[must_use]
    pub fn event_data(&self) -> bool {
        self.0[3].get_bit(2)
    }

    /// Returns the value of the Endpoint ID field.
    #[must_use]
    pub fn endpoint_id(&self) -> u8 {
        self.0[3].get_bits(16..=20).try_into().unwrap()
    }

    /// Returns the value of the Slot ID field.
    #[must_use]
    pub fn slot_id(&self) -> u8 {
        self.0[3].get_bits(24..=31).try_into().unwrap()
    }
}
impl_debug_for_event_trb!(TransferEvent {
    trb_pointer,
    trb_transfer_length,
    event_data,
    endpoint_id,
    slot_id
});

event!(
    CommandCompletion,
    "Command Completion Event TRB",
    Type::CommandCompletion
);
reserved!(CommandCompletion(Type::CommandCompletion){
    [0]0..=3;
    [3]1..=9
});
impl CommandCompletion {
    /// Returns the value of the Command TRB Pointer field.
    #[must_use]
    pub fn command_trb_pointer(&self) -> u64 {
        let l: u64 = self.0[0].into();
        let u: u64 = self.0[1].into();

        (u << 32) | l
    }

    /// Returns the value of the Command Completion Parameter field.
    #[must_use]
    pub fn command_completion_parameter(&self) -> u32 {
        self.0[2].get_bits(0..=23)
    }

    /// Returns the value of the VF (Virtual Function) ID field.
    #[must_use]
    pub fn vf_id(&self) -> u8 {
        self.0[3].get_bits(16..=23).try_into().unwrap()
    }

    /// Returns the value of the Slot ID field.
    #[must_use]
    pub fn slot_id(&self) -> u8 {
        self.0[3].get_bits(24..=31).try_into().unwrap()
    }
}
impl_debug_for_event_trb!(CommandCompletion {
    command_trb_pointer,
    command_completion_parameter,
    vf_id,
    slot_id
});

event!(
    BandwidthRequest,
    "Bandwidth Request Event TRB",
    Type::BandwidthRequest
);
reserved!(BandwidthRequest(Type::BandwidthRequest){
    [0]0..=31;
    [1]0..=31;
    [2]0..=23;
    [3]1..=9;
    [3]16..=23
});
impl BandwidthRequest {
    /// Returns the value of the Slot ID field.
    #[must_use]
    pub fn slot_id(&self) -> u8 {
        self.0[3].get_bits(24..=31).try_into().unwrap()
    }
}
impl_debug_for_event_trb!(BandwidthRequest { slot_id });

event!(Doorbell, "Doorbell Event TRB", Type::Doorbell);
reserved!(Doorbell(Type::Doorbell){
    [0]5..=31;
    [1]0..=31;
    [2]0..=23;
    [3]1..=9
});
impl Doorbell {
    /// Returns the value of the DB Reason field.
    #[must_use]
    pub fn db_reason(&self) -> u8 {
        self.0[0].get_bits(0..=4).try_into().unwrap()
    }
}
impl_debug_for_event_trb!(Doorbell { db_reason });

event!(
    HostController,
    "Host Controller Event TRB",
    Type::HostController
);
reserved!(HostController(Type::HostController){
    [0]0..=31;
    [1]0..=31;
    [2]0..=23;
    [3]1..=9;
    [3]16..=31
});
impl_debug_for_event_trb!(HostController {});

event!(
    DeviceNotification,
    "Device Notification Event TRB",
    Type::DeviceNotification
);
reserved!(DeviceNotification(Type::DeviceNotification){
    [0]0..=31;
    [1]0..=31;
    [2]0..=23;
    [3]1..=9;
    [3]16..=31
});
impl DeviceNotification {
    /// Returns the value of the Notification Type field.
    #[must_use]
    pub fn notification_type(&self) -> u8 {
        self.0[0].get_bits(4..=7).try_into().unwrap()
    }

    /// Returns the value of the Device Notification Data field.
    #[must_use]
    pub fn device_notification_data(&self) -> u64 {
        let l: u64 = self.0[0].get_bits(8..=31).into();
        let u: u64 = self.0[1].into();

        ((u << 32) | l) >> 8
    }

    /// Returns the value of the Slot ID field.
    #[must_use]
    pub fn slot_id(&self) -> u8 {
        self.0[3].get_bits(24..=31).try_into().unwrap()
    }
}
impl_debug_for_event_trb!(DeviceNotification {
    notification_type,
    device_notification_data,
    slot_id
});

event!(MfindexWrap, "MFINDEX Wrap Event TRB", Type::MfindexWrap);
reserved!(MfindexWrap(Type::MfindexWrap){
    [0]0..=3;
    [2]0..=23;
    [3]1..=9;
    [3]16..=23
});
impl_debug_for_event_trb!(MfindexWrap {});

/// The TRB Completion Codes.
///
/// The description of each error is quoted from eXtensible Host Controller Interface for Universal
/// Serial Bus (xHCI) Requirements Specification May 2019 Revision 1.2, Section 6.4.5, Table 6-90.
/// Refer to this specification for more detail.
#[derive(Copy, Clone, Debug, Ord, PartialOrd, Eq, PartialEq, Hash, FromPrimitive)]
pub enum CompletionCode {
    /// Indicates that the Completion Code field has not been updated by the TRB producer.
    Invalid = 0,
    /// Indicates successful completion of the TRB operation.
    Success = 1,
    /// Indicates that the Host Controller is unable to keep up the reception of incoming data
    /// (overrun) or is unable to supply data fast enough during transmission (underrun).
    DataBufferError = 2,
    /// Asserted when "babbling" is detected during the transaction generated by this TRB.
    BabbleDetectedError = 3,
    /// Asserted in the case where the host did not receive a valid response from the device.
    UsbTransactionError = 4,
    /// Asserted when a TRB parameter error condition is detected in a TRB.
    TrbError = 5,
    /// Asserted when a Stall condition is detected for a TRB.
    StallError = 6,
    /// Asserted by a Configure Endpoint Command or an Address Device Command if there are not
    /// adequate xHC resources available to successfully complete the command.
    ResourceError = 7,
    /// Asserted by a Configure Endpoint Command if periodic endpoints are declared and the xHC is
    /// not able to allocate the required Bandwidth.
    BandwidthError = 8,
    /// Asserted if a adding one more device would result in the host controller to exceed the
    /// maximum Number of Device Slots for this implementation.
    NoSlotsAvailableError = 9,
    /// Asserted if an invalid Stream Context Type value is detected.
    InvalidStreamTypeError = 10,
    /// Asserted if a command is issued to a Device Slot that is in the Disabled state.
    SlotNotEnabledError = 11,
    /// Asserted if a doorbell is rung for an endpoint that is in the Disabled state.
    EndpointNotEnabledError = 12,
    /// Asserted if the number of bytes received was less than the TD Transfer Size.
    ShortPacket = 13,
    /// Asserted in a Transfer Event TRB if the Transfer Ring is empty when an enabled Isoch
    /// endpoint is scheduled to transmit data.
    RingUnderrun = 14,
    /// Asserted in a Transfer Event TRB if the Transfer Ring is empty when an enabled Isoch
    /// endpoint is scheduled to receive data.
    RingOverrun = 15,
    /// Asserted by a Force Event command if the target VF's Event Ring is full.
    VfEventRingFullError = 16,
    /// Asserted by a command if a Context parameter is invalid.
    ParameterError = 17,
    /// Asserted during an Isoch transfer if the TD exceeds the bandwidth allocated to the
    /// endpoint.
    BandwidthOverrunError = 18,
    /// Asserted if a command is issued to transition from an illegal context state.
    ContextStateError = 19,
    /// Asserted if the xHC was unable to complete a periodic data transfer associated within the
    /// ESIT, because it did not receive a PING_RESPONSE in time.
    NoPingResponseError = 20,
    /// Asserted if the Event Ring is full, the xHC is unable to post an Event to the ring.
    EventRingFullError = 21,
    /// Asserted if the xHC detects a problem with a device that does not allow it to be
    /// successfully accessed.
    IncompatibleDeviceError = 22,
    /// Asserted if the xHC was unable to service a Isochronous endpoint within the Interval time.
    MissedServiceError = 23,
    /// Asserted in a Command Completion Event due to a Command Stop operation.
    CommandRingStopped = 24,
    /// Asserted in a Command Completion Event of an aborted command if the command was terminated
    /// by a Command Abort (CA) operation.
    CommandAborted = 25,
    /// Asserted in a Transfer Event if the transfer was terminated by a Stop Endpoint Command.
    Stopped = 26,
    /// Asserted in a Transfer Event if the transfer was terminated by a Stop Endpoint Command and
    /// the Transfer Event TRB Transfer Length field is invalid.
    StoppedLengthInvalid = 27,
    /// Asserted in a Transfer Event if the transfer was terminated by a Stop Endpoint Command, and
    /// the transfer was stopped after Short Packet conditions were met, but before the end of the
    /// TD was reached.
    StoppedShortPacket = 28,
    /// Asserted by the Evaluate Context Command if the proposed Max Exit Latency would not allow
    /// the periodic endpoints of the Device Slot to be scheduled.
    MaxExitLatencyTooLargeError = 29,
    /// Asserted if the data buffer defined by an Isoch TD on an IN endpoint is less than the Max
    /// ESIT Payload in size and the device attempts to send more data than it can hold.
    IsochBufferOverrun = 31,
    /// Asserted if the xHC internal event overrun condition.
    EventLostError = 32,
    /// May be reported by an event when other error codes do not apply.
    UndefinedError = 33,
    /// Asserted if an invalid Stream ID is received.
    InvalidStreamIdError = 34,
    /// Asserted by a Configure Endpoint Command if periodic endpoints are declared and the xHC is
    /// not able to allocate the required Bandwidth due to a Secondary Bandwidth Domain.
    SecondaryBandwidthError = 35,
    /// Asserted if an error is detected on a USB2 protocol endpoint for a split transaction.
    SplitTransactionError = 36,
}