mirror of
https://github.com/lm-sensors/lm-sensors.git
synced 2026-10-23 11:54:33 +00:00
Move i2cdetect, i2cdump, i2cset and i2cget to a separate package
(i2c-tools). git-svn-id: http://lm-sensors.org/svn/lm-sensors/branches/lm-sensors-3.0.0@4480 7894878c-1315-0410-8ee3-d5d059ff63e0
This commit is contained in:
1 parent
9ab400fad3
commit
d7b4debbf6
14 files changed
+10
-1981
No files matched your search
@@ -34,7 +34,7 @@ Details:
|
||||
bus are being accessed. No access is provided for non-i2c
|
||||
busses such as ISA.
|
||||
|
||||
For good examples, see prog/detect/i2cdetect.c and
|
||||
For good examples, see i2cdetect.c (in the i2c-tools package) and
|
||||
prog/detect/sensors-detect.
|
||||
|
||||
|
||||
@@ -56,8 +56,8 @@ Details:
|
||||
bus are being accessed. No access is provided for non-i2c
|
||||
busses such as ISA.
|
||||
|
||||
For good examples, see prog/detect/i2cdetect.c,
|
||||
prog/dump/i2cdump.c, and prog/dump/i2cset.c.
|
||||
For good examples, see i2cdetect.c, i2cdump.c, and i2cset.c (all in the
|
||||
i2c-tools package).
|
||||
|
||||
|
||||
3A. /proc access (2.4 kernels)
|
||||
|
||||
@@ -18,34 +18,11 @@ see useful_addresses.html.
|
||||
* prog/daemon/healthd.sh (written in bash, not installed)
|
||||
An example of a very simple hardware health monitoring daemon.
|
||||
|
||||
* prog/detect/i2cdetect (written in C, installed by 'make install')
|
||||
This program scans your complete I2C or SMBus adapter for connected devices.
|
||||
Syntax:
|
||||
i2cdetect 0
|
||||
Here the '0' stands for the bus number (run "i2cdetect -l"
|
||||
to list all installed busses).
|
||||
|
||||
* prog/detect/sensors-detect (written in Perl, installed by 'make install')
|
||||
This program tries to detect the available SMBus adapters and the chips
|
||||
connected to them, as well as Super-I/O and misc chips. It also generates
|
||||
modprobe lines and module options. This program is interactive.
|
||||
|
||||
* prog/dump/i2cdump (written in C, installed by 'make install')
|
||||
This program dumps the registers of an I2C device.
|
||||
Usual syntax:
|
||||
i2cdump 0 0x4c b
|
||||
Here the '0' stands for the bus number (run i2cdump with no arguments
|
||||
to list all installed busses).
|
||||
'0x49' is the device address, and 'b' or 'w' stands for byte
|
||||
or word data.
|
||||
|
||||
* prog/dump/i2cset (written in C, installed by 'make install')
|
||||
prog/dump/i2cget (written in C, installed by 'make install')
|
||||
These programs are used to write to or read from a register of an
|
||||
I2C device. Usual syntax:
|
||||
i2cset bus device address data
|
||||
i2cget bus device address
|
||||
|
||||
* prog/dump/isadump (written in C, installed by 'make install')
|
||||
This program dumps the registers of ISA or Super-I/O chips.
|
||||
Usual syntax:
|
||||
|
||||
+3
-14
@@ -22,28 +22,18 @@ MODULE_DIR := prog/detect
|
||||
PROGDETECTDIR := $(MODULE_DIR)
|
||||
|
||||
PROGDETECTMAN8DIR := $(MANDIR)/man8
|
||||
PROGDETECTMAN8FILES := $(MODULE_DIR)/i2cdetect.8 $(MODULE_DIR)/sensors-detect.8
|
||||
PROGDETECTMAN8FILES := $(MODULE_DIR)/sensors-detect.8
|
||||
|
||||
# Regrettably, even 'simply expanded variables' will not put their currently
|
||||
# defined value verbatim into the command-list of rules...
|
||||
PROGDETECTTARGETS := $(MODULE_DIR)/i2cdetect
|
||||
PROGDETECTSOURCES := $(MODULE_DIR)/i2cdetect.c
|
||||
PROGDETECTSBININSTALL := $(MODULE_DIR)/sensors-detect \
|
||||
$(MODULE_DIR)/i2cdetect
|
||||
|
||||
# Include all dependency files. We use '.rd' to indicate this will create
|
||||
# executables.
|
||||
INCLUDEFILES += $(PROGDETECTSOURCES:.c=.rd)
|
||||
PROGDETECTSBININSTALL := $(MODULE_DIR)/sensors-detect
|
||||
|
||||
REMOVEDETECTBIN := $(patsubst $(MODULE_DIR)/%,$(DESTDIR)$(SBINDIR)/%,$(PROGDETECTSBININSTALL))
|
||||
REMOVEDETECTMAN := $(patsubst $(MODULE_DIR)/%,$(DESTDIR)$(PROGDETECTMAN8DIR)/%,$(PROGDETECTMAN8FILES))
|
||||
|
||||
all-prog-detect: $(PROGDETECTTARGETS)
|
||||
all-prog-detect:
|
||||
user :: all-prog-detect
|
||||
|
||||
$(MODULE_DIR)/i2cdetect: $(MODULE_DIR)/i2cdetect.ro prog/dump/i2cbusses.ro
|
||||
$(CC) $(EXLDFLAGS) -o $@ $^
|
||||
|
||||
install-prog-detect: all-prog-detect
|
||||
$(MKDIR) $(DESTDIR)$(SBINDIR) $(DESTDIR)$(PROGDETECTMAN8DIR)
|
||||
$(INSTALL) -m 755 $(PROGDETECTSBININSTALL) $(DESTDIR)$(SBINDIR)
|
||||
@@ -55,5 +45,4 @@ user_uninstall::
|
||||
$(RM) $(REMOVEDETECTMAN)
|
||||
|
||||
clean-prog-detect:
|
||||
$(RM) $(PROGDETECTDIR)/*.rd $(PROGDETECTDIR)/*.ro $(PROGDETECTTARGETS)
|
||||
clean :: clean-prog-detect
|
||||
@@ -1,88 +0,0 @@
|
||||
.TH I2CDETECT 8 "October 2006"
|
||||
.SH NAME
|
||||
i2cdetect \- detect I2C chips
|
||||
|
||||
.SH SYNOPSIS
|
||||
.B i2cdetect
|
||||
.RI [ -y ]
|
||||
.RI [ -a ]
|
||||
.RI [ -q | -r ]
|
||||
.I i2cbus
|
||||
.RI [ "first last" ]
|
||||
.br
|
||||
.B i2cdetect
|
||||
.I -F
|
||||
.I i2cbus
|
||||
.br
|
||||
.B i2cdetect
|
||||
.I -V
|
||||
.br
|
||||
.B i2cdetect
|
||||
.I -l
|
||||
|
||||
.SH DESCRIPTION
|
||||
i2cdetect is a userspace program to scan an I2C bus for devices. It
|
||||
outputs a table with the list of detected devices on the specified bus.
|
||||
\fIi2cbus\fR indicates the number of the I2C bus to be scanned, and
|
||||
should correspond to one of the busses listed by \fIi2cdetect -l\fR.
|
||||
The optional parameters \fIfirst\fR and \fIlast\fR restrict the scanning
|
||||
range (default: from 0x03 to 0x77).
|
||||
.PP
|
||||
i2cdetect can also be used to query the functionalities of an I2C bus
|
||||
(see option \fB-F\fP.)
|
||||
|
||||
.SH WARNING
|
||||
This program can confuse your I2C bus, cause data loss and worse!
|
||||
|
||||
.SH INTERPRETING THE OUTPUT
|
||||
Each cell in the output table will contain one of the following symbols:
|
||||
.IP \(bu "\w'\(bu'u+1n"
|
||||
"--". The address was probed but no chip answered.
|
||||
.IP \(bu
|
||||
"UU". Probing was skipped, because this address is currently in use by
|
||||
a driver. This strongly suggests that there is a chip at this address.
|
||||
.IP \(bu
|
||||
An address number in hexadecimal, e.g. "2d" or "4e". A chip
|
||||
was found at this address.
|
||||
|
||||
.SH OPTIONS
|
||||
.TP
|
||||
.B "\-y"
|
||||
Disable interactive mode. By default, i2cdetect 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.
|
||||
.TP
|
||||
.B "\-a"
|
||||
Force scanning of non-regular addresses. Not recommended.
|
||||
.TP
|
||||
.B "\-q"
|
||||
Use SMBus "quick write" commands for probing (by default, the command
|
||||
used is the one believed to be the safest for each address).
|
||||
Not recommended. This is known to corrupt the Atmel AT24RF08 EEPROM
|
||||
found on many IBM Thinkpad laptops.
|
||||
.TP
|
||||
.B "\-r"
|
||||
Use SMBus "read byte" commands for probing (by default, the command
|
||||
used is the one believed to be the safest for each address).
|
||||
Not recommended. This is known to lock SMBus on various write-only
|
||||
chips (most notably clock chips at address 0x69).
|
||||
.TP
|
||||
.B "\-F"
|
||||
Display the list of functionalities implemented by the adapter and exit.
|
||||
.TP
|
||||
.B "\-V"
|
||||
Display the version and exit.
|
||||
.TP
|
||||
.B "\-l"
|
||||
Output a list of installed busses.
|
||||
|
||||
.SH SEE ALSO
|
||||
i2cdump(8), sensors-detect(8)
|
||||
|
||||
.SH AUTHOR
|
||||
Frodo Looijaard, Mark D. Studebaker, and the lm_sensors group
|
||||
http://www.lm-sensors.org/
|
||||
This manual page was written by Aurelien Jarno <aurel32@debian.org>, for
|
||||
the Debian GNU/Linux system. It was then reviewed by the lm_sensors team and
|
||||
is now part of the lm_sensors source distribution.
|
||||
@@ -1,347 +0,0 @@
|
||||
/*
|
||||
i2cdetect.c - a user-space program to scan for I2C devices
|
||||
Copyright (C) 1999-2004 Frodo Looijaard <frodol@dds.nl>,
|
||||
Mark D. Studebaker <mdsxyz123@yahoo.com> and
|
||||
Jean Delvare <khali@linux-fr.org>
|
||||
|
||||
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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include "../dump/i2cbusses.h"
|
||||
#include "i2c-dev.h"
|
||||
#include "version.h"
|
||||
|
||||
#define MODE_AUTO 0
|
||||
#define MODE_QUICK 1
|
||||
#define MODE_READ 2
|
||||
#define MODE_FUNC 3
|
||||
|
||||
void help(void)
|
||||
{
|
||||
fprintf(stderr,
|
||||
"Syntax: i2cdetect [-y] [-a] [-q|-r] I2CBUS [FIRST LAST]\n"
|
||||
" i2cdetect -F I2CBUS\n"
|
||||
" i2cdetect -l\n"
|
||||
" i2cdetect -V\n"
|
||||
" I2CBUS is an integer\n"
|
||||
" With -a, probe all addresses (NOT RECOMMENDED)\n"
|
||||
" With -q, uses only quick write commands for probing (NOT "
|
||||
"RECOMMENDED)\n"
|
||||
" With -r, uses only read byte commands for probing (NOT "
|
||||
"RECOMMENDED)\n"
|
||||
" If provided, FIRST and LAST limit the probing range.\n"
|
||||
" With -l, lists installed busses only\n");
|
||||
print_i2c_busses(0);
|
||||
}
|
||||
|
||||
int scan_i2c_bus(int file, const int mode, const int first, const int last)
|
||||
{
|
||||
int i, j;
|
||||
int res;
|
||||
|
||||
printf(" 0 1 2 3 4 5 6 7 8 9 a b c d e f\n");
|
||||
|
||||
for (i = 0; i < 128; i += 16) {
|
||||
printf("%02x: ", i);
|
||||
for(j = 0; j < 16; j++) {
|
||||
fflush(stdout);
|
||||
|
||||
/* Skip unwanted addresses */
|
||||
if (i+j < first || i+j > last) {
|
||||
printf(" ");
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Set slave address */
|
||||
if (ioctl(file, I2C_SLAVE, i+j) < 0) {
|
||||
if (errno == EBUSY) {
|
||||
printf("UU ");
|
||||
continue;
|
||||
} else {
|
||||
fprintf(stderr, "Error: Could not set "
|
||||
"address to 0x%02x: %s\n", i+j,
|
||||
strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Probe this address */
|
||||
switch (mode) {
|
||||
case MODE_QUICK:
|
||||
/* This is known to corrupt the Atmel AT24RF08
|
||||
EEPROM */
|
||||
res = i2c_smbus_write_quick(file,
|
||||
I2C_SMBUS_WRITE);
|
||||
break;
|
||||
case MODE_READ:
|
||||
/* This is known to lock SMBus on various
|
||||
write-only chips (mainly clock chips) */
|
||||
res = i2c_smbus_read_byte(file);
|
||||
break;
|
||||
default:
|
||||
if ((i+j >= 0x30 && i+j <= 0x37)
|
||||
|| (i+j >= 0x50 && i+j <= 0x5F))
|
||||
res = i2c_smbus_read_byte(file);
|
||||
else
|
||||
res = i2c_smbus_write_quick(file,
|
||||
I2C_SMBUS_WRITE);
|
||||
}
|
||||
|
||||
if (res < 0)
|
||||
printf("-- ");
|
||||
else
|
||||
printf("%02x ", i+j);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct func
|
||||
{
|
||||
long value;
|
||||
const char* name;
|
||||
};
|
||||
|
||||
static const struct func all_func[] = {
|
||||
{ .value = I2C_FUNC_I2C,
|
||||
.name = "I2C" },
|
||||
{ .value = I2C_FUNC_SMBUS_QUICK,
|
||||
.name = "SMBus Quick Command" },
|
||||
{ .value = I2C_FUNC_SMBUS_WRITE_BYTE,
|
||||
.name = "SMBus Send Byte" },
|
||||
{ .value = I2C_FUNC_SMBUS_READ_BYTE,
|
||||
.name = "SMBus Receive Byte" },
|
||||
{ .value = I2C_FUNC_SMBUS_WRITE_BYTE_DATA,
|
||||
.name = "SMBus Write Byte" },
|
||||
{ .value = I2C_FUNC_SMBUS_READ_BYTE_DATA,
|
||||
.name = "SMBus Read Byte" },
|
||||
{ .value = I2C_FUNC_SMBUS_WRITE_WORD_DATA,
|
||||
.name = "SMBus Write Word" },
|
||||
{ .value = I2C_FUNC_SMBUS_READ_WORD_DATA,
|
||||
.name = "SMBus Read Word" },
|
||||
{ .value = I2C_FUNC_SMBUS_PROC_CALL,
|
||||
.name = "SMBus Process Call" },
|
||||
{ .value = I2C_FUNC_SMBUS_WRITE_BLOCK_DATA,
|
||||
.name = "SMBus Block Write" },
|
||||
{ .value = I2C_FUNC_SMBUS_READ_BLOCK_DATA,
|
||||
.name = "SMBus Block Read" },
|
||||
{ .value = I2C_FUNC_SMBUS_BLOCK_PROC_CALL,
|
||||
.name = "SMBus Block Process Call" },
|
||||
{ .value = I2C_FUNC_SMBUS_HWPEC_CALC,
|
||||
.name = "SMBus PEC" },
|
||||
{ .value = I2C_FUNC_SMBUS_WRITE_I2C_BLOCK,
|
||||
.name = "I2C Block Write" },
|
||||
{ .value = I2C_FUNC_SMBUS_READ_I2C_BLOCK,
|
||||
.name = "I2C Block Read" },
|
||||
{ }
|
||||
};
|
||||
|
||||
void print_functionality(unsigned long funcs)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; all_func[i].value; i++) {
|
||||
printf("%-32s %s\n", all_func[i].name,
|
||||
(funcs & all_func[i].value) ? "yes" : "no");
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
char *end;
|
||||
int i2cbus, file, res;
|
||||
char filename[20];
|
||||
unsigned long funcs;
|
||||
int mode = MODE_AUTO;
|
||||
int first = 0x03, last = 0x77;
|
||||
int flags = 0;
|
||||
int yes = 0, version = 0, list = 0;
|
||||
|
||||
/* handle (optional) flags first */
|
||||
while (1+flags < argc && argv[1+flags][0] == '-') {
|
||||
switch (argv[1+flags][1]) {
|
||||
case 'V': version = 1; break;
|
||||
case 'y': yes = 1; break;
|
||||
case 'l': list = 1; break;
|
||||
case 'F':
|
||||
if (mode != MODE_AUTO && mode != MODE_FUNC) {
|
||||
fprintf(stderr, "Error: Different modes "
|
||||
"specified!\n");
|
||||
exit(1);
|
||||
}
|
||||
mode = MODE_FUNC;
|
||||
break;
|
||||
case 'r':
|
||||
if (mode == MODE_QUICK) {
|
||||
fprintf(stderr, "Error: Different modes "
|
||||
"specified!\n");
|
||||
exit(1);
|
||||
}
|
||||
mode = MODE_READ;
|
||||
break;
|
||||
case 'q':
|
||||
if (mode == MODE_READ) {
|
||||
fprintf(stderr, "Error: Different modes "
|
||||
"specified!\n");
|
||||
exit(1);
|
||||
}
|
||||
mode = MODE_QUICK;
|
||||
break;
|
||||
case 'a':
|
||||
first = 0x00;
|
||||
last = 0x7F;
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "Warning: Unsupported flag "
|
||||
"\"-%c\"!\n", argv[1+flags][1]);
|
||||
help();
|
||||
exit(1);
|
||||
}
|
||||
flags++;
|
||||
}
|
||||
|
||||
if (version) {
|
||||
fprintf(stderr, "i2cdetect version %s\n", LM_VERSION);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
if (list) {
|
||||
print_i2c_busses(1);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
if (argc < flags + 2) {
|
||||
fprintf(stderr, "Error: No i2c-bus specified!\n");
|
||||
help();
|
||||
exit(1);
|
||||
}
|
||||
i2cbus = strtol(argv[flags+1], &end, 0);
|
||||
if (*end) {
|
||||
fprintf(stderr, "Error: I2CBUS argument not a number!\n");
|
||||
help();
|
||||
exit(1);
|
||||
}
|
||||
if ((i2cbus < 0) || (i2cbus > 0xff)) {
|
||||
fprintf(stderr, "Error: I2CBUS argument out of range "
|
||||
"(0-255)!\n");
|
||||
help();
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* read address range if present */
|
||||
if (argc == flags + 4 && mode != MODE_FUNC) {
|
||||
int tmp;
|
||||
|
||||
tmp = strtol(argv[flags+2], &end, 0);
|
||||
if (*end) {
|
||||
fprintf(stderr, "Error: FIRST argment not a "
|
||||
"number!\n");
|
||||
help();
|
||||
exit(1);
|
||||
}
|
||||
if (tmp < first || tmp > last) {
|
||||
fprintf(stderr, "Error: FIRST argument out of range "
|
||||
"(0x%02x-0x%02x)!\n", first, last);
|
||||
help();
|
||||
exit(1);
|
||||
}
|
||||
first = tmp;
|
||||
|
||||
tmp = strtol(argv[flags+3], &end, 0);
|
||||
if (*end) {
|
||||
fprintf(stderr, "Error: LAST argment not a "
|
||||
"number!\n");
|
||||
help();
|
||||
exit(1);
|
||||
}
|
||||
if (tmp < first || tmp > last) {
|
||||
fprintf(stderr, "Error: LAST argument out of range "
|
||||
"(0x%02x-0x%02x)!\n", first, last);
|
||||
help();
|
||||
exit(1);
|
||||
}
|
||||
last = tmp;
|
||||
} else if (argc != flags + 2) {
|
||||
help();
|
||||
exit(1);
|
||||
}
|
||||
|
||||
file = open_i2c_dev(i2cbus, filename, 0);
|
||||
if (file < 0) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (ioctl(file, I2C_FUNCS, &funcs) < 0) {
|
||||
fprintf(stderr, "Error: Could not get the adapter "
|
||||
"functionality matrix: %s\n", strerror(errno));
|
||||
close(file);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Special case, we only list the implemented functionalities */
|
||||
if (mode == MODE_FUNC) {
|
||||
close(file);
|
||||
printf("Functionalities implemented by %s:\n", filename);
|
||||
print_functionality(funcs);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
if (mode != MODE_READ && !(funcs & I2C_FUNC_SMBUS_QUICK)) {
|
||||
fprintf(stderr, "Error: Can't use SMBus Quick Write command "
|
||||
"on this bus (ISA bus?)\n");
|
||||
close(file);
|
||||
exit(1);
|
||||
}
|
||||
if (mode != MODE_QUICK && !(funcs & I2C_FUNC_SMBUS_READ_BYTE)) {
|
||||
fprintf(stderr, "Error: Can't use SMBus Read Byte command "
|
||||
"on this bus (ISA bus?)\n");
|
||||
close(file);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (!yes) {
|
||||
char s[2];
|
||||
|
||||
fprintf(stderr, "WARNING! This program can confuse your I2C "
|
||||
"bus, cause data loss and worse!\n");
|
||||
|
||||
fprintf(stderr, "I will probe file %s%s.\n", filename,
|
||||
mode==MODE_QUICK?" using quick write commands":
|
||||
mode==MODE_READ?" using read byte commands":"");
|
||||
fprintf(stderr, "I will probe address range 0x%02x-0x%02x.\n",
|
||||
first, last);
|
||||
|
||||
fprintf(stderr, "Continue? [Y/n] ");
|
||||
fflush(stderr);
|
||||
if (!fgets(s, 2, stdin)
|
||||
|| (s[0] != '\n' && s[0] != 'y' && s[0] != 'Y')) {
|
||||
fprintf(stderr, "Aborting on user request.\n");
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
res = scan_i2c_bus(file, mode, first, last);
|
||||
|
||||
close(file);
|
||||
|
||||
exit(res?1:0);
|
||||
}
|
||||
+4
-18
@@ -22,18 +22,13 @@ MODULE_DIR := prog/dump
|
||||
PROGDUMPDIR := $(MODULE_DIR)
|
||||
|
||||
PROGDUMPMAN8DIR := $(MANDIR)/man8
|
||||
PROGDUMPMAN8FILES := $(MODULE_DIR)/i2cdump.8 $(MODULE_DIR)/i2cset.8 \
|
||||
$(MODULE_DIR)/i2cget.8
|
||||
PROGDUMPMAN8FILES :=
|
||||
|
||||
# Regrettably, even 'simply expanded variables' will not put their currently
|
||||
# defined value verbatim into the command-list of rules...
|
||||
PROGDUMPTARGETS := $(MODULE_DIR)/i2cdump $(MODULE_DIR)/i2cset \
|
||||
$(MODULE_DIR)/i2cget
|
||||
PROGDUMPSOURCES := $(MODULE_DIR)/i2cdump.c $(MODULE_DIR)/i2cset.c \
|
||||
$(MODULE_DIR)/i2cget.c $(MODULE_DIR)/i2cbusses.c \
|
||||
$(MODULE_DIR)/util.c
|
||||
PROGDUMPBININSTALL := $(MODULE_DIR)/i2cdump $(MODULE_DIR)/i2cset \
|
||||
$(MODULE_DIR)/i2cget
|
||||
PROGDUMPTARGETS :=
|
||||
PROGDUMPSOURCES := $(MODULE_DIR)/util.c
|
||||
PROGDUMPBININSTALL :=
|
||||
|
||||
# Only build isadump and isaset on x86 machines.
|
||||
ifneq (,$(findstring $(MACHINE), i386 i486 i586 i686 x86_64))
|
||||
@@ -54,15 +49,6 @@ REMOVEDUMPMAN := $(patsubst $(MODULE_DIR)/%,$(DESTDIR)$(PROGDUMPMAN8DIR)/%,$(PRO
|
||||
all-prog-dump: $(PROGDUMPTARGETS)
|
||||
user :: all-prog-dump
|
||||
|
||||
$(MODULE_DIR)/i2cdump: $(MODULE_DIR)/i2cdump.ro $(MODULE_DIR)/i2cbusses.ro $(MODULE_DIR)/util.ro
|
||||
$(CC) $(EXLDFLAGS) -o $@ $^
|
||||
|
||||
$(MODULE_DIR)/i2cset: $(MODULE_DIR)/i2cset.ro $(MODULE_DIR)/i2cbusses.ro $(MODULE_DIR)/util.ro
|
||||
$(CC) $(EXLDFLAGS) -o $@ $^
|
||||
|
||||
$(MODULE_DIR)/i2cget: $(MODULE_DIR)/i2cget.ro $(MODULE_DIR)/i2cbusses.ro $(MODULE_DIR)/util.ro
|
||||
$(CC) $(EXLDFLAGS) -o $@ $^
|
||||
|
||||
$(MODULE_DIR)/isadump: $(MODULE_DIR)/isadump.ro $(MODULE_DIR)/superio.ro $(MODULE_DIR)/util.ro
|
||||
$(CC) $(EXLDFLAGS) -o $@ $^
|
||||
|
||||
|
||||
@@ -1,259 +0,0 @@
|
||||
/*
|
||||
i2cbusses: Print the installed i2c busses for both 2.4 and 2.6 kernels.
|
||||
Part of user-space programs to access for I2C
|
||||
devices.
|
||||
Copyright (c) 1999-2003 Frodo Looijaard <frodol@dds.nl> and
|
||||
Mark D. Studebaker <mdsxyz123@yahoo.com>
|
||||
|
||||
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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <limits.h>
|
||||
#include <dirent.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include "i2cbusses.h"
|
||||
#include "i2c-dev.h"
|
||||
|
||||
enum adt { adt_dummy, adt_isa, adt_i2c, adt_smbus, adt_unknown };
|
||||
|
||||
struct adap_type {
|
||||
const char *funcs;
|
||||
const char* algo;
|
||||
};
|
||||
|
||||
static struct adap_type adap_types[5] = {
|
||||
{ .funcs = "dummy",
|
||||
.algo = "Dummy bus", },
|
||||
{ .funcs = "isa",
|
||||
.algo = "ISA bus", },
|
||||
{ .funcs = "i2c",
|
||||
.algo = "I2C adapter", },
|
||||
{ .funcs = "smbus",
|
||||
.algo = "SMBus adapter", },
|
||||
{ .funcs = "unknown",
|
||||
.algo = "N/A", },
|
||||
};
|
||||
|
||||
static enum adt i2c_get_funcs(int i2cbus)
|
||||
{
|
||||
unsigned long funcs;
|
||||
int file;
|
||||
char filename[20];
|
||||
enum adt ret;
|
||||
|
||||
file = open_i2c_dev(i2cbus, filename, 1);
|
||||
if (file < 0)
|
||||
return adt_unknown;
|
||||
|
||||
if (ioctl(file, I2C_FUNCS, &funcs) < 0)
|
||||
ret = adt_unknown;
|
||||
else if (funcs & I2C_FUNC_I2C)
|
||||
ret = adt_i2c;
|
||||
else if (funcs & (I2C_FUNC_SMBUS_BYTE |
|
||||
I2C_FUNC_SMBUS_BYTE_DATA |
|
||||
I2C_FUNC_SMBUS_WORD_DATA))
|
||||
ret = adt_smbus;
|
||||
else
|
||||
ret = adt_dummy;
|
||||
|
||||
close(file);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
this just prints out the installed i2c busses in a consistent format, whether
|
||||
on a 2.4 kernel using /proc or a 2.6 kernel using /sys.
|
||||
If procfmt == 1, print out exactly /proc/bus/i2c format on stdout.
|
||||
This allows this to be used in a program to emulate /proc/bus/i2c on a
|
||||
sysfs system.
|
||||
*/
|
||||
void print_i2c_busses(int procfmt)
|
||||
{
|
||||
FILE *fptr;
|
||||
char s[100];
|
||||
struct dirent *de, *dde;
|
||||
DIR *dir, *ddir;
|
||||
FILE *f;
|
||||
char *border;
|
||||
char dev[NAME_MAX], fstype[NAME_MAX], sysfs[NAME_MAX], n[NAME_MAX];
|
||||
int foundsysfs = 0;
|
||||
int count=0;
|
||||
|
||||
|
||||
/* look in /proc/bus/i2c */
|
||||
if((fptr = fopen("/proc/bus/i2c", "r"))) {
|
||||
while(fgets(s, 100, fptr)) {
|
||||
if(count++ == 0 && !procfmt)
|
||||
fprintf(stderr," Installed I2C busses:\n");
|
||||
if(procfmt)
|
||||
printf("%s", s);
|
||||
else
|
||||
fprintf(stderr, " %s", s);
|
||||
}
|
||||
fclose(fptr);
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* look in sysfs */
|
||||
/* First figure out where sysfs was mounted */
|
||||
if ((f = fopen("/proc/mounts", "r")) == NULL) {
|
||||
goto done;
|
||||
}
|
||||
while (fgets(n, NAME_MAX, f)) {
|
||||
sscanf(n, "%[^ ] %[^ ] %[^ ] %*s\n", dev, sysfs, fstype);
|
||||
if (strcasecmp(fstype, "sysfs") == 0) {
|
||||
foundsysfs++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
fclose(f);
|
||||
if (! foundsysfs) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* Bus numbers in i2c-adapter don't necessarily match those in
|
||||
i2c-dev and what we really care about are the i2c-dev numbers.
|
||||
Unfortunately the names are harder to get in i2c-dev */
|
||||
strcat(sysfs, "/class/i2c-dev");
|
||||
if(!(dir = opendir(sysfs)))
|
||||
goto done;
|
||||
/* go through the busses */
|
||||
while ((de = readdir(dir)) != NULL) {
|
||||
if (!strcmp(de->d_name, "."))
|
||||
continue;
|
||||
if (!strcmp(de->d_name, ".."))
|
||||
continue;
|
||||
|
||||
/* this should work for kernels 2.6.5 or higher and */
|
||||
/* is preferred because is unambiguous */
|
||||
sprintf(n, "%s/%s/name", sysfs, de->d_name);
|
||||
f = fopen(n, "r");
|
||||
/* this seems to work for ISA */
|
||||
if(f == NULL) {
|
||||
sprintf(n, "%s/%s/device/name", sysfs, de->d_name);
|
||||
f = fopen(n, "r");
|
||||
}
|
||||
/* non-ISA is much harder */
|
||||
/* and this won't find the correct bus name if a driver
|
||||
has more than one bus */
|
||||
if(f == NULL) {
|
||||
sprintf(n, "%s/%s/device", sysfs, de->d_name);
|
||||
if(!(ddir = opendir(n)))
|
||||
continue;
|
||||
while ((dde = readdir(ddir)) != NULL) {
|
||||
if (!strcmp(dde->d_name, "."))
|
||||
continue;
|
||||
if (!strcmp(dde->d_name, ".."))
|
||||
continue;
|
||||
if ((!strncmp(dde->d_name, "i2c-", 4))) {
|
||||
sprintf(n, "%s/%s/device/%s/name",
|
||||
sysfs, de->d_name, dde->d_name);
|
||||
if((f = fopen(n, "r")))
|
||||
goto found;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
found:
|
||||
if (f != NULL) {
|
||||
int i2cbus;
|
||||
enum adt type;
|
||||
char x[120];
|
||||
char *px;
|
||||
|
||||
px = fgets(x, 120, f);
|
||||
fclose(f);
|
||||
if (!px) {
|
||||
fprintf(stderr, "%s: read error\n", n);
|
||||
continue;
|
||||
}
|
||||
if((border = index(x, '\n')) != NULL)
|
||||
*border = 0;
|
||||
if(count++ == 0 && !procfmt)
|
||||
fprintf(stderr," Installed I2C busses:\n");
|
||||
/* match 2.4 /proc/bus/i2c format as closely as possible */
|
||||
if(!strncmp(x, "ISA ", 4)) {
|
||||
type = adt_isa;
|
||||
} else if(!sscanf(de->d_name, "i2c-%d", &i2cbus)) {
|
||||
type = adt_dummy;
|
||||
} else {
|
||||
/* Attempt to probe for adapter capabilities */
|
||||
type = i2c_get_funcs(i2cbus);
|
||||
}
|
||||
|
||||
if (procfmt)
|
||||
printf("%s\t%-10s\t%-32s\t%s\n", de->d_name,
|
||||
adap_types[type].funcs, x, adap_types[type].algo);
|
||||
else
|
||||
fprintf(stderr, " %s\t%-10s\t%s\n", de->d_name,
|
||||
adap_types[type].funcs, x);
|
||||
}
|
||||
}
|
||||
closedir(dir);
|
||||
|
||||
done:
|
||||
if(count == 0 && !procfmt)
|
||||
fprintf(stderr,"Error: No I2C busses found!\n"
|
||||
"Be sure you have done 'modprobe i2c-dev'\n"
|
||||
"and also modprobed your i2c bus drivers\n");
|
||||
}
|
||||
|
||||
int open_i2c_dev(const int i2cbus, char *filename, const int quiet)
|
||||
{
|
||||
int file;
|
||||
|
||||
sprintf(filename, "/dev/i2c/%d", i2cbus);
|
||||
file = open(filename, O_RDWR);
|
||||
|
||||
if (file < 0 && errno == ENOENT) {
|
||||
sprintf(filename, "/dev/i2c-%d", i2cbus);
|
||||
file = open(filename, O_RDWR);
|
||||
}
|
||||
|
||||
if (file < 0 && !quiet) {
|
||||
if (errno == ENOENT) {
|
||||
fprintf(stderr, "Error: Could not open file "
|
||||
"`/dev/i2c-%d' or `/dev/i2c/%d': %s\n",
|
||||
i2cbus, i2cbus, strerror(ENOENT));
|
||||
} else {
|
||||
fprintf(stderr, "Error: Could not open file "
|
||||
"`%s': %s\n", filename, strerror(errno));
|
||||
if (errno == EACCES)
|
||||
fprintf(stderr, "Run as root?\n");
|
||||
}
|
||||
}
|
||||
|
||||
return file;
|
||||
}
|
||||
|
||||
int set_slave_addr(int file, int address, int force)
|
||||
{
|
||||
/* With force, let the user read from/write to the registers
|
||||
even when a driver is also running */
|
||||
if (ioctl(file, force ? I2C_SLAVE_FORCE : I2C_SLAVE, address) < 0) {
|
||||
fprintf(stderr,
|
||||
"Error: Could not set address to 0x%02x: %s\n",
|
||||
address, strerror(errno));
|
||||
return -errno;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
/*
|
||||
i2cbusses.h - Part of the lm_sensors project
|
||||
|
||||
Copyright (C) 2004 The lm_sensors group
|
||||
|
||||
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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#ifndef _I2CBUSSES_H
|
||||
#define _I2CBUSSES_H
|
||||
|
||||
void print_i2c_busses(int procfmt);
|
||||
|
||||
int open_i2c_dev(const int i2cbus, char *filename, const int quiet);
|
||||
int set_slave_addr(int file, int address, int force);
|
||||
|
||||
#endif
|
||||
@@ -1,80 +0,0 @@
|
||||
.TH I2CDUMP 8 "June 2007"
|
||||
.SH NAME
|
||||
i2cdump \- examine I2C registers
|
||||
|
||||
.SH SYNOPSIS
|
||||
.B i2cdump
|
||||
.RB [ -f ]
|
||||
.RB [ -y ]
|
||||
.I i2cbus
|
||||
.I address
|
||||
.RI [ mode ]
|
||||
.RI [ "bank " [ bankreg ]]
|
||||
.br
|
||||
.B i2cdump
|
||||
.B -V
|
||||
|
||||
.SH DESCRIPTION
|
||||
i2cdump is a small helper program to examine registers
|
||||
visible through the I2C bus.
|
||||
|
||||
.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, i2cdump
|
||||
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 i2cdump to return invalid
|
||||
results. So use at your own risk and only if you know what you're doing.
|
||||
.TP
|
||||
.B -y
|
||||
Disable interactive mode. By default, i2cdump 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.
|
||||
.PP
|
||||
At least two options must be provided to i2cdump. \fIi2cbus\fR indicates the
|
||||
number of the I2C bus to be scanned. This number should correspond to one
|
||||
of the busses listed by \fIi2cdetect -l\fR. \fIaddress\fR indicates the
|
||||
address to be scanned on that bus, and is an integer between 0x00 and 0x7F.
|
||||
.PP
|
||||
The \fImode\fR parameter, if specified, is one of the letters \fBb\fP, \fBw\fP,
|
||||
\fBs\fP, or \fBi\fP, corresponding to a read size of a single byte, a 16-bit
|
||||
word, an SMBus block, an I2C block, respectively. The \fBc\fP mode is a
|
||||
little different, it reads all bytes consecutively, and is useful for chips that
|
||||
have an address auto-increment feature, such as EEPROMs. The \fBW\fP mode is
|
||||
also special, it is similar to \fBw\fP except that a read command will only
|
||||
be issued on even register addresses; this is again mainly useful for EEPROMs.
|
||||
.PP
|
||||
A \fBp\fP can also be appended to the \fImode\fR parameter (except for
|
||||
\fBi\fP and \fBW\fP) to enable PEC. If the \fImode\fR parameter is omitted,
|
||||
i2cdump defaults to byte access without PEC.
|
||||
.PP
|
||||
The \fIbank\fR and \fIbankreg\fR parameters are useful on the W83781D and
|
||||
similar chips (at the time of writing, all Winbond and Asus chips).
|
||||
\fIbank\fR is an integer between 0 and 7, and \fIbankreg\fR is an integer
|
||||
between 0x00 and 0xFF (default value: 0x4E). The W83781D data sheet has more
|
||||
information on bank selection.
|
||||
|
||||
.SH WARNING
|
||||
i2cdump can be dangerous if used improperly. Most notably, the \fBc\fP mode
|
||||
starts with WRITING a byte to the chip. On most chips it will be stored in the
|
||||
address pointer register, which is OK, but some chips with a single register
|
||||
or no (visible) register at all will most likely see this as a real WRITE,
|
||||
resulting in possible misbehavior or corruption. Do not use i2cdump
|
||||
on random addresses. Anyway, it is of little use unless you have an idea of
|
||||
what you are looking for and have some general knowledge about hardware
|
||||
monitoring chips internals.
|
||||
|
||||
.SH SEE ALSO
|
||||
i2cset(8), i2cdetect(8), isadump(8)
|
||||
|
||||
.SH AUTHOR
|
||||
Frodo Looijaard, Mark D. Studebaker, and the lm_sensors group
|
||||
http://www.lm-sensors.org/
|
||||
This manual page was originally written by David Z Maze <dmaze@debian.org> for
|
||||
the Debian GNU/Linux system. It was then reviewed by the lm_sensors team and
|
||||
is now part of the lm_sensors source distribution.
|
||||
@@ -1,426 +0,0 @@
|
||||
/*
|
||||
i2cdump.c - a user-space program to dump I2C registers
|
||||
Copyright (C) 2002-2003 Frodo Looijaard <frodol@dds.nl>, and
|
||||
Mark D. Studebaker <mdsxyz123@yahoo.com>
|
||||
Copyright (C) 2004 The lm_sensors group
|
||||
|
||||
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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include "util.h"
|
||||
#include "i2cbusses.h"
|
||||
#include "i2c-dev.h"
|
||||
#include "version.h"
|
||||
|
||||
void help(void)
|
||||
{
|
||||
fprintf(stderr, "Syntax: i2cdump [-f] [-y] I2CBUS ADDRESS [MODE] "
|
||||
"[BANK [BANKREG]]\n"
|
||||
" i2cdump -V\n"
|
||||
" MODE is one of:\n"
|
||||
" b (byte, default)\n"
|
||||
" w (word)\n"
|
||||
" W (word on even register addresses)\n"
|
||||
" s (SMBus block)\n"
|
||||
" i (I2C block)\n"
|
||||
" c (consecutive byte)\n"
|
||||
" Append 'p' to 'b', 'w', 's' or 'c' for PEC checking\n"
|
||||
" I2CBUS is an integer\n"
|
||||
" ADDRESS is an integer 0x00 - 0x7f\n"
|
||||
" BANK and BANKREG are for byte and word accesses (default "
|
||||
"bank 0, reg 0x4e)\n"
|
||||
" BANK is the command for smbusblock accesses (default 0)\n");
|
||||
print_i2c_busses(0);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
char *end;
|
||||
int i, j, res, i2cbus, address, size, file;
|
||||
int bank = 0, bankreg = 0x4E, old_bank = 0;
|
||||
char filename[20];
|
||||
unsigned long funcs;
|
||||
int block[256], s_length = 0;
|
||||
int pec = 0, even = 0;
|
||||
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, "Warning: Unsupported flag "
|
||||
"\"-%c\"!\n", argv[1+flags][1]);
|
||||
help();
|
||||
exit(1);
|
||||
}
|
||||
flags++;
|
||||
}
|
||||
|
||||
if (version) {
|
||||
fprintf(stderr, "i2cdump version %s\n", LM_VERSION);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
if (argc < flags + 2) {
|
||||
fprintf(stderr, "Error: No i2c-bus specified!\n");
|
||||
help();
|
||||
exit(1);
|
||||
}
|
||||
i2cbus = strtol(argv[flags+1], &end, 0);
|
||||
if (*end) {
|
||||
fprintf(stderr, "Error: First argument not a number!\n");
|
||||
help();
|
||||
exit(1);
|
||||
}
|
||||
if (i2cbus < 0 || i2cbus > 0xff) {
|
||||
fprintf(stderr, "Error: I2CBUS argument out of range!\n");
|
||||
help();
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (argc < flags + 3) {
|
||||
fprintf(stderr, "Error: No address specified!\n");
|
||||
help();
|
||||
exit(1);
|
||||
}
|
||||
address = strtol(argv[flags+2], &end, 0);
|
||||
if (*end) {
|
||||
fprintf(stderr, "Error: Second argument not a number!\n");
|
||||
help();
|
||||
exit(1);
|
||||
}
|
||||
if (address < 0 || address > 0x7f) {
|
||||
fprintf(stderr, "Error: Address out of range!\n");
|
||||
help();
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (argc < flags + 4) {
|
||||
fprintf(stderr, "No size specified (using byte-data access)\n");
|
||||
size = I2C_SMBUS_BYTE_DATA;
|
||||
} else if (!strncmp(argv[flags+3], "b", 1)) {
|
||||
size = I2C_SMBUS_BYTE_DATA;
|
||||
pec = argv[flags+3][1] == 'p';
|
||||
} else if (!strncmp(argv[flags+3], "w", 1)) {
|
||||
size = I2C_SMBUS_WORD_DATA;
|
||||
pec = argv[flags+3][1] == 'p';
|
||||
} else if (!strncmp(argv[flags+3], "W", 1)) {
|
||||
size = I2C_SMBUS_WORD_DATA;
|
||||
even = 1;
|
||||
} else if (!strncmp(argv[flags+3], "s", 1)) {
|
||||
size = I2C_SMBUS_BLOCK_DATA;
|
||||
pec = argv[flags+3][1] == 'p';
|
||||
} else if (!strncmp(argv[flags+3], "c", 1)) {
|
||||
size = I2C_SMBUS_BYTE;
|
||||
pec = argv[flags+3][1] == 'p';
|
||||
} else if (!strcmp(argv[flags+3], "i"))
|
||||
size = I2C_SMBUS_I2C_BLOCK_DATA;
|
||||
else {
|
||||
fprintf(stderr, "Error: Invalid mode!\n");
|
||||
help();
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (argc > flags + 4) {
|
||||
bank = strtol(argv[flags+4], &end, 0);
|
||||
if (*end || size == I2C_SMBUS_I2C_BLOCK_DATA) {
|
||||
fprintf(stderr, "Error: Invalid bank number!\n");
|
||||
help();
|
||||
exit(1);
|
||||
}
|
||||
if ((size == I2C_SMBUS_BYTE_DATA || size == I2C_SMBUS_WORD_DATA)
|
||||
&& (bank < 0 || bank > 15)) {
|
||||
fprintf(stderr, "Error: bank out of range!\n");
|
||||
help();
|
||||
exit(1);
|
||||
}
|
||||
if (size == I2C_SMBUS_BLOCK_DATA
|
||||
&& (bank < 0 || bank > 0xff)) {
|
||||
fprintf(stderr, "Error: block command out of range!\n");
|
||||
help();
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (argc > flags + 5) {
|
||||
bankreg = strtol(argv[flags+5], &end, 0);
|
||||
if (*end || size == I2C_SMBUS_BLOCK_DATA) {
|
||||
fprintf(stderr, "Error: Invalid bank register "
|
||||
"number!\n");
|
||||
help();
|
||||
exit(1);
|
||||
}
|
||||
if (bankreg < 0 || bankreg > 0xff) {
|
||||
fprintf(stderr, "Error: bank out of range "
|
||||
"(0-0xff)!\n");
|
||||
help();
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
file = open_i2c_dev(i2cbus, filename, 0);
|
||||
if (file < 0) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* check adapter functionality */
|
||||
if (ioctl(file, I2C_FUNCS, &funcs) < 0) {
|
||||
fprintf(stderr, "Error: Could not get the adapter "
|
||||
"functionality matrix: %s\n", strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
switch(size) {
|
||||
case I2C_SMBUS_BYTE:
|
||||
if (!((funcs & I2C_FUNC_SMBUS_BYTE) == I2C_FUNC_SMBUS_BYTE)) {
|
||||
fprintf(stderr, "Error: Adapter for i2c bus %d does "
|
||||
"not have byte capability\n", i2cbus);
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
|
||||
case I2C_SMBUS_BYTE_DATA:
|
||||
if (!(funcs & I2C_FUNC_SMBUS_READ_BYTE_DATA)) {
|
||||
fprintf(stderr, "Error: Adapter for i2c bus %d does "
|
||||
"not have byte read capability\n", i2cbus);
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
|
||||
case I2C_SMBUS_WORD_DATA:
|
||||
if (!(funcs & I2C_FUNC_SMBUS_READ_WORD_DATA)) {
|
||||
fprintf(stderr, "Error: Adapter for i2c bus %d does "
|
||||
"not have word read capability\n", i2cbus);
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
|
||||
case I2C_SMBUS_BLOCK_DATA:
|
||||
if (!(funcs & I2C_FUNC_SMBUS_READ_BLOCK_DATA)) {
|
||||
fprintf(stderr, "Error: Adapter for i2c bus %d does "
|
||||
"not have smbus block read capability\n",
|
||||
i2cbus);
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
|
||||
case I2C_SMBUS_I2C_BLOCK_DATA:
|
||||
if (!(funcs & I2C_FUNC_SMBUS_READ_I2C_BLOCK)) {
|
||||
fprintf(stderr, "Error: Adapter for i2c bus %d does "
|
||||
"not have i2c block read capability\n",
|
||||
i2cbus);
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (set_slave_addr(file, address, force) < 0)
|
||||
exit(1);
|
||||
|
||||
if (pec) {
|
||||
if (ioctl(file, I2C_PEC, 1) < 0) {
|
||||
fprintf(stderr, "Error: Could not set PEC: %s\n",
|
||||
strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
if (!(funcs & (I2C_FUNC_SMBUS_HWPEC_CALC | I2C_FUNC_I2C))) {
|
||||
fprintf(stderr, "Warning: Adapter for i2c bus %d does "
|
||||
"not seem to actually support PEC\n", i2cbus);
|
||||
}
|
||||
}
|
||||
|
||||
if (!yes) {
|
||||
fprintf(stderr, "WARNING! This program can confuse your I2C "
|
||||
"bus, cause data loss and worse!\n");
|
||||
|
||||
fprintf(stderr, "I will probe file %s, address 0x%x, mode "
|
||||
"%s\n", filename, address,
|
||||
size == I2C_SMBUS_BLOCK_DATA ? "smbus block" :
|
||||
size == I2C_SMBUS_I2C_BLOCK_DATA ? "i2c block" :
|
||||
size == I2C_SMBUS_BYTE ? "byte consecutive read" :
|
||||
size == I2C_SMBUS_BYTE_DATA ? "byte" : "word");
|
||||
if (pec)
|
||||
fprintf(stderr, "PEC checking enabled.\n");
|
||||
if (even)
|
||||
fprintf(stderr, "Only probing even register "
|
||||
"addresses.\n");
|
||||
if (bank) {
|
||||
if (size == I2C_SMBUS_BLOCK_DATA)
|
||||
fprintf(stderr, "Using command 0x%02x.\n",
|
||||
bank);
|
||||
else
|
||||
fprintf(stderr, "Probing bank %d using bank "
|
||||
"register 0x%02x.\n", bank, bankreg);
|
||||
}
|
||||
|
||||
fprintf(stderr, "Continue? [Y/n] ");
|
||||
fflush(stderr);
|
||||
if (!user_ack(1)) {
|
||||
fprintf(stderr, "Aborting on user request.\n");
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
/* See Winbond w83781d data sheet for bank details */
|
||||
if (bank && size != I2C_SMBUS_BLOCK_DATA) {
|
||||
res = i2c_smbus_read_byte_data(file, bankreg);
|
||||
if (res >= 0) {
|
||||
old_bank = res;
|
||||
res = i2c_smbus_write_byte_data(file, bankreg,
|
||||
bank | (old_bank & 0xf0));
|
||||
}
|
||||
if (res < 0) {
|
||||
fprintf(stderr, "Error: Bank switching failed\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
/* handle all but word data */
|
||||
if (size != I2C_SMBUS_WORD_DATA || even) {
|
||||
/* do the block transaction */
|
||||
if (size == I2C_SMBUS_BLOCK_DATA
|
||||
|| size == I2C_SMBUS_I2C_BLOCK_DATA) {
|
||||
unsigned char cblock[288];
|
||||
|
||||
if (size == I2C_SMBUS_BLOCK_DATA) {
|
||||
res = i2c_smbus_read_block_data(file, bank,
|
||||
cblock);
|
||||
/* Remember returned block length for a nicer
|
||||
display later */
|
||||
s_length = res;
|
||||
} else {
|
||||
for (res = 0; res < 256; res += i) {
|
||||
i = i2c_smbus_read_i2c_block_data(file,
|
||||
res, 32, cblock + res);
|
||||
if (i <= 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (res <= 0) {
|
||||
fprintf(stderr, "Error: Block read failed, "
|
||||
"return code %d\n", res);
|
||||
exit(1);
|
||||
}
|
||||
if (res >= 256)
|
||||
res = 256;
|
||||
for (i = 0; i < res; i++)
|
||||
block[i] = cblock[i];
|
||||
if (size != I2C_SMBUS_BLOCK_DATA)
|
||||
for (i = res; i < 256; i++)
|
||||
block[i] = -1;
|
||||
}
|
||||
|
||||
if (size == I2C_SMBUS_BYTE) {
|
||||
res = i2c_smbus_write_byte(file, 0);
|
||||
if(res != 0) {
|
||||
fprintf(stderr, "Error: Write start address "
|
||||
"failed, return code %d\n", res);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
printf(" 0 1 2 3 4 5 6 7 8 9 a b c d e f"
|
||||
" 0123456789abcdef\n");
|
||||
for (i = 0; i < 256; i+=16) {
|
||||
if (size == I2C_SMBUS_BLOCK_DATA && i >= s_length)
|
||||
break;
|
||||
printf("%02x: ", i);
|
||||
for (j = 0; j < 16; j++) {
|
||||
fflush(stdout);
|
||||
if (size == I2C_SMBUS_BYTE_DATA) {
|
||||
block[i+j] = res =
|
||||
i2c_smbus_read_byte_data(file, i+j);
|
||||
} else if (size == I2C_SMBUS_WORD_DATA) {
|
||||
res = i2c_smbus_read_word_data(file,
|
||||
i+j);
|
||||
if (res < 0) {
|
||||
block[i+j] = res;
|
||||
block[i+j+1] = res;
|
||||
} else {
|
||||
block[i+j] = res & 0xff;
|
||||
block[i+j+1] = res >> 8;
|
||||
}
|
||||
} else if (size == I2C_SMBUS_BYTE) {
|
||||
block[i+j] = res =
|
||||
i2c_smbus_read_byte(file);
|
||||
} else
|
||||
res = block[i+j];
|
||||
|
||||
if (size == I2C_SMBUS_BLOCK_DATA
|
||||
&& i+j >= s_length) {
|
||||
printf(" ");
|
||||
} else if (res < 0) {
|
||||
printf("XX ");
|
||||
if (size == I2C_SMBUS_WORD_DATA)
|
||||
printf("XX ");
|
||||
} else {
|
||||
printf("%02x ", block[i+j]);
|
||||
if (size == I2C_SMBUS_WORD_DATA)
|
||||
printf("%02x ", block[i+j+1]);
|
||||
}
|
||||
if (size == I2C_SMBUS_WORD_DATA)
|
||||
j++;
|
||||
}
|
||||
printf(" ");
|
||||
|
||||
for (j = 0; j < 16; j++) {
|
||||
if (size == I2C_SMBUS_BLOCK_DATA
|
||||
&& i+j >= s_length)
|
||||
break;
|
||||
|
||||
res = block[i+j];
|
||||
if (res < 0)
|
||||
printf("X");
|
||||
else
|
||||
if ((res & 0xff) == 0x00
|
||||
|| (res & 0xff) == 0xff)
|
||||
printf(".");
|
||||
else
|
||||
if ((res & 0xff) < 32
|
||||
|| (res & 0xff) >= 127)
|
||||
printf("?");
|
||||
else
|
||||
printf("%c", res & 0xff);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
} else {
|
||||
printf(" 0,8 1,9 2,a 3,b 4,c 5,d 6,e 7,f\n");
|
||||
for (i = 0; i < 256; i+=8) {
|
||||
printf("%02x: ", i);
|
||||
for (j = 0; j < 8; j++) {
|
||||
res = i2c_smbus_read_word_data(file, i+j);
|
||||
if (res < 0)
|
||||
printf("XXXX ");
|
||||
else
|
||||
printf("%04x ", res & 0xffff);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
if (bank && size != I2C_SMBUS_BLOCK_DATA) {
|
||||
i2c_smbus_write_byte_data(file, bankreg, old_bank);
|
||||
}
|
||||
exit(0);
|
||||
}
|
||||
@@ -1,68 +0,0 @@
|
||||
.TH I2CGET 8 "June 2007"
|
||||
.SH "NAME"
|
||||
i2cget \- read from I2C/SMBus chip registers
|
||||
|
||||
.SH SYNOPSIS
|
||||
.B i2cget
|
||||
.RB [ -f ]
|
||||
.RB [ -y ]
|
||||
.I i2cbus
|
||||
.I chip-address
|
||||
.RI [ data-address " [" mode ]]
|
||||
.br
|
||||
.B i2cget
|
||||
.B -V
|
||||
|
||||
.SH DESCRIPTION
|
||||
i2cget is a small helper program to read registers visible through the I2C
|
||||
bus (or SMBus).
|
||||
|
||||
.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, i2cget
|
||||
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 i2cget 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, i2cget 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 two required options to i2cget. \fIi2cbus\fR indicates the number
|
||||
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\fR specifies the address on that chip to read from, and is
|
||||
an integer between 0x00 and 0xFF. If omitted, the currently active register
|
||||
will be read (if that makes sense for the considered chip).
|
||||
.PP
|
||||
The \fImode\fR parameter, if specified, is one of the letters \fBb\fP,
|
||||
\fBw\fP or \fBc\fP, corresponding to a read byte data, a read word data or a
|
||||
write byte/read byte transaction, respectively. A \fBp\fP can also be appended
|
||||
to the \fImode\fR parameter to enable PEC. If the \fImode\fR parameter is omitted,
|
||||
i2cget defaults to a read byte data transaction, unless \fIdata-address\fR is
|
||||
also omitted, in which case the default (and only valid) transaction is a
|
||||
single read byte.
|
||||
|
||||
.SH WARNING
|
||||
i2cget 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)
|
||||
|
||||
.SH AUTHOR
|
||||
Jean Delvare
|
||||
http://www.lm-sensors.org/
|
||||
This manual page was strongly inspired from those written by David Z Maze
|
||||
for i2cset.
|
||||
@@ -1,263 +0,0 @@
|
||||
/*
|
||||
i2cget.c - A user-space program to read an I2C register.
|
||||
Copyright (C) 2005 Jean Delvare <khali@linux-fr.org>
|
||||
|
||||
Based on i2cset.c:
|
||||
Copyright (C) 2001-2003 Frodo Looijaard <frodol@dds.nl>, and
|
||||
Mark D. Studebaker <mdsxyz123@yahoo.com>
|
||||
Copyright (C) 2004-2005 Jean Delvare <khali@linux-fr.org>
|
||||
|
||||
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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include "util.h"
|
||||
#include "i2cbusses.h"
|
||||
#include "i2c-dev.h"
|
||||
#include "version.h"
|
||||
|
||||
void help(void) __attribute__ ((noreturn));
|
||||
|
||||
void help(void)
|
||||
{
|
||||
fprintf(stderr, "Syntax: i2cget [-f] [-y] I2CBUS CHIP-ADDRESS "
|
||||
"[DATA-ADDRESS [MODE]]\n"
|
||||
" i2cget -V\n"
|
||||
" MODE can be: 'b' (read byte data, default)\n"
|
||||
" 'w' (read word data)\n"
|
||||
" 'c' (write byte/read byte)\n"
|
||||
" If DATA-ADDRESS is omitted, a single read byte command is "
|
||||
"issued\n"
|
||||
" Append 'p' to MODE for PEC checking\n"
|
||||
" I2CBUS is an integer\n");
|
||||
print_i2c_busses(0);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int check_funcs(int file, int i2cbus, int size, int daddress, int pec)
|
||||
{
|
||||
unsigned long funcs;
|
||||
|
||||
/* check adapter functionality */
|
||||
if (ioctl(file, I2C_FUNCS, &funcs) < 0) {
|
||||
fprintf(stderr, "Error: Could not get the adapter "
|
||||
"functionality matrix: %s\n", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
switch (size) {
|
||||
case I2C_SMBUS_BYTE:
|
||||
if (!(funcs & I2C_FUNC_SMBUS_READ_BYTE)) {
|
||||
fprintf(stderr, "Error: Adapter for i2c bus %d does "
|
||||
"not have read byte capability\n", i2cbus);
|
||||
return -1;
|
||||
}
|
||||
if (daddress >= 0
|
||||
&& !(funcs & I2C_FUNC_SMBUS_WRITE_BYTE)) {
|
||||
fprintf(stderr, "Error: Adapter for i2c bus %d does "
|
||||
"not have write byte capability\n", i2cbus);
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
|
||||
case I2C_SMBUS_BYTE_DATA:
|
||||
if (!(funcs & I2C_FUNC_SMBUS_READ_BYTE_DATA)) {
|
||||
fprintf(stderr, "Error: Adapter for i2c bus %d does "
|
||||
"not have read byte data capability\n", i2cbus);
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
|
||||
case I2C_SMBUS_WORD_DATA:
|
||||
if (!(funcs & I2C_FUNC_SMBUS_READ_WORD_DATA)) {
|
||||
fprintf(stderr, "Error: Adapter for i2c bus %d does "
|
||||
"not have read word data capability\n", i2cbus);
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (pec
|
||||
&& !(funcs & (I2C_FUNC_SMBUS_HWPEC_CALC | I2C_FUNC_I2C))) {
|
||||
fprintf(stderr, "Warning: Adapter for i2c bus %d does "
|
||||
"not seem to support PEC\n", i2cbus);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int confirm(const char *filename, int address, int size, int daddress, int pec)
|
||||
{
|
||||
int dont = 0;
|
||||
|
||||
fprintf(stderr, "WARNING! This program can confuse your I2C "
|
||||
"bus, cause data loss and worse!\n");
|
||||
|
||||
/* Don't let the user break his/her EEPROMs */
|
||||
if (address >= 0x50 && address <= 0x57 && pec) {
|
||||
fprintf(stderr, "STOP! EEPROMs are I2C devices, not "
|
||||
"SMBus devices. Using PEC\non I2C devices may "
|
||||
"result in unexpected results, such as\n"
|
||||
"trashing the contents of EEPROMs. We can't "
|
||||
"let you do that, sorry.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (size == I2C_SMBUS_BYTE && daddress >= 0 && pec) {
|
||||
fprintf(stderr, "WARNING! All I2C chips and some SMBus chips "
|
||||
"will interpret a write\nbyte command with PEC as a"
|
||||
"write byte data command, effectively writing a\n"
|
||||
"value into a register!\n");
|
||||
dont++;
|
||||
}
|
||||
|
||||
fprintf(stderr, "I will read from device file %s, chip "
|
||||
"address 0x%02x, ", filename, address);
|
||||
if (daddress < 0)
|
||||
fprintf(stderr, "current data\naddress");
|
||||
else
|
||||
fprintf(stderr, "data address\n0x%02x", daddress);
|
||||
fprintf(stderr, ", using %s.\n",
|
||||
size == I2C_SMBUS_BYTE ? (daddress < 0 ?
|
||||
"read byte" : "write byte/read byte") :
|
||||
size == I2C_SMBUS_BYTE_DATA ? "read byte data" :
|
||||
"read word data");
|
||||
if (pec)
|
||||
fprintf(stderr, "PEC checking enabled.\n");
|
||||
|
||||
fprintf(stderr, "Continue? [%s] ", dont ? "y/N" : "Y/n");
|
||||
fflush(stderr);
|
||||
if (!user_ack(!dont)) {
|
||||
fprintf(stderr, "Aborting on user request.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
char *end;
|
||||
int res, i2cbus, address, file;
|
||||
int size = I2C_SMBUS_BYTE_DATA;
|
||||
int daddress;
|
||||
char filename[20];
|
||||
int pec = 0;
|
||||
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, "Warning: Unsupported flag "
|
||||
"\"-%c\"!\n", argv[1+flags][1]);
|
||||
help();
|
||||
exit(1);
|
||||
}
|
||||
flags++;
|
||||
}
|
||||
|
||||
if (version) {
|
||||
fprintf(stderr, "i2cget version %s\n", LM_VERSION);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
if (argc - flags < 3)
|
||||
help();
|
||||
|
||||
i2cbus = strtol(argv[flags+1], &end, 0);
|
||||
if (*end || i2cbus < 0 || i2cbus > 0x3f) {
|
||||
fprintf(stderr, "Error: I2CBUS argument invalid!\n");
|
||||
help();
|
||||
}
|
||||
|
||||
address = strtol(argv[flags+2], &end, 0);
|
||||
if (*end || address < 3 || address > 0x77) {
|
||||
fprintf(stderr, "Error: Chip address invalid!\n");
|
||||
help();
|
||||
}
|
||||
|
||||
if (!(flags+3 < argc)) {
|
||||
size = I2C_SMBUS_BYTE;
|
||||
daddress = -1;
|
||||
} else {
|
||||
daddress = strtol(argv[flags+3], &end, 0);
|
||||
if (*end || daddress < 0 || daddress > 0xff) {
|
||||
fprintf(stderr, "Error: Data address invalid!\n");
|
||||
help();
|
||||
}
|
||||
}
|
||||
|
||||
if (flags+4 < argc) {
|
||||
switch (argv[flags+4][0]) {
|
||||
case 'b': size = I2C_SMBUS_BYTE_DATA; break;
|
||||
case 'w': size = I2C_SMBUS_WORD_DATA; break;
|
||||
case 'c': size = I2C_SMBUS_BYTE; break;
|
||||
default:
|
||||
fprintf(stderr, "Error: Invalid mode!\n");
|
||||
help();
|
||||
}
|
||||
pec = argv[flags+4][1] == 'p';
|
||||
}
|
||||
|
||||
file = open_i2c_dev(i2cbus, filename, 0);
|
||||
if (file < 0
|
||||
|| check_funcs(file, i2cbus, size, daddress, pec)
|
||||
|| set_slave_addr(file, address, force))
|
||||
exit(1);
|
||||
|
||||
if (!yes && !confirm(filename, address, size, daddress, pec))
|
||||
exit(0);
|
||||
|
||||
if (pec && ioctl(file, I2C_PEC, 1) < 0) {
|
||||
fprintf(stderr, "Error: Could not set PEC: %s\n",
|
||||
strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
switch (size) {
|
||||
case I2C_SMBUS_BYTE:
|
||||
if (daddress >= 0) {
|
||||
res = i2c_smbus_write_byte(file, daddress);
|
||||
if (res < 0)
|
||||
fprintf(stderr, "Warning - write failed\n");
|
||||
}
|
||||
res = i2c_smbus_read_byte(file);
|
||||
break;
|
||||
case I2C_SMBUS_WORD_DATA:
|
||||
res = i2c_smbus_read_word_data(file, daddress);
|
||||
break;
|
||||
default: /* I2C_SMBUS_BYTE_DATA */
|
||||
res = i2c_smbus_read_byte_data(file, daddress);
|
||||
}
|
||||
close(file);
|
||||
|
||||
if (res < 0) {
|
||||
fprintf(stderr, "Error: Read failed\n");
|
||||
exit(2);
|
||||
}
|
||||
|
||||
printf("0x%0*x\n", size == I2C_SMBUS_WORD_DATA ? 4 : 2, res);
|
||||
|
||||
exit(0);
|
||||
}
|
||||
@@ -1,77 +0,0 @@
|
||||
.TH I2CSET 8 "June 2007"
|
||||
.SH "NAME"
|
||||
i2cset \- set I2C registers
|
||||
|
||||
.SH SYNOPSIS
|
||||
.B i2cset
|
||||
.RB [ -f ]
|
||||
.RB [ -y ]
|
||||
.I i2cbus
|
||||
.I chip-address
|
||||
.I data-address
|
||||
.I value
|
||||
.RI [ mode ]
|
||||
.RI [ mask ]
|
||||
.br
|
||||
.B i2cset
|
||||
.B -V
|
||||
|
||||
.SH DESCRIPTION
|
||||
i2cset is a small helper program to set registers visible through the I2C
|
||||
bus.
|
||||
|
||||
.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, i2cset
|
||||
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 i2cset to silently write to
|
||||
the wrong register. So use at your own risk and only if you know what
|
||||
you're doing.
|
||||
.TP
|
||||
.B -y
|
||||
Disable interactive mode. By default, i2cset 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.
|
||||
.PP
|
||||
There are four required options to i2cset. \fIi2cbus\fR indicates the number
|
||||
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 0x00 and 0x7F.
|
||||
\fIdata-address\fR specifies the address on that chip to write to, and is an
|
||||
integer between 0x00 and 0xFF. \fIvalue\fR is the value to write to that
|
||||
location on the chip.
|
||||
.PP
|
||||
The \fImode\fR parameter, if specified, is one of the letters \fBb\fP or
|
||||
\fBw\fP, corresponding to a write size of a single byte or a 16-bit word,
|
||||
respectively. A \fBp\fP can also be appended to the \fImode\fR parameter to
|
||||
enable PEC. If the \fImode\fR parameter is omitted, i2cset defaults to byte
|
||||
mode without PEC. The \fIvalue\fR provided must be within range for the
|
||||
specified data type (0x00-0xFF for bytes, 0x0000-0xFFFF for words).
|
||||
.PP
|
||||
The \fImask\fR parameter, if specified, describes which bits of \fIvalue\fR
|
||||
will be actually written to \fIdata-address\fR. Bits set to 1 in the mask
|
||||
are taken from \fIvalue\fR, while bits set to 0 will be read from
|
||||
\fIdata-address\fR and thus preserved by the operation.
|
||||
|
||||
.SH WARNING
|
||||
i2cset can be extremely dangerous if used improperly. It can confuse your
|
||||
I2C bus, cause data loss, or have more serious side effects. Writing to
|
||||
a serial EEPROM on a memory DIMM (chip addresses between 0x50 and 0x57) may
|
||||
DESTROY your memory, leaving your system unbootable! Be extremely careful
|
||||
using this program.
|
||||
|
||||
.SH SEE ALSO
|
||||
i2cdump(8), isaset(8)
|
||||
|
||||
.SH AUTHOR
|
||||
Frodo Looijaard, Mark D. Studebaker, and the lm_sensors group
|
||||
http://www.lm-sensors.org/
|
||||
This manual page was originally written by David Z Maze <dmaze@debian.org> for
|
||||
the Debian GNU/Linux system. It was then reviewed by the lm_sensors team and
|
||||
is now part of the lm_sensors source distribution.
|
||||
@@ -1,286 +0,0 @@
|
||||
/*
|
||||
i2cset.c - A user-space program to write an I2C register.
|
||||
Copyright (C) 2001-2003 Frodo Looijaard <frodol@dds.nl>, and
|
||||
Mark D. Studebaker <mdsxyz123@yahoo.com>
|
||||
Copyright (C) 2004-2005 Jean Delvare <khali@linux-fr.org>
|
||||
|
||||
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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include "i2cbusses.h"
|
||||
#include "util.h"
|
||||
#include "i2c-dev.h"
|
||||
#include "version.h"
|
||||
|
||||
void help(void) __attribute__ ((noreturn));
|
||||
|
||||
void help(void)
|
||||
{
|
||||
fprintf(stderr, "Syntax: i2cset [-f] [-y] I2CBUS CHIP-ADDRESS DATA-ADDRESS "
|
||||
"VALUE [MODE] [MASK]\n"
|
||||
" i2cset -V\n"
|
||||
" MODE is 'b[yte]' or 'w[ord]' (default b)\n"
|
||||
" Append 'p' to MODE for PEC checking\n"
|
||||
" I2CBUS is an integer\n");
|
||||
print_i2c_busses(0);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
char *end;
|
||||
int res, i2cbus, address, size, file;
|
||||
int value, daddress, vmask = 0;
|
||||
int e1;
|
||||
char filename[20];
|
||||
unsigned long funcs;
|
||||
int pec = 0;
|
||||
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, "Warning: Unsupported flag "
|
||||
"\"-%c\"!\n", argv[1+flags][1]);
|
||||
help();
|
||||
exit(1);
|
||||
}
|
||||
flags++;
|
||||
}
|
||||
|
||||
if (version) {
|
||||
fprintf(stderr, "i2cset version %s\n", LM_VERSION);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
if (argc < flags + 5)
|
||||
help();
|
||||
|
||||
i2cbus = strtol(argv[flags+1], &end, 0);
|
||||
if (*end || i2cbus < 0 || i2cbus > 0x3f) {
|
||||
fprintf(stderr, "Error: I2CBUS argument invalid!\n");
|
||||
help();
|
||||
}
|
||||
|
||||
address = strtol(argv[flags+2], &end, 0);
|
||||
if (*end || address < 0 || address > 0x7f) {
|
||||
fprintf(stderr, "Error: Chip address invalid!\n");
|
||||
help();
|
||||
}
|
||||
|
||||
daddress = strtol(argv[flags+3], &end, 0);
|
||||
if (*end || daddress < 0 || daddress > 0xff) {
|
||||
fprintf(stderr, "Error: Data address invalid!\n");
|
||||
help();
|
||||
}
|
||||
|
||||
value = strtol(argv[flags+4], &end, 0);
|
||||
if (*end) {
|
||||
fprintf(stderr, "Error: Data value invalid!\n");
|
||||
help();
|
||||
}
|
||||
|
||||
if (argc < flags + 6) {
|
||||
fprintf(stderr, "No size specified (using byte-data access)\n");
|
||||
size = I2C_SMBUS_BYTE_DATA;
|
||||
} else if (argv[flags+5][0] == 'b') {
|
||||
size = I2C_SMBUS_BYTE_DATA;
|
||||
pec = argv[flags+5][1] == 'p';
|
||||
} else if (argv[flags+5][0] == 'w') {
|
||||
size = I2C_SMBUS_WORD_DATA;
|
||||
pec = argv[flags+5][1] == 'p';
|
||||
} else {
|
||||
fprintf(stderr, "Error: Invalid mode!\n");
|
||||
help();
|
||||
}
|
||||
|
||||
if (argc >= flags + 7) {
|
||||
vmask = strtol(argv[flags+6], &end, 0);
|
||||
if (*end || vmask == 0) {
|
||||
fprintf(stderr, "Error: Data value mask invalid!\n");
|
||||
help();
|
||||
}
|
||||
}
|
||||
|
||||
if (value < 0
|
||||
|| (size == I2C_SMBUS_BYTE_DATA && value > 0xff)
|
||||
|| (size == I2C_SMBUS_WORD_DATA && value > 0xffff)) {
|
||||
fprintf(stderr, "Error: Data value out of range!\n");
|
||||
help();
|
||||
}
|
||||
|
||||
file = open_i2c_dev(i2cbus, filename, 0);
|
||||
if (file < 0) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* check adapter functionality */
|
||||
if (ioctl(file, I2C_FUNCS, &funcs) < 0) {
|
||||
fprintf(stderr, "Error: Could not get the adapter "
|
||||
"functionality matrix: %s\n", strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
switch (size) {
|
||||
case I2C_SMBUS_BYTE_DATA:
|
||||
if (!(funcs & I2C_FUNC_SMBUS_WRITE_BYTE_DATA)) {
|
||||
fprintf(stderr, "Error: Adapter for i2c bus %d does "
|
||||
"not have byte write capability\n", i2cbus);
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
|
||||
case I2C_SMBUS_WORD_DATA:
|
||||
if (!(funcs & I2C_FUNC_SMBUS_WRITE_WORD_DATA)) {
|
||||
fprintf(stderr, "Error: Adapter for i2c bus %d does "
|
||||
"not have word write capability\n", i2cbus);
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (set_slave_addr(file, address, force) < 0)
|
||||
exit(1);
|
||||
|
||||
if (!yes) {
|
||||
int dont = 0;
|
||||
|
||||
fprintf(stderr, "WARNING! This program can confuse your I2C "
|
||||
"bus, cause data loss and worse!\n");
|
||||
|
||||
if (address >= 0x50 && address <= 0x57) {
|
||||
fprintf(stderr, "DANGEROUS! Writing to a serial "
|
||||
"EEPROM on a memory DIMM\nmay render your "
|
||||
"memory USELESS and make your system "
|
||||
"UNBOOTABLE!\n");
|
||||
dont = 1;
|
||||
}
|
||||
|
||||
fprintf(stderr, "I will write to device file %s, chip address "
|
||||
"0x%02x, data address\n0x%02x, data 0x%02x%s, mode "
|
||||
"%s.\n", filename, address, daddress, value,
|
||||
vmask ? " (masked)" : "",
|
||||
size == I2C_SMBUS_BYTE_DATA ? "byte" : "word");
|
||||
if (pec)
|
||||
fprintf(stderr, "PEC checking enabled.\n");
|
||||
|
||||
fprintf(stderr, "Continue? [%s] ", dont ? "y/N" : "Y/n");
|
||||
fflush(stderr);
|
||||
if (!user_ack(!dont)) {
|
||||
fprintf(stderr, "Aborting on user request.\n");
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
if (vmask) {
|
||||
int oldvalue;
|
||||
|
||||
if (size == I2C_SMBUS_WORD_DATA) {
|
||||
oldvalue = i2c_smbus_read_word_data(file, daddress);
|
||||
} else {
|
||||
oldvalue = i2c_smbus_read_byte_data(file, daddress);
|
||||
}
|
||||
|
||||
if (oldvalue < 0) {
|
||||
fprintf(stderr, "Error: Failed to read old value\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
value = (value & vmask) | (oldvalue & ~vmask);
|
||||
|
||||
if (!yes) {
|
||||
fprintf(stderr, "Old value 0x%0*x, write mask "
|
||||
"0x%0*x: Will write 0x%0*x to register "
|
||||
"0x%02x\n",
|
||||
size == I2C_SMBUS_WORD_DATA ? 4 : 2, oldvalue,
|
||||
size == I2C_SMBUS_WORD_DATA ? 4 : 2, vmask,
|
||||
size == I2C_SMBUS_WORD_DATA ? 4 : 2, value,
|
||||
daddress);
|
||||
|
||||
fprintf(stderr, "Continue? [Y/n] ");
|
||||
fflush(stderr);
|
||||
if (!user_ack(1)) {
|
||||
fprintf(stderr, "Aborting on user request.\n");
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (pec) {
|
||||
if (ioctl(file, I2C_PEC, 1) < 0) {
|
||||
fprintf(stderr, "Error: Could not set PEC: %s\n",
|
||||
strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
if (!(funcs & (I2C_FUNC_SMBUS_HWPEC_CALC | I2C_FUNC_I2C))) {
|
||||
fprintf(stderr, "Warning: Adapter for i2c bus %d does "
|
||||
"not seem to actually support PEC\n", i2cbus);
|
||||
}
|
||||
}
|
||||
|
||||
e1 = 0;
|
||||
if (size == I2C_SMBUS_WORD_DATA) {
|
||||
res = i2c_smbus_write_word_data(file, daddress, value);
|
||||
} else {
|
||||
res = i2c_smbus_write_byte_data(file, daddress, value);
|
||||
}
|
||||
if (res < 0) {
|
||||
fprintf(stderr, "Warning - write failed\n");
|
||||
e1++;
|
||||
}
|
||||
|
||||
if (pec) {
|
||||
if (ioctl(file, I2C_PEC, 0) < 0) {
|
||||
fprintf(stderr, "Error: Could not clear PEC: %s\n",
|
||||
strerror(errno));
|
||||
close(file);
|
||||
exit(e1);
|
||||
}
|
||||
}
|
||||
|
||||
if (size == I2C_SMBUS_WORD_DATA) {
|
||||
res = i2c_smbus_read_word_data(file, daddress);
|
||||
} else {
|
||||
res = i2c_smbus_read_byte_data(file, daddress);
|
||||
}
|
||||
close(file);
|
||||
|
||||
if (res < 0) {
|
||||
fprintf(stderr, "Warning - readback failed\n");
|
||||
e1++;
|
||||
} else
|
||||
if (res != value) {
|
||||
e1++;
|
||||
fprintf(stderr, "Warning - data mismatch - wrote "
|
||||
"0x%0*x, read back 0x%0*x\n",
|
||||
size == I2C_SMBUS_WORD_DATA ? 4 : 2, value,
|
||||
size == I2C_SMBUS_WORD_DATA ? 4 : 2, res);
|
||||
} else {
|
||||
fprintf(stderr, "Value 0x%0*x written, readback matched\n",
|
||||
size == I2C_SMBUS_WORD_DATA ? 4 : 2, value);
|
||||
}
|
||||
|
||||
exit(e1);
|
||||
}
|
||||
Reference in new issue
Block a user