Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
google
GitHub Repository: google/crosvm
Path: blob/main/devices/src/usb/xhci/device_slot.rs
5394 views
1
// Copyright 2019 The ChromiumOS Authors
2
// Use of this source code is governed by a BSD-style license that can be
3
// found in the LICENSE file.
4
5
use std::mem::size_of;
6
use std::sync::atomic::AtomicBool;
7
use std::sync::atomic::Ordering;
8
use std::sync::Arc;
9
10
use base::debug;
11
use base::error;
12
use base::info;
13
use bit_field::Error as BitFieldError;
14
use remain::sorted;
15
use sync::Mutex;
16
use thiserror::Error;
17
use vm_memory::GuestAddress;
18
use vm_memory::GuestMemory;
19
use vm_memory::GuestMemoryError;
20
21
use super::interrupter::Interrupter;
22
use super::transfer_ring_controller::TransferRingController;
23
use super::transfer_ring_controller::TransferRingControllerError;
24
use super::transfer_ring_controller::TransferRingControllers;
25
use super::usb_hub;
26
use super::usb_hub::UsbHub;
27
use super::xhci_abi::AddressDeviceCommandTrb;
28
use super::xhci_abi::ConfigureEndpointCommandTrb;
29
use super::xhci_abi::DequeuePtr;
30
use super::xhci_abi::DeviceContext;
31
use super::xhci_abi::DeviceSlotState;
32
use super::xhci_abi::EndpointContext;
33
use super::xhci_abi::EndpointState;
34
use super::xhci_abi::EvaluateContextCommandTrb;
35
use super::xhci_abi::InputControlContext;
36
use super::xhci_abi::SlotContext;
37
use super::xhci_abi::StreamContextArray;
38
use super::xhci_abi::TrbCompletionCode;
39
use super::xhci_abi::DEVICE_CONTEXT_ENTRY_SIZE;
40
use super::xhci_backend_device::XhciBackendDevice;
41
use super::xhci_regs::valid_max_pstreams;
42
use super::xhci_regs::valid_slot_id;
43
use super::xhci_regs::MAX_PORTS;
44
use super::xhci_regs::MAX_SLOTS;
45
use crate::register_space::Register;
46
use crate::usb::backend::error::Error as BackendProviderError;
47
use crate::usb::xhci::ring_buffer_stop_cb::fallible_closure;
48
use crate::usb::xhci::ring_buffer_stop_cb::RingBufferStopCallback;
49
use crate::utils::EventLoop;
50
use crate::utils::FailHandle;
51
52
#[sorted]
53
#[derive(Error, Debug)]
54
pub enum Error {
55
#[error("failed to allocate streams: {0}")]
56
AllocStreams(BackendProviderError),
57
#[error("bad device context: {0}")]
58
BadDeviceContextAddr(GuestAddress),
59
#[error("bad endpoint context: {0}")]
60
BadEndpointContext(GuestAddress),
61
#[error("device slot get a bad endpoint id: {0}")]
62
BadEndpointId(u8),
63
#[error("bad input context address: {0}")]
64
BadInputContextAddr(GuestAddress),
65
#[error("device slot get a bad port id: {0}")]
66
BadPortId(u8),
67
#[error("bad stream context type: {0}")]
68
BadStreamContextType(u8),
69
#[error("callback failed")]
70
CallbackFailed,
71
#[error("failed to create transfer controller: {0}")]
72
CreateTransferController(TransferRingControllerError),
73
#[error("failed to free streams: {0}")]
74
FreeStreams(BackendProviderError),
75
#[error("failed to get endpoint state: {0}")]
76
GetEndpointState(BitFieldError),
77
#[error("failed to get port: {0}")]
78
GetPort(u8),
79
#[error("failed to get slot context state: {0}")]
80
GetSlotContextState(BitFieldError),
81
#[error("failed to get trc: {0}")]
82
GetTrc(u8),
83
#[error("failed to read guest memory: {0}")]
84
ReadGuestMemory(GuestMemoryError),
85
#[error("failed to reset port: {0}")]
86
ResetPort(BackendProviderError),
87
#[error("failed to upgrade weak reference")]
88
WeakReferenceUpgrade,
89
#[error("failed to write guest memory: {0}")]
90
WriteGuestMemory(GuestMemoryError),
91
}
92
93
type Result<T> = std::result::Result<T, Error>;
94
95
/// See spec 4.5.1 for dci.
96
/// index 0: Control endpoint. Device Context Index: 1.
97
/// index 1: Endpoint 1 out. Device Context Index: 2
98
/// index 2: Endpoint 1 in. Device Context Index: 3.
99
/// index 3: Endpoint 2 out. Device Context Index: 4
100
/// ...
101
/// index 30: Endpoint 15 in. Device Context Index: 31
102
pub const TRANSFER_RING_CONTROLLERS_INDEX_END: usize = 31;
103
/// End of device context index.
104
pub const DCI_INDEX_END: u8 = (TRANSFER_RING_CONTROLLERS_INDEX_END + 1) as u8;
105
/// Device context index of first transfer endpoint.
106
pub const FIRST_TRANSFER_ENDPOINT_DCI: u8 = 2;
107
108
fn valid_endpoint_id(endpoint_id: u8) -> bool {
109
endpoint_id < DCI_INDEX_END && endpoint_id > 0
110
}
111
112
#[derive(Clone)]
113
pub struct DeviceSlots {
114
fail_handle: Arc<dyn FailHandle>,
115
hub: Arc<UsbHub>,
116
slots: Vec<Arc<DeviceSlot>>,
117
}
118
119
impl DeviceSlots {
120
pub fn new(
121
fail_handle: Arc<dyn FailHandle>,
122
dcbaap: Register<u64>,
123
hub: Arc<UsbHub>,
124
interrupter: Arc<Mutex<Interrupter>>,
125
event_loop: Arc<EventLoop>,
126
mem: GuestMemory,
127
) -> DeviceSlots {
128
let mut slots = Vec::new();
129
for slot_id in 1..=MAX_SLOTS {
130
slots.push(Arc::new(DeviceSlot::new(
131
slot_id,
132
dcbaap.clone(),
133
hub.clone(),
134
interrupter.clone(),
135
event_loop.clone(),
136
mem.clone(),
137
)));
138
}
139
DeviceSlots {
140
fail_handle,
141
hub,
142
slots,
143
}
144
}
145
146
/// Note that slot id starts from 1. Slot index start from 0.
147
pub fn slot(&self, slot_id: u8) -> Option<Arc<DeviceSlot>> {
148
if valid_slot_id(slot_id) {
149
Some(self.slots[slot_id as usize - 1].clone())
150
} else {
151
error!(
152
"trying to index a wrong slot id {}, max slot = {}",
153
slot_id, MAX_SLOTS
154
);
155
None
156
}
157
}
158
159
/// Reset the device connected to a specific port.
160
pub fn reset_port(&self, port_id: u8) -> Result<()> {
161
if let Some(port) = self.hub.get_port(port_id) {
162
if let Some(backend_device) = port.backend_device().as_mut() {
163
backend_device.lock().reset().map_err(Error::ResetPort)?;
164
}
165
}
166
167
// No device on port, so nothing to reset.
168
Ok(())
169
}
170
171
/// Stop all device slots and reset them.
172
pub fn stop_all_and_reset<C: FnMut() + 'static + Send>(&self, mut callback: C) {
173
info!("xhci: stopping all device slots and resetting host hub");
174
let slots = self.slots.clone();
175
let hub = self.hub.clone();
176
let auto_callback = RingBufferStopCallback::new(fallible_closure(
177
self.fail_handle.clone(),
178
move || -> std::result::Result<(), usb_hub::Error> {
179
for slot in &slots {
180
slot.reset();
181
}
182
hub.reset()?;
183
callback();
184
Ok(())
185
},
186
));
187
self.stop_all(auto_callback);
188
}
189
190
/// Stop all devices. The auto callback will be executed when all trc is stopped. It could
191
/// happen asynchronously, if there are any pending transfers.
192
pub fn stop_all(&self, auto_callback: RingBufferStopCallback) {
193
for slot in &self.slots {
194
slot.stop_all_trc(auto_callback.clone());
195
}
196
}
197
198
/// Disable a slot. This might happen asynchronously, if there is any pending transfers. The
199
/// callback will be invoked when slot is actually disabled.
200
pub fn disable_slot<
201
C: FnMut(TrbCompletionCode) -> std::result::Result<(), ()> + 'static + Send,
202
>(
203
&self,
204
slot_id: u8,
205
cb: C,
206
) -> Result<()> {
207
xhci_trace!("device slot {} is being disabled", slot_id);
208
DeviceSlot::disable(
209
self.fail_handle.clone(),
210
&self.slots[slot_id as usize - 1],
211
cb,
212
)
213
}
214
215
/// Reset a slot. This is a shortcut call for DeviceSlot::reset_slot.
216
pub fn reset_slot<
217
C: FnMut(TrbCompletionCode) -> std::result::Result<(), ()> + 'static + Send,
218
>(
219
&self,
220
slot_id: u8,
221
cb: C,
222
) -> Result<()> {
223
xhci_trace!("device slot {} is resetting", slot_id);
224
DeviceSlot::reset_slot(
225
self.fail_handle.clone(),
226
&self.slots[slot_id as usize - 1],
227
cb,
228
)
229
}
230
231
pub fn stop_endpoint<
232
C: FnMut(TrbCompletionCode) -> std::result::Result<(), ()> + 'static + Send,
233
>(
234
&self,
235
slot_id: u8,
236
endpoint_id: u8,
237
cb: C,
238
) -> Result<()> {
239
self.slots[slot_id as usize - 1].stop_endpoint(self.fail_handle.clone(), endpoint_id, cb)
240
}
241
242
pub fn reset_endpoint<
243
C: FnMut(TrbCompletionCode) -> std::result::Result<(), ()> + 'static + Send,
244
>(
245
&self,
246
slot_id: u8,
247
endpoint_id: u8,
248
cb: C,
249
) -> Result<()> {
250
self.slots[slot_id as usize - 1].reset_endpoint(self.fail_handle.clone(), endpoint_id, cb)
251
}
252
}
253
254
// Usb port id. Valid ids starts from 1, to MAX_PORTS.
255
struct PortId(Mutex<u8>);
256
257
impl PortId {
258
fn new() -> Self {
259
PortId(Mutex::new(0))
260
}
261
262
fn set(&self, value: u8) -> Result<()> {
263
if !(1..=MAX_PORTS).contains(&value) {
264
return Err(Error::BadPortId(value));
265
}
266
*self.0.lock() = value;
267
Ok(())
268
}
269
270
fn reset(&self) {
271
*self.0.lock() = 0;
272
}
273
274
fn get(&self) -> Result<u8> {
275
let val = *self.0.lock();
276
if val == 0 {
277
return Err(Error::BadPortId(val));
278
}
279
Ok(val)
280
}
281
}
282
283
pub struct DeviceSlot {
284
slot_id: u8,
285
port_id: PortId, // Valid port id starts from 1, to MAX_PORTS.
286
dcbaap: Register<u64>,
287
hub: Arc<UsbHub>,
288
interrupter: Arc<Mutex<Interrupter>>,
289
event_loop: Arc<EventLoop>,
290
mem: GuestMemory,
291
enabled: AtomicBool,
292
transfer_ring_controllers: Mutex<Vec<Option<TransferRingControllers>>>,
293
}
294
295
impl DeviceSlot {
296
/// Create a new device slot.
297
pub fn new(
298
slot_id: u8,
299
dcbaap: Register<u64>,
300
hub: Arc<UsbHub>,
301
interrupter: Arc<Mutex<Interrupter>>,
302
event_loop: Arc<EventLoop>,
303
mem: GuestMemory,
304
) -> Self {
305
let mut transfer_ring_controllers = Vec::new();
306
transfer_ring_controllers.resize_with(TRANSFER_RING_CONTROLLERS_INDEX_END, || None);
307
DeviceSlot {
308
slot_id,
309
port_id: PortId::new(),
310
dcbaap,
311
hub,
312
interrupter,
313
event_loop,
314
mem,
315
enabled: AtomicBool::new(false),
316
transfer_ring_controllers: Mutex::new(transfer_ring_controllers),
317
}
318
}
319
320
fn get_trc(&self, i: usize, stream_id: u16) -> Option<Arc<TransferRingController>> {
321
let trcs = self.transfer_ring_controllers.lock();
322
match &trcs[i] {
323
Some(TransferRingControllers::Endpoint(trc)) => Some(trc.clone()),
324
Some(TransferRingControllers::Stream(trcs)) => {
325
let stream_id = stream_id as usize;
326
if stream_id > 0 && stream_id <= trcs.len() {
327
Some(trcs[stream_id - 1].clone())
328
} else {
329
None
330
}
331
}
332
None => None,
333
}
334
}
335
336
fn get_trcs(&self, i: usize) -> Option<TransferRingControllers> {
337
let trcs = self.transfer_ring_controllers.lock();
338
trcs[i].clone()
339
}
340
341
fn set_trcs(&self, i: usize, trc: Option<TransferRingControllers>) {
342
let mut trcs = self.transfer_ring_controllers.lock();
343
trcs[i] = trc;
344
}
345
346
fn trc_len(&self) -> usize {
347
self.transfer_ring_controllers.lock().len()
348
}
349
350
/// The arguments are identical to the fields in each doorbell register. The
351
/// target value:
352
/// 1: Reserved
353
/// 2: Control endpoint
354
/// 3: Endpoint 1 out
355
/// 4: Endpoint 1 in
356
/// 5: Endpoint 2 out
357
/// ...
358
/// 32: Endpoint 15 in
359
///
360
/// Steam ID will be useful when host controller support streams.
361
/// The stream ID must be zero for endpoints that do not have streams
362
/// configured.
363
/// This function will return false if it fails to trigger transfer ring start.
364
pub fn ring_doorbell(&self, target: u8, stream_id: u16) -> Result<bool> {
365
if !valid_endpoint_id(target) {
366
error!(
367
"device slot {}: Invalid target written to doorbell register. target: {}",
368
self.slot_id, target
369
);
370
return Ok(false);
371
}
372
xhci_trace!(
373
"device slot {}: ring_doorbell target = {} stream_id = {}",
374
self.slot_id,
375
target,
376
stream_id
377
);
378
// See DCI in spec.
379
let endpoint_index = (target - 1) as usize;
380
let transfer_ring_controller = match self.get_trc(endpoint_index, stream_id) {
381
Some(tr) => tr,
382
None => {
383
error!("Device endpoint is not inited");
384
return Ok(false);
385
}
386
};
387
let mut context = self.get_device_context()?;
388
let endpoint_state = context.endpoint_context[endpoint_index]
389
.get_endpoint_state()
390
.map_err(Error::GetEndpointState)?;
391
if endpoint_state == EndpointState::Running || endpoint_state == EndpointState::Stopped {
392
if endpoint_state == EndpointState::Stopped {
393
context.endpoint_context[endpoint_index].set_endpoint_state(EndpointState::Running);
394
self.set_device_context(context)?;
395
}
396
// endpoint is started, start transfer ring
397
transfer_ring_controller.start();
398
} else {
399
error!("doorbell rung when endpoint state is {:?}", endpoint_state);
400
}
401
Ok(true)
402
}
403
404
/// Enable the slot. This function returns false if it's already enabled. It's not an error
405
/// when this was called for an already enabled slot, because this is repeatedly called to find
406
/// and enable the next available slot.
407
pub fn enable(&self) -> bool {
408
let was_already_enabled = self.enabled.swap(true, Ordering::SeqCst);
409
!was_already_enabled
410
}
411
412
/// Disable this device slot. If the slot is not enabled, callback will be invoked immediately
413
/// with error. Otherwise, callback will be invoked when all trc is stopped.
414
pub fn disable<C: FnMut(TrbCompletionCode) -> std::result::Result<(), ()> + 'static + Send>(
415
fail_handle: Arc<dyn FailHandle>,
416
slot: &Arc<DeviceSlot>,
417
mut callback: C,
418
) -> Result<()> {
419
if slot.enabled.swap(false, Ordering::SeqCst) {
420
let slot_weak = Arc::downgrade(slot);
421
let auto_callback =
422
RingBufferStopCallback::new(fallible_closure(fail_handle, move || {
423
// Slot should still be alive when the callback is invoked. If it's not, there
424
// must be a bug somewhere.
425
let slot = slot_weak.upgrade().ok_or(Error::WeakReferenceUpgrade)?;
426
let mut device_context = slot.get_device_context()?;
427
device_context
428
.slot_context
429
.set_slot_state(DeviceSlotState::DisabledOrEnabled);
430
slot.set_device_context(device_context)?;
431
slot.reset();
432
debug!(
433
"device slot {}: all trc disabled, sending trb",
434
slot.slot_id
435
);
436
callback(TrbCompletionCode::Success).map_err(|_| Error::CallbackFailed)
437
}));
438
slot.stop_all_trc(auto_callback);
439
Ok(())
440
} else {
441
callback(TrbCompletionCode::SlotNotEnabledError).map_err(|_| Error::CallbackFailed)
442
}
443
}
444
445
// Assigns the device address and initializes slot and endpoint 0 context.
446
pub fn set_address(
447
self: &Arc<Self>,
448
trb: &AddressDeviceCommandTrb,
449
) -> Result<TrbCompletionCode> {
450
if !self.enabled.load(Ordering::SeqCst) {
451
error!(
452
"trying to set address to a disabled device slot {}",
453
self.slot_id
454
);
455
return Ok(TrbCompletionCode::SlotNotEnabledError);
456
}
457
let device_context = self.get_device_context()?;
458
let state = device_context
459
.slot_context
460
.get_slot_state()
461
.map_err(Error::GetSlotContextState)?;
462
match state {
463
DeviceSlotState::DisabledOrEnabled => {}
464
DeviceSlotState::Default if !trb.get_block_set_address_request() => {}
465
_ => {
466
error!("slot {} has unexpected slot state", self.slot_id);
467
return Ok(TrbCompletionCode::ContextStateError);
468
}
469
}
470
471
// Copy all fields of the slot context and endpoint 0 context from the input context
472
// to the output context.
473
let input_context_ptr = GuestAddress(trb.get_input_context_pointer());
474
// Copy slot context.
475
self.copy_context(input_context_ptr, 0)?;
476
// Copy control endpoint context.
477
self.copy_context(input_context_ptr, 1)?;
478
479
// Read back device context.
480
let mut device_context = self.get_device_context()?;
481
let port_id = device_context.slot_context.get_root_hub_port_number();
482
self.port_id.set(port_id)?;
483
debug!(
484
"port id {} is assigned to slot id {}",
485
port_id, self.slot_id
486
);
487
488
// Initialize the control endpoint. Endpoint id = 1.
489
let trc = TransferRingController::new(
490
self.mem.clone(),
491
self.hub.get_port(port_id).ok_or(Error::GetPort(port_id))?,
492
self.event_loop.clone(),
493
self.interrupter.clone(),
494
self.slot_id,
495
1,
496
Arc::downgrade(self),
497
None,
498
)
499
.map_err(Error::CreateTransferController)?;
500
self.set_trcs(0, Some(TransferRingControllers::Endpoint(trc)));
501
502
// Assign slot ID as device address if block_set_address_request is not set.
503
if trb.get_block_set_address_request() {
504
device_context
505
.slot_context
506
.set_slot_state(DeviceSlotState::Default);
507
} else {
508
let port = self.hub.get_port(port_id).ok_or(Error::GetPort(port_id))?;
509
match port.backend_device().as_mut() {
510
Some(backend) => {
511
backend.lock().set_address(self.slot_id as u32);
512
}
513
None => {
514
return Ok(TrbCompletionCode::TransactionError);
515
}
516
}
517
518
device_context
519
.slot_context
520
.set_usb_device_address(self.slot_id);
521
device_context
522
.slot_context
523
.set_slot_state(DeviceSlotState::Addressed);
524
}
525
526
// TODO(jkwang) trc should always exists. Fix this.
527
self.get_trc(0, 0)
528
.ok_or(Error::GetTrc(0))?
529
.set_dequeue_pointer(
530
device_context.endpoint_context[0]
531
.get_tr_dequeue_pointer()
532
.get_gpa(),
533
);
534
535
self.get_trc(0, 0)
536
.ok_or(Error::GetTrc(0))?
537
.set_consumer_cycle_state(device_context.endpoint_context[0].get_dequeue_cycle_state());
538
539
// Setting endpoint 0 to running
540
device_context.endpoint_context[0].set_endpoint_state(EndpointState::Running);
541
self.set_device_context(device_context)?;
542
Ok(TrbCompletionCode::Success)
543
}
544
545
// Adds or drops multiple endpoints in the device slot.
546
pub fn configure_endpoint(
547
self: &Arc<Self>,
548
trb: &ConfigureEndpointCommandTrb,
549
) -> Result<TrbCompletionCode> {
550
let input_control_context = if trb.get_deconfigure() {
551
// From section 4.6.6 of the xHCI spec:
552
// Setting the deconfigure (DC) flag to '1' in the Configure Endpoint Command
553
// TRB is equivalent to setting Input Context Drop Context flags 2-31 to '1'
554
// and Add Context 2-31 flags to '0'.
555
let mut c = InputControlContext::new();
556
c.set_add_context_flags(0);
557
c.set_drop_context_flags(0xfffffffc);
558
c
559
} else {
560
self.mem
561
.read_obj_from_addr(GuestAddress(trb.get_input_context_pointer()))
562
.map_err(Error::ReadGuestMemory)?
563
};
564
565
for device_context_index in 1..DCI_INDEX_END {
566
if input_control_context.drop_context_flag(device_context_index) {
567
self.drop_one_endpoint(device_context_index)?;
568
}
569
if input_control_context.add_context_flag(device_context_index) {
570
self.copy_context(
571
GuestAddress(trb.get_input_context_pointer()),
572
device_context_index,
573
)?;
574
self.add_one_endpoint(device_context_index)?;
575
}
576
}
577
578
if trb.get_deconfigure() {
579
self.set_state(DeviceSlotState::Addressed)?;
580
} else {
581
self.set_state(DeviceSlotState::Configured)?;
582
}
583
Ok(TrbCompletionCode::Success)
584
}
585
586
// Evaluates the device context by reading new values for certain fields of
587
// the slot context and/or control endpoint context.
588
pub fn evaluate_context(&self, trb: &EvaluateContextCommandTrb) -> Result<TrbCompletionCode> {
589
if !self.enabled.load(Ordering::SeqCst) {
590
return Ok(TrbCompletionCode::SlotNotEnabledError);
591
}
592
// TODO(jkwang) verify this
593
// The spec has multiple contradictions about validating context parameters in sections
594
// 4.6.7, 6.2.3.3. To keep things as simple as possible we do no further validation here.
595
let input_control_context: InputControlContext = self
596
.mem
597
.read_obj_from_addr(GuestAddress(trb.get_input_context_pointer()))
598
.map_err(Error::ReadGuestMemory)?;
599
600
let mut device_context = self.get_device_context()?;
601
if input_control_context.add_context_flag(0) {
602
let input_slot_context: SlotContext = self
603
.mem
604
.read_obj_from_addr(GuestAddress(
605
trb.get_input_context_pointer() + DEVICE_CONTEXT_ENTRY_SIZE as u64,
606
))
607
.map_err(Error::ReadGuestMemory)?;
608
device_context
609
.slot_context
610
.set_interrupter_target(input_slot_context.get_interrupter_target());
611
612
device_context
613
.slot_context
614
.set_max_exit_latency(input_slot_context.get_max_exit_latency());
615
}
616
617
// From 6.2.3.3: "Endpoint Contexts 2 throught 31 shall not be evaluated by the Evaluate
618
// Context Command".
619
if input_control_context.add_context_flag(1) {
620
let ep0_context: EndpointContext = self
621
.mem
622
.read_obj_from_addr(GuestAddress(
623
trb.get_input_context_pointer() + 2 * DEVICE_CONTEXT_ENTRY_SIZE as u64,
624
))
625
.map_err(Error::ReadGuestMemory)?;
626
device_context.endpoint_context[0]
627
.set_max_packet_size(ep0_context.get_max_packet_size());
628
}
629
self.set_device_context(device_context)?;
630
Ok(TrbCompletionCode::Success)
631
}
632
633
/// Reset the device slot to default state and deconfigures all but the
634
/// control endpoint.
635
pub fn reset_slot<
636
C: FnMut(TrbCompletionCode) -> std::result::Result<(), ()> + 'static + Send,
637
>(
638
fail_handle: Arc<dyn FailHandle>,
639
slot: &Arc<DeviceSlot>,
640
mut callback: C,
641
) -> Result<()> {
642
let weak_s = Arc::downgrade(slot);
643
let auto_callback =
644
RingBufferStopCallback::new(fallible_closure(fail_handle, move || -> Result<()> {
645
let s = weak_s.upgrade().ok_or(Error::WeakReferenceUpgrade)?;
646
for i in FIRST_TRANSFER_ENDPOINT_DCI..DCI_INDEX_END {
647
s.drop_one_endpoint(i)?;
648
}
649
let mut ctx = s.get_device_context()?;
650
ctx.slot_context.set_slot_state(DeviceSlotState::Default);
651
ctx.slot_context.set_context_entries(1);
652
ctx.slot_context.set_root_hub_port_number(0);
653
s.set_device_context(ctx)?;
654
callback(TrbCompletionCode::Success).map_err(|_| Error::CallbackFailed)?;
655
Ok(())
656
}));
657
slot.stop_all_trc(auto_callback);
658
Ok(())
659
}
660
661
/// Stop all transfer ring controllers.
662
pub fn stop_all_trc(&self, auto_callback: RingBufferStopCallback) {
663
for i in 0..self.trc_len() {
664
if let Some(trcs) = self.get_trcs(i) {
665
match trcs {
666
TransferRingControllers::Endpoint(trc) => {
667
trc.stop(auto_callback.clone());
668
}
669
TransferRingControllers::Stream(trcs) => {
670
for trc in trcs {
671
trc.stop(auto_callback.clone());
672
}
673
}
674
}
675
}
676
}
677
}
678
679
/// Stop an endpoint.
680
pub fn stop_endpoint<
681
C: FnMut(TrbCompletionCode) -> std::result::Result<(), ()> + 'static + Send,
682
>(
683
&self,
684
fail_handle: Arc<dyn FailHandle>,
685
endpoint_id: u8,
686
mut cb: C,
687
) -> Result<()> {
688
if !valid_endpoint_id(endpoint_id) {
689
error!("trb indexing wrong endpoint id");
690
return cb(TrbCompletionCode::TrbError).map_err(|_| Error::CallbackFailed);
691
}
692
let index = endpoint_id - 1;
693
let mut device_context = self.get_device_context()?;
694
let endpoint_context = &mut device_context.endpoint_context[index as usize];
695
match self.get_trcs(index as usize) {
696
Some(TransferRingControllers::Endpoint(trc)) => {
697
let auto_cb = RingBufferStopCallback::new(fallible_closure(
698
fail_handle,
699
move || -> Result<()> {
700
cb(TrbCompletionCode::Success).map_err(|_| Error::CallbackFailed)
701
},
702
));
703
trc.stop(auto_cb);
704
let dequeue_pointer = trc.get_dequeue_pointer();
705
let dcs = trc.get_consumer_cycle_state();
706
endpoint_context.set_tr_dequeue_pointer(DequeuePtr::new(dequeue_pointer));
707
endpoint_context.set_dequeue_cycle_state(dcs);
708
}
709
Some(TransferRingControllers::Stream(trcs)) => {
710
let stream_context_array_addr = endpoint_context.get_tr_dequeue_pointer().get_gpa();
711
let mut stream_context_array: StreamContextArray = self
712
.mem
713
.read_obj_from_addr(stream_context_array_addr)
714
.map_err(Error::ReadGuestMemory)?;
715
let auto_cb = RingBufferStopCallback::new(fallible_closure(
716
fail_handle,
717
move || -> Result<()> {
718
cb(TrbCompletionCode::Success).map_err(|_| Error::CallbackFailed)
719
},
720
));
721
for (i, trc) in trcs.iter().enumerate() {
722
let dequeue_pointer = trc.get_dequeue_pointer();
723
let dcs = trc.get_consumer_cycle_state();
724
trc.stop(auto_cb.clone());
725
stream_context_array.stream_contexts[i + 1]
726
.set_tr_dequeue_pointer(DequeuePtr::new(dequeue_pointer));
727
stream_context_array.stream_contexts[i + 1].set_dequeue_cycle_state(dcs);
728
}
729
self.mem
730
.write_obj_at_addr(stream_context_array, stream_context_array_addr)
731
.map_err(Error::WriteGuestMemory)?;
732
}
733
None => {
734
error!("endpoint at index {} is not started", index);
735
cb(TrbCompletionCode::ContextStateError).map_err(|_| Error::CallbackFailed)?;
736
}
737
}
738
endpoint_context.set_endpoint_state(EndpointState::Stopped);
739
self.set_device_context(device_context)?;
740
Ok(())
741
}
742
743
/// Reset an endpoint.
744
pub fn reset_endpoint<
745
C: FnMut(TrbCompletionCode) -> std::result::Result<(), ()> + 'static + Send,
746
>(
747
&self,
748
fail_handle: Arc<dyn FailHandle>,
749
endpoint_id: u8,
750
mut cb: C,
751
) -> Result<()> {
752
if !valid_endpoint_id(endpoint_id) {
753
error!("trb indexing wrong endpoint id");
754
return cb(TrbCompletionCode::TrbError).map_err(|_| Error::CallbackFailed);
755
}
756
let index = endpoint_id - 1;
757
let mut device_context = self.get_device_context()?;
758
let endpoint_context = &mut device_context.endpoint_context[index as usize];
759
if endpoint_context
760
.get_endpoint_state()
761
.map_err(Error::GetEndpointState)?
762
!= EndpointState::Halted
763
{
764
error!("endpoint at index {} is not halted", index);
765
return cb(TrbCompletionCode::ContextStateError).map_err(|_| Error::CallbackFailed);
766
}
767
match self.get_trcs(index as usize) {
768
Some(TransferRingControllers::Endpoint(trc)) => {
769
let auto_cb = RingBufferStopCallback::new(fallible_closure(
770
fail_handle,
771
move || -> Result<()> {
772
cb(TrbCompletionCode::Success).map_err(|_| Error::CallbackFailed)
773
},
774
));
775
trc.stop(auto_cb);
776
let dequeue_pointer = trc.get_dequeue_pointer();
777
let dcs = trc.get_consumer_cycle_state();
778
endpoint_context.set_tr_dequeue_pointer(DequeuePtr::new(dequeue_pointer));
779
endpoint_context.set_dequeue_cycle_state(dcs);
780
}
781
Some(TransferRingControllers::Stream(trcs)) => {
782
let stream_context_array_addr = endpoint_context.get_tr_dequeue_pointer().get_gpa();
783
let mut stream_context_array: StreamContextArray = self
784
.mem
785
.read_obj_from_addr(stream_context_array_addr)
786
.map_err(Error::ReadGuestMemory)?;
787
let auto_cb = RingBufferStopCallback::new(fallible_closure(
788
fail_handle,
789
move || -> Result<()> {
790
cb(TrbCompletionCode::Success).map_err(|_| Error::CallbackFailed)
791
},
792
));
793
for (i, trc) in trcs.iter().enumerate() {
794
let dequeue_pointer = trc.get_dequeue_pointer();
795
let dcs = trc.get_consumer_cycle_state();
796
trc.stop(auto_cb.clone());
797
stream_context_array.stream_contexts[i + 1]
798
.set_tr_dequeue_pointer(DequeuePtr::new(dequeue_pointer));
799
stream_context_array.stream_contexts[i + 1].set_dequeue_cycle_state(dcs);
800
}
801
self.mem
802
.write_obj_at_addr(stream_context_array, stream_context_array_addr)
803
.map_err(Error::WriteGuestMemory)?;
804
}
805
None => {
806
error!("endpoint at index {} is not started", index);
807
cb(TrbCompletionCode::ContextStateError).map_err(|_| Error::CallbackFailed)?;
808
}
809
}
810
endpoint_context.set_endpoint_state(EndpointState::Stopped);
811
self.set_device_context(device_context)?;
812
Ok(())
813
}
814
815
/// Set transfer ring dequeue pointer.
816
pub fn set_tr_dequeue_ptr(
817
&self,
818
endpoint_id: u8,
819
stream_id: u16,
820
ptr: u64,
821
) -> Result<TrbCompletionCode> {
822
if !valid_endpoint_id(endpoint_id) {
823
error!("trb indexing wrong endpoint id");
824
return Ok(TrbCompletionCode::TrbError);
825
}
826
let index = (endpoint_id - 1) as usize;
827
match self.get_trc(index, stream_id) {
828
Some(trc) => {
829
trc.set_dequeue_pointer(GuestAddress(ptr));
830
let mut ctx = self.get_device_context()?;
831
ctx.endpoint_context[index]
832
.set_tr_dequeue_pointer(DequeuePtr::new(GuestAddress(ptr)));
833
self.set_device_context(ctx)?;
834
Ok(TrbCompletionCode::Success)
835
}
836
None => {
837
error!("set tr dequeue ptr failed due to no trc started");
838
Ok(TrbCompletionCode::ContextStateError)
839
}
840
}
841
}
842
843
// Reset and reset_slot are different.
844
// Reset_slot handles command ring `reset slot` command. It will reset the slot state.
845
// Reset handles xhci reset. It will destroy everything.
846
fn reset(&self) {
847
for i in 0..self.trc_len() {
848
self.set_trcs(i, None);
849
}
850
debug!("resetting device slot {}!", self.slot_id);
851
self.enabled.store(false, Ordering::SeqCst);
852
self.port_id.reset();
853
}
854
855
fn create_stream_trcs(
856
self: &Arc<Self>,
857
stream_context_array_addr: GuestAddress,
858
max_pstreams: u8,
859
device_context_index: u8,
860
) -> Result<TransferRingControllers> {
861
let pstreams = 1usize << (max_pstreams + 1);
862
let stream_context_array: StreamContextArray = self
863
.mem
864
.read_obj_from_addr(stream_context_array_addr)
865
.map_err(Error::ReadGuestMemory)?;
866
let mut trcs = Vec::new();
867
868
// Stream ID 0 is reserved (xHCI spec Section 4.12.2)
869
for i in 1..pstreams {
870
let stream_context = &stream_context_array.stream_contexts[i];
871
let context_type = stream_context.get_stream_context_type();
872
if context_type != 1 {
873
// We only support Linear Stream Context Array for now
874
return Err(Error::BadStreamContextType(context_type));
875
}
876
let trc = TransferRingController::new(
877
self.mem.clone(),
878
self.hub
879
.get_port(self.port_id.get()?)
880
.ok_or(Error::GetPort(self.port_id.get()?))?,
881
self.event_loop.clone(),
882
self.interrupter.clone(),
883
self.slot_id,
884
device_context_index,
885
Arc::downgrade(self),
886
Some(i as u16),
887
)
888
.map_err(Error::CreateTransferController)?;
889
trc.set_dequeue_pointer(stream_context.get_tr_dequeue_pointer().get_gpa());
890
trc.set_consumer_cycle_state(stream_context.get_dequeue_cycle_state());
891
trcs.push(trc);
892
}
893
Ok(TransferRingControllers::Stream(trcs))
894
}
895
896
fn add_one_endpoint(self: &Arc<Self>, device_context_index: u8) -> Result<()> {
897
xhci_trace!(
898
"adding one endpoint, device context index {}",
899
device_context_index
900
);
901
let mut device_context = self.get_device_context()?;
902
let transfer_ring_index = (device_context_index - 1) as usize;
903
let endpoint_context = &mut device_context.endpoint_context[transfer_ring_index];
904
let max_pstreams = endpoint_context.get_max_primary_streams();
905
let tr_dequeue_pointer = endpoint_context.get_tr_dequeue_pointer().get_gpa();
906
let endpoint_context_addr = self
907
.get_device_context_addr()?
908
.unchecked_add(size_of::<SlotContext>() as u64)
909
.unchecked_add(size_of::<EndpointContext>() as u64 * transfer_ring_index as u64);
910
let trcs = if max_pstreams > 0 {
911
if !valid_max_pstreams(max_pstreams) {
912
return Err(Error::BadEndpointContext(endpoint_context_addr));
913
}
914
let endpoint_type = endpoint_context.get_endpoint_type();
915
if endpoint_type != 2 && endpoint_type != 6 {
916
// Stream is only supported on a bulk endpoint
917
return Err(Error::BadEndpointId(transfer_ring_index as u8));
918
}
919
if endpoint_context.get_linear_stream_array() != 1 {
920
// We only support Linear Stream Context Array for now
921
return Err(Error::BadEndpointContext(endpoint_context_addr));
922
}
923
924
let trcs =
925
self.create_stream_trcs(tr_dequeue_pointer, max_pstreams, device_context_index)?;
926
927
if let Some(port) = self.hub.get_port(self.port_id.get()?) {
928
if let Some(backend_device) = port.backend_device().as_mut() {
929
let mut endpoint_address = device_context_index / 2;
930
if device_context_index % 2 == 1 {
931
endpoint_address |= 1u8 << 7;
932
}
933
let streams = 1 << (max_pstreams + 1);
934
// Subtracting 1 is to ignore Stream ID 0
935
backend_device
936
.lock()
937
.alloc_streams(endpoint_address, streams - 1)
938
.map_err(Error::AllocStreams)?;
939
}
940
}
941
trcs
942
} else {
943
let trc = TransferRingController::new(
944
self.mem.clone(),
945
self.hub
946
.get_port(self.port_id.get()?)
947
.ok_or(Error::GetPort(self.port_id.get()?))?,
948
self.event_loop.clone(),
949
self.interrupter.clone(),
950
self.slot_id,
951
device_context_index,
952
Arc::downgrade(self),
953
None,
954
)
955
.map_err(Error::CreateTransferController)?;
956
trc.set_dequeue_pointer(tr_dequeue_pointer);
957
trc.set_consumer_cycle_state(endpoint_context.get_dequeue_cycle_state());
958
TransferRingControllers::Endpoint(trc)
959
};
960
self.set_trcs(transfer_ring_index, Some(trcs));
961
endpoint_context.set_endpoint_state(EndpointState::Running);
962
self.set_device_context(device_context)
963
}
964
965
fn drop_one_endpoint(self: &Arc<Self>, device_context_index: u8) -> Result<()> {
966
let endpoint_index = (device_context_index - 1) as usize;
967
let mut device_context = self.get_device_context()?;
968
let endpoint_context = &mut device_context.endpoint_context[endpoint_index];
969
if endpoint_context.get_max_primary_streams() > 0 {
970
if let Some(port) = self.hub.get_port(self.port_id.get()?) {
971
if let Some(backend_device) = port.backend_device().as_mut() {
972
let mut endpoint_address = device_context_index / 2;
973
if device_context_index % 2 == 1 {
974
endpoint_address |= 1u8 << 7;
975
}
976
backend_device
977
.lock()
978
.free_streams(endpoint_address)
979
.map_err(Error::FreeStreams)?;
980
}
981
}
982
}
983
self.set_trcs(endpoint_index, None);
984
endpoint_context.set_endpoint_state(EndpointState::Disabled);
985
self.set_device_context(device_context)
986
}
987
988
fn get_device_context(&self) -> Result<DeviceContext> {
989
let ctx = self
990
.mem
991
.read_obj_from_addr(self.get_device_context_addr()?)
992
.map_err(Error::ReadGuestMemory)?;
993
Ok(ctx)
994
}
995
996
fn set_device_context(&self, device_context: DeviceContext) -> Result<()> {
997
self.mem
998
.write_obj_at_addr(device_context, self.get_device_context_addr()?)
999
.map_err(Error::WriteGuestMemory)
1000
}
1001
1002
fn copy_context(
1003
&self,
1004
input_context_ptr: GuestAddress,
1005
device_context_index: u8,
1006
) -> Result<()> {
1007
// Note that it could be slot context or device context. They have the same size. Won't
1008
// make a difference here.
1009
let ctx: EndpointContext = self
1010
.mem
1011
.read_obj_from_addr(
1012
input_context_ptr
1013
.checked_add(
1014
(device_context_index as u64 + 1) * DEVICE_CONTEXT_ENTRY_SIZE as u64,
1015
)
1016
.ok_or(Error::BadInputContextAddr(input_context_ptr))?,
1017
)
1018
.map_err(Error::ReadGuestMemory)?;
1019
xhci_trace!("copy_context {:?}", ctx);
1020
let device_context_ptr = self.get_device_context_addr()?;
1021
self.mem
1022
.write_obj_at_addr(
1023
ctx,
1024
device_context_ptr
1025
.checked_add(device_context_index as u64 * DEVICE_CONTEXT_ENTRY_SIZE as u64)
1026
.ok_or(Error::BadDeviceContextAddr(device_context_ptr))?,
1027
)
1028
.map_err(Error::WriteGuestMemory)
1029
}
1030
1031
fn get_device_context_addr(&self) -> Result<GuestAddress> {
1032
let addr: u64 = self
1033
.mem
1034
.read_obj_from_addr(GuestAddress(
1035
self.dcbaap.get_value() + size_of::<u64>() as u64 * self.slot_id as u64,
1036
))
1037
.map_err(Error::ReadGuestMemory)?;
1038
Ok(GuestAddress(addr))
1039
}
1040
1041
fn set_state(&self, state: DeviceSlotState) -> Result<()> {
1042
let mut ctx = self.get_device_context()?;
1043
ctx.slot_context.set_slot_state(state);
1044
self.set_device_context(ctx)
1045
}
1046
1047
pub fn halt_endpoint(&self, endpoint_id: u8) -> Result<()> {
1048
if !valid_endpoint_id(endpoint_id) {
1049
return Err(Error::BadEndpointId(endpoint_id));
1050
}
1051
let index = endpoint_id - 1;
1052
let mut device_context = self.get_device_context()?;
1053
let endpoint_context = &mut device_context.endpoint_context[index as usize];
1054
match self.get_trcs(index as usize) {
1055
Some(trcs) => match trcs {
1056
TransferRingControllers::Endpoint(trc) => {
1057
endpoint_context
1058
.set_tr_dequeue_pointer(DequeuePtr::new(trc.get_dequeue_pointer()));
1059
endpoint_context.set_dequeue_cycle_state(trc.get_consumer_cycle_state());
1060
}
1061
TransferRingControllers::Stream(trcs) => {
1062
let stream_context_array_addr =
1063
endpoint_context.get_tr_dequeue_pointer().get_gpa();
1064
let mut stream_context_array: StreamContextArray = self
1065
.mem
1066
.read_obj_from_addr(stream_context_array_addr)
1067
.map_err(Error::ReadGuestMemory)?;
1068
for (i, trc) in trcs.iter().enumerate() {
1069
stream_context_array.stream_contexts[i + 1]
1070
.set_tr_dequeue_pointer(DequeuePtr::new(trc.get_dequeue_pointer()));
1071
stream_context_array.stream_contexts[i + 1]
1072
.set_dequeue_cycle_state(trc.get_consumer_cycle_state());
1073
}
1074
self.mem
1075
.write_obj_at_addr(stream_context_array, stream_context_array_addr)
1076
.map_err(Error::WriteGuestMemory)?;
1077
}
1078
},
1079
None => {
1080
error!("trc for endpoint {} not found", endpoint_id);
1081
return Err(Error::BadEndpointId(endpoint_id));
1082
}
1083
}
1084
endpoint_context.set_endpoint_state(EndpointState::Halted);
1085
self.set_device_context(device_context)?;
1086
Ok(())
1087
}
1088
}
1089
1090
#[cfg(test)]
1091
mod tests {
1092
use std::thread;
1093
1094
use base::Event;
1095
1096
use super::*;
1097
use crate::usb::xhci::xhci_controller::XhciFailHandle;
1098
use crate::usb::xhci::XhciRegs;
1099
1100
struct TestDeviceSlots {
1101
pub device_slots: DeviceSlots,
1102
event_loop: Arc<EventLoop>,
1103
join_handle: Option<thread::JoinHandle<()>>,
1104
}
1105
1106
impl TestDeviceSlots {
1107
fn cleanup(&mut self) {
1108
if let Some(join_handle) = self.join_handle.take() {
1109
self.event_loop.stop();
1110
join_handle.join().unwrap();
1111
}
1112
}
1113
}
1114
1115
fn setup_test_device_slots() -> TestDeviceSlots {
1116
let test_reg32 = register!(
1117
name: "test",
1118
ty: u32,
1119
offset: 0x0,
1120
reset_value: 0,
1121
guest_writeable_mask: 0x0,
1122
guest_write_1_to_clear_mask: 0,
1123
);
1124
let test_reg64 = register!(
1125
name: "test",
1126
ty: u64,
1127
offset: 0x0,
1128
reset_value: 0,
1129
guest_writeable_mask: 0x0,
1130
guest_write_1_to_clear_mask: 0,
1131
);
1132
let xhci_regs = XhciRegs {
1133
usbcmd: test_reg32.clone(),
1134
usbsts: test_reg32.clone(),
1135
dnctrl: test_reg32.clone(),
1136
crcr: test_reg64.clone(),
1137
dcbaap: test_reg64.clone(),
1138
config: test_reg64.clone(),
1139
portsc: vec![test_reg32.clone(); 16],
1140
doorbells: Vec::new(),
1141
iman: test_reg32.clone(),
1142
imod: test_reg32.clone(),
1143
erstsz: test_reg32.clone(),
1144
erstba: test_reg64.clone(),
1145
erdp: test_reg64.clone(),
1146
};
1147
let fail_handle: Arc<dyn FailHandle> = Arc::new(XhciFailHandle::new(&xhci_regs));
1148
let mem = GuestMemory::new(&[]).unwrap();
1149
let event = Event::new().unwrap();
1150
let interrupter = Arc::new(Mutex::new(Interrupter::new(mem.clone(), event, &xhci_regs)));
1151
let hub = Arc::new(UsbHub::new(&xhci_regs, interrupter.clone()));
1152
let (event_loop, join_handle) =
1153
EventLoop::start("test".to_string(), Some(fail_handle.clone())).unwrap();
1154
let event_loop = Arc::new(event_loop);
1155
1156
let device_slots = DeviceSlots::new(
1157
fail_handle.clone(),
1158
test_reg64.clone(),
1159
hub,
1160
interrupter,
1161
event_loop.clone(),
1162
mem,
1163
);
1164
TestDeviceSlots {
1165
device_slots,
1166
event_loop,
1167
join_handle: Some(join_handle),
1168
}
1169
}
1170
1171
#[test]
1172
fn valid_slot() {
1173
let mut test_device_slots = setup_test_device_slots();
1174
for i in 1..=MAX_SLOTS {
1175
let slot = test_device_slots.device_slots.slot(i);
1176
assert!(slot.is_some());
1177
}
1178
1179
test_device_slots.cleanup();
1180
}
1181
1182
#[test]
1183
fn invalid_slot() {
1184
let mut test_device_slots = setup_test_device_slots();
1185
let slot = test_device_slots.device_slots.slot(0);
1186
assert!(slot.is_none());
1187
let slot = test_device_slots.device_slots.slot(MAX_SLOTS + 1);
1188
assert!(slot.is_none());
1189
1190
test_device_slots.cleanup();
1191
}
1192
1193
#[test]
1194
fn slot_is_disabled_first() {
1195
let mut test_device_slots = setup_test_device_slots();
1196
for i in 1..=MAX_SLOTS {
1197
let _ = test_device_slots
1198
.device_slots
1199
.disable_slot(i, move |completion_code| {
1200
assert_eq!(completion_code, TrbCompletionCode::SlotNotEnabledError);
1201
Ok(())
1202
});
1203
}
1204
1205
test_device_slots.cleanup();
1206
}
1207
1208
#[test]
1209
fn slot_enable_disable_enable() {
1210
let mut test_device_slots = setup_test_device_slots();
1211
for i in 1..=MAX_SLOTS {
1212
assert!(test_device_slots.device_slots.slot(i).unwrap().enable());
1213
let _ = test_device_slots
1214
.device_slots
1215
.disable_slot(i, move |completion_code| {
1216
assert_eq!(completion_code, TrbCompletionCode::Success);
1217
Ok(())
1218
});
1219
assert!(test_device_slots.device_slots.slot(i).unwrap().enable());
1220
}
1221
1222
test_device_slots.cleanup();
1223
}
1224
1225
#[test]
1226
fn slot_enable_disable_disable() {
1227
let mut test_device_slots = setup_test_device_slots();
1228
for i in 1..=MAX_SLOTS {
1229
assert!(test_device_slots.device_slots.slot(i).unwrap().enable());
1230
let _ = test_device_slots
1231
.device_slots
1232
.disable_slot(i, move |completion_code| {
1233
assert_eq!(completion_code, TrbCompletionCode::Success);
1234
Ok(())
1235
});
1236
let _ = test_device_slots
1237
.device_slots
1238
.disable_slot(i, move |completion_code| {
1239
assert_eq!(completion_code, TrbCompletionCode::SlotNotEnabledError);
1240
Ok(())
1241
});
1242
}
1243
1244
test_device_slots.cleanup();
1245
}
1246
1247
#[test]
1248
fn slot_find_disabled() {
1249
let mut test_device_slots = setup_test_device_slots();
1250
for i in 1..=MAX_SLOTS {
1251
assert!(test_device_slots.device_slots.slot(i).unwrap().enable());
1252
}
1253
let free_slot = 5;
1254
let _ = test_device_slots
1255
.device_slots
1256
.disable_slot(free_slot, move |completion_code| {
1257
assert_eq!(completion_code, TrbCompletionCode::Success);
1258
Ok(())
1259
});
1260
let mut found = false;
1261
for i in 1..=MAX_SLOTS {
1262
if test_device_slots.device_slots.slot(i).unwrap().enable() {
1263
assert_eq!(free_slot, i);
1264
found = true;
1265
break;
1266
}
1267
}
1268
assert!(found);
1269
1270
test_device_slots.cleanup();
1271
}
1272
}
1273
1274