#![allow(dead_code)]
#![allow(non_camel_case_types)]
use nix;
use std::mem;
use std::ptr;
use std::io::Cursor;
use std::os::unix::prelude::*;
use byteorder::{NativeEndian, ReadBytesExt, WriteBytesExt};
pub type I2CError = nix::Error;
bitflags! {
struct I2CMsgFlags: u16 {
const I2C_M_TEN = 0x0010;
const I2C_M_RD = 0x0001;
const I2C_M_STOP = 0x8000;
const I2C_M_NOSTART = 0x4000;
const I2C_M_REV_DIR_ADDR = 0x2000;
const I2C_M_IGNORE_NAK = 0x1000;
const I2C_M_NO_RD_ACK = 0x0800;
const I2C_M_RECV_LEN = 0x0400;
}
}
#[repr(C)]
struct i2c_msg {
addr: u16,
flags: u16,
len: u16,
buf: *mut u8,
}
bitflags! {
struct I2CFunctions: u32 {
const I2C_FUNC_I2C = 0x00000001;
const I2C_FUNC_10BIT_ADDR = 0x00000002;
const I2C_FUNC_PROTOCOL_MANGLING = 0x00000004;
const I2C_FUNC_SMBUS_PEC = 0x00000008;
const I2C_FUNC_NOSTART = 0x00000010;
const I2C_FUNC_SMBUS_BLOCK_PROC_CALL = 0x00008000;
const I2C_FUNC_SMBUS_QUICK = 0x00010000;
const I2C_FUNC_SMBUS_READ_BYTE = 0x00020000;
const I2C_FUNC_SMBUS_WRITE_BYTE = 0x00040000;
const I2C_FUNC_SMBUS_READ_BYTE_DATA = 0x00080000;
const I2C_FUNC_SMBUS_WRITE_BYTE_DATA = 0x00100000;
const I2C_FUNC_SMBUS_READ_WORD_DATA = 0x00200000;
const I2C_FUNC_SMBUS_WRITE_WORD_DATA = 0x00400000;
const I2C_FUNC_SMBUS_PROC_CALL = 0x00800000;
const I2C_FUNC_SMBUS_READ_BLOCK_DATA = 0x01000000;
const I2C_FUNC_SMBUS_WRITE_BLOCK_DATA = 0x02000000;
const I2C_FUNC_SMBUS_READ_I2C_BLOCK = 0x04000000;
const I2C_FUNC_SMBUS_WRITE_I2C_BLOCK = 0x08000000;
const I2C_FUNC_SMBUS_BYTE = (I2CFunctions::I2C_FUNC_SMBUS_READ_BYTE.bits |
I2CFunctions::I2C_FUNC_SMBUS_WRITE_BYTE.bits);
const I2C_FUNC_SMBUS_BYTE_DATA = (I2CFunctions::I2C_FUNC_SMBUS_READ_BYTE_DATA.bits |
I2CFunctions::I2C_FUNC_SMBUS_WRITE_BYTE_DATA.bits);
const I2C_FUNC_SMBUS_WORD_DATA = (I2CFunctions::I2C_FUNC_SMBUS_READ_WORD_DATA.bits |
I2CFunctions::I2C_FUNC_SMBUS_WRITE_WORD_DATA.bits);
const I2C_FUNC_SMBUS_BLOCK_DATA = (I2CFunctions::I2C_FUNC_SMBUS_READ_BLOCK_DATA.bits |
I2CFunctions::I2C_FUNC_SMBUS_WRITE_BLOCK_DATA.bits);
const I2C_FUNC_SMBUS_I2C_BLOCK = (I2CFunctions::I2C_FUNC_SMBUS_READ_I2C_BLOCK.bits |
I2CFunctions::I2C_FUNC_SMBUS_WRITE_I2C_BLOCK.bits);
const I2C_FUNC_SMBUS_EMUL = (I2CFunctions::I2C_FUNC_SMBUS_QUICK.bits |
I2CFunctions::I2C_FUNC_SMBUS_BYTE.bits |
I2CFunctions::I2C_FUNC_SMBUS_BYTE_DATA.bits |
I2CFunctions::I2C_FUNC_SMBUS_WORD_DATA.bits |
I2CFunctions::I2C_FUNC_SMBUS_PROC_CALL.bits |
I2CFunctions::I2C_FUNC_SMBUS_WRITE_BLOCK_DATA.bits |
I2CFunctions::I2C_FUNC_SMBUS_I2C_BLOCK.bits |
I2CFunctions::I2C_FUNC_SMBUS_PEC.bits);
}
}
const I2C_SMBUS_BLOCK_MAX: u8 = 32;
#[repr(C)]
struct i2c_smbus_data {
block: [u8; (I2C_SMBUS_BLOCK_MAX + 2) as usize],
}
impl i2c_smbus_data {
fn empty() -> i2c_smbus_data {
unsafe { mem::zeroed() }
}
}
#[repr(u8)]
enum I2CSMBusReadWrite {
I2C_SMBUS_READ = 1,
I2C_SMBUS_WRITE = 0,
}
#[repr(u32)]
enum I2CSMBusSize {
I2C_SMBUS_QUICK = 0,
I2C_SMBUS_BYTE = 1,
I2C_SMBUS_BYTE_DATA = 2,
I2C_SMBUS_WORD_DATA = 3,
I2C_SMBUS_PROC_CALL = 4,
I2C_SMBUS_BLOCK_DATA = 5,
I2C_SMBUS_I2C_BLOCK_BROKEN = 6,
I2C_SMBUS_BLOCK_PROC_CALL = 7, I2C_SMBUS_I2C_BLOCK_DATA = 8,
}
const I2C_RETRIES: u16 = 0x0701;
const I2C_TIMEOUT: u16 = 0x0702;
const I2C_SLAVE: u16 = 0x0703;
const I2C_SLAVE_FORCE: u16 = 0x0706;
const I2C_TENBIT: u16 = 0x0704;
const I2C_FUNCS: u16 = 0x0705;
const I2C_RDWR: u16 = 0x0707;
const I2C_PEC: u16 = 0x0708;
const I2C_SMBUS: u16 = 0x0720;
const I2C_RDRW_IOCTL_MAX_MSGS: u8 = 42;
#[repr(C)]
pub struct i2c_smbus_ioctl_data {
read_write: u8,
command: u8,
size: u32,
data: *mut i2c_smbus_data,
}
#[repr(C)]
struct i2c_rdwr_ioctl_data {
msgs: *mut i2c_msg,
nmsgs: u32,
}
mod ioctl {
use super::{I2C_SLAVE, I2C_SMBUS};
pub use super::i2c_smbus_ioctl_data;
ioctl_write_int_bad!(set_i2c_slave_address, I2C_SLAVE);
ioctl_write_ptr_bad!(i2c_smbus, I2C_SMBUS, i2c_smbus_ioctl_data);
}
pub fn i2c_set_slave_address(fd: RawFd, slave_address: u16) -> Result<(), nix::Error> {
unsafe {
ioctl::set_i2c_slave_address(fd, slave_address as i32)?;
}
Ok(())
}
unsafe fn i2c_smbus_access(fd: RawFd,
read_write: I2CSMBusReadWrite,
command: u8, size: I2CSMBusSize,
data: *mut i2c_smbus_data)
-> Result<(), I2CError> {
let mut args = i2c_smbus_ioctl_data {
read_write: read_write as u8,
command: command,
size: size as u32,
data: data,
};
ioctl::i2c_smbus(fd, &mut args).map(drop)
}
#[inline]
pub fn i2c_smbus_write_quick(fd: RawFd, bit: bool) -> Result<(), I2CError> {
let read_write = match bit {
true => I2CSMBusReadWrite::I2C_SMBUS_READ,
false => I2CSMBusReadWrite::I2C_SMBUS_WRITE,
};
unsafe {
i2c_smbus_access(fd,
read_write,
0,
I2CSMBusSize::I2C_SMBUS_QUICK,
ptr::null_mut())
}
}
#[inline]
pub fn i2c_smbus_read_byte(fd: RawFd) -> Result<u8, I2CError> {
let mut data = i2c_smbus_data::empty();
unsafe {
i2c_smbus_access(fd,
I2CSMBusReadWrite::I2C_SMBUS_READ,
0,
I2CSMBusSize::I2C_SMBUS_BYTE,
&mut data)?
}
Ok(data.block[0])
}
#[inline]
pub fn i2c_smbus_write_byte(fd: RawFd, value: u8) -> Result<(), I2CError> {
unsafe {
i2c_smbus_access(fd,
I2CSMBusReadWrite::I2C_SMBUS_WRITE,
value,
I2CSMBusSize::I2C_SMBUS_BYTE,
ptr::null_mut())
}
}
#[inline]
pub fn i2c_smbus_read_byte_data(fd: RawFd, register: u8) -> Result<u8, I2CError> {
let mut data = i2c_smbus_data::empty();
unsafe {
i2c_smbus_access(fd,
I2CSMBusReadWrite::I2C_SMBUS_READ,
register,
I2CSMBusSize::I2C_SMBUS_BYTE_DATA,
&mut data)?;
}
Ok(data.block[0])
}
#[inline]
pub fn i2c_smbus_write_byte_data(fd: RawFd, register: u8, value: u8) -> Result<(), I2CError> {
let mut data = i2c_smbus_data::empty();
data.block[0] = value;
unsafe {
i2c_smbus_access(fd,
I2CSMBusReadWrite::I2C_SMBUS_WRITE,
register,
I2CSMBusSize::I2C_SMBUS_BYTE_DATA,
&mut data)?;
}
Ok(())
}
#[inline]
pub fn i2c_smbus_read_word_data(fd: RawFd, register: u8) -> Result<u16, I2CError> {
let mut data = i2c_smbus_data::empty();
unsafe {
i2c_smbus_access(fd,
I2CSMBusReadWrite::I2C_SMBUS_READ,
register,
I2CSMBusSize::I2C_SMBUS_WORD_DATA,
&mut data)?;
};
Ok(Cursor::new(&data.block[..])
.read_u16::<NativeEndian>()
.unwrap())
}
#[inline]
pub fn i2c_smbus_write_word_data(fd: RawFd, register: u8, value: u16) -> Result<(), I2CError> {
let mut data = i2c_smbus_data::empty();
Cursor::new(&mut data.block[..])
.write_u16::<NativeEndian>(value)
.unwrap();
unsafe {
i2c_smbus_access(fd,
I2CSMBusReadWrite::I2C_SMBUS_WRITE,
register,
I2CSMBusSize::I2C_SMBUS_WORD_DATA,
&mut data)?;
};
Ok(())
}
#[inline]
pub fn i2c_smbus_process_call(fd: RawFd, register: u8, value: u16) -> Result<u16, I2CError> {
let mut data = i2c_smbus_data::empty();
Cursor::new(&mut data.block[..])
.write_u16::<NativeEndian>(value)
.unwrap();
unsafe {
i2c_smbus_access(fd,
I2CSMBusReadWrite::I2C_SMBUS_WRITE,
register,
I2CSMBusSize::I2C_SMBUS_PROC_CALL,
&mut data)?;
}
Ok(Cursor::new(&data.block[..])
.read_u16::<NativeEndian>()
.unwrap())
}
#[inline]
pub fn i2c_smbus_read_block_data(fd: RawFd, register: u8) -> Result<Vec<u8>, I2CError> {
let mut data = i2c_smbus_data::empty();
unsafe {
i2c_smbus_access(fd,
I2CSMBusReadWrite::I2C_SMBUS_READ,
register,
I2CSMBusSize::I2C_SMBUS_BLOCK_DATA,
&mut data)?;
}
let count = data.block[0];
Ok((&data.block[1..(count + 1) as usize]).to_vec())
}
pub fn i2c_smbus_read_i2c_block_data(fd: RawFd, register: u8, len: u8) -> Result<Vec<u8>, I2CError> {
let mut data = i2c_smbus_data::empty();
data.block[0] = len;
unsafe {
i2c_smbus_access(fd,
I2CSMBusReadWrite::I2C_SMBUS_READ,
register,
I2CSMBusSize::I2C_SMBUS_I2C_BLOCK_DATA,
&mut data)?;
}
let count = data.block[0];
Ok((&data.block[1..(count + 1) as usize]).to_vec())
}
#[inline]
pub fn i2c_smbus_write_block_data(fd: RawFd, register: u8, values: &[u8]) -> Result<(), I2CError> {
let mut data = i2c_smbus_data::empty();
let len: usize = if values.len() > 32 {
32
} else {
values.len()
};
data.block[0] = len as u8;
for i in 1..(len + 1) {
data.block[i] = values[i - 1];
}
unsafe {
i2c_smbus_access(fd,
I2CSMBusReadWrite::I2C_SMBUS_WRITE,
register,
I2CSMBusSize::I2C_SMBUS_BLOCK_DATA,
&mut data)?;
}
Ok(())
}
#[inline]
pub fn i2c_smbus_write_i2c_block_data(fd: RawFd,
register: u8,
values: &[u8])
-> Result<(), I2CError> {
let mut data = i2c_smbus_data::empty();
let len: usize = if values.len() > 32 {
32
} else {
values.len()
};
data.block[0] = len as u8;
for i in 1..(len + 1) {
data.block[i] = values[i - 1];
}
unsafe {
i2c_smbus_access(fd,
I2CSMBusReadWrite::I2C_SMBUS_WRITE,
register,
I2CSMBusSize::I2C_SMBUS_I2C_BLOCK_DATA,
&mut data)?;
}
Ok(())
}
#[inline]
pub fn i2c_smbus_process_call_block(fd: RawFd, register: u8, values: &[u8]) -> Result<Vec<u8>, I2CError> {
let mut data = i2c_smbus_data::empty();
let len: usize = if values.len() > 31 {
31
} else {
values.len()
};
data.block[0] = len as u8;
for i in 1..(len + 1) {
data.block[i] = values[i - 1];
}
unsafe {
i2c_smbus_access(fd,
I2CSMBusReadWrite::I2C_SMBUS_WRITE,
register,
I2CSMBusSize::I2C_SMBUS_BLOCK_PROC_CALL,
&mut data)?;
};
let count = data.block[0];
Ok((&data.block[1..(count + 1) as usize]).to_vec())
}