1#![allow(dead_code)]
10#![allow(non_camel_case_types)]
11
12use byteorder::{NativeEndian, ReadBytesExt, WriteBytesExt};
13use nix;
14use std::io::Cursor;
15use std::marker::PhantomData;
16use std::mem;
17use std::os::unix::prelude::*;
18use std::ptr;
19
20pub type I2CError = nix::Error;
21
22#[repr(C)]
24pub struct i2c_msg<'a> {
25 pub(crate) addr: u16,
27 pub(crate) flags: u16,
29 pub(crate) len: u16,
31 pub(crate) buf: *const u8,
33
34 pub(crate) _p: PhantomData<&'a mut [u8]>,
35}
36
37bitflags! {
38 struct I2CFunctions: u32 {
39 const I2C_FUNC_I2C = 0x0000_0001;
40 const I2C_FUNC_10BIT_ADDR = 0x0000_0002;
41 const I2C_FUNC_PROTOCOL_MANGLING = 0x0000_0004; const I2C_FUNC_SMBUS_PEC = 0x0000_0008;
43 const I2C_FUNC_NOSTART = 0x0000_0010; const I2C_FUNC_SMBUS_BLOCK_PROC_CALL = 0x0000_8000; const I2C_FUNC_SMBUS_QUICK = 0x0001_0000;
46 const I2C_FUNC_SMBUS_READ_BYTE = 0x0002_0000;
47 const I2C_FUNC_SMBUS_WRITE_BYTE = 0x0004_0000;
48 const I2C_FUNC_SMBUS_READ_BYTE_DATA = 0x0008_0000;
49 const I2C_FUNC_SMBUS_WRITE_BYTE_DATA = 0x0010_0000;
50 const I2C_FUNC_SMBUS_READ_WORD_DATA = 0x0020_0000;
51 const I2C_FUNC_SMBUS_WRITE_WORD_DATA = 0x0040_0000;
52 const I2C_FUNC_SMBUS_PROC_CALL = 0x0080_0000;
53 const I2C_FUNC_SMBUS_READ_BLOCK_DATA = 0x0100_0000;
54 const I2C_FUNC_SMBUS_WRITE_BLOCK_DATA = 0x0200_0000;
55 const I2C_FUNC_SMBUS_READ_I2C_BLOCK = 0x0400_0000; const I2C_FUNC_SMBUS_WRITE_I2C_BLOCK = 0x0800_0000; const I2C_FUNC_SMBUS_BYTE = (I2CFunctions::I2C_FUNC_SMBUS_READ_BYTE.bits() |
59 I2CFunctions::I2C_FUNC_SMBUS_WRITE_BYTE.bits());
60 const I2C_FUNC_SMBUS_BYTE_DATA = (I2CFunctions::I2C_FUNC_SMBUS_READ_BYTE_DATA.bits() |
61 I2CFunctions::I2C_FUNC_SMBUS_WRITE_BYTE_DATA.bits());
62 const I2C_FUNC_SMBUS_WORD_DATA = (I2CFunctions::I2C_FUNC_SMBUS_READ_WORD_DATA.bits() |
63 I2CFunctions::I2C_FUNC_SMBUS_WRITE_WORD_DATA.bits());
64 const I2C_FUNC_SMBUS_BLOCK_DATA = (I2CFunctions::I2C_FUNC_SMBUS_READ_BLOCK_DATA.bits() |
65 I2CFunctions::I2C_FUNC_SMBUS_WRITE_BLOCK_DATA.bits());
66 const I2C_FUNC_SMBUS_I2C_BLOCK = (I2CFunctions::I2C_FUNC_SMBUS_READ_I2C_BLOCK.bits() |
67 I2CFunctions::I2C_FUNC_SMBUS_WRITE_I2C_BLOCK.bits());
68 const I2C_FUNC_SMBUS_EMUL = (I2CFunctions::I2C_FUNC_SMBUS_QUICK.bits() |
69 I2CFunctions::I2C_FUNC_SMBUS_BYTE.bits() |
70 I2CFunctions::I2C_FUNC_SMBUS_BYTE_DATA.bits() |
71 I2CFunctions::I2C_FUNC_SMBUS_WORD_DATA.bits() |
72 I2CFunctions::I2C_FUNC_SMBUS_PROC_CALL.bits() |
73 I2CFunctions::I2C_FUNC_SMBUS_WRITE_BLOCK_DATA.bits() |
74 I2CFunctions::I2C_FUNC_SMBUS_I2C_BLOCK.bits() |
75 I2CFunctions::I2C_FUNC_SMBUS_PEC.bits());
76 }
77}
78
79const I2C_SMBUS_BLOCK_MAX: u8 = 32;
81
82#[repr(C)]
93struct i2c_smbus_data {
94 block: [u8; (I2C_SMBUS_BLOCK_MAX + 2) as usize],
95}
96
97impl i2c_smbus_data {
98 fn empty() -> i2c_smbus_data {
99 unsafe { mem::zeroed() }
100 }
101}
102
103#[repr(u8)]
104enum I2CSMBusReadWrite {
105 I2C_SMBUS_READ = 1,
106 I2C_SMBUS_WRITE = 0,
107}
108
109#[repr(u32)]
110enum I2CSMBusSize {
111 I2C_SMBUS_QUICK = 0,
112 I2C_SMBUS_BYTE = 1,
113 I2C_SMBUS_BYTE_DATA = 2,
114 I2C_SMBUS_WORD_DATA = 3,
115 I2C_SMBUS_PROC_CALL = 4,
116 I2C_SMBUS_BLOCK_DATA = 5,
117 I2C_SMBUS_I2C_BLOCK_BROKEN = 6,
118 I2C_SMBUS_BLOCK_PROC_CALL = 7, I2C_SMBUS_I2C_BLOCK_DATA = 8,
120}
121
122const I2C_RETRIES: u16 = 0x0701;
124const I2C_TIMEOUT: u16 = 0x0702;
125const I2C_SLAVE: u16 = 0x0703;
126const I2C_SLAVE_FORCE: u16 = 0x0706;
127const I2C_TENBIT: u16 = 0x0704;
128const I2C_FUNCS: u16 = 0x0705;
129const I2C_RDWR: u16 = 0x0707;
130const I2C_PEC: u16 = 0x0708;
131const I2C_SMBUS: u16 = 0x0720;
132const I2C_RDRW_IOCTL_MAX_MSGS: u8 = 42;
133
134#[repr(C)]
136pub struct i2c_smbus_ioctl_data {
137 read_write: u8,
139 command: u8,
141 size: u32,
143 data: *mut i2c_smbus_data,
145}
146
147#[repr(C)]
150pub struct i2c_rdwr_ioctl_data<'a> {
151 msgs: *mut i2c_msg<'a>,
153 nmsgs: u32,
155}
156
157mod ioctl {
158 pub use super::i2c_rdwr_ioctl_data;
159 pub use super::i2c_smbus_ioctl_data;
160 use super::{I2C_PEC, I2C_RDWR, I2C_SLAVE, I2C_SLAVE_FORCE, I2C_SMBUS};
161
162 ioctl_write_int_bad!(set_i2c_slave_address, I2C_SLAVE);
163 ioctl_write_int_bad!(set_i2c_slave_address_force, I2C_SLAVE_FORCE);
164 ioctl_write_int_bad!(set_smbus_pec, I2C_PEC);
165 ioctl_write_ptr_bad!(i2c_smbus, I2C_SMBUS, i2c_smbus_ioctl_data);
166 ioctl_write_ptr_bad!(i2c_rdwr, I2C_RDWR, i2c_rdwr_ioctl_data);
167}
168
169pub fn i2c_set_slave_address(fd: RawFd, slave_address: u16) -> Result<(), nix::Error> {
170 unsafe {
171 ioctl::set_i2c_slave_address(fd, i32::from(slave_address))?;
172 }
173 Ok(())
174}
175
176pub fn i2c_set_slave_address_force(fd: RawFd, slave_address: u16) -> Result<(), nix::Error> {
177 unsafe {
178 ioctl::set_i2c_slave_address_force(fd, i32::from(slave_address))?;
179 }
180 Ok(())
181}
182
183pub fn i2c_set_smbus_pec(fd: RawFd, enable: bool) -> Result<(), nix::Error> {
184 unsafe {
185 ioctl::set_smbus_pec(fd, i32::from(enable))?;
186 }
187 Ok(())
188}
189
190unsafe fn i2c_smbus_access(
191 fd: RawFd,
192 read_write: I2CSMBusReadWrite,
193 command: u8, size: I2CSMBusSize,
195 data: *mut i2c_smbus_data,
196) -> Result<(), I2CError> {
197 let args = i2c_smbus_ioctl_data {
198 read_write: read_write as u8,
199 command,
200 size: size as u32,
201 data,
202 };
203
204 ioctl::i2c_smbus(fd, &args).map(drop)
206}
207
208#[inline]
209pub fn i2c_smbus_write_quick(fd: RawFd, bit: bool) -> Result<(), I2CError> {
210 let read_write = if bit {
211 I2CSMBusReadWrite::I2C_SMBUS_READ
212 } else {
213 I2CSMBusReadWrite::I2C_SMBUS_WRITE
214 };
215 unsafe {
216 i2c_smbus_access(
217 fd,
218 read_write,
219 0,
220 I2CSMBusSize::I2C_SMBUS_QUICK,
221 ptr::null_mut(),
222 )
223 }
224}
225
226#[inline]
227pub fn i2c_smbus_read_byte(fd: RawFd) -> Result<u8, I2CError> {
228 let mut data = i2c_smbus_data::empty();
229 unsafe {
230 i2c_smbus_access(
231 fd,
232 I2CSMBusReadWrite::I2C_SMBUS_READ,
233 0,
234 I2CSMBusSize::I2C_SMBUS_BYTE,
235 &mut data,
236 )?
237 }
238 Ok(data.block[0])
239}
240
241#[inline]
242pub fn i2c_smbus_write_byte(fd: RawFd, value: u8) -> Result<(), I2CError> {
243 unsafe {
244 i2c_smbus_access(
245 fd,
246 I2CSMBusReadWrite::I2C_SMBUS_WRITE,
247 value,
248 I2CSMBusSize::I2C_SMBUS_BYTE,
249 ptr::null_mut(),
250 )
251 }
252}
253
254#[inline]
255pub fn i2c_smbus_read_byte_data(fd: RawFd, register: u8) -> Result<u8, I2CError> {
256 let mut data = i2c_smbus_data::empty();
257 unsafe {
258 i2c_smbus_access(
259 fd,
260 I2CSMBusReadWrite::I2C_SMBUS_READ,
261 register,
262 I2CSMBusSize::I2C_SMBUS_BYTE_DATA,
263 &mut data,
264 )?;
265 }
266 Ok(data.block[0])
267}
268
269#[inline]
270pub fn i2c_smbus_write_byte_data(fd: RawFd, register: u8, value: u8) -> Result<(), I2CError> {
271 let mut data = i2c_smbus_data::empty();
272 data.block[0] = value;
273 unsafe {
274 i2c_smbus_access(
275 fd,
276 I2CSMBusReadWrite::I2C_SMBUS_WRITE,
277 register,
278 I2CSMBusSize::I2C_SMBUS_BYTE_DATA,
279 &mut data,
280 )
281 }
282}
283
284#[inline]
285pub fn i2c_smbus_read_word_data(fd: RawFd, register: u8) -> Result<u16, I2CError> {
286 let mut data = i2c_smbus_data::empty();
287 unsafe {
288 i2c_smbus_access(
289 fd,
290 I2CSMBusReadWrite::I2C_SMBUS_READ,
291 register,
292 I2CSMBusSize::I2C_SMBUS_WORD_DATA,
293 &mut data,
294 )?;
295 };
296
297 Ok(Cursor::new(&data.block[..])
298 .read_u16::<NativeEndian>()
299 .unwrap())
300}
301
302#[inline]
303pub fn i2c_smbus_write_word_data(fd: RawFd, register: u8, value: u16) -> Result<(), I2CError> {
304 let mut data = i2c_smbus_data::empty();
305 Cursor::new(&mut data.block[..])
306 .write_u16::<NativeEndian>(value)
307 .unwrap();
308
309 unsafe {
310 i2c_smbus_access(
311 fd,
312 I2CSMBusReadWrite::I2C_SMBUS_WRITE,
313 register,
314 I2CSMBusSize::I2C_SMBUS_WORD_DATA,
315 &mut data,
316 )
317 }
318}
319
320#[inline]
321pub fn i2c_smbus_process_call(fd: RawFd, register: u8, value: u16) -> Result<u16, I2CError> {
322 let mut data = i2c_smbus_data::empty();
323 Cursor::new(&mut data.block[..])
324 .write_u16::<NativeEndian>(value)
325 .unwrap();
326
327 unsafe {
328 i2c_smbus_access(
329 fd,
330 I2CSMBusReadWrite::I2C_SMBUS_WRITE,
331 register,
332 I2CSMBusSize::I2C_SMBUS_PROC_CALL,
333 &mut data,
334 )?;
335 }
336 Ok(Cursor::new(&data.block[..])
337 .read_u16::<NativeEndian>()
338 .unwrap())
339}
340
341#[inline]
342pub fn i2c_smbus_read_block_data(fd: RawFd, register: u8) -> Result<Vec<u8>, I2CError> {
343 let mut data = i2c_smbus_data::empty();
344 unsafe {
345 i2c_smbus_access(
346 fd,
347 I2CSMBusReadWrite::I2C_SMBUS_READ,
348 register,
349 I2CSMBusSize::I2C_SMBUS_BLOCK_DATA,
350 &mut data,
351 )?;
352 }
353
354 let count = data.block[0];
357 Ok((data.block[1..(count + 1) as usize]).to_vec())
358}
359
360pub fn i2c_smbus_read_i2c_block_data(
361 fd: RawFd,
362 register: u8,
363 len: u8,
364) -> Result<Vec<u8>, I2CError> {
365 let mut data = i2c_smbus_data::empty();
366 data.block[0] = len;
367 unsafe {
368 i2c_smbus_access(
369 fd,
370 I2CSMBusReadWrite::I2C_SMBUS_READ,
371 register,
372 I2CSMBusSize::I2C_SMBUS_I2C_BLOCK_DATA,
373 &mut data,
374 )?;
375 }
376
377 let count = data.block[0];
380 Ok((data.block[1..(count + 1) as usize]).to_vec())
381}
382
383#[inline]
384fn copy_to_i2c_block_data(values: &[u8], max_size: usize) -> i2c_smbus_data {
385 let mut data = i2c_smbus_data::empty();
386 let len: usize = if values.len() > max_size {
387 max_size
388 } else {
389 values.len()
390 };
391 data.block[0] = len as u8;
392 data.block[1..=len].copy_from_slice(&values[..len]);
393 data
394}
395
396#[inline]
397pub fn i2c_smbus_write_block_data(fd: RawFd, register: u8, values: &[u8]) -> Result<(), I2CError> {
398 let mut data = copy_to_i2c_block_data(values, 32);
399 unsafe {
400 i2c_smbus_access(
401 fd,
402 I2CSMBusReadWrite::I2C_SMBUS_WRITE,
403 register,
404 I2CSMBusSize::I2C_SMBUS_BLOCK_DATA,
405 &mut data,
406 )
407 }
408}
409
410#[inline]
411pub fn i2c_smbus_write_i2c_block_data(
412 fd: RawFd,
413 register: u8,
414 values: &[u8],
415) -> Result<(), I2CError> {
416 let mut data = copy_to_i2c_block_data(values, 32);
417 unsafe {
418 i2c_smbus_access(
419 fd,
420 I2CSMBusReadWrite::I2C_SMBUS_WRITE,
421 register,
422 I2CSMBusSize::I2C_SMBUS_I2C_BLOCK_DATA,
423 &mut data,
424 )
425 }
426}
427
428#[inline]
429pub fn i2c_smbus_process_call_block(
430 fd: RawFd,
431 register: u8,
432 values: &[u8],
433) -> Result<Vec<u8>, I2CError> {
434 let mut data = copy_to_i2c_block_data(values, 31);
435 unsafe {
436 i2c_smbus_access(
437 fd,
438 I2CSMBusReadWrite::I2C_SMBUS_WRITE,
439 register,
440 I2CSMBusSize::I2C_SMBUS_BLOCK_PROC_CALL,
441 &mut data,
442 )?;
443 };
444
445 let count = data.block[0];
448 Ok((data.block[1..(count + 1) as usize]).to_vec())
449}
450
451#[inline]
452pub fn i2c_rdwr(fd: RawFd, values: &mut [i2c_msg]) -> Result<u32, I2CError> {
453 let i2c_data = i2c_rdwr_ioctl_data {
454 msgs: values.as_mut_ptr(),
455 nmsgs: values.len() as u32,
456 };
457
458 let n;
459 unsafe {
460 n = ioctl::i2c_rdwr(fd, &i2c_data)?;
461 }
462 Ok(n as u32)
463}