devices/usb/xhci/
transfer_ring_controller.rs

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
5use std::sync::Arc;
6use std::sync::Weak;
7
8use anyhow::Context;
9use base::Event;
10use sync::Mutex;
11use vm_memory::GuestMemory;
12
13use super::device_slot::DeviceSlot;
14use super::interrupter::Interrupter;
15use super::usb_hub::UsbPort;
16use super::xhci_abi::TransferDescriptor;
17use super::xhci_transfer::XhciTransferManager;
18use crate::usb::xhci::ring_buffer_controller::Error as RingBufferControllerError;
19use crate::usb::xhci::ring_buffer_controller::RingBufferController;
20use crate::usb::xhci::ring_buffer_controller::TransferDescriptorHandler;
21use crate::utils::EventLoop;
22
23/// Transfer ring controller manages transfer ring.
24pub type TransferRingController = RingBufferController<TransferRingTrbHandler>;
25
26#[derive(Clone)]
27pub enum TransferRingControllers {
28    Endpoint(Arc<TransferRingController>),
29    Stream(Vec<Arc<TransferRingController>>),
30}
31
32pub type TransferRingControllerError = RingBufferControllerError;
33
34/// TransferRingTrbHandler handles trbs on transfer ring.
35pub struct TransferRingTrbHandler {
36    mem: GuestMemory,
37    port: Arc<UsbPort>,
38    interrupter: Arc<Mutex<Interrupter>>,
39    slot_id: u8,
40    endpoint_id: u8,
41    transfer_manager: XhciTransferManager,
42    stream_id: Option<u16>,
43}
44
45impl TransferDescriptorHandler for TransferRingTrbHandler {
46    fn handle_transfer_descriptor(
47        &self,
48        descriptor: TransferDescriptor,
49        completion_event: Event,
50    ) -> anyhow::Result<()> {
51        let xhci_transfer = self.transfer_manager.create_transfer(
52            self.mem.clone(),
53            self.port.clone(),
54            self.interrupter.clone(),
55            self.slot_id,
56            self.endpoint_id,
57            descriptor,
58            completion_event,
59            self.stream_id,
60        );
61        xhci_transfer
62            .send_to_backend_if_valid()
63            .context("failed to send transfer to backend")
64    }
65
66    fn stop(&self) -> bool {
67        let backend = self.port.backend_device();
68        if backend.is_some() {
69            self.transfer_manager.cancel_all();
70            true
71        } else {
72            false
73        }
74    }
75}
76
77impl TransferRingController {
78    pub fn new(
79        mem: GuestMemory,
80        port: Arc<UsbPort>,
81        event_loop: Arc<EventLoop>,
82        interrupter: Arc<Mutex<Interrupter>>,
83        slot_id: u8,
84        endpoint_id: u8,
85        device_slot: Weak<DeviceSlot>,
86        stream_id: Option<u16>,
87    ) -> Result<Arc<TransferRingController>, TransferRingControllerError> {
88        RingBufferController::new_with_handler(
89            format!("transfer ring slot_{slot_id} ep_{endpoint_id}"),
90            mem.clone(),
91            event_loop,
92            TransferRingTrbHandler {
93                mem,
94                port,
95                interrupter,
96                slot_id,
97                endpoint_id,
98                transfer_manager: XhciTransferManager::new(device_slot),
99                stream_id,
100            },
101        )
102    }
103}