i2cdev/
ffi.rs

1// Copyright 2015, Paul Osborne <osbpau@gmail.com>
2//
3// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4// http://www.apache.org/license/LICENSE-2.0> or the MIT license
5// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
6// option.  This file may not be copied, modified, or distributed
7// except according to those terms.
8
9#![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    /// slave address
24    pub(crate) addr: u16,
25    /// serialized I2CMsgFlags
26    pub(crate) flags: u16,
27    /// msg length
28    pub(crate) len: u16,
29    /// pointer to msg data
30    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; /* I2C_M_IGNORE_NAK etc. */
38        const I2C_FUNC_SMBUS_PEC = 0x0000_0008;
39        const I2C_FUNC_NOSTART = 0x0000_0010; /* I2C_M_NOSTART */
40        const I2C_FUNC_SMBUS_BLOCK_PROC_CALL = 0x0000_8000; /* SMBus 2.0 */
41        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; /* I2C-like block xfer  */
52        const I2C_FUNC_SMBUS_WRITE_I2C_BLOCK = 0x0800_0000; /* w/ 1-byte reg. addr. */
53
54        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
75/// As specified in SMBus standard
76const I2C_SMBUS_BLOCK_MAX: u8 = 32;
77
78// In C, this is a union, but the largest item is clearly
79// the largest.  Rust does not have unions at this time,
80// so we improvise.  See https://github.com/rust-lang/rust/issues/5492
81//
82// union i2c_smbus_data {
83//     __u8 byte;
84//     __u16 word;
85//     __u8 block[I2C_SMBUS_BLOCK_MAX + 2]; /* block[0] is used for length */
86//                            /* and one more for user-space compatibility */
87// };
88#[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, // SMBus 2.0
115    I2C_SMBUS_I2C_BLOCK_DATA = 8,
116}
117
118// from include/uapi/linux/i2c-dev.h
119const 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/// This is the structure as used in the I2C_SMBUS ioctl call
131#[repr(C)]
132pub struct i2c_smbus_ioctl_data {
133    // __u8 read_write;
134    read_write: u8,
135    // __u8 command;
136    command: u8,
137    // __u32 size;
138    size: u32,
139    // union i2c_smbus_data __user *data;
140    data: *mut i2c_smbus_data,
141}
142
143/// This is the structure as used in the I2C_RDWR ioctl call
144// see linux/i2c-dev.h
145#[repr(C)]
146pub struct i2c_rdwr_ioctl_data {
147    // struct i2c_msg __user *msgs;
148    msgs: *mut i2c_msg,
149    // __u32 nmsgs;
150    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, // can be address or something else
190    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    // remove type information
201    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    // create a vector from the data in the block starting at byte
351    // 1 and ending after count bytes after that
352    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    // create a vector from the data in the block starting at byte
374    // 1 and ending after count bytes after that
375    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    // create a vector from the data in the block starting at byte
442    // 1 and ending after count bytes after that
443    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}