devices/virtio/video/
response.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
5//! Data structures for commands of virtio video devices.
6
7use std::io;
8
9use data_model::Le32;
10use data_model::Le64;
11
12use crate::virtio::video::command::QueueType;
13use crate::virtio::video::control::*;
14use crate::virtio::video::error::VideoError;
15use crate::virtio::video::format::*;
16use crate::virtio::video::params::Params;
17use crate::virtio::video::protocol::*;
18use crate::virtio::Writer;
19
20pub trait Response {
21    /// Writes an object to virtqueue.
22    fn write(&self, w: &mut Writer) -> Result<(), io::Error>;
23}
24
25#[derive(Debug, Clone)]
26pub enum CmdError {
27    InvalidResourceId,
28    InvalidStreamId,
29    InvalidParameter,
30    InvalidOperation,
31    UnsupportedControl,
32}
33
34/// A response to a `VideoCmd`. These correspond to `VIRTIO_VIDEO_RESP_*`.
35#[derive(Debug, Clone)]
36pub enum CmdResponse {
37    NoData,
38    QueryCapability(Vec<FormatDesc>),
39    ResourceQueue {
40        timestamp: u64,
41        flags: u32,
42        size: u32,
43    },
44    GetParams {
45        queue_type: QueueType,
46        params: Params,
47        is_ext: bool,
48    },
49    QueryControl(QueryCtrlResponse),
50    GetControl(CtrlVal),
51    // TODO(alexlau): SetControl is unused, remove this after encoder CL lands.
52    #[allow(dead_code)]
53    SetControl,
54    Error(CmdError),
55}
56
57impl From<VideoError> for CmdResponse {
58    fn from(error: VideoError) -> Self {
59        let cmd_error = match error {
60            VideoError::InvalidResourceId { .. } => CmdError::InvalidResourceId,
61            VideoError::InvalidStreamId(_) => CmdError::InvalidStreamId,
62            VideoError::InvalidParameter => CmdError::InvalidParameter,
63            VideoError::UnsupportedControl(_) => CmdError::UnsupportedControl,
64            _ => CmdError::InvalidOperation,
65        };
66        CmdResponse::Error(cmd_error)
67    }
68}
69
70impl Response for CmdResponse {
71    /// Writes a response to virtqueue.
72    fn write(&self, w: &mut Writer) -> Result<(), io::Error> {
73        use CmdResponse::*;
74
75        let type_ = Le32::from(match self {
76            NoData => VIRTIO_VIDEO_RESP_OK_NODATA,
77            QueryCapability(_) => VIRTIO_VIDEO_RESP_OK_QUERY_CAPABILITY,
78            ResourceQueue { .. } => VIRTIO_VIDEO_RESP_OK_RESOURCE_QUEUE,
79            GetParams { .. } => VIRTIO_VIDEO_RESP_OK_GET_PARAMS,
80            QueryControl(_) => VIRTIO_VIDEO_RESP_OK_QUERY_CONTROL,
81            GetControl(_) => VIRTIO_VIDEO_RESP_OK_GET_CONTROL,
82            SetControl => VIRTIO_VIDEO_RESP_OK_NODATA,
83            Error(e) => {
84                match e {
85                    // TODO(b/1518105): Add more detailed error code when a new protocol supports
86                    // them.
87                    CmdError::InvalidResourceId => VIRTIO_VIDEO_RESP_ERR_INVALID_RESOURCE_ID,
88                    CmdError::InvalidStreamId => VIRTIO_VIDEO_RESP_ERR_INVALID_STREAM_ID,
89                    CmdError::InvalidParameter => VIRTIO_VIDEO_RESP_ERR_INVALID_PARAMETER,
90                    CmdError::InvalidOperation => VIRTIO_VIDEO_RESP_ERR_INVALID_OPERATION,
91                    CmdError::UnsupportedControl => VIRTIO_VIDEO_RESP_ERR_UNSUPPORTED_CONTROL,
92                }
93            }
94        });
95
96        let hdr = virtio_video_cmd_hdr {
97            type_,
98            ..Default::default()
99        };
100
101        match self {
102            NoData | Error(_) => w.write_obj(hdr),
103            QueryCapability(descs) => {
104                w.write_obj(virtio_video_query_capability_resp {
105                    hdr,
106                    num_descs: Le32::from(descs.len() as u32),
107                    ..Default::default()
108                })?;
109                descs.iter().try_for_each(|d| d.write(w))
110            }
111            ResourceQueue {
112                timestamp,
113                flags,
114                size,
115            } => w.write_obj(virtio_video_resource_queue_resp {
116                hdr,
117                timestamp: Le64::from(*timestamp),
118                flags: Le32::from(*flags),
119                size: Le32::from(*size),
120            }),
121            GetParams {
122                queue_type,
123                params,
124                is_ext,
125            } => {
126                if *is_ext {
127                    let params = params.to_virtio_video_params_ext(*queue_type);
128                    w.write_obj(virtio_video_get_params_ext_resp { hdr, params })
129                } else {
130                    let params = params.to_virtio_video_params(*queue_type);
131                    w.write_obj(virtio_video_get_params_resp { hdr, params })
132                }
133            }
134            QueryControl(r) => {
135                w.write_obj(virtio_video_query_control_resp { hdr })?;
136                r.write(w)
137            }
138            GetControl(val) => {
139                w.write_obj(virtio_video_get_control_resp { hdr })?;
140                val.write(w)
141            }
142            SetControl => w.write_obj(virtio_video_set_control_resp { hdr }),
143        }
144    }
145}