use std::cmp;
use std::borrow::Borrow;
use {i2c, sys, PhysicalGpu};
pub struct I2c<G = PhysicalGpu> {
inner: G,
display_mask: u32,
port: Option<u8>,
port_is_ddc: bool,
address: u8,
speed: sys::i2c::I2cSpeed,
}
impl<G> I2c<G> {
pub fn new(gpu: G, display_mask: u32) -> Self {
I2c {
inner: gpu,
display_mask: display_mask,
port: None,
port_is_ddc: false,
address: 0,
speed: sys::i2c::I2cSpeed::_100Khz,
}
}
pub fn set_display_mask(&mut self, display_mask: u32) {
self.display_mask = display_mask;
}
pub fn set_address(&mut self, address: u8) {
self.address = address;
}
pub fn set_port(&mut self, port: Option<u8>, port_is_ddc: bool) {
self.port = port;
self.port_is_ddc = port_is_ddc;
}
pub fn set_speed(&mut self, speed: sys::i2c::I2cSpeed) {
self.speed = speed;
}
}
impl<G: Borrow<PhysicalGpu>> I2c<G> {
pub fn nvapi_read(&self, register: &[u8], bytes: &mut [u8]) -> sys::Result<usize> {
self.inner.borrow().i2c_read(
self.display_mask,
self.port, self.port_is_ddc,
self.address,
register, bytes,
self.speed,
)
}
pub fn nvapi_write(&self, register: &[u8], bytes: &[u8]) -> sys::Result<()> {
self.inner.borrow().i2c_write(
self.display_mask,
self.port, self.port_is_ddc,
self.address,
register, bytes,
self.speed,
)
}
}
impl<G> i2c::Master for I2c<G> {
type Error = sys::Status;
}
impl<G> i2c::Address for I2c<G> {
fn set_slave_address(&mut self, addr: u16, tenbit: bool) -> sys::Result<()> {
if tenbit {
Err(sys::Status::InvalidArgument)
} else {
self.address = addr as u8;
Ok(())
}
}
}
impl<G: Borrow<PhysicalGpu>> i2c::ReadWrite for I2c<G> {
fn i2c_read(&mut self, value: &mut [u8]) -> Result<usize, Self::Error> {
self.nvapi_read(&[], value)
}
fn i2c_write(&mut self, value: &[u8]) -> Result<(), Self::Error> {
self.nvapi_write(&[], value)
}
}
impl<G: Borrow<PhysicalGpu>> i2c::Smbus for I2c<G> {
fn smbus_write_quick(&mut self, value: bool) -> Result<(), Self::Error> {
if value {
self.nvapi_read(&[], &mut []).map(drop)
} else {
self.nvapi_write(&[], &[])
}
}
fn smbus_read_byte(&mut self) -> Result<u8, Self::Error> {
let mut buf = [0];
self.nvapi_read(&[], &mut buf)
.map(|_| buf[0])
}
fn smbus_write_byte(&mut self, value: u8) -> Result<(), Self::Error> {
self.nvapi_write(&[], &[value])
}
fn smbus_read_byte_data(&mut self, command: u8) -> Result<u8, Self::Error> {
let mut buf = [0];
self.nvapi_read(&[command], &mut buf)
.map(|_| buf[0])
}
fn smbus_write_byte_data(&mut self, command: u8, value: u8) -> Result<(), Self::Error> {
self.nvapi_write(&[command], &[value])
}
fn smbus_read_word_data(&mut self, command: u8) -> Result<u16, Self::Error> {
let mut buf = [0, 0];
self.nvapi_read(&[command], &mut buf)
.map(|_| buf[0] as u16 | (buf[0] as u16) << 8)
}
fn smbus_write_word_data(&mut self, command: u8, value: u16) -> Result<(), Self::Error> {
self.nvapi_write(&[command], &[value as u8, (value >> 8) as u8])
}
fn smbus_process_call(&mut self, command: u8, value: u16) -> Result<u16, Self::Error> {
unimplemented!()
}
fn smbus_read_block_data(&mut self, command: u8, value: &mut [u8]) -> Result<usize, Self::Error> {
let mut buf = [0; 33];
self.nvapi_read(&[command], &mut buf)
.map(|len| {
let len = cmp::min(cmp::min(len, buf[0] as usize), value.len());
value[..len].copy_from_slice(&buf[1..1 + len]);
buf[0] as usize
})
}
fn smbus_write_block_data(&mut self, command: u8, value: &[u8]) -> Result<(), Self::Error> {
self.nvapi_write(&[command, value.len() as _], value)
}
}
impl<G: Borrow<PhysicalGpu>> i2c::BlockTransfer for I2c<G> {
fn i2c_read_block_data(&mut self, command: u8, value: &mut [u8]) -> Result<usize, Self::Error> {
self.nvapi_read(&[command], value)
}
fn i2c_write_block_data(&mut self, command: u8, value: &[u8]) -> Result<(), Self::Error> {
self.nvapi_write(&[command], value)
}
}