// Copyright 2019 The Chromium OS Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. use crate::usb::xhci::ring_buffer_controller::{ Error as RingBufferControllerError, RingBufferController, TransferDescriptorHandler, }; use crate::utils::EventLoop; use std::sync::Arc; use sync::Mutex; use sys_util::{error, EventFd, GuestMemory}; use super::interrupter::Interrupter; use super::usb_hub::UsbPort; use super::xhci_abi::TransferDescriptor; use super::xhci_transfer::XhciTransferManager; /// Transfer ring controller manages transfer ring. pub type TransferRingController = RingBufferController; pub type TransferRingControllerError = RingBufferControllerError; /// TransferRingTrbHandler handles trbs on transfer ring. pub struct TransferRingTrbHandler { mem: GuestMemory, port: Arc, interrupter: Arc>, slot_id: u8, endpoint_id: u8, transfer_manager: XhciTransferManager, } impl TransferDescriptorHandler for TransferRingTrbHandler { fn handle_transfer_descriptor( &self, descriptor: TransferDescriptor, completion_event: EventFd, ) -> Result<(), ()> { let xhci_transfer = self.transfer_manager.create_transfer( self.mem.clone(), self.port.clone(), self.interrupter.clone(), self.slot_id, self.endpoint_id, descriptor, completion_event, ); xhci_transfer.send_to_backend_if_valid().map_err(|e| { error!("failed to send transfer to backend: {}", e); }) } fn stop(&self) -> bool { let backend = self.port.get_backend_device(); if backend.is_some() { self.transfer_manager.cancel_all(); true } else { false } } } impl TransferRingController { pub fn new( mem: GuestMemory, port: Arc, event_loop: Arc, interrupter: Arc>, slot_id: u8, endpoint_id: u8, ) -> Result, TransferRingControllerError> { RingBufferController::new_with_handler( format!("transfer ring slot_{} ep_{}", slot_id, endpoint_id), mem.clone(), event_loop, TransferRingTrbHandler { mem, port, interrupter, slot_id, endpoint_id, transfer_manager: XhciTransferManager::new(), }, ) } }