| // Copyright 2020 The Chromium OS Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| //! Data structures for commands of virtio video devices. |
| |
| use std::io; |
| |
| use data_model::{Le32, Le64}; |
| |
| use crate::virtio::video::command::QueueType; |
| use crate::virtio::video::control::*; |
| use crate::virtio::video::error::VideoError; |
| use crate::virtio::video::format::*; |
| use crate::virtio::video::params::Params; |
| use crate::virtio::video::protocol::*; |
| use crate::virtio::Writer; |
| |
| pub trait Response { |
| /// Writes an object to virtqueue. |
| fn write(&self, w: &mut Writer) -> Result<(), io::Error>; |
| } |
| |
| #[derive(Debug)] |
| pub enum CmdError { |
| InvalidResourceId, |
| InvalidStreamId, |
| InvalidParameter, |
| InvalidOperation, |
| } |
| |
| /// A response to a `VideoCmd`. These correspond to `VIRTIO_VIDEO_RESP_*`. |
| #[derive(Debug)] |
| pub enum CmdResponse { |
| NoData, |
| QueryCapability(Vec<FormatDesc>), |
| ResourceQueue { |
| timestamp: u64, |
| flags: u32, |
| size: u32, |
| }, |
| GetParams { |
| queue_type: QueueType, |
| params: Params, |
| }, |
| QueryControl(QueryCtrlResponse), |
| GetControl(CtrlVal), |
| // TODO(alexlau): SetControl is unused, remove this after encoder CL lands. |
| #[allow(dead_code)] |
| SetControl, |
| Error(CmdError), |
| } |
| |
| impl From<VideoError> for CmdResponse { |
| fn from(error: VideoError) -> Self { |
| let cmd_error = match error { |
| VideoError::InvalidResourceId { .. } => CmdError::InvalidResourceId, |
| VideoError::InvalidStreamId(_) => CmdError::InvalidStreamId, |
| VideoError::InvalidParameter => CmdError::InvalidParameter, |
| _ => CmdError::InvalidOperation, |
| }; |
| CmdResponse::Error(cmd_error) |
| } |
| } |
| |
| impl Response for CmdResponse { |
| /// Writes a response to virtqueue. |
| fn write(&self, w: &mut Writer) -> Result<(), io::Error> { |
| use CmdResponse::*; |
| |
| let type_ = Le32::from(match self { |
| NoData => VIRTIO_VIDEO_RESP_OK_NODATA, |
| QueryCapability(_) => VIRTIO_VIDEO_RESP_OK_QUERY_CAPABILITY, |
| ResourceQueue { .. } => VIRTIO_VIDEO_RESP_OK_RESOURCE_QUEUE, |
| GetParams { .. } => VIRTIO_VIDEO_RESP_OK_GET_PARAMS, |
| QueryControl(_) => VIRTIO_VIDEO_RESP_OK_QUERY_CONTROL, |
| GetControl(_) => VIRTIO_VIDEO_RESP_OK_GET_CONTROL, |
| SetControl => VIRTIO_VIDEO_RESP_OK_NODATA, |
| Error(e) => { |
| match e { |
| // TODO(b/1518105): Add more detailed error code when a new protocol supports |
| // them. |
| CmdError::InvalidResourceId => VIRTIO_VIDEO_RESP_ERR_INVALID_RESOURCE_ID, |
| CmdError::InvalidStreamId => VIRTIO_VIDEO_RESP_ERR_INVALID_STREAM_ID, |
| CmdError::InvalidParameter => VIRTIO_VIDEO_RESP_ERR_INVALID_PARAMETER, |
| CmdError::InvalidOperation => VIRTIO_VIDEO_RESP_ERR_INVALID_OPERATION, |
| } |
| } |
| }); |
| |
| let hdr = virtio_video_cmd_hdr { |
| type_, |
| ..Default::default() |
| }; |
| |
| match self { |
| NoData | Error(_) => w.write_obj(hdr), |
| QueryCapability(descs) => { |
| w.write_obj(virtio_video_query_capability_resp { |
| hdr, |
| num_descs: Le32::from(descs.len() as u32), |
| ..Default::default() |
| })?; |
| descs.iter().map(|d| d.write(w)).collect() |
| } |
| ResourceQueue { |
| timestamp, |
| flags, |
| size, |
| } => w.write_obj(virtio_video_resource_queue_resp { |
| hdr, |
| timestamp: Le64::from(*timestamp), |
| flags: Le32::from(*flags), |
| size: Le32::from(*size), |
| }), |
| GetParams { queue_type, params } => { |
| let params = params.to_virtio_video_params(*queue_type); |
| w.write_obj(virtio_video_get_params_resp { hdr, params }) |
| } |
| QueryControl(r) => { |
| w.write_obj(virtio_video_query_control_resp { hdr })?; |
| r.write(w) |
| } |
| GetControl(val) => { |
| w.write_obj(virtio_video_get_control_resp { hdr })?; |
| val.write(w) |
| } |
| SetControl => w.write_obj(virtio_video_set_control_resp { hdr }), |
| } |
| } |
| } |