blob: 0b5d3b64b24e68a070f29d764bda015c147acc3f [file] [log] [blame]
// 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(),
},
)
}
}