summary refs log blame commit diff
path: root/devices/src/proxy.rs
blob: cc315505e4c93d5c31ab6e57cec9516570a438a3 (plain) (tree)
1
2
3
4
5
6
7
8
9





                                                                         
                                                                 
                    
 
                     
 
                             
                  



















                      
                        


                          

 
                        
                                            
                        


                  

                                                                                      

     
                                                                                     

                                             
                             
                   

                                                              
              



                                                                           
                                                                 
                                 

                                
                       

                                                                                     
                  



                             
     
 
 
                                



                                     
                                                                                   




                                                     
                                                   




                         

     
                                                           
                                                                       



                                                                 
         
     
 
                                                      

                                                        
                                                          


                                                   



                                                   


                                                     
                                             



                         




                           
                                           

     
// 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);
    }
}