xref: /aosp_15_r20/external/crosvm/devices/src/virtio/video/response.rs (revision bb4ee6a4ae7042d18b07a98463b9c8b875e44b39)
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 
7 use std::io;
8 
9 use data_model::Le32;
10 use data_model::Le64;
11 
12 use crate::virtio::video::command::QueueType;
13 use crate::virtio::video::control::*;
14 use crate::virtio::video::error::VideoError;
15 use crate::virtio::video::format::*;
16 use crate::virtio::video::params::Params;
17 use crate::virtio::video::protocol::*;
18 use crate::virtio::Writer;
19 
20 pub trait Response {
21     /// Writes an object to virtqueue.
write(&self, w: &mut Writer) -> Result<(), io::Error>22     fn write(&self, w: &mut Writer) -> Result<(), io::Error>;
23 }
24 
25 #[derive(Debug, Clone)]
26 pub 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)]
36 pub 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 
57 impl From<VideoError> for CmdResponse {
from(error: VideoError) -> Self58     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 
70 impl Response for CmdResponse {
71     /// Writes a response to virtqueue.
write(&self, w: &mut Writer) -> Result<(), io::Error>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 }
146