i2cdump: code rework
Split i2cdump_main() into shorter functions. Simplify the code a bit. Make block an array of ints so that we can store negative results of read functions (fixes a bug found by Denys Vlasenko). Signed-off-by: Bartosz Golaszewski <bartekgola@gmail.com> Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
This commit is contained in:
parent
2204472497
commit
aeb11a9496
@ -816,139 +816,44 @@ int i2cset_main(int argc, char **argv)
|
||||
#endif /* ENABLE_I2CSET */
|
||||
|
||||
#if ENABLE_I2CDUMP
|
||||
//usage:#define i2cdump_trivial_usage
|
||||
//usage: "[-f] [-r FIRST-LAST] [-y] BUS ADDR [MODE]"
|
||||
//usage:#define i2cdump_full_usage "\n\n"
|
||||
//usage: "Examine I2C registers\n"
|
||||
//usage: "\n I2CBUS i2c bus number"
|
||||
//usage: "\n ADDRESS 0x03 - 0x77"
|
||||
//usage: "\nMODE is:"
|
||||
//usage: "\n b byte (default)"
|
||||
//usage: "\n w word"
|
||||
//usage: "\n W word on even register addresses"
|
||||
//usage: "\n i I2C block"
|
||||
//usage: "\n s SMBus block"
|
||||
//usage: "\n c consecutive byte"
|
||||
//usage: "\n Append p for SMBus PEC"
|
||||
//usage: "\n"
|
||||
//usage: "\n -f force access"
|
||||
//usage: "\n -y disable interactive mode"
|
||||
//usage: "\n -r limit the number of registers being accessed"
|
||||
int i2cdump_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
|
||||
int i2cdump_main(int argc UNUSED_PARAM, char **argv)
|
||||
static int read_block_data(int buf_fd, int mode, int *block)
|
||||
{
|
||||
const unsigned opt_f = (1 << 0), opt_y = (1 << 1),
|
||||
opt_r = (1 << 2);
|
||||
const char *const optstr = "fyr:";
|
||||
uint8_t cblock[I2C_SMBUS_BLOCK_MAX + I2C_MAX_REGS];
|
||||
int res, blen = 0, tmp, i;
|
||||
|
||||
int bus_num, bus_addr, mode = I2C_SMBUS_BYTE_DATA, even = 0, pec = 0;
|
||||
unsigned first = 0x00, last = 0xff;
|
||||
int fd, i, j, res, blen = 0, tmp;
|
||||
unsigned char cblock[I2C_SMBUS_BLOCK_MAX + I2C_MAX_REGS];
|
||||
unsigned char block[I2C_SMBUS_BLOCK_MAX];
|
||||
char *opt_r_str, *dash;
|
||||
unsigned opts;
|
||||
|
||||
opt_complementary = "-2:?3"; /* from 2 to 3 args */
|
||||
opts = getopt32(argv, optstr, &opt_r_str);
|
||||
argv += optind;
|
||||
|
||||
bus_num = i2c_bus_lookup(argv[0]);
|
||||
bus_addr = i2c_parse_bus_addr(argv[1]);
|
||||
|
||||
if (argv[2]) {
|
||||
switch (argv[2][0]) {
|
||||
case 'b': /* Already set */ break;
|
||||
case 'c': mode = I2C_SMBUS_BYTE; break;
|
||||
case 'w': mode = I2C_SMBUS_WORD_DATA; break;
|
||||
case 'W':
|
||||
mode = I2C_SMBUS_WORD_DATA;
|
||||
even = 1;
|
||||
break;
|
||||
case 's': mode = I2C_SMBUS_BLOCK_DATA; break;
|
||||
case 'i': mode = I2C_SMBUS_I2C_BLOCK_DATA; break;
|
||||
default:
|
||||
bb_error_msg_and_die("invalid mode");
|
||||
}
|
||||
|
||||
if (argv[2][1] == 'p') {
|
||||
if (argv[2][0] == 'W' || argv[2][0] == 'i') {
|
||||
bb_error_msg_and_die(
|
||||
"pec not supported for -W and -i");
|
||||
} else {
|
||||
pec = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (opts & opt_r) {
|
||||
first = strtol(opt_r_str, &dash, 0);
|
||||
if (dash == opt_r_str || *dash != '-' || first > 0xff)
|
||||
bb_error_msg_and_die("invalid range");
|
||||
last = xstrtou_range(++dash, 0, first, 0xff);
|
||||
|
||||
/* Range is not available for every mode */
|
||||
switch (mode) {
|
||||
case I2C_SMBUS_BYTE:
|
||||
case I2C_SMBUS_BYTE_DATA:
|
||||
break;
|
||||
case I2C_SMBUS_WORD_DATA:
|
||||
if (!even || (!(first % 2) && last % 2))
|
||||
break;
|
||||
/* Fall through */
|
||||
default:
|
||||
bb_error_msg_and_die(
|
||||
"range not compatible with selected mode");
|
||||
}
|
||||
}
|
||||
|
||||
fd = i2c_dev_open(bus_num);
|
||||
check_read_funcs(fd, mode, -1 /* data_addr */, pec);
|
||||
i2c_set_slave_addr(fd, bus_addr, opts & opt_f);
|
||||
|
||||
if (pec)
|
||||
i2c_set_pec(fd, 1);
|
||||
|
||||
if (!(opts & opt_y))
|
||||
confirm_action(bus_addr, mode, -1 /* data_addr */, pec);
|
||||
|
||||
/* All but word data */
|
||||
if (mode != I2C_SMBUS_WORD_DATA || even) {
|
||||
/*
|
||||
* FIXME This section has been ported from upstream i2cdump.
|
||||
* It has been reworked a bit but is still pretty spaghetti
|
||||
* and needs splitting into several functions.
|
||||
*/
|
||||
if (mode == I2C_SMBUS_BLOCK_DATA ||
|
||||
mode == I2C_SMBUS_I2C_BLOCK_DATA) {
|
||||
res = i2c_smbus_read_block_data(fd, 0, cblock);
|
||||
if (mode == I2C_SMBUS_BLOCK_DATA || mode == I2C_SMBUS_I2C_BLOCK_DATA) {
|
||||
res = i2c_smbus_read_block_data(buf_fd, 0, cblock);
|
||||
blen = res;
|
||||
} else {
|
||||
for (res = 0; res < I2C_MAX_REGS; res += tmp) {
|
||||
tmp = i2c_smbus_read_i2c_block_data(
|
||||
fd, res, I2C_SMBUS_BLOCK_MAX,
|
||||
buf_fd, res, I2C_SMBUS_BLOCK_MAX,
|
||||
cblock + res);
|
||||
if (tmp < 0) {
|
||||
bb_error_msg_and_die(
|
||||
"block read failed");
|
||||
bb_error_msg_and_die("block read failed");
|
||||
}
|
||||
}
|
||||
if (res >= I2C_MAX_REGS)
|
||||
res = I2C_MAX_REGS;
|
||||
for (i = 0; i < res; i++)
|
||||
block[i] = cblock[i];
|
||||
if (mode != I2C_SMBUS_BLOCK_DATA)
|
||||
for (i = res; i < I2C_MAX_REGS; i++)
|
||||
cblock[i] = -1;
|
||||
}
|
||||
|
||||
if (mode == I2C_SMBUS_BYTE) {
|
||||
res = i2c_smbus_write_byte(fd, first);
|
||||
if (res < 0)
|
||||
bb_perror_msg_and_die(
|
||||
"write start address failed");
|
||||
if (res >= I2C_MAX_REGS)
|
||||
res = I2C_MAX_REGS;
|
||||
|
||||
for (i = 0; i < res; i++)
|
||||
block[i] = cblock[i];
|
||||
|
||||
if (mode != I2C_SMBUS_BLOCK_DATA)
|
||||
for (i = res; i < I2C_MAX_REGS; i++)
|
||||
block[i] = -1;
|
||||
}
|
||||
|
||||
return blen;
|
||||
}
|
||||
|
||||
/* Dump all but word data. */
|
||||
static void dump_data(int bus_fd, int mode, unsigned first,
|
||||
unsigned last, int *block, int blen)
|
||||
{
|
||||
int i, j, res;
|
||||
|
||||
printf(" 0 1 2 3 4 5 6 7 8 9 a b c d e f"
|
||||
" 0123456789abcdef\n");
|
||||
|
||||
@ -975,11 +880,11 @@ int i2cdump_main(int argc UNUSED_PARAM, char **argv)
|
||||
|
||||
switch (mode) {
|
||||
case I2C_SMBUS_BYTE_DATA:
|
||||
res = i2c_smbus_read_byte_data(fd, i+j);
|
||||
res = i2c_smbus_read_byte_data(bus_fd, i+j);
|
||||
block[i+j] = res;
|
||||
break;
|
||||
case I2C_SMBUS_WORD_DATA:
|
||||
res = i2c_smbus_read_word_data(fd, i+j);
|
||||
res = i2c_smbus_read_word_data(bus_fd, i+j);
|
||||
if (res < 0) {
|
||||
block[i+j] = res;
|
||||
block[i+j+1] = res;
|
||||
@ -989,7 +894,7 @@ int i2cdump_main(int argc UNUSED_PARAM, char **argv)
|
||||
}
|
||||
break;
|
||||
case I2C_SMBUS_BYTE:
|
||||
res = i2c_smbus_read_byte(fd);
|
||||
res = i2c_smbus_read_byte(bus_fd);
|
||||
block[i+j] = res;
|
||||
break;
|
||||
default:
|
||||
@ -1025,7 +930,6 @@ int i2cdump_main(int argc UNUSED_PARAM, char **argv)
|
||||
|
||||
res = block[i+j];
|
||||
if (res < 0) {
|
||||
//FIXME: impossible, block[] is uchar[]
|
||||
printf("X");
|
||||
} else if (res == 0x00 || res == 0xff) {
|
||||
printf(".");
|
||||
@ -1037,7 +941,12 @@ int i2cdump_main(int argc UNUSED_PARAM, char **argv)
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
} else {
|
||||
}
|
||||
|
||||
static void dump_word_data(int bus_fd, unsigned first, unsigned last)
|
||||
{
|
||||
int i, j, rv;
|
||||
|
||||
/* Word data. */
|
||||
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) {
|
||||
@ -1054,14 +963,123 @@ int i2cdump_main(int argc UNUSED_PARAM, char **argv)
|
||||
continue;
|
||||
}
|
||||
|
||||
res = i2c_smbus_read_word_data(fd, i+j);
|
||||
if (res < 0)
|
||||
rv = i2c_smbus_read_word_data(bus_fd, i+j);
|
||||
if (rv < 0)
|
||||
printf("XXXX ");
|
||||
else
|
||||
printf("%04x ", res & 0xffff);
|
||||
printf("%04x ", rv & 0xffff);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
//usage:#define i2cdump_trivial_usage
|
||||
//usage: "[-f] [-r FIRST-LAST] [-y] BUS ADDR [MODE]"
|
||||
//usage:#define i2cdump_full_usage "\n\n"
|
||||
//usage: "Examine I2C registers\n"
|
||||
//usage: "\n I2CBUS i2c bus number"
|
||||
//usage: "\n ADDRESS 0x03 - 0x77"
|
||||
//usage: "\nMODE is:"
|
||||
//usage: "\n b byte (default)"
|
||||
//usage: "\n w word"
|
||||
//usage: "\n W word on even register addresses"
|
||||
//usage: "\n i I2C block"
|
||||
//usage: "\n s SMBus block"
|
||||
//usage: "\n c consecutive byte"
|
||||
//usage: "\n Append p for SMBus PEC"
|
||||
//usage: "\n"
|
||||
//usage: "\n -f force access"
|
||||
//usage: "\n -y disable interactive mode"
|
||||
//usage: "\n -r limit the number of registers being accessed"
|
||||
int i2cdump_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
|
||||
int i2cdump_main(int argc UNUSED_PARAM, char **argv)
|
||||
{
|
||||
const unsigned opt_f = (1 << 0), opt_y = (1 << 1),
|
||||
opt_r = (1 << 2);
|
||||
const char *const optstr = "fyr:";
|
||||
|
||||
int bus_num, bus_addr, mode = I2C_SMBUS_BYTE_DATA, even = 0, pec = 0;
|
||||
unsigned first = 0x00, last = 0xff, opts;
|
||||
int *block = (int *)bb_common_bufsiz1;
|
||||
char *opt_r_str, *dash;
|
||||
int fd, res, blen;
|
||||
|
||||
opt_complementary = "-2:?3"; /* from 2 to 3 args */
|
||||
opts = getopt32(argv, optstr, &opt_r_str);
|
||||
argv += optind;
|
||||
|
||||
bus_num = i2c_bus_lookup(argv[0]);
|
||||
bus_addr = i2c_parse_bus_addr(argv[1]);
|
||||
|
||||
if (argv[2]) {
|
||||
switch (argv[2][0]) {
|
||||
case 'b': /* Already set. */ break;
|
||||
case 'c': mode = I2C_SMBUS_BYTE; break;
|
||||
case 'w': mode = I2C_SMBUS_WORD_DATA; break;
|
||||
case 'W':
|
||||
mode = I2C_SMBUS_WORD_DATA;
|
||||
even = 1;
|
||||
break;
|
||||
case 's': mode = I2C_SMBUS_BLOCK_DATA; break;
|
||||
case 'i': mode = I2C_SMBUS_I2C_BLOCK_DATA; break;
|
||||
default:
|
||||
bb_error_msg_and_die("invalid mode");
|
||||
}
|
||||
|
||||
if (argv[2][1] == 'p') {
|
||||
if (argv[2][0] == 'W' || argv[2][0] == 'i') {
|
||||
bb_error_msg_and_die(
|
||||
"pec not supported for -W and -i");
|
||||
} else {
|
||||
pec = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (opts & opt_r) {
|
||||
first = strtol(opt_r_str, &dash, 0);
|
||||
if (dash == opt_r_str || *dash != '-' || first > 0xff)
|
||||
bb_error_msg_and_die("invalid range");
|
||||
last = xstrtou_range(++dash, 0, first, 0xff);
|
||||
|
||||
/* Range is not available for every mode. */
|
||||
switch (mode) {
|
||||
case I2C_SMBUS_BYTE:
|
||||
case I2C_SMBUS_BYTE_DATA:
|
||||
break;
|
||||
case I2C_SMBUS_WORD_DATA:
|
||||
if (!even || (!(first % 2) && last % 2))
|
||||
break;
|
||||
/* Fall through */
|
||||
default:
|
||||
bb_error_msg_and_die(
|
||||
"range not compatible with selected mode");
|
||||
}
|
||||
}
|
||||
|
||||
fd = i2c_dev_open(bus_num);
|
||||
check_read_funcs(fd, mode, -1 /* data_addr */, pec);
|
||||
i2c_set_slave_addr(fd, bus_addr, opts & opt_f);
|
||||
|
||||
if (pec)
|
||||
i2c_set_pec(fd, 1);
|
||||
|
||||
if (!(opts & opt_y))
|
||||
confirm_action(bus_addr, mode, -1 /* data_addr */, pec);
|
||||
|
||||
/* All but word data. */
|
||||
if (mode != I2C_SMBUS_WORD_DATA || even) {
|
||||
blen = read_block_data(fd, mode, block);
|
||||
|
||||
if (mode == I2C_SMBUS_BYTE) {
|
||||
res = i2c_smbus_write_byte(fd, first);
|
||||
if (res < 0)
|
||||
bb_perror_msg_and_die("write start address");
|
||||
}
|
||||
|
||||
dump_data(fd, mode, first, last, block, blen);
|
||||
} else {
|
||||
dump_word_data(fd, first, last);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
Loading…
x
Reference in New Issue
Block a user