i2cdev2/
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 nix;
13use std::mem;
14use std::ptr;
15use std::io::Cursor;
16use std::os::unix::prelude::*;
17use std::marker::PhantomData;
18use byteorder::{NativeEndian, ReadBytesExt, WriteBytesExt};
19use core::{I2CMsg};
20use libc::c_int;
21
22pub type I2CError = nix::Error;
23
24#[repr(C)]
25#[derive(Debug)]
26/// C version of i2c_msg structure
27// See linux/i2c.h
28struct i2c_msg<'a> {
29    /// slave address
30    addr: u16,
31    /// serialized I2CMsgFlags
32    flags: u16,
33    /// msg length
34    len: u16,
35    /// pointer to msg data
36    buf: *mut u8,
37    _phantom: PhantomData<&'a mut u8>,
38}
39
40impl<'a, 'b> From<&'b mut I2CMsg<'a>> for i2c_msg<'a> {
41    fn from(msg: &mut I2CMsg) -> Self {
42        i2c_msg {
43            addr: msg.addr,
44            flags: msg.flags,
45            len: msg.data.len() as u16,
46            buf: msg.data.as_mut_ptr(),
47            _phantom: PhantomData
48        }
49    }
50}
51
52bitflags! {
53    struct I2CFunctions: u32 {
54        const I2C_FUNC_I2C = 0x00000001;
55        const I2C_FUNC_10BIT_ADDR = 0x00000002;
56        const I2C_FUNC_PROTOCOL_MANGLING = 0x00000004; /* I2C_M_IGNORE_NAK etc. */
57        const I2C_FUNC_SMBUS_PEC = 0x00000008;
58        const I2C_FUNC_NOSTART = 0x00000010; /* I2C_M_NOSTART */
59        const I2C_FUNC_SMBUS_BLOCK_PROC_CALL = 0x00008000; /* SMBus 2.0 */
60        const I2C_FUNC_SMBUS_QUICK = 0x00010000;
61        const I2C_FUNC_SMBUS_READ_BYTE = 0x00020000;
62        const I2C_FUNC_SMBUS_WRITE_BYTE = 0x00040000;
63        const I2C_FUNC_SMBUS_READ_BYTE_DATA = 0x00080000;
64        const I2C_FUNC_SMBUS_WRITE_BYTE_DATA = 0x00100000;
65        const I2C_FUNC_SMBUS_READ_WORD_DATA = 0x00200000;
66        const I2C_FUNC_SMBUS_WRITE_WORD_DATA = 0x00400000;
67        const I2C_FUNC_SMBUS_PROC_CALL = 0x00800000;
68        const I2C_FUNC_SMBUS_READ_BLOCK_DATA = 0x01000000;
69        const I2C_FUNC_SMBUS_WRITE_BLOCK_DATA  = 0x02000000;
70        const I2C_FUNC_SMBUS_READ_I2C_BLOCK = 0x04000000; /* I2C-like block xfer  */
71        const I2C_FUNC_SMBUS_WRITE_I2C_BLOCK = 0x08000000; /* w/ 1-byte reg. addr. */
72
73        const I2C_FUNC_SMBUS_BYTE = (I2CFunctions::I2C_FUNC_SMBUS_READ_BYTE.bits |
74                                     I2CFunctions::I2C_FUNC_SMBUS_WRITE_BYTE.bits);
75        const I2C_FUNC_SMBUS_BYTE_DATA = (I2CFunctions::I2C_FUNC_SMBUS_READ_BYTE_DATA.bits |
76                                          I2CFunctions::I2C_FUNC_SMBUS_WRITE_BYTE_DATA.bits);
77        const I2C_FUNC_SMBUS_WORD_DATA = (I2CFunctions::I2C_FUNC_SMBUS_READ_WORD_DATA.bits |
78                                          I2CFunctions::I2C_FUNC_SMBUS_WRITE_WORD_DATA.bits);
79        const I2C_FUNC_SMBUS_BLOCK_DATA = (I2CFunctions::I2C_FUNC_SMBUS_READ_BLOCK_DATA.bits |
80                                           I2CFunctions::I2C_FUNC_SMBUS_WRITE_BLOCK_DATA.bits);
81        const I2C_FUNC_SMBUS_I2C_BLOCK = (I2CFunctions::I2C_FUNC_SMBUS_READ_I2C_BLOCK.bits |
82                                          I2CFunctions::I2C_FUNC_SMBUS_WRITE_I2C_BLOCK.bits);
83        const I2C_FUNC_SMBUS_EMUL = (I2CFunctions::I2C_FUNC_SMBUS_QUICK.bits |
84                                     I2CFunctions::I2C_FUNC_SMBUS_BYTE.bits |
85                                     I2CFunctions::I2C_FUNC_SMBUS_BYTE_DATA.bits |
86                                     I2CFunctions::I2C_FUNC_SMBUS_WORD_DATA.bits |
87                                     I2CFunctions::I2C_FUNC_SMBUS_PROC_CALL.bits |
88                                     I2CFunctions::I2C_FUNC_SMBUS_WRITE_BLOCK_DATA.bits |
89                                     I2CFunctions::I2C_FUNC_SMBUS_I2C_BLOCK.bits |
90                                     I2CFunctions::I2C_FUNC_SMBUS_PEC.bits);
91    }
92}
93
94
95/// As specified in SMBus standard
96const I2C_SMBUS_BLOCK_MAX: u8 = 32;
97
98// In C, this is a union, but the largest item is clearly
99// the largest.  Rust does not have unions at this time,
100// so we improvise.  See https://github.com/rust-lang/rust/issues/5492
101//
102// union i2c_smbus_data {
103//     __u8 byte;
104//     __u16 word;
105//     __u8 block[I2C_SMBUS_BLOCK_MAX + 2]; /* block[0] is used for length */
106//                            /* and one more for user-space compatibility */
107// };
108#[repr(C)]
109struct i2c_smbus_data {
110    block: [u8; (I2C_SMBUS_BLOCK_MAX + 2) as usize],
111}
112
113impl i2c_smbus_data {
114    fn empty() -> i2c_smbus_data {
115        unsafe { mem::zeroed() }
116    }
117}
118
119#[repr(u8)]
120enum I2CSMBusReadWrite {
121    I2C_SMBUS_READ = 1,
122    I2C_SMBUS_WRITE = 0,
123}
124
125#[repr(u32)]
126enum I2CSMBusSize {
127    I2C_SMBUS_QUICK = 0,
128    I2C_SMBUS_BYTE = 1,
129    I2C_SMBUS_BYTE_DATA = 2,
130    I2C_SMBUS_WORD_DATA = 3,
131    I2C_SMBUS_PROC_CALL = 4,
132    I2C_SMBUS_BLOCK_DATA = 5,
133    I2C_SMBUS_I2C_BLOCK_BROKEN = 6,
134    I2C_SMBUS_BLOCK_PROC_CALL = 7, // SMBus 2.0
135    I2C_SMBUS_I2C_BLOCK_DATA = 8,
136}
137
138// from include/uapi/linux/i2c-dev.h
139const I2C_RETRIES: u16 = 0x0701;
140const I2C_TIMEOUT: u16 = 0x0702;
141const I2C_SLAVE: u16 = 0x0703;
142const I2C_SLAVE_FORCE: u16 = 0x0706;
143const I2C_TENBIT: u16 = 0x0704;
144const I2C_FUNCS: u16 = 0x0705;
145const I2C_RDWR: u16 = 0x0707;
146const I2C_PEC: u16 = 0x0708;
147const I2C_SMBUS: u16 = 0x0720;
148const I2C_RDRW_IOCTL_MAX_MSGS: u8 = 42;
149
150/// This is the structure as used in the I2C_SMBUS ioctl call
151#[repr(C)]
152pub struct i2c_smbus_ioctl_data {
153    // __u8 read_write;
154    read_write: u8,
155    // __u8 command;
156    command: u8,
157    // __u32 size;
158    size: u32,
159    // union i2c_smbus_data __user *data;
160    data: *mut i2c_smbus_data,
161}
162
163/// This is the structure as used in the I2C_RDWR ioctl call
164// see linux/i2c-dev.h
165#[repr(C)]
166pub struct i2c_rdwr_ioctl_data<'a> {
167    // struct i2c_msg __user *msgs;
168    msgs: *mut i2c_msg<'a>,
169    // __u32 nmsgs;
170    nmsgs: u32,
171}
172
173mod ioctl {
174    use super::{I2C_SLAVE, I2C_SMBUS, I2C_RDWR};
175    pub use super::i2c_smbus_ioctl_data;
176    pub use super::i2c_rdwr_ioctl_data;
177
178    ioctl_write_int_bad!(set_i2c_slave_address, I2C_SLAVE);
179    ioctl_write_ptr_bad!(i2c_smbus, I2C_SMBUS, i2c_smbus_ioctl_data);
180    ioctl_write_ptr_bad!(i2c_rdwr, I2C_RDWR, i2c_rdwr_ioctl_data);
181}
182
183pub fn i2c_set_slave_address(fd: RawFd, slave_address: u16) -> Result<(), nix::Error> {
184    unsafe {
185        ioctl::set_i2c_slave_address(fd, slave_address as i32)?;
186    }
187    Ok(())
188}
189
190unsafe fn i2c_smbus_access(fd: RawFd,
191                           read_write: I2CSMBusReadWrite,
192                           command: u8, // can be address or something else
193                           size: I2CSMBusSize,
194                           data: *mut i2c_smbus_data)
195                           -> Result<(), I2CError> {
196    let mut args = i2c_smbus_ioctl_data {
197        read_write: read_write as u8,
198        command: command,
199        size: size as u32,
200        data: data,
201    };
202
203    // remove type information
204    ioctl::i2c_smbus(fd, &mut args).map(drop)
205}
206
207#[inline]
208pub fn i2c_smbus_write_quick(fd: RawFd, bit: bool) -> Result<(), I2CError> {
209    let read_write = match bit {
210        true => I2CSMBusReadWrite::I2C_SMBUS_READ,
211        false => I2CSMBusReadWrite::I2C_SMBUS_WRITE,
212    };
213    unsafe {
214        i2c_smbus_access(fd,
215                         read_write,
216                         0,
217                         I2CSMBusSize::I2C_SMBUS_QUICK,
218                         ptr::null_mut())
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(fd,
227                         I2CSMBusReadWrite::I2C_SMBUS_READ,
228                         0,
229                         I2CSMBusSize::I2C_SMBUS_BYTE,
230                         &mut data)?
231    }
232    Ok(data.block[0])
233}
234
235#[inline]
236pub fn i2c_smbus_write_byte(fd: RawFd, value: u8) -> Result<(), I2CError> {
237    unsafe {
238        i2c_smbus_access(fd,
239                         I2CSMBusReadWrite::I2C_SMBUS_WRITE,
240                         value,
241                         I2CSMBusSize::I2C_SMBUS_BYTE,
242                         ptr::null_mut())
243    }
244}
245
246#[inline]
247pub fn i2c_smbus_read_byte_data(fd: RawFd, register: u8) -> Result<u8, I2CError> {
248    let mut data = i2c_smbus_data::empty();
249    unsafe {
250        i2c_smbus_access(fd,
251                         I2CSMBusReadWrite::I2C_SMBUS_READ,
252                         register,
253                         I2CSMBusSize::I2C_SMBUS_BYTE_DATA,
254                         &mut data)?;
255    }
256    Ok(data.block[0])
257}
258
259#[inline]
260pub fn i2c_smbus_write_byte_data(fd: RawFd, register: u8, value: u8) -> Result<(), I2CError> {
261    let mut data = i2c_smbus_data::empty();
262    data.block[0] = value;
263    unsafe {
264        i2c_smbus_access(fd,
265                         I2CSMBusReadWrite::I2C_SMBUS_WRITE,
266                         register,
267                         I2CSMBusSize::I2C_SMBUS_BYTE_DATA,
268                         &mut data)?;
269    }
270    Ok(())
271}
272
273#[inline]
274pub fn i2c_smbus_read_word_data(fd: RawFd, register: u8) -> Result<u16, I2CError> {
275    let mut data = i2c_smbus_data::empty();
276    unsafe {
277        i2c_smbus_access(fd,
278                         I2CSMBusReadWrite::I2C_SMBUS_READ,
279                         register,
280                         I2CSMBusSize::I2C_SMBUS_WORD_DATA,
281                         &mut data)?;
282    };
283
284    Ok(Cursor::new(&data.block[..])
285           .read_u16::<NativeEndian>()
286           .unwrap())
287}
288
289
290#[inline]
291pub fn i2c_smbus_write_word_data(fd: RawFd, register: u8, value: u16) -> Result<(), I2CError> {
292    let mut data = i2c_smbus_data::empty();
293    Cursor::new(&mut data.block[..])
294        .write_u16::<NativeEndian>(value)
295        .unwrap();
296
297    unsafe {
298        i2c_smbus_access(fd,
299                         I2CSMBusReadWrite::I2C_SMBUS_WRITE,
300                         register,
301                         I2CSMBusSize::I2C_SMBUS_WORD_DATA,
302                         &mut data)?;
303    };
304    Ok(())
305}
306
307#[inline]
308pub fn i2c_smbus_process_call(fd: RawFd, register: u8, value: u16) -> Result<u16, I2CError> {
309    let mut data = i2c_smbus_data::empty();
310    Cursor::new(&mut data.block[..])
311        .write_u16::<NativeEndian>(value)
312        .unwrap();
313
314    unsafe {
315        i2c_smbus_access(fd,
316                         I2CSMBusReadWrite::I2C_SMBUS_WRITE,
317                         register,
318                         I2CSMBusSize::I2C_SMBUS_PROC_CALL,
319                         &mut data)?;
320    }
321    Ok(Cursor::new(&data.block[..])
322           .read_u16::<NativeEndian>()
323           .unwrap())
324}
325
326#[inline]
327pub fn i2c_smbus_read_block_data(fd: RawFd, register: u8) -> Result<Vec<u8>, I2CError> {
328    let mut data = i2c_smbus_data::empty();
329    unsafe {
330        i2c_smbus_access(fd,
331                         I2CSMBusReadWrite::I2C_SMBUS_READ,
332                         register,
333                         I2CSMBusSize::I2C_SMBUS_BLOCK_DATA,
334                         &mut data)?;
335    }
336
337    // create a vector from the data in the block starting at byte
338    // 1 and ending after count bytes after that
339    let count = data.block[0];
340    Ok((&data.block[1..(count + 1) as usize]).to_vec())
341}
342
343pub fn i2c_smbus_read_i2c_block_data(fd: RawFd, register: u8, len: u8) -> Result<Vec<u8>, I2CError> {
344    let mut data = i2c_smbus_data::empty();
345    data.block[0] = len;
346    unsafe {
347        i2c_smbus_access(fd,
348                         I2CSMBusReadWrite::I2C_SMBUS_READ,
349                         register,
350                         I2CSMBusSize::I2C_SMBUS_I2C_BLOCK_DATA,
351                         &mut data)?;
352    }
353
354    // create a vector from the data in the block starting at byte
355    // 1 and ending after count bytes after that
356    let count = data.block[0];
357    Ok((&data.block[1..(count + 1) as usize]).to_vec())
358}
359
360#[inline]
361pub fn i2c_smbus_write_block_data(fd: RawFd, register: u8, values: &[u8]) -> Result<(), I2CError> {
362    let mut data = i2c_smbus_data::empty();
363    let len: usize = if values.len() > 32 {
364        32
365    } else {
366        values.len()
367    };
368    data.block[0] = len as u8;
369    for i in 1..(len + 1) {
370        data.block[i] = values[i - 1];
371    }
372    unsafe {
373        i2c_smbus_access(fd,
374                         I2CSMBusReadWrite::I2C_SMBUS_WRITE,
375                         register,
376                         I2CSMBusSize::I2C_SMBUS_BLOCK_DATA,
377                         &mut data)?;
378    }
379    Ok(())
380}
381
382#[inline]
383pub fn i2c_smbus_write_i2c_block_data(fd: RawFd,
384                                      register: u8,
385                                      values: &[u8])
386                                      -> Result<(), I2CError> {
387    let mut data = i2c_smbus_data::empty();
388    let len: usize = if values.len() > 32 {
389        32
390    } else {
391        values.len()
392    };
393    data.block[0] = len as u8;
394    for i in 1..(len + 1) {
395        data.block[i] = values[i - 1];
396    }
397    unsafe {
398        i2c_smbus_access(fd,
399                         I2CSMBusReadWrite::I2C_SMBUS_WRITE,
400                         register,
401                         I2CSMBusSize::I2C_SMBUS_I2C_BLOCK_DATA,
402                         &mut data)?;
403    }
404    Ok(())
405}
406
407#[inline]
408pub fn i2c_smbus_process_call_block(fd: RawFd, register: u8, values: &[u8]) -> Result<Vec<u8>, I2CError> {
409    let mut data = i2c_smbus_data::empty();
410    let len: usize = if values.len() > 31 {
411        31
412    } else {
413        values.len()
414    };
415    data.block[0] = len as u8;
416    for i in 1..(len + 1) {
417        data.block[i] = values[i - 1];
418    }
419    unsafe {
420        i2c_smbus_access(fd,
421                         I2CSMBusReadWrite::I2C_SMBUS_WRITE,
422                         register,
423                         I2CSMBusSize::I2C_SMBUS_BLOCK_PROC_CALL,
424                         &mut data)?;
425    };
426
427    // create a vector from the data in the block starting at byte
428    // 1 and ending after count bytes after that
429    let count = data.block[0];
430    Ok((&data.block[1..(count + 1) as usize]).to_vec())
431}
432
433// Returns the number of messages succesfully processed
434unsafe fn i2c_rdwr_access(fd: RawFd,
435                          msgs: *mut i2c_msg,
436                          nmsgs: usize)
437                          -> Result<(c_int), I2CError> {
438    let args = i2c_rdwr_ioctl_data {
439        msgs,
440        nmsgs: nmsgs as u32,
441    };
442
443    ioctl::i2c_rdwr(fd, &args)
444}
445
446pub fn i2c_rdwr_read_write(fd: RawFd,
447                           msgs: &mut Vec<I2CMsg>) -> Result<(i32), I2CError> {
448    // Building the msgs to push is safe.
449    // We have to use iter_mut as buf needs to be mutable.
450    let mut cmsgs = msgs.iter_mut().map(<i2c_msg>::from).collect::<Vec<_>>();
451
452    // But calling the ioctl is definitely not!
453    unsafe {
454        i2c_rdwr_access(fd,
455                        cmsgs.as_mut_ptr(),
456                        cmsgs.len())
457    }
458}
459