diff --git a/tool/Cargo.lock b/tool/Cargo.lock index 774aedb..eb21cca 100644 --- a/tool/Cargo.lock +++ b/tool/Cargo.lock @@ -1,32 +1,47 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. [[package]] -name = "lazy_static" -version = "1.4.0" +name = "cc" +version = "1.0.60" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "hidapi" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cc 1.0.60 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.78 (registry+https://github.com/rust-lang/crates.io-index)", + "pkg-config 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "libc" version = "0.2.78" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "pkg-config" +version = "0.3.18" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "redox_hwio" version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", -] [[package]] name = "system76_ectool" -version = "0.2.0" +version = "0.2.1" dependencies = [ + "hidapi 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.78 (registry+https://github.com/rust-lang/crates.io-index)", "redox_hwio 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [metadata] -"checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +"checksum cc 1.0.60 (registry+https://github.com/rust-lang/crates.io-index)" = "ef611cc68ff783f18535d77ddd080185275713d852c4f5cbb6122c462a7a825c" +"checksum hidapi 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "5c6ffb97f2ec5835ec73bcea5256fc2cd57a13c5958230778ef97f11900ba661" "checksum libc 0.2.78 (registry+https://github.com/rust-lang/crates.io-index)" = "aa7087f49d294270db4e1928fc110c976cd4b9e5a16348e0a1df09afa99e6c98" +"checksum pkg-config 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)" = "d36492546b6af1463394d46f0c834346f31548646f6ba10849802c9c9a27ac33" "checksum redox_hwio 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "41aa2c4c67329a04106644cad336238aa5adecfd73d06fb10339d472ce6d8070" diff --git a/tool/Cargo.toml b/tool/Cargo.toml index 8fffd1c..9b6cde8 100644 --- a/tool/Cargo.toml +++ b/tool/Cargo.toml @@ -1,11 +1,12 @@ [package] name = "system76_ectool" -version = "0.2.0" +version = "0.2.1" edition = "2018" description = "System76 EC tool" license = "MIT" authors = ["Jeremy Soller "] repository = "https://github.com/system76/ec" +documentation = "https://docs.rs/system76_ectool" [lib] name = "ectool" @@ -16,9 +17,12 @@ required-features = ["std"] [dependencies] libc = { version = "0.2", optional = true } -redox_hwio = "0.1.3" +hidapi = { version = "1.2", optional = true } +redox_hwio = { version = "0.1.3", optional = true } [features] default = ["std"] -stable = ["redox_hwio/stable"] std = ["libc"] + +[package.metadata.docs.rs] +all-features = true diff --git a/tool/src/access/hid.rs b/tool/src/access/hid.rs new file mode 100644 index 0000000..0455096 --- /dev/null +++ b/tool/src/access/hid.rs @@ -0,0 +1,76 @@ +use hidapi::HidDevice; + +use crate::{ + Access, + Error, +}; + +/// Use USB HID access, only for USB ECs +pub struct AccessHid { + device: HidDevice, + retries: u32, + timeout: i32, +} + +impl AccessHid { + /// Use hidapi device with specified retries and timeout for each try in milliseconds + pub fn new(device: HidDevice, retries: u32, timeout: i32) -> Result { + //TODO: probe? + Ok(Self { + device, + retries, + timeout, + }) + } + + unsafe fn command_try(&mut self, cmd: u8, data: &mut [u8]) -> Result, Error> { + const HID_CMD: usize = 1; + const HID_RES: usize = 2; + const HID_DATA: usize = 3; + + let mut hid_data = [0; 33]; + if data.len() + HID_DATA > hid_data.len() { + return Err(Error::DataLength(data.len())); + } + + hid_data[HID_CMD] = cmd; + for i in 0..data.len() { + hid_data[HID_DATA + i] = data[i]; + } + + let count = self.device.write(&hid_data).map_err(Error::Hid)?; + if count != hid_data.len() { + return Err(Error::Verify); + } + + let count = self.device.read_timeout(&mut hid_data[1..], self.timeout).map_err(Error::Hid)?; + if count == hid_data.len() - 1 { + for i in 0..data.len() { + data[i] = hid_data[HID_DATA + i]; + } + + Ok(Some(hid_data[HID_RES])) + } else if count == 0 { + Ok(None) + } else { + Err(Error::Verify) + } + } +} + +impl Access for AccessHid { + unsafe fn command(&mut self, cmd: u8, data: &mut [u8]) -> Result { + for _ in 0..self.retries { + match self.command_try(cmd, data)? { + Some(some) => return Ok(some), + None => continue, + } + } + + Err(Error::Timeout) + } + + fn data_size(&self) -> usize { + 32 - 2 + } +} diff --git a/tool/src/access/lpc/mod.rs b/tool/src/access/lpc/mod.rs index 3f94965..fbdc735 100644 --- a/tool/src/access/lpc/mod.rs +++ b/tool/src/access/lpc/mod.rs @@ -1,14 +1,16 @@ -pub(crate) const SMFI_CMD_BASE: u16 = 0xE00; -pub(crate) const SMFI_CMD_SIZE: usize = 0x100; +const SMFI_CMD_BASE: u16 = 0xE00; +const SMFI_CMD_SIZE: usize = 0x100; -pub(crate) const SMFI_DBG_BASE: u16 = 0xF00; -pub(crate) const SMFI_DBG_SIZE: usize = 0x100; +const SMFI_DBG_BASE: u16 = 0xF00; +const SMFI_DBG_SIZE: usize = 0x100; -pub(crate) const SMFI_CMD_CMD: u8 = 0x00; -pub(crate) const SMFI_CMD_RES: u8 = 0x01; -pub(crate) const SMFI_CMD_DATA: u8 = 0x02; +const SMFI_CMD_CMD: u8 = 0x00; +const SMFI_CMD_RES: u8 = 0x01; +const SMFI_CMD_DATA: u8 = 0x02; +#[cfg(feature = "redox_hwio")] pub use self::direct::AccessLpcDirect; +#[cfg(feature = "redox_hwio")] mod direct; #[cfg(all(feature = "std", target_os = "linux"))] diff --git a/tool/src/access/mod.rs b/tool/src/access/mod.rs index b57c4b3..8f75a74 100644 --- a/tool/src/access/mod.rs +++ b/tool/src/access/mod.rs @@ -1,6 +1,19 @@ use crate::Error; +#[cfg(feature = "hidapi")] +pub use self::hid::AccessHid; +#[cfg(feature = "hidapi")] +mod hid; + +#[cfg(any( + feature = "redox_hwio", + all(feature = "std", target_os = "linux") +))] pub use self::lpc::*; +#[cfg(any( + feature = "redox_hwio", + all(feature = "std", target_os = "linux") +))] mod lpc; /// Access method for running an EC command diff --git a/tool/src/error.rs b/tool/src/error.rs index bbcff47..cdfca47 100644 --- a/tool/src/error.rs +++ b/tool/src/error.rs @@ -21,5 +21,8 @@ pub enum Error { WouldBlock, /// Encountered a std::io::Error #[cfg(feature = "std")] - Io(std::io::Error) + Io(std::io::Error), + /// Encountered a hidapi::Error + #[cfg(feature = "hidapi")] + Hid(hidapi::HidError), } diff --git a/tool/src/lib.rs b/tool/src/lib.rs index ffc2fd4..1129f2d 100644 --- a/tool/src/lib.rs +++ b/tool/src/lib.rs @@ -1,5 +1,19 @@ #![cfg_attr(not(feature = "std"), no_std)] +//! Library for accessing System76 ECs +//! First, construct an access method, using an object implementing the `Access` trait. Next, an Ec +//! object can be contructed, which exposes the command interface. +//! +//! There are some differences between targets and features that are listed below: +//! - `AccessHid` requires the `hidapi` feature. Only functional on USB ECs. +//! - `AccessLpcDirect` requires the `redox_hwio` feature and a nightly compiler. This method is +//! only recommended for use in firmware with LPC ECs, as mutual exclusion is not guaranteed. +//! - `AccessLpcLinux` requires the `std` feature and `linux` target_os. Recommended for LPC ECs, +//! as this method can utilize mutual exclusion. +//! - `EcLegacy`, `Pmc`, and `SuperIo` all require the `redox_hwio` feature and a nightly +//! compiler. It is only recommended to use these in firmware, as mutual exclusion is not +//! guaranteed. + pub use self::access::*; mod access; @@ -12,16 +26,22 @@ mod error; pub use self::firmware::Firmware; mod firmware; +#[cfg(feature = "redox_hwio")] pub use self::legacy::EcLegacy; +#[cfg(feature = "redox_hwio")] mod legacy; +#[cfg(feature = "redox_hwio")] pub use self::pmc::Pmc; +#[cfg(feature = "redox_hwio")] mod pmc; pub use self::spi::{Spi, SpiRom, SpiTarget}; mod spi; +#[cfg(feature = "redox_hwio")] pub use self::super_io::SuperIo; +#[cfg(feature = "redox_hwio")] mod super_io; pub use self::timeout::Timeout;