blob: 4bb2d32c052bb2ef65cf930fba57480669bc4259 [file] [log] [blame]
diff -aruN i2c-tools-3.1.2/tools/i2cgetwide.8 i2c-tools-3.1.2.N/tools/i2cgetwide.8
--- i2c-tools-3.1.2/tools/i2cgetwide.8 1969-12-31 16:00:00.000000000 -0800
+++ i2c-tools-3.1.2.N/tools/i2cgetwide.8 2016-03-21 14:39:29.584650609 -0700
@@ -0,0 +1,68 @@
+.TH I2CGETWIDE 8 "March 2016"
+.SH "NAME"
+i2cgetwide \- read from I2C chip registers of arbitrary data/address length
+
+.SH SYNOPSIS
+.B i2cgetwide
+.RB [ -f ]
+.RB [ -y ]
+.I i2cbus
+.I chip-address
+.I data-address-length
+.I data-address
+.I data-length
+.br
+.B i2cgetwide
+.B -V
+
+.SH DESCRIPTION
+i2cgetwide is a small helper program to read registers visible through the I2C
+bus. This should be used for registers whose addresses are greater than 1 byte
+and register value is greater than 1 byte.
+
+.SH OPTIONS
+.TP
+.B -V
+Display the version and exit.
+.TP
+.B -f
+Force access to the device even if it is already busy. By default, i2cgetwide
+will refuse to access a device which is already under the control of a
+kernel driver. Using this flag is dangerous, it can seriously confuse the
+kernel driver in question. It can also cause i2cgetwide to return an invalid
+value. So use at your own risk and only if you know what you're doing.
+.TP
+.B -y
+Disable interactive mode. By default, i2cgetwide will wait for a confirmation
+from the user before messing with the I2C bus. When this flag is used, it
+will perform the operation directly. This is mainly meant to be used in
+scripts. Use with caution.
+.PP
+There are five required options to i2cgetwide. \fIi2cbus\fR indicates the number
+or name of the I2C bus to be scanned. This number should correspond to one of
+the busses listed by \fIi2cdetect -l\fR. \fIchip-address\fR specifies the
+address of the chip on that bus, and is an integer between 0x03 and 0x77.
+.PP
+\fIdata-address-length\fR specifies the length of the address of the register
+on that chip.
+.PP
+\fIdata-length\fR specifies the length of the value of the register
+on that chip.
+.PP
+\fIdata-address\fR specifies the address on that chip to read from, and it is a
+list of length \fIdata-address-length\fR.
+
+.SH WARNING
+i2cgetwide can be extremely dangerous if used improperly. I2C and SMBus are designed
+in such a way that an SMBus read transaction can be seen as a write transaction by
+certain chips. This is particularly true if setting \fImode\fR to \fBcp\fP (write byte/read
+byte with PEC). Be extremely careful using this program.
+
+.SH SEE ALSO
+i2cdump(8), i2cset(8) i2cget(8)
+
+.SH AUTHOR
+Renga Aravamudhan
+
+This manual page was strongly inspired from those written by Jean Delvare
+for i2cget.
diff -aruN i2c-tools-3.1.2/tools/i2cgetwide.c i2c-tools-3.1.2.N/tools/i2cgetwide.c
--- i2c-tools-3.1.2/tools/i2cgetwide.c 1969-12-31 16:00:00.000000000 -0800
+++ i2c-tools-3.1.2.N/tools/i2cgetwide.c 2016-03-22 16:35:55.809045663 -0700
@@ -0,0 +1,192 @@
+/*
+ i2cgetwide.c - A user-space program to read a wide I2C register.
+
+ Based on i2cget.c:
+ Copyright (C) 2001-2003 Frodo Looijaard <frodol@dds.nl>, and
+ Mark D. Studebaker <mdsxyz123@yahoo.com>
+ Copyright (C) 2004-2005 Jean Delvare
+ Copyright (C) 2005-2012 Jean Delvare <jdelvare@suse.de>
+
+ 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 <sys/ioctl.h>
+#include <errno.h>
+#include <stdint.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <linux/i2c-dev.h>
+#include "i2cbusses.h"
+#include "util.h"
+#include "../version.h"
+
+static void help(void) __attribute__ ((noreturn));
+
+static void help(void)
+{
+ fprintf(stderr,
+ "Usage: i2cgetwide [-f] [-y] [-V] I2CBUS CHIP-ADDRESS DATA-ADDRESS-LENGTH DATA-LENGTH DATA_ADDRESS\n"
+ " I2CBUS is an integer or an I2C bus name\n"
+ " CHIP-ADDRESS is an integer (0x03 - 0x77)\n"
+ " DATA-ADDRESS-LENGTH is the length of register address in bytes\n"
+ " DATA-LENGTH is the length of the register content in bytes\n"
+ " DATA-ADDRESS is the register address is specified as a list of DATA-ADDRESS-LENGTH bytes\n");
+ exit(1);
+}
+
+static int confirm(const char *filename, int address)
+{
+ int dont = 0;
+
+ fprintf(stderr, "WARNING! This program can confuse your I2C "
+ "bus, cause data loss and worse!\n");
+
+ fprintf(stderr, "I will read from device file %s, chip "
+ "address 0x%02x, ", filename, address);
+
+ fprintf(stderr, "Continue? [Y/n] ");
+ fflush(stderr);
+ if (!user_ack(!dont)) {
+ fprintf(stderr, "Aborting on user request.\n");
+ return 0;
+ }
+
+ return 1;
+}
+
+static __s32 i2c_rdwr_read(int file, __u16 address,
+ void *reg, size_t reg_size,
+ void *buf, size_t count)
+{
+ struct i2c_rdwr_ioctl_data args;
+ struct i2c_msg xfer[2];
+
+ xfer[0].addr = address;
+ xfer[0].flags = 0;
+ xfer[0].buf = reg;
+ xfer[0].len = reg_size;
+
+ xfer[1].addr = address;
+ xfer[1].flags = I2C_M_RD;
+ xfer[1].buf = buf;
+ xfer[1].len = count;
+
+ args.msgs = xfer;
+ args.nmsgs = 2;
+
+ return ioctl(file,I2C_RDWR,&args);
+}
+
+int main(int argc, char *argv[])
+{
+ int res, i2cbus, address, file;
+ int daddress_length, data_length, i;
+ char *end;
+ unsigned char daddress[I2C_SMBUS_I2C_BLOCK_MAX], data[I2C_SMBUS_I2C_BLOCK_MAX];
+ char filename[20];
+ int flags = 0;
+ int force = 0, yes = 0, version = 0;
+
+ /* handle (optional) flags first */
+ while (1+flags < argc && argv[1+flags][0] == '-') {
+ switch (argv[1+flags][1]) {
+ case 'V': version = 1; break;
+ case 'f': force = 1; break;
+ case 'y': yes = 1; break;
+ default:
+ fprintf(stderr, "Error: Unsupported option "
+ "\"%s\"!\n", argv[1+flags]);
+ help();
+ exit(1);
+ }
+ flags++;
+ }
+
+ if (version) {
+ fprintf(stderr, "i2cgetwide version %s\n", VERSION);
+ exit(0);
+ }
+
+ if (argc < flags + 5)
+ help();
+
+ i2cbus = lookup_i2c_bus(argv[flags+1]);
+ if (i2cbus < 0)
+ help();
+
+ address = parse_i2c_address(argv[flags+2]);
+ if (address < 0)
+ help();
+
+ daddress_length = strtol(argv[flags+3], &end, 0);
+ if (*end) {
+ fprintf(stderr, "Error in register address length\n");
+ help();
+ }
+ if ( (daddress_length <= 0) || (daddress_length > 4) ) {
+ fprintf(stderr, "Register address length cannot be <=0 or >4 \n");
+ help();
+ }
+
+ data_length = strtol(argv[flags+4], &end, 0);
+ if (*end) {
+ fprintf(stderr, "Error in data length\n");
+ help();
+ }
+ if ( (data_length <= 0) || (data_length > 4) ) {
+ fprintf(stderr, "Register data length cannot be <=0 or >4 \n");
+ help();
+ }
+
+ if (argc < flags + 5 + daddress_length) {
+ fprintf(stderr, "Error in register address \n");
+ help();
+ }
+
+ for(i = 0; i < daddress_length; i++) {
+ daddress[i] = strtol(argv[flags+5+i], &end, 0);
+ if (*end) {
+ fprintf(stderr, "Error in register address\n");
+ help();
+ }
+ }
+
+ file = open_i2c_dev(i2cbus, filename, sizeof(filename), 0);
+ if (file < 0
+ || set_slave_addr(file, address, force))
+ exit(1);
+
+ if (!yes && !confirm(filename, address))
+ exit(0);
+
+ res = i2c_rdwr_read(file, address, daddress, daddress_length,
+ data, data_length);
+ close(file);
+
+ if (res < 0) {
+ fprintf(stderr, "Error: Read failed\n");
+ exit(2);
+ }
+
+ printf("0x");
+ for(i = 0; i < data_length; i++)
+ printf("%02x", data[i]);
+ printf("\n");
+
+ exit(0);
+}
diff -aruN i2c-tools-3.1.2/tools/Module.mk i2c-tools-3.1.2.N/tools/Module.mk
--- i2c-tools-3.1.2/tools/Module.mk 2014-02-20 00:37:15.711233000 -0800
+++ i2c-tools-3.1.2.N/tools/Module.mk 2016-03-21 14:39:29.584650609 -0700
@@ -13,7 +13,7 @@
-Wcast-align -Wwrite-strings -Wnested-externs -Winline \
-W -Wundef -Wmissing-prototypes -Iinclude
-TOOLS_TARGETS := i2cdetect i2cdump i2cset i2cget
+TOOLS_TARGETS := i2cdetect i2cdump i2cset i2cget i2cgetwide
#
# Programs
@@ -31,6 +31,9 @@
$(TOOLS_DIR)/i2cget: $(TOOLS_DIR)/i2cget.o $(TOOLS_DIR)/i2cbusses.o $(TOOLS_DIR)/util.o
$(CC) $(LDFLAGS) -o $@ $^
+$(TOOLS_DIR)/i2cgetwide: $(TOOLS_DIR)/i2cgetwide.o $(TOOLS_DIR)/i2cbusses.o $(TOOLS_DIR)/util.o
+ $(CC) $(LDFLAGS) -o $@ $^
+
#
# Objects
#
@@ -47,6 +50,9 @@
$(TOOLS_DIR)/i2cget.o: $(TOOLS_DIR)/i2cget.c $(TOOLS_DIR)/i2cbusses.h $(TOOLS_DIR)/util.h version.h $(INCLUDE_DIR)/linux/i2c-dev.h
$(CC) $(CFLAGS) $(TOOLS_CFLAGS) -c $< -o $@
+$(TOOLS_DIR)/i2cgetwide.o: $(TOOLS_DIR)/i2cgetwide.c $(TOOLS_DIR)/i2cbusses.h $(TOOLS_DIR)/util.h version.h $(INCLUDE_DIR)/linux/i2c-dev.h
+ $(CC) $(CFLAGS) $(TOOLS_CFLAGS) -c $< -o $@
+
$(TOOLS_DIR)/i2cbusses.o: $(TOOLS_DIR)/i2cbusses.c $(TOOLS_DIR)/i2cbusses.h $(INCLUDE_DIR)/linux/i2c-dev.h
$(CC) $(CFLAGS) $(TOOLS_CFLAGS) -c $< -o $@