| diff -ruN iotools-1.5~/i2c_rw.c iotools-1.5/i2c_rw.c |
| --- iotools-1.5~/i2c_rw.c 1969-12-31 16:00:00.000000000 -0800 |
| +++ iotools-1.5/i2c_rw.c 2017-03-16 09:52:49.386028184 -0700 |
| @@ -0,0 +1,166 @@ |
| +/* |
| + Copyright 2017 Google Inc. |
| + |
| + This program is free software; you can redistribute it and/or |
| + modify it under the terms of the GNU General Public License |
| + as published by the Free Software Foundation; either version 2 |
| + of the License, or (at your option) any later version. |
| + |
| + This program is distributed in the hope that it will be useful, |
| + but WITHOUT ANY WARRANTY; without even the implied warranty of |
| + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| + GNU General Public License for more details. |
| + |
| + You should have received a copy of the GNU General Public License |
| + along with this program; if not, write to the Free Software |
| + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
| +*/ |
| + |
| +#include <errno.h> |
| +#include <fcntl.h> |
| +#include <limits.h> |
| +#include <stdint.h> |
| +#include <stdlib.h> |
| +#include <stdio.h> |
| +#include <string.h> |
| +#include <unistd.h> |
| +#include <sys/ioctl.h> |
| +#include "commands.h" |
| +#include "linux-i2c-dev.h" |
| + |
| +#define I2C_MAX_LEN 32 |
| + |
| +struct i2c_params { |
| + uint8_t i2c_bus; |
| + uint8_t address; |
| + uint8_t read_len; |
| + uint8_t write_len; |
| + uint8_t read_data[I2C_MAX_LEN]; |
| + uint8_t write_data[I2C_MAX_LEN]; |
| +}; |
| + |
| +static int |
| +parse_uint8(const char *arg, uint8_t *ret) |
| +{ |
| + unsigned long ldata; |
| + char *end; |
| + |
| + ldata = strtoul(arg, &end, 0); |
| + if (ldata == LONG_MAX || *end != '\0') { |
| + return -1; |
| + } |
| + *ret = (uint8_t)ldata; |
| + return 0; |
| +} |
| + |
| +static int |
| +i2c_params(int argc, const char *argv[], struct i2c_params *params) |
| +{ |
| + int len, arg = 1; |
| + |
| + memset(params, 0, sizeof(struct i2c_params)); |
| + |
| + if (parse_uint8(argv[arg++], ¶ms->i2c_bus)) { |
| + fprintf(stderr, "invalid adapter value\n"); |
| + return -1; |
| + } |
| + if (parse_uint8(argv[arg++], ¶ms->address)) { |
| + fprintf(stderr, "invalid address value\n"); |
| + return -1; |
| + } |
| + if (parse_uint8(argv[arg++], ¶ms->read_len)) { |
| + fprintf(stderr, "invalid read length value\n"); |
| + return -1; |
| + } |
| + if (params->read_len > I2C_MAX_LEN) { |
| + fprintf(stderr, "invalid read length value %d\n", |
| + params->read_len); |
| + return -1; |
| + } |
| + |
| + /* Data to write */ |
| + for (len = 0; arg < argc; arg++, len++) { |
| + if (parse_uint8(argv[arg], ¶ms->write_data[len])) { |
| + fprintf(stderr, "error parsing write data %d", len); |
| + return -1; |
| + } |
| + } |
| + params->write_len = len; |
| + |
| + return 0; |
| +} |
| + |
| +static int |
| +i2c_xfer(int argc, const char *argv[], const struct cmd_info *info) |
| +{ |
| + int i, ret = 0; |
| + struct i2c_params params; |
| + struct i2c_rdwr_ioctl_data data; |
| + struct i2c_msg msg[2]; |
| + char devfile[15]; |
| + int fd; |
| + |
| + if (i2c_params(argc, argv, ¶ms) < 0) |
| + return -1; |
| + |
| + memset(msg, 0, sizeof(struct i2c_msg) * 2); |
| + memset(&data, 0, sizeof(struct i2c_rdwr_ioctl_data)); |
| + |
| + if (params.write_len > 0) { |
| + /* Write message */ |
| + msg[data.nmsgs].addr = params.address; |
| + msg[data.nmsgs].flags = 0; |
| + msg[data.nmsgs].len = params.write_len; |
| + msg[data.nmsgs].buf = params.write_data; |
| + data.nmsgs++; |
| + } |
| + |
| + if (params.read_len > 0) { |
| + /* Read message */ |
| + msg[data.nmsgs].addr = params.address; |
| + msg[data.nmsgs].flags = I2C_M_RD; |
| + msg[data.nmsgs].len = params.read_len; |
| + msg[data.nmsgs].buf = params.read_data; |
| + data.nmsgs++; |
| + } |
| + |
| + data.msgs = msg; |
| + |
| + /* Open slave device */ |
| + sprintf(devfile, "/dev/i2c-%d", params.i2c_bus); |
| + fd = open(devfile, O_RDWR); |
| + if (fd < 0) { |
| + fprintf(stderr, "Couldn't open i2c device file: %s\n", |
| + strerror(errno)); |
| + return -1; |
| + } |
| + |
| + ret = ioctl(fd, I2C_RDWR, &data); |
| + close(fd); |
| + |
| + if (ret < 0 || ret != data.nmsgs) { |
| + fprintf(stderr, "i2c transfer failed: %s\n", |
| + strerror(errno)); |
| + ret = -1; |
| + } |
| + |
| + /* Print out the read data */ |
| + if (params.read_len > 0) { |
| + for (i = 0; i < params.read_len; i++) { |
| + printf("0x%02x ", params.read_data[i]); |
| + } |
| + printf("\n"); |
| + } |
| + |
| + return ret; |
| +} |
| + |
| +MAKE_PREREQ_PARAMS_VAR_ARGS(i2c_xfer_params, 3, I2C_MAX_LEN + 3, |
| + "<adapter> <address> <read_count> [write bytes...]", 0); |
| + |
| +static const struct cmd_info i2c_cmds[] = { |
| + MAKE_CMD_WITH_PARAMS(i2c_xfer, &i2c_xfer, NULL, &i2c_xfer_params) |
| +}; |
| + |
| +MAKE_CMD_GROUP(I2C, "commands to access I2C devices", i2c_cmds); |
| +REGISTER_CMD_GROUP(I2C); |
| diff -ruN iotools-1.5~/linux-i2c-dev.h iotools-1.5/linux-i2c-dev.h |
| --- iotools-1.5~/linux-i2c-dev.h 2013-04-23 10:01:37.000000000 -0700 |
| +++ iotools-1.5/linux-i2c-dev.h 2017-03-16 09:33:43.519882173 -0700 |
| @@ -38,17 +38,17 @@ |
| */ |
| struct i2c_msg { |
| __u16 addr; /* slave address */ |
| - unsigned short flags; |
| -#define I2C_M_TEN 0x10 /* we have a ten bit chip address */ |
| -#define I2C_M_RD 0x01 |
| -#define I2C_M_NOSTART 0x4000 |
| -#define I2C_M_REV_DIR_ADDR 0x2000 |
| -#define I2C_M_IGNORE_NAK 0x1000 |
| -#define I2C_M_NO_RD_ACK 0x0800 |
| - short len; /* msg length */ |
| - char *buf; /* pointer to msg data */ |
| - int err; |
| - short done; |
| + __u16 flags; |
| +#define I2C_M_TEN 0x0010 /* this is a ten bit chip address */ |
| +#define I2C_M_RD 0x0001 /* read data, from slave to master */ |
| +#define I2C_M_STOP 0x8000 /* if I2C_FUNC_PROTOCOL_MANGLING */ |
| +#define I2C_M_NOSTART 0x4000 /* if I2C_FUNC_NOSTART */ |
| +#define I2C_M_REV_DIR_ADDR 0x2000 /* if I2C_FUNC_PROTOCOL_MANGLING */ |
| +#define I2C_M_IGNORE_NAK 0x1000 /* if I2C_FUNC_PROTOCOL_MANGLING */ |
| +#define I2C_M_NO_RD_ACK 0x0800 /* if I2C_FUNC_PROTOCOL_MANGLING */ |
| +#define I2C_M_RECV_LEN 0x0400 /* length will be first received byte */ |
| + __u16 len; /* msg length */ |
| + __u8 *buf; /* pointer to msg data */ |
| }; |
| |
| /* To determine what functionality is present */ |
| @@ -191,7 +191,7 @@ |
| /* This is the structure as used in the I2C_RDWR ioctl call */ |
| struct i2c_rdwr_ioctl_data { |
| struct i2c_msg *msgs; /* pointers to i2c_msgs */ |
| - int nmsgs; /* number of i2c_msgs */ |
| + __u32 nmsgs; /* number of i2c_msgs */ |
| }; |
| |
| |