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; 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) { int blen = 0; if (mode == I2C_SMBUS_BLOCK_DATA || mode == I2C_SMBUS_I2C_BLOCK_DATA) 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; }
int i2cset_main(int argc, char **argv) { const unsigned opt_f = (1 << 0), opt_y = (1 << 1), opt_m = (1 << 2), opt_r = (1 << 3); const char *const optstr = "fym:r"; int bus_num, bus_addr, data_addr, mode = I2C_SMBUS_BYTE, pec = 0; int val, blen = 0, mask = 0, fd, status; unsigned char block[I2C_SMBUS_BLOCK_MAX]; char *opt_m_arg = NULL; unsigned opts; opt_complementary = "-3"; /* from 3 to ? args */ opts = getopt32(argv, optstr, &opt_m_arg); argv += optind; argc -= optind; bus_num = i2c_bus_lookup(argv[0]); bus_addr = i2c_parse_bus_addr(argv[1]); data_addr = i2c_parse_data_addr(argv[2]); if (argv[3]) { if (!argv[4] && argv[3][0] != 'c') { mode = I2C_SMBUS_BYTE_DATA; /* Implicit b */ } else { switch (argv[argc-1][0]) { case 'c': /* Already set */ break; case 'b': mode = I2C_SMBUS_BYTE_DATA; break; case 'w': mode = I2C_SMBUS_WORD_DATA; break; case 's': mode = I2C_SMBUS_BLOCK_DATA; break; case 'i': mode = I2C_SMBUS_I2C_BLOCK_DATA; break; default: bb_error_msg("invalid mode"); bb_show_usage(); } pec = argv[argc-1][1] == 'p'; if (mode == I2C_SMBUS_BLOCK_DATA || mode == I2C_SMBUS_I2C_BLOCK_DATA) { if (pec && mode == I2C_SMBUS_I2C_BLOCK_DATA) bb_error_msg_and_die( "PEC not supported for I2C " "block writes"); if (opts & opt_m) bb_error_msg_and_die( "mask not supported for block " "writes"); } } } /* Prepare the value(s) to be written according to current mode. */ switch (mode) { case I2C_SMBUS_BYTE_DATA: val = xstrtou_range(argv[3], 0, 0, 0xff); break; case I2C_SMBUS_WORD_DATA: val = xstrtou_range(argv[3], 0, 0, 0xffff); break; case I2C_SMBUS_BLOCK_DATA: case I2C_SMBUS_I2C_BLOCK_DATA: for (blen = 3; blen < (argc - 1); blen++) block[blen] = xstrtou_range(argv[blen], 0, 0, 0xff); val = -1; break; default: val = -1; break; } if (opts & opt_m) { mask = xstrtou_range(opt_m_arg, 0, 0, (mode == I2C_SMBUS_BYTE || mode == I2C_SMBUS_BYTE_DATA) ? 0xff : 0xffff); } fd = i2c_dev_open(bus_num); check_write_funcs(fd, mode, pec); i2c_set_slave_addr(fd, bus_addr, opts & opt_f); if (!(opts & opt_y)) confirm_action(bus_addr, mode, data_addr, pec); /* * If we're using mask - read the current value here and adjust the * value to be written. */ if (opts & opt_m) { int tmpval; switch (mode) { case I2C_SMBUS_BYTE: tmpval = i2c_smbus_read_byte(fd); break; case I2C_SMBUS_WORD_DATA: tmpval = i2c_smbus_read_word_data(fd, data_addr); break; default: tmpval = i2c_smbus_read_byte_data(fd, data_addr); } if (tmpval < 0) bb_perror_msg_and_die("can't read old value"); val = (val & mask) | (tmpval & ~mask); if (!(opts & opt_y)) { bb_error_msg("old value 0x%0*x, write mask " "0x%0*x, will write 0x%0*x to register " "0x%02x", mode == I2C_SMBUS_WORD_DATA ? 4 : 2, tmpval, mode == I2C_SMBUS_WORD_DATA ? 4 : 2, mask, mode == I2C_SMBUS_WORD_DATA ? 4 : 2, val, data_addr); confirm_or_abort(); } } if (pec) i2c_set_pec(fd, 1); switch (mode) { case I2C_SMBUS_BYTE: status = i2c_smbus_write_byte(fd, data_addr); break; case I2C_SMBUS_WORD_DATA: status = i2c_smbus_write_word_data(fd, data_addr, val); break; case I2C_SMBUS_BLOCK_DATA: status = i2c_smbus_write_block_data(fd, data_addr, blen, block); break; case I2C_SMBUS_I2C_BLOCK_DATA: status = i2c_smbus_write_i2c_block_data(fd, data_addr, blen, block); break; default: /* I2C_SMBUS_BYTE_DATA */ status = i2c_smbus_write_byte_data(fd, data_addr, val); break; } if (status < 0) bb_perror_msg_and_die("write failed"); if (pec) i2c_set_pec(fd, 0); /* Clear PEC. */ /* No readback required - we're done. */ if (!(opts & opt_r)) return 0; switch (mode) { case I2C_SMBUS_BYTE: status = i2c_smbus_read_byte(fd); val = data_addr; break; case I2C_SMBUS_WORD_DATA: status = i2c_smbus_read_word_data(fd, data_addr); break; default: /* I2C_SMBUS_BYTE_DATA */ status = i2c_smbus_read_byte_data(fd, data_addr); } if (status < 0) { puts("Warning - readback failed"); } else if (status != val) { printf("Warning - data mismatch - wrote " "0x%0*x, read back 0x%0*x\n", mode == I2C_SMBUS_WORD_DATA ? 4 : 2, val, mode == I2C_SMBUS_WORD_DATA ? 4 : 2, status); } else { printf("Value 0x%0*x written, readback matched\n", mode == I2C_SMBUS_WORD_DATA ? 4 : 2, val); } return 0; }
static int i2c_parse_data_addr(const char *data_addr) { /* Data address must be an 8 bit integer. */ return xstrtou_range(data_addr, 16, 0, 0xff); }
static int i2c_parse_bus_addr(const char *addr_str) { /* Slave address must be in range 0x03 - 0x77. */ return xstrtou_range(addr_str, 16, 0x03, 0x77); }
static int i2c_bus_lookup(const char *bus_str) { return xstrtou_range(bus_str, 10, 0, 0xfffff); }
int run_parts_main(int argc, char **argv) { const char *umask_p = "22"; llist_t *arg_list = NULL; unsigned n; int ret; #if ENABLE_FEATURE_RUN_PARTS_LONG_OPTIONS applet_long_options = runparts_longopts; #endif /* We require exactly one argument: the directory name */ opt_complementary = "=1:a::"; getopt32(argv, "a:u:t"USE_FEATURE_RUN_PARTS_FANCY("l"), &arg_list, &umask_p); umask(xstrtou_range(umask_p, 8, 0, 07777)); n = 1; while (arg_list && n < NUM_CMD) { cmd[n] = arg_list->data; arg_list = arg_list->link; n++; } /* cmd[n] = NULL; - is already zeroed out */ /* run-parts has to sort executables by name before running them */ recursive_action(argv[optind], ACTION_RECURSE|ACTION_FOLLOWLINKS, act, /* file action */ act, /* dir action */ NULL, /* user data */ 1 /* depth */ ); if (!names) return 0; qsort(names, cur, sizeof(char *), bb_alphasort); n = 0; while (1) { char *name = *names++; if (!name) break; if (option_mask32 & (RUN_PARTS_OPT_t | RUN_PARTS_OPT_l)) { puts(name); continue; } cmd[0] = name; ret = wait4pid(spawn(cmd)); if (ret == 0) continue; n = 1; if (ret < 0) bb_perror_msg("failed to exec %s", name); else /* ret > 0 */ bb_error_msg("%s exited with return code %d", name, ret); } return n; }