1 // Copyright 2020 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 5 use std::collections::BTreeMap; 6 7 use crate::virtio::queue::DescriptorChain; 8 use crate::virtio::video::command::QueueType; 9 use crate::virtio::video::device::AsyncCmdResponse; 10 use crate::virtio::video::device::AsyncCmdTag; 11 use crate::virtio::video::error::VideoError; 12 use crate::virtio::video::protocol; 13 use crate::virtio::video::response::CmdResponse; 14 15 /// AsyncCmdDescMap is a BTreeMap which stores descriptor chains in which asynchronous 16 /// responses will be written. 17 #[derive(Default)] 18 pub struct AsyncCmdDescMap(BTreeMap<AsyncCmdTag, DescriptorChain>); 19 20 impl AsyncCmdDescMap { insert(&mut self, tag: AsyncCmdTag, descriptor_chain: DescriptorChain)21 pub fn insert(&mut self, tag: AsyncCmdTag, descriptor_chain: DescriptorChain) { 22 self.0.insert(tag, descriptor_chain); 23 } 24 remove(&mut self, tag: &AsyncCmdTag) -> Option<DescriptorChain>25 pub fn remove(&mut self, tag: &AsyncCmdTag) -> Option<DescriptorChain> { 26 self.0.remove(tag) 27 } 28 29 /// Returns a list of `AsyncCmdResponse`s to cancel pending commands that target 30 /// stream `target_stream_id`. 31 /// If `target_queue_type` is specified, then only create the requests for the specified queue. 32 /// Otherwise, create the requests for both input and output queue. 33 /// If `processing_tag` is specified, a cancellation request for that tag will 34 /// not be created. create_cancellation_responses( &self, target_stream_id: &u32, target_queue_type: Option<QueueType>, processing_tag: Option<AsyncCmdTag>, ) -> Vec<AsyncCmdResponse>35 pub fn create_cancellation_responses( 36 &self, 37 target_stream_id: &u32, 38 target_queue_type: Option<QueueType>, 39 processing_tag: Option<AsyncCmdTag>, 40 ) -> Vec<AsyncCmdResponse> { 41 let mut responses = vec![]; 42 for tag in self.0.keys().filter(|&&k| Some(k) != processing_tag) { 43 match tag { 44 AsyncCmdTag::Queue { 45 stream_id, 46 queue_type, 47 .. 48 } if stream_id == target_stream_id 49 && target_queue_type.as_ref().unwrap_or(queue_type) == queue_type => 50 { 51 responses.push(AsyncCmdResponse::from_response( 52 *tag, 53 CmdResponse::ResourceQueue { 54 timestamp: 0, 55 flags: protocol::VIRTIO_VIDEO_BUFFER_FLAG_ERR, 56 size: 0, 57 }, 58 )); 59 } 60 AsyncCmdTag::Drain { stream_id } if stream_id == target_stream_id => { 61 // TODO(b/1518105): Use more appropriate error code if a new protocol supports 62 // one. 63 responses.push(AsyncCmdResponse::from_error( 64 *tag, 65 VideoError::InvalidOperation, 66 )); 67 } 68 AsyncCmdTag::Clear { 69 stream_id, 70 queue_type, 71 } if stream_id == target_stream_id 72 && target_queue_type.as_ref().unwrap_or(queue_type) == queue_type => 73 { 74 // TODO(b/1518105): Use more appropriate error code if a new protocol supports 75 // one. 76 responses.push(AsyncCmdResponse::from_error( 77 *tag, 78 VideoError::InvalidOperation, 79 )); 80 } 81 _ => { 82 // Keep commands for other streams. 83 } 84 } 85 } 86 responses 87 } 88 } 89