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