libmctp: Initial commit
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
diff --git a/Cargo.toml b/Cargo.toml
index caeae02..99543d9 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -29,6 +29,7 @@
p256 = { version = "0.5.0" , default-features = false, features = ["arithmetic", "ecdsa", "ecdsa-core"] }
subtle = { version = "2.3.0", default-features = false, features = ["i128"] }
generic-array = { version = "0.14.3" }
+libmctp = { version = "0.1.0" }
# We need to override this to allow builds for targets that don't support atomics.
# Once a version newer then 0.4.11 is released we can update to use that.
diff --git a/examples/libmctp.rs b/examples/libmctp.rs
new file mode 100644
index 0000000..8623665
--- /dev/null
+++ b/examples/libmctp.rs
@@ -0,0 +1,105 @@
+#![no_std]
+/// This is a example of a MCTP master device
+use libmctp::smbus::{MCTPSMBusContext, VendorIDFormat};
+use libtock::i2c_master::I2cBuffer;
+use libtock::println;
+use libtock::result::TockResult;
+use libtock::syscalls;
+
+libtock_core::stack_size! {0x800}
+
+// The address of this device
+const MY_ID: u8 = 0x23;
+const DEST_ID: u8 = 0x10;
+// Support vendor defined protocol 0x7E
+const MSG_TYPES: [u8; 1] = [0x7E];
+// Specify a PCI vendor ID that we support
+const VENDOR_IDS: [libmctp::smbus::VendorIDFormat; 1] = [VendorIDFormat {
+ // PCI Vendor ID
+ format: 0x00,
+ // PCI VID
+ data: 0x1414,
+ // Extra data
+ numeric_value: 4,
+}];
+
+#[libtock::main]
+async fn main() -> TockResult<()> {
+ let mut drivers = libtock::retrieve_drivers()?;
+ drivers.console.create_console();
+ println!("Starting libmctp example");
+ let i2c_driver = drivers.i2c.init_driver()?;
+
+ // Check that I2C exists
+ if i2c_driver.check_present().is_err() {
+ println!("No I2C device, yielding");
+ loop {
+ unsafe { syscalls::raw::yieldk() };
+ }
+ }
+ println!("Found the I2C device");
+
+ println!("Setting callback");
+ let mut callback = |_, _| {
+ println!("I2C Callback");
+ };
+
+ let _subscription = i2c_driver.subscribe(&mut callback)?;
+ println!("Creating MCTP SMBus Context");
+ let ctx = MCTPSMBusContext::new(MY_ID, &MSG_TYPES, &VENDOR_IDS);
+
+ let mut buf: [u8; 32] = [0; 32];
+
+ println!("Creating the request");
+ let len = ctx
+ .get_request()
+ .get_vendor_defined_message_support(0xB, 0, &mut buf);
+
+ println!("Creating master write buffer");
+ let mut master_write_buffer = I2cBuffer::default();
+ // Skip the first byte, as that is the destination address
+ for (i, d) in buf[1..].iter().enumerate() {
+ master_write_buffer[i] = *d;
+ }
+ let dest_buffer = i2c_driver.init_buffer(&mut master_write_buffer)?;
+ println!(" done");
+
+ let _ = i2c_driver.write(DEST_ID as usize, len.unwrap());
+
+ unsafe { syscalls::raw::yieldk() };
+
+ // Read 4 bytes for the SMBus header
+ let _ = i2c_driver.read(DEST_ID as usize, 4);
+
+ unsafe { syscalls::raw::yieldk() };
+
+ // Copy into a temp buffer
+ let mut temp_buffer = [0; libtock::hmac::DEST_BUFFER_SIZE];
+ dest_buffer.read_bytes(&mut temp_buffer[1..4]);
+
+ // Determine the full length
+ let bytes = ctx.get_length(&temp_buffer).unwrap();
+
+ // Read the full packet. The slave will re-send the data, so do
+ // a full read
+ let _ = i2c_driver.read(DEST_ID as usize, bytes - 1);
+
+ unsafe { syscalls::raw::yieldk() };
+
+ // Copy in the full packet, with space for the destination address
+ dest_buffer.read_bytes(&mut temp_buffer[1..bytes - 1]);
+
+ // Set the destination address as this isn't filled in the buffer from
+ // the kernel
+ temp_buffer[0] = DEST_ID << 1;
+
+ // Decode the response
+ let ret = ctx.decode_packet(&temp_buffer[0..bytes]);
+
+ // Print the outcome of the decode
+ println!("ret: {:?}", ret);
+
+ loop {
+ unsafe { syscalls::raw::yieldk() };
+ }
+}