devices/virtio/video/
async_cmd_desc_map.rs

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
5use std::collections::BTreeMap;
6
7use crate::virtio::video::command::QueueType;
8use crate::virtio::video::device::AsyncCmdResponse;
9use crate::virtio::video::device::AsyncCmdTag;
10use crate::virtio::video::error::VideoError;
11use crate::virtio::video::protocol;
12use crate::virtio::video::response::CmdResponse;
13use crate::virtio::DescriptorChain;
14
15/// AsyncCmdDescMap is a BTreeMap which stores descriptor chains in which asynchronous
16/// responses will be written.
17#[derive(Default)]
18pub struct AsyncCmdDescMap(BTreeMap<AsyncCmdTag, DescriptorChain>);
19
20impl AsyncCmdDescMap {
21    pub fn insert(&mut self, tag: AsyncCmdTag, descriptor_chain: DescriptorChain) {
22        self.0.insert(tag, descriptor_chain);
23    }
24
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.
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}