// Copyright 2017 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.
//! Runs hardware devices in child processes.
use msg_socket::{MsgOnSocket, MsgReceiver, MsgSender, MsgSocket};
use sys_util::error;
use crate::BusDevice;
#[derive(Debug, MsgOnSocket)]
pub enum Command {
Read {
len: u32,
offset: u64,
},
Write {
len: u32,
offset: u64,
data: [u8; 8],
},
ReadConfig(u32),
WriteConfig {
reg_idx: u32,
offset: u32,
len: u32,
data: [u8; 4],
},
Shutdown,
}
#[derive(MsgOnSocket)]
pub enum CommandResult {
Ok,
ReadResult([u8; 8]),
ReadConfigResult(u32),
}
pub struct ProxyDevice {
sock: MsgSocket<Command, CommandResult>,
debug_label: String,
}
impl ProxyDevice {
pub fn new(sock: MsgSocket<Command, CommandResult>, debug_label: String) -> Self {
Self { sock, debug_label }
}
/// Send a command that does not expect a response from the child device process.
fn send_no_result(&self, cmd: &Command) {
let res = self.sock.send(cmd);
if let Err(e) = res {
error!(
"failed write to child device process {}: {}",
self.debug_label, e,
);
}
}
/// Send a command and read its response from the child device process.
fn sync_send(&self, cmd: &Command) -> Option<CommandResult> {
self.send_no_result(cmd);
match self.sock.recv() {
Err(e) => {
error!(
"failed to read result of {:?} from child device process {}: {}",
cmd, self.debug_label, e,
);
None
}
Ok(r) => Some(r),
}
}
}
impl BusDevice for ProxyDevice {
fn debug_label(&self) -> String {
self.debug_label.clone()
}
fn config_register_write(&mut self, reg_idx: usize, offset: u64, data: &[u8]) {
let len = data.len() as u32;
let mut buffer = [0u8; 4];
buffer[0..data.len()].clone_from_slice(data);
let reg_idx = reg_idx as u32;
let offset = offset as u32;
self.send_no_result(&Command::WriteConfig {
reg_idx,
offset,
len,
data: buffer,
});
}
fn config_register_read(&self, reg_idx: usize) -> u32 {
let res = self.sync_send(&Command::ReadConfig(reg_idx as u32));
if let Some(CommandResult::ReadConfigResult(val)) = res {
val
} else {
0
}
}
fn read(&mut self, offset: u64, data: &mut [u8]) {
let len = data.len() as u32;
if let Some(CommandResult::ReadResult(buffer)) =
self.sync_send(&Command::Read { len, offset })
{
let len = data.len();
data.clone_from_slice(&buffer[0..len]);
}
}
fn write(&mut self, offset: u64, data: &[u8]) {
let mut buffer = [0u8; 8];
let len = data.len() as u32;
buffer[0..data.len()].clone_from_slice(data);
self.send_no_result(&Command::Write {
len,
offset,
data: buffer,
});
}
}
impl Drop for ProxyDevice {
fn drop(&mut self) {
self.sync_send(&Command::Shutdown);
}
}