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