i2c_linux_sys/
lib.rs

1//#![deny(missing_docs)]
2#![doc(html_root_url = "https://docs.rs/i2c-linux-sys/0.2.1/")]
3
4#[macro_use]
5extern crate bitflags;
6extern crate byteorder;
7extern crate libc;
8
9use std::{fmt, io, ptr, mem, cmp};
10use std::os::unix::io::RawFd;
11use byteorder::{NativeEndian, ByteOrder};
12use libc::c_int;
13
14bitflags! {
15    pub struct Flags: u16 {
16        /// read data, from slave to master
17        const RD = I2C_M_RD;
18        /// this is a ten bit chip address
19        const TEN = I2C_M_TEN;
20        /// length will be first received byte
21        const RECV_LEN = I2C_M_RECV_LEN;
22        /// if I2C_FUNC_PROTOCOL_MANGLING
23        const NO_RD_ACK = I2C_M_NO_RD_ACK;
24        /// if I2C_FUNC_PROTOCOL_MANGLING
25        const IGNORE_NACK = I2C_M_IGNORE_NAK;
26        /// if I2C_FUNC_PROTOCOL_MANGLING
27        const REV_DIR_ADDR = I2C_M_REV_DIR_ADDR;
28        /// I2C_FUNC_NOSTART
29        const NO_START = I2C_M_NOSTART;
30        /// if I2C_FUNC_PROTOCOL_MANGLING
31        const STOP = I2C_M_STOP;
32    }
33}
34
35/// read data, from slave to master
36pub const I2C_M_RD: u16 = 0x0001;
37/// this is a ten bit chip address
38pub const I2C_M_TEN: u16 = 0x0010;
39/// length will be first received byte
40pub const I2C_M_RECV_LEN: u16 = 0x0400;
41/// if `I2C_FUNC_PROTOCOL_MANGLING`
42pub const I2C_M_NO_RD_ACK: u16 = 0x0800;
43/// if `I2C_FUNC_PROTOCOL_MANGLING`
44pub const I2C_M_IGNORE_NAK: u16 = 0x1000;
45/// if `I2C_FUNC_PROTOCOL_MANGLING`
46pub const I2C_M_REV_DIR_ADDR: u16 = 0x2000;
47/// if `I2C_FUNC_NOSTART`
48pub const I2C_M_NOSTART: u16 = 0x4000;
49/// if `I2C_FUNC_PROTOCOL_MANGLING`
50pub const I2C_M_STOP: u16 = 0x8000;
51
52bitflags! {
53    /// To determine what functionality is present
54    pub struct Functionality: u32 {
55        /// Plain i2c-level commands (`I2C_RDWR`)
56        ///
57        /// Pure SMBus adapters typically can not do these.
58        const I2C = I2C_FUNC_I2C;
59        /// Handles the 10-bit address extensions
60        const TENBIT_ADDR = I2C_FUNC_10BIT_ADDR;
61        /// I2C_M_IGNORE_NAK etc.
62        const PROTOCOL_MANGLING = I2C_FUNC_PROTOCOL_MANGLING;
63        const SMBUS_PEC = I2C_FUNC_SMBUS_PEC;
64        /// I2C_M_NOSTART
65        const NO_START = I2C_FUNC_NOSTART;
66        const SLAVE = I2C_FUNC_SLAVE;
67        /// SMBus 2.0
68        const SMBUS_BLOCK_PROC_CALL = I2C_FUNC_SMBUS_BLOCK_PROC_CALL;
69        const SMBUS_QUICK = I2C_FUNC_SMBUS_QUICK;
70        const SMBUS_READ_BYTE = I2C_FUNC_SMBUS_READ_BYTE;
71        const SMBUS_WRITE_BYTE = I2C_FUNC_SMBUS_WRITE_BYTE;
72        const SMBUS_READ_BYTE_DATA = I2C_FUNC_SMBUS_READ_BYTE_DATA;
73        const SMBUS_WRITE_BYTE_DATA = I2C_FUNC_SMBUS_WRITE_BYTE_DATA;
74        const SMBUS_READ_WORD_DATA = I2C_FUNC_SMBUS_READ_WORD_DATA;
75        const SMBUS_WRITE_WORD_DATA = I2C_FUNC_SMBUS_WRITE_WORD_DATA;
76        const SMBUS_PROC_CALL = I2C_FUNC_SMBUS_PROC_CALL;
77        const SMBUS_READ_BLOCK_DATA = I2C_FUNC_SMBUS_READ_BLOCK_DATA;
78        const SMBUS_WRITE_BLOCK_DATA = I2C_FUNC_SMBUS_WRITE_BLOCK_DATA;
79        /// I2C-like block xfer
80        const SMBUS_READ_I2C_BLOCK = I2C_FUNC_SMBUS_READ_I2C_BLOCK;
81        /// w/ 1-byte reg. addr.
82        const SMBUS_WRITE_I2C_BLOCK = I2C_FUNC_SMBUS_WRITE_I2C_BLOCK;
83        const SMBUS_HOST_NOTIFY = I2C_FUNC_SMBUS_HOST_NOTIFY;
84
85        const SMBUS_BYTE = I2C_FUNC_SMBUS_BYTE;
86        const SMBUS_BYTE_DATA = I2C_FUNC_SMBUS_BYTE_DATA;
87        const SMBUS_WORD_DATA = I2C_FUNC_SMBUS_WORD_DATA;
88        const SMBUS_BLOCK_DATA = I2C_FUNC_SMBUS_BLOCK_DATA;
89        const SMBUS_I2C_BLOCK = I2C_FUNC_SMBUS_I2C_BLOCK;
90
91        const SMBUS_EMUL = I2C_FUNC_SMBUS_EMUL;
92    }
93}
94
95pub const I2C_FUNC_I2C: u32 = 0x00000001;
96pub const I2C_FUNC_10BIT_ADDR: u32 = 0x00000002;
97/// `I2C_M_IGNORE_NAK` etc.
98pub const I2C_FUNC_PROTOCOL_MANGLING: u32 = 0x00000004;
99pub const I2C_FUNC_SMBUS_PEC: u32 = 0x00000008;
100/// `I2C_M_NOSTART`
101pub const I2C_FUNC_NOSTART: u32 = 0x00000010;
102pub const I2C_FUNC_SLAVE: u32 = 0x00000020;
103
104/// SMBus 2.0
105pub const I2C_FUNC_SMBUS_BLOCK_PROC_CALL: u32 = 0x00008000;
106pub const I2C_FUNC_SMBUS_QUICK: u32 = 0x00010000;
107pub const I2C_FUNC_SMBUS_READ_BYTE: u32 = 0x00020000;
108pub const I2C_FUNC_SMBUS_WRITE_BYTE: u32 = 0x00040000;
109pub const I2C_FUNC_SMBUS_READ_BYTE_DATA: u32 = 0x00080000;
110pub const I2C_FUNC_SMBUS_WRITE_BYTE_DATA: u32 = 0x00100000;
111pub const I2C_FUNC_SMBUS_READ_WORD_DATA: u32 = 0x00200000;
112pub const I2C_FUNC_SMBUS_WRITE_WORD_DATA: u32 = 0x00400000;
113pub const I2C_FUNC_SMBUS_PROC_CALL: u32 = 0x00800000;
114pub const I2C_FUNC_SMBUS_READ_BLOCK_DATA: u32 = 0x01000000;
115pub const I2C_FUNC_SMBUS_WRITE_BLOCK_DATA: u32 = 0x02000000;
116/// I2C-like block xfer
117pub const I2C_FUNC_SMBUS_READ_I2C_BLOCK: u32 = 0x04000000;
118/// w/ 1-byte reg. addr.
119pub const I2C_FUNC_SMBUS_WRITE_I2C_BLOCK: u32 = 0x08000000;
120pub const I2C_FUNC_SMBUS_HOST_NOTIFY: u32 = 0x10000000;
121
122pub const I2C_FUNC_SMBUS_BYTE: u32 = I2C_FUNC_SMBUS_READ_BYTE | I2C_FUNC_SMBUS_WRITE_BYTE;
123pub const I2C_FUNC_SMBUS_BYTE_DATA: u32 = I2C_FUNC_SMBUS_READ_BYTE_DATA | I2C_FUNC_SMBUS_WRITE_BYTE_DATA;
124pub const I2C_FUNC_SMBUS_WORD_DATA: u32 = I2C_FUNC_SMBUS_READ_WORD_DATA | I2C_FUNC_SMBUS_WRITE_WORD_DATA;
125pub const I2C_FUNC_SMBUS_BLOCK_DATA: u32 = I2C_FUNC_SMBUS_READ_BLOCK_DATA | I2C_FUNC_SMBUS_WRITE_BLOCK_DATA;
126pub const I2C_FUNC_SMBUS_I2C_BLOCK: u32 = I2C_FUNC_SMBUS_READ_I2C_BLOCK | I2C_FUNC_SMBUS_WRITE_I2C_BLOCK;
127
128pub const I2C_FUNC_SMBUS_EMUL: u32 = I2C_FUNC_SMBUS_QUICK |
129    I2C_FUNC_SMBUS_BYTE | I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
130    I2C_FUNC_SMBUS_PROC_CALL |
131    I2C_FUNC_SMBUS_WRITE_BLOCK_DATA | I2C_FUNC_SMBUS_I2C_BLOCK |
132    I2C_FUNC_SMBUS_PEC;
133
134/// `i2c_smbus_xfer` read or write markers
135#[derive(Copy, Clone, Debug, PartialOrd, Ord, PartialEq, Eq, Hash)]
136#[repr(u8)]
137pub enum SmbusReadWrite {
138    Read = 1,
139    Write = 0,
140}
141
142pub const I2C_SMBUS_READ: SmbusReadWrite = SmbusReadWrite::Read;
143pub const I2C_SMBUS_WRITE: SmbusReadWrite = SmbusReadWrite::Write;
144
145/// SMBus transaction types (size parameter in the above functions)
146///
147/// Note: these no longer correspond to the (arbitrary) PIIX4 internal codes!
148#[derive(Copy, Clone, Debug, PartialOrd, Ord, PartialEq, Eq, Hash)]
149#[repr(u32)]
150pub enum SmbusTransaction {
151    Quick = I2C_SMBUS_QUICK,
152    Byte = I2C_SMBUS_BYTE,
153    ByteData = I2C_SMBUS_BYTE_DATA,
154    WordData = I2C_SMBUS_WORD_DATA,
155    ProcCall = I2C_SMBUS_PROC_CALL,
156    BlockData = I2C_SMBUS_BLOCK_DATA,
157    I2cBlockBroken = I2C_SMBUS_I2C_BLOCK_BROKEN,
158    /// SMBus 2.0
159    BlockProcCall = I2C_SMBUS_BLOCK_PROC_CALL,
160    I2cBlockData = I2C_SMBUS_I2C_BLOCK_DATA,
161}
162
163pub const I2C_SMBUS_QUICK: u32 = 0;
164pub const I2C_SMBUS_BYTE: u32 = 1;
165pub const I2C_SMBUS_BYTE_DATA: u32 = 2;
166pub const I2C_SMBUS_WORD_DATA: u32 = 3;
167pub const I2C_SMBUS_PROC_CALL: u32 = 4;
168pub const I2C_SMBUS_BLOCK_DATA: u32 = 5;
169pub const I2C_SMBUS_I2C_BLOCK_BROKEN: u32 = 6;
170/// SMBus 2.0
171pub const I2C_SMBUS_BLOCK_PROC_CALL: u32 = 7;
172pub const I2C_SMBUS_I2C_BLOCK_DATA: u32 = 8;
173
174/// As specified in SMBus standard
175pub const I2C_SMBUS_BLOCK_MAX: usize = 32;
176
177#[repr(C)]
178#[derive(Copy, Clone, Debug)]
179/// an I2C transaction segment beginning with START
180///
181/// An i2c_msg is the low level representation of one segment of an I2C
182/// transaction. It is visible to drivers in the `i2c_transfer()` procedure,
183/// to userspace from i2c-dev, and to I2C adapter drivers through the
184/// `i2c_adapter.master_xfer()` method.
185///
186/// Except when I2C "protocol mangling" is used, all I2C adapters implement
187/// the standard rules for I2C transactions. Each transaction begins with a
188/// START. That is followed by the slave address, and a bit encoding read
189/// versus write. Then follow all the data bytes, possibly including a byte
190/// with SMBus PEC. The transfer terminates with a NAK, or when all those
191/// bytes have been transferred and ACKed. If this is the last message in a
192/// group, it is followed by a STOP. Otherwise it is followed by the next
193/// `i2c_msg` transaction segment, beginning with a (repeated) START.
194///
195/// Alternatively, when the adapter supports `I2C_FUNC_PROTOCOL_MANGLING` then
196/// passing certain `flags` may have changed those standard protocol behaviors.
197/// Those flags are only for use with broken/nonconforming slaves, and with
198/// adapters which are known to support the specific mangling options they
199/// need (one or more of `IGNORE_NACK`, `NO_RD_ACK`, `NOSTART`, and `REV_DIR_ADDR`).
200pub struct i2c_msg {
201    /// Slave address, either seven or ten bits.
202    ///
203    /// When this is a ten
204    /// bit address, `I2C_M_TEN` must be set in `flags` and the adapter
205    /// must support `I2C_FUNC_10BIT_ADDR`.
206    pub addr: u16,
207    /// `I2C_M_RD` is handled by all adapters.
208    ///
209    /// No other flags may be
210    /// provided unless the adapter exported the relevant `I2C_FUNC_*`
211    /// flags through `i2c_get_functionality()`.
212    pub flags: Flags,
213    /// Number of data bytes in `buf` being read from or written to the
214    /// I2C slave address.
215    ///
216    /// For read transactions where `I2C_M_RECV_LEN`
217    /// is set, the caller guarantees that this buffer can hold up to
218    /// 32 bytes in addition to the initial length byte sent by the
219    /// slave (plus, if used, the SMBus PEC); and this value will be
220    /// incremented by the number of block data bytes received.
221    pub len: u16,
222    /// The buffer into which data is read, or from which it's written.
223    pub buf: *mut u8,
224}
225
226#[repr(C)]
227#[derive(Copy, Clone, Debug)]
228/// This is the structure as used in the `I2C_RDWR` ioctl call
229pub struct i2c_rdwr_ioctl_data {
230    /// ptr to array of simple messages
231    pub msgs: *mut i2c_msg,
232    /// number of messages to exchange
233    pub nmsgs: c_int,
234}
235
236#[repr(C)]
237#[derive(Copy, Clone)]
238/// Data for SMBus Messages
239pub struct i2c_smbus_data {
240    _alignment: [u16; 0],
241    /// `block[0]` is used for length and one more for user-space compatibility
242    pub block: [u8; I2C_SMBUS_BLOCK_MAX + 2],
243}
244
245impl i2c_smbus_data {
246    pub fn from_byte(v: u8) -> Self {
247        let mut data = Self::default();
248        data.set_byte(v);
249        data
250    }
251
252    pub fn from_word(v: u16) -> Self {
253        let mut data = Self::default();
254        data.set_word(v);
255        data
256    }
257
258    pub fn from_block(v: &[u8]) -> Self {
259        let mut data = Self::default();
260        data.set_block(v);
261        data
262    }
263
264    pub fn byte(&self) -> u8 {
265        self.block[0]
266    }
267
268    pub fn set_byte(&mut self, v: u8) {
269        self.block[0] = v;
270    }
271
272    pub fn word(&self) -> u16 {
273        NativeEndian::read_u16(&self.block[..2])
274    }
275
276    pub fn set_word(&mut self, v: u16) {
277        NativeEndian::write_u16(&mut self.block[..2], v)
278    }
279
280    pub fn block(&self) -> Option<&[u8]> {
281        let len = self.block[0] as usize;
282        if len <= I2C_SMBUS_BLOCK_MAX {
283            Some(&self.block[1..1 + len])
284        } else {
285            None
286        }
287    }
288
289    pub fn block_mut(&mut self) -> Option<&mut [u8]> {
290        let len = self.block[0] as usize;
291        if len <= I2C_SMBUS_BLOCK_MAX {
292            Some(&mut self.block[1..1 + len])
293        } else {
294            None
295        }
296    }
297
298    pub fn set_block(&mut self, v: &[u8]) {
299        assert!(v.len() <= I2C_SMBUS_BLOCK_MAX);
300
301        self.block[0] = v.len() as u8;
302        self.block[1..1 + v.len()].copy_from_slice(v);
303    }
304}
305
306impl fmt::Debug for i2c_smbus_data {
307    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
308        f.debug_struct("i2c_smbus_data")
309            .field("byte", &self.byte())
310            .field("word", &self.word())
311            .field("block", &self.block())
312            .finish()
313    }
314}
315
316impl Default for i2c_smbus_data {
317    fn default() -> Self {
318        unsafe { mem::zeroed() }
319    }
320}
321
322#[repr(C)]
323#[derive(Copy, Clone, Debug)]
324/// This is the structure as used in the I2C_SMBUS ioctl call
325pub struct i2c_smbus_ioctl_data {
326    pub read_write: SmbusReadWrite,
327    pub command: u8,
328    pub size: SmbusTransaction,
329    pub data: *mut i2c_smbus_data,
330}
331
332/// number of times a device address should be polled when not acknowledging
333pub const I2C_RETRIES: u16 = 0x0701;
334/// set timeout in units of 10 ms
335pub const I2C_TIMEOUT: u16 = 0x0702;
336
337/// Use this slave address
338///
339/// NOTE: Slave address is 7 or 10 bits, but 10-bit addresses
340/// are NOT supported! (due to code brokenness)
341pub const I2C_SLAVE: u16 = 0x0703;
342/// Use this slave address, even if it is already in use by a driver!
343pub const I2C_SLAVE_FORCE: u16 = 0x0706;
344/// 0 for 7 bit addrs, != 0 for 10 bit
345pub const I2C_TENBIT: u16 = 0x0704;
346
347/// Get the adapter functionality mask
348pub const I2C_FUNCS: u16 = 0x0705;
349
350/// Combined R/W transfer (one STOP only)
351pub const I2C_RDWR: u16 = 0x0707;
352
353/// != 0 to use PEC with SMBus
354pub const I2C_PEC: u16 = 0x0708;
355/// SMBus transfer
356pub const I2C_SMBUS: u16 = 0x0720;
357
358pub const I2C_RDWR_IOCTL_MAX_MSGS: usize = 42;
359
360pub mod ioctls {
361    use libc::{ioctl, c_int, c_ulong};
362    use std::os::unix::io::RawFd;
363    use std::io;
364
365    #[inline]
366    fn ioctl_result(res: c_int) -> io::Result<c_int> {
367        if res == -1 {
368            Err(io::Error::last_os_error())
369        } else {
370            Ok(res)
371        }
372    }
373
374    pub unsafe fn i2c_retries(fd: RawFd, value: c_int) -> io::Result<c_int> {
375        ioctl_result(ioctl(fd, super::I2C_RETRIES as _, value))
376    }
377
378    pub unsafe fn i2c_timeout(fd: RawFd, value: c_int) -> io::Result<c_int> {
379        ioctl_result(ioctl(fd, super::I2C_TIMEOUT as _, value))
380    }
381
382    pub unsafe fn i2c_slave(fd: RawFd, value: c_int) -> io::Result<c_int> {
383        ioctl_result(ioctl(fd, super::I2C_SLAVE as _, value))
384    }
385
386    pub unsafe fn i2c_slave_force(fd: RawFd, value: c_int) -> io::Result<c_int> {
387        ioctl_result(ioctl(fd, super::I2C_SLAVE_FORCE as _, value))
388    }
389
390    pub unsafe fn i2c_tenbit(fd: RawFd, value: c_int) -> io::Result<c_int> {
391        ioctl_result(ioctl(fd, super::I2C_TENBIT as _, value))
392    }
393
394    pub unsafe fn i2c_funcs(fd: RawFd, value: *mut c_ulong) -> io::Result<c_int> {
395        ioctl_result(ioctl(fd, super::I2C_FUNCS as _, value))
396    }
397
398    pub unsafe fn i2c_rdwr(fd: RawFd, value: *mut super::i2c_rdwr_ioctl_data) -> io::Result<c_int> {
399        ioctl_result(ioctl(fd, super::I2C_RDWR as _, value))
400    }
401
402    pub unsafe fn i2c_pec(fd: RawFd, value: c_int) -> io::Result<c_int> {
403        ioctl_result(ioctl(fd, super::I2C_PEC as _, value))
404    }
405
406    pub unsafe fn i2c_smbus(fd: RawFd, value: *mut super::i2c_smbus_ioctl_data) -> io::Result<c_int> {
407        ioctl_result(ioctl(fd, super::I2C_SMBUS as _, value))
408    }
409}
410
411/// `I2C_RETRIES`
412#[inline]
413pub fn i2c_set_retries(fd: RawFd, value: usize) -> io::Result<()> {
414    unsafe {
415        ioctls::i2c_retries(fd, value as _).map(drop)
416    }
417}
418
419/// `I2C_TIMEOUT`
420#[inline]
421pub fn i2c_set_timeout_ms(fd: RawFd, value: usize) -> io::Result<()> {
422    unsafe {
423        ioctls::i2c_timeout(fd, (value / 10) as _).map(drop)
424    }
425}
426
427/// `I2C_SLAVE` and `I2C_SLAVE_FORCE`
428#[inline]
429pub fn i2c_set_slave_address(fd: RawFd, address: u16, force: bool) -> io::Result<()> {
430    unsafe {
431        if force {
432            ioctls::i2c_slave(fd, address as _)
433        } else {
434            ioctls::i2c_slave_force(fd, address as _)
435        }.map(drop)
436    }
437}
438
439/// `I2C_TENBIT`
440#[inline]
441pub fn i2c_set_slave_address_10bit(fd: RawFd, tenbit: bool) -> io::Result<()> {
442    unsafe {
443        ioctls::i2c_tenbit(fd, if tenbit { 1 } else { 0 }).map(drop)
444    }
445}
446
447/// `I2C_FUNCS`
448#[inline]
449pub fn i2c_get_functionality(fd: RawFd) -> io::Result<Functionality> {
450    unsafe {
451        let mut res = 0;
452        ioctls::i2c_funcs(fd, &mut res)
453            .map(|_| Functionality::from_bits_truncate(res as _))
454    }
455}
456
457/// `I2C_PEC`
458#[inline]
459pub fn i2c_pec(fd: RawFd, pec: bool) -> io::Result<()> {
460    unsafe {
461        ioctls::i2c_pec(fd, if pec { 1 } else { 0 }).map(drop)
462    }
463}
464
465/// `I2C_RDWR`
466#[inline]
467pub unsafe fn i2c_rdwr(fd: RawFd, msgs: &mut [i2c_msg]) -> io::Result<()> {
468    let mut data = i2c_rdwr_ioctl_data {
469        msgs: msgs.as_mut_ptr(),
470        nmsgs: msgs.len() as _,
471    };
472    ioctls::i2c_rdwr(fd, &mut data).map(drop)
473}
474
475/// `I2C_SMBUS`
476#[inline]
477pub unsafe fn i2c_smbus(fd: RawFd, data: &mut i2c_smbus_ioctl_data) -> io::Result<()> {
478    ioctls::i2c_smbus(fd, data).map(drop)
479}
480
481pub fn i2c_smbus_write_quick(fd: RawFd, value: SmbusReadWrite) -> io::Result<()> {
482    unsafe {
483        i2c_smbus(fd, &mut i2c_smbus_ioctl_data {
484            read_write: value,
485            command: 0,
486            size: SmbusTransaction::Quick,
487            data: ptr::null_mut(),
488        })
489    }
490}
491
492pub fn i2c_smbus_read_byte(fd: RawFd) -> io::Result<u8> {
493    unsafe {
494        let mut data = i2c_smbus_data::default();
495        let mut ioctl = i2c_smbus_ioctl_data {
496            read_write: SmbusReadWrite::Read,
497            command: 0,
498            size: SmbusTransaction::Byte,
499            data: &mut data,
500        };
501        i2c_smbus(fd, &mut ioctl)
502            .map(|_| data.byte())
503    }
504}
505
506pub fn i2c_smbus_write_byte(fd: RawFd, value: u8) -> io::Result<()> {
507    unsafe {
508        let mut ioctl = i2c_smbus_ioctl_data {
509            read_write: SmbusReadWrite::Write,
510            command: value,
511            size: SmbusTransaction::Byte,
512            data: ptr::null_mut(),
513        };
514        i2c_smbus(fd, &mut ioctl)
515    }
516}
517
518pub fn i2c_smbus_read_byte_data(fd: RawFd, command: u8) -> io::Result<u8> {
519    unsafe {
520        let mut data = i2c_smbus_data::default();
521        let mut ioctl = i2c_smbus_ioctl_data {
522            read_write: SmbusReadWrite::Read,
523            command: command,
524            size: SmbusTransaction::ByteData,
525            data: &mut data,
526        };
527        i2c_smbus(fd, &mut ioctl)
528            .map(|_| data.byte())
529    }
530}
531
532pub fn i2c_smbus_write_byte_data(fd: RawFd, command: u8, value: u8) -> io::Result<()> {
533    unsafe {
534        let mut data = i2c_smbus_data::from_byte(value);
535        let mut ioctl = i2c_smbus_ioctl_data {
536            read_write: SmbusReadWrite::Write,
537            command: command,
538            size: SmbusTransaction::ByteData,
539            data: &mut data,
540        };
541        i2c_smbus(fd, &mut ioctl)
542    }
543}
544
545pub fn i2c_smbus_read_word_data(fd: RawFd, command: u8) -> io::Result<u16> {
546    unsafe {
547        let mut data = i2c_smbus_data::default();
548        let mut ioctl = i2c_smbus_ioctl_data {
549            read_write: SmbusReadWrite::Read,
550            command: command,
551            size: SmbusTransaction::WordData,
552            data: &mut data,
553        };
554        i2c_smbus(fd, &mut ioctl)
555            .map(|_| data.word())
556    }
557}
558
559pub fn i2c_smbus_write_word_data(fd: RawFd, command: u8, value: u16) -> io::Result<()> {
560    unsafe {
561        let mut data = i2c_smbus_data::from_word(value);
562        let mut ioctl = i2c_smbus_ioctl_data {
563            read_write: SmbusReadWrite::Write,
564            command: command,
565            size: SmbusTransaction::WordData,
566            data: &mut data,
567        };
568        i2c_smbus(fd, &mut ioctl)
569    }
570}
571
572pub fn i2c_smbus_process_call(fd: RawFd, command: u8, value: u16) -> io::Result<u16> {
573    unsafe {
574        let mut data = i2c_smbus_data::from_word(value);
575        let mut ioctl = i2c_smbus_ioctl_data {
576            read_write: SmbusReadWrite::Write,
577            command: command,
578            size: SmbusTransaction::ProcCall,
579            data: &mut data,
580        };
581        i2c_smbus(fd, &mut ioctl)
582            .map(|_| data.word())
583    }
584}
585
586pub fn i2c_smbus_read_block_data(fd: RawFd, command: u8, value: &mut [u8]) -> io::Result<usize> {
587    unsafe {
588        let mut data = i2c_smbus_data::default();
589        let mut ioctl = i2c_smbus_ioctl_data {
590            read_write: SmbusReadWrite::Read,
591            command: command,
592            size: SmbusTransaction::BlockData,
593            data: &mut data,
594        };
595        i2c_smbus(fd, &mut ioctl)
596            .map(|_| {
597                let block = data.block().expect("kernel provided an invalid block length");
598                let len = cmp::min(block.len(), value.len());
599                value[..len].copy_from_slice(&block[..len]);
600                block.len()
601            })
602    }
603}
604
605pub fn i2c_smbus_write_block_data(fd: RawFd, command: u8, value: &[u8]) -> io::Result<()> {
606    unsafe {
607        let mut data = i2c_smbus_data::from_block(value);
608        let mut ioctl = i2c_smbus_ioctl_data {
609            read_write: SmbusReadWrite::Write,
610            command: command,
611            size: SmbusTransaction::BlockData,
612            data: &mut data,
613        };
614        i2c_smbus(fd, &mut ioctl)
615    }
616}
617
618pub fn i2c_smbus_read_i2c_block_data(fd: RawFd, command: u8, value: &mut [u8]) -> io::Result<usize> {
619    assert!(value.len() <= I2C_SMBUS_BLOCK_MAX);
620
621    unsafe {
622        let mut data = i2c_smbus_data::from_byte(value.len() as u8);
623        let mut ioctl = i2c_smbus_ioctl_data {
624            read_write: SmbusReadWrite::Read,
625            command: command,
626            size: if value.len() == I2C_SMBUS_BLOCK_MAX { SmbusTransaction::I2cBlockBroken } else { SmbusTransaction::I2cBlockData },
627            data: &mut data,
628        };
629        i2c_smbus(fd, &mut ioctl)
630            .map(|_| {
631                let block = data.block().expect("kernel provided an invalid block length");
632                let len = cmp::min(block.len(), value.len());
633                value[..len].copy_from_slice(&block[..len]);
634                block.len()
635            })
636    }
637}
638
639pub fn i2c_smbus_write_i2c_block_data(fd: RawFd, command: u8, value: &[u8]) -> io::Result<()> {
640    unsafe {
641        let mut data = i2c_smbus_data::from_block(value);
642        let mut ioctl = i2c_smbus_ioctl_data {
643            read_write: SmbusReadWrite::Write,
644            command: command,
645            size: SmbusTransaction::I2cBlockBroken,
646            data: &mut data,
647        };
648        i2c_smbus(fd, &mut ioctl)
649    }
650}
651
652pub fn i2c_smbus_block_process_call(fd: RawFd, command: u8, write: &[u8], read: &mut [u8]) -> io::Result<usize> {
653    assert!(read.len() <= I2C_SMBUS_BLOCK_MAX - 1);
654
655    unsafe {
656        let mut data = i2c_smbus_data::from_block(write);
657        let mut ioctl = i2c_smbus_ioctl_data {
658            read_write: SmbusReadWrite::Write,
659            command: command,
660            size: SmbusTransaction::BlockProcCall,
661            data: &mut data,
662        };
663        i2c_smbus(fd, &mut ioctl)
664            .map(|_| {
665                let block = data.block().expect("kernel provided an invalid block length");
666                let len = cmp::min(block.len(), read.len());
667                read[..len].copy_from_slice(&block[..len]);
668                block.len()
669            })
670    }
671}