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::usb::xhci::RingBufferStopCallback;
22use crate::utils::EventLoop;
23
24/// Transfer ring controller manages transfer ring.
25pub type TransferRingController = RingBufferController<TransferRingTrbHandler>;
26
27#[derive(Clone)]
28pub enum TransferRingControllers {
29    Endpoint(Arc<TransferRingController>),
30    Stream(Vec<Arc<TransferRingController>>),
31}
32
33pub type TransferRingControllerError = RingBufferControllerError;
34
35/// TransferRingTrbHandler handles trbs on transfer ring.
36pub struct TransferRingTrbHandler {
37    mem: GuestMemory,
38    port: Arc<UsbPort>,
39    interrupter: Arc<Mutex<Interrupter>>,
40    slot_id: u8,
41    endpoint_id: u8,
42    transfer_manager: XhciTransferManager,
43    stream_id: Option<u16>,
44}
45
46impl TransferDescriptorHandler for TransferRingTrbHandler {
47    fn handle_transfer_descriptor(
48        &self,
49        descriptor: TransferDescriptor,
50        trigger_event: Event,
51    ) -> anyhow::Result<()> {
52        let xhci_transfer = self.transfer_manager.create_transfer(
53            self.mem.clone(),
54            self.port.clone(),
55            self.interrupter.clone(),
56            self.slot_id,
57            self.endpoint_id,
58            descriptor,
59            trigger_event,
60            self.stream_id,
61        );
62        xhci_transfer
63            .send_to_backend_if_valid()
64            .context("failed to send transfer to backend")
65    }
66
67    fn cancel_transfers(&self, callback: RingBufferStopCallback) {
68        self.transfer_manager.cancel_all(callback);
69    }
70}
71
72impl TransferRingController {
73    pub fn new(
74        mem: GuestMemory,
75        port: Arc<UsbPort>,
76        event_loop: Arc<EventLoop>,
77        interrupter: Arc<Mutex<Interrupter>>,
78        slot_id: u8,
79        endpoint_id: u8,
80        device_slot: Weak<DeviceSlot>,
81        stream_id: Option<u16>,
82    ) -> Result<Arc<TransferRingController>, TransferRingControllerError> {
83        RingBufferController::new_with_handler(
84            format!("transfer ring slot_{slot_id} ep_{endpoint_id}"),
85            mem.clone(),
86            event_loop,
87            TransferRingTrbHandler {
88                mem,
89                port,
90                interrupter,
91                slot_id,
92                endpoint_id,
93                transfer_manager: XhciTransferManager::new(device_slot),
94                stream_id,
95            },
96        )
97    }
98}