| // 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<TransferRingTrbHandler>; |
| |
| pub type TransferRingControllerError = RingBufferControllerError; |
| |
| /// TransferRingTrbHandler handles trbs on transfer ring. |
| pub struct TransferRingTrbHandler { |
| mem: GuestMemory, |
| port: Arc<UsbPort>, |
| interrupter: Arc<Mutex<Interrupter>>, |
| 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<UsbPort>, |
| event_loop: Arc<EventLoop>, |
| interrupter: Arc<Mutex<Interrupter>>, |
| slot_id: u8, |
| endpoint_id: u8, |
| ) -> Result<Arc<TransferRingController>, 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(), |
| }, |
| ) |
| } |
| } |