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