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