// 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(Debug, MsgOnSocket)] pub enum CommandResult { Ok, ReadResult([u8; 8]), ReadConfigResult(u32), } pub struct ProxyDevice { sock: MsgSocket, debug_label: String, } impl ProxyDevice { pub fn new(sock: MsgSocket, 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 { 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); } }