busybox/miscutils/i2c_tools.c
<<
>>
Prefs
   1/* vi: set sw=4 ts=4: */
   2/*
   3 * Minimal i2c-tools implementation for busybox.
   4 * Parts of code ported from i2c-tools:
   5 *              http://www.lm-sensors.org/wiki/I2CTools.
   6 *
   7 * Copyright (C) 2014 by Bartosz Golaszewski <bartekgola@gmail.com>
   8 *
   9 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
  10 */
  11//config:config I2CGET
  12//config:       bool "i2cget (5.5 kb)"
  13//config:       default y
  14//config:       help
  15//config:       Read from I2C/SMBus chip registers.
  16//config:
  17//config:config I2CSET
  18//config:       bool "i2cset (6.7 kb)"
  19//config:       default y
  20//config:       help
  21//config:       Set I2C registers.
  22//config:
  23//config:config I2CDUMP
  24//config:       bool "i2cdump (7.1 kb)"
  25//config:       default y
  26//config:       help
  27//config:       Examine I2C registers.
  28//config:
  29//config:config I2CDETECT
  30//config:       bool "i2cdetect (7.1 kb)"
  31//config:       default y
  32//config:       help
  33//config:       Detect I2C chips.
  34//config:
  35//config:config I2CTRANSFER
  36//config:       bool "i2ctransfer (4.0 kb)"
  37//config:       default y
  38//config:       help
  39//config:       Send user-defined I2C messages in one transfer.
  40//config:
  41
  42//applet:IF_I2CGET(APPLET(i2cget, BB_DIR_USR_SBIN, BB_SUID_DROP))
  43//applet:IF_I2CSET(APPLET(i2cset, BB_DIR_USR_SBIN, BB_SUID_DROP))
  44//applet:IF_I2CDUMP(APPLET(i2cdump, BB_DIR_USR_SBIN, BB_SUID_DROP))
  45//applet:IF_I2CDETECT(APPLET(i2cdetect, BB_DIR_USR_SBIN, BB_SUID_DROP))
  46//applet:IF_I2CTRANSFER(APPLET(i2ctransfer, BB_DIR_USR_SBIN, BB_SUID_DROP))
  47/* not NOEXEC: if hw operation stalls, use less memory in "hung" process */
  48
  49//kbuild:lib-$(CONFIG_I2CGET) += i2c_tools.o
  50//kbuild:lib-$(CONFIG_I2CSET) += i2c_tools.o
  51//kbuild:lib-$(CONFIG_I2CDUMP) += i2c_tools.o
  52//kbuild:lib-$(CONFIG_I2CDETECT) += i2c_tools.o
  53//kbuild:lib-$(CONFIG_I2CTRANSFER) += i2c_tools.o
  54
  55/*
  56 * Unsupported stuff:
  57 *
  58 * - upstream i2c-tools can also look-up i2c busses by name, we only accept
  59 *   numbers,
  60 * - bank and bankreg parameters for i2cdump are not supported because of
  61 *   their limited usefulness (see i2cdump manual entry for more info),
  62 * - i2cdetect doesn't look for bus info in /proc as it does in upstream, but
  63 *   it shouldn't be a problem in modern kernels.
  64 */
  65
  66#include "libbb.h"
  67
  68#include <linux/i2c.h>
  69
  70#define I2CDUMP_NUM_REGS                256
  71
  72#define I2CDETECT_MODE_AUTO             0
  73#define I2CDETECT_MODE_QUICK            1
  74#define I2CDETECT_MODE_READ             2
  75
  76/* linux/i2c-dev.h from i2c-tools overwrites the one from linux uapi
  77 * and defines symbols already defined by linux/i2c.h.
  78 * Also, it defines a bunch of static inlines which we would rather NOT
  79 * inline. What a mess.
  80 * We need only these definitions from linux/i2c-dev.h:
  81 */
  82#define I2C_SLAVE                       0x0703
  83#define I2C_SLAVE_FORCE                 0x0706
  84#define I2C_FUNCS                       0x0705
  85#define I2C_PEC                         0x0708
  86#define I2C_SMBUS                       0x0720
  87#define I2C_RDWR                        0x0707
  88#define I2C_RDWR_IOCTL_MAX_MSGS         42
  89#define I2C_RDWR_IOCTL_MAX_MSGS_STR     "42"
  90struct i2c_smbus_ioctl_data {
  91        __u8 read_write;
  92        __u8 command;
  93        __u32 size;
  94        union i2c_smbus_data *data;
  95};
  96struct i2c_rdwr_ioctl_data {
  97        struct i2c_msg *msgs;   /* pointers to i2c_msgs */
  98        __u32 nmsgs;            /* number of i2c_msgs */
  99};
 100/* end linux/i2c-dev.h */
 101
 102/*
 103 * This is needed for ioctl_or_perror_and_die() since it only accepts pointers.
 104 */
 105static ALWAYS_INLINE void *itoptr(int i)
 106{
 107        return (void*)(intptr_t)i;
 108}
 109
 110static int32_t i2c_smbus_access(int fd, char read_write, uint8_t cmd,
 111                                int size, union i2c_smbus_data *data)
 112{
 113        struct i2c_smbus_ioctl_data args;
 114
 115        args.read_write = read_write;
 116        args.command = cmd;
 117        args.size = size;
 118        args.data = data;
 119
 120        return ioctl(fd, I2C_SMBUS, &args);
 121}
 122
 123static int32_t i2c_smbus_read_byte(int fd)
 124{
 125        union i2c_smbus_data data;
 126        int err;
 127
 128        err = i2c_smbus_access(fd, I2C_SMBUS_READ, 0, I2C_SMBUS_BYTE, &data);
 129        if (err < 0)
 130                return err;
 131
 132        return data.byte;
 133}
 134
 135#if ENABLE_I2CGET || ENABLE_I2CSET || ENABLE_I2CDUMP
 136static int32_t i2c_smbus_write_byte(int fd, uint8_t val)
 137{
 138        return i2c_smbus_access(fd, I2C_SMBUS_WRITE,
 139                                val, I2C_SMBUS_BYTE, NULL);
 140}
 141
 142static int32_t i2c_smbus_read_byte_data(int fd, uint8_t cmd)
 143{
 144        union i2c_smbus_data data;
 145        int err;
 146
 147        err = i2c_smbus_access(fd, I2C_SMBUS_READ, cmd,
 148                               I2C_SMBUS_BYTE_DATA, &data);
 149        if (err < 0)
 150                return err;
 151
 152        return data.byte;
 153}
 154
 155static int32_t i2c_smbus_read_word_data(int fd, uint8_t cmd)
 156{
 157        union i2c_smbus_data data;
 158        int err;
 159
 160        err = i2c_smbus_access(fd, I2C_SMBUS_READ, cmd,
 161                               I2C_SMBUS_WORD_DATA, &data);
 162        if (err < 0)
 163                return err;
 164
 165        return data.word;
 166}
 167#endif /* ENABLE_I2CGET || ENABLE_I2CSET || ENABLE_I2CDUMP */
 168
 169#if ENABLE_I2CSET
 170static int32_t i2c_smbus_write_byte_data(int file,
 171                                         uint8_t cmd, uint8_t value)
 172{
 173        union i2c_smbus_data data;
 174
 175        data.byte = value;
 176
 177        return i2c_smbus_access(file, I2C_SMBUS_WRITE, cmd,
 178                                I2C_SMBUS_BYTE_DATA, &data);
 179}
 180
 181static int32_t i2c_smbus_write_word_data(int file, uint8_t cmd, uint16_t value)
 182{
 183        union i2c_smbus_data data;
 184
 185        data.word = value;
 186
 187        return i2c_smbus_access(file, I2C_SMBUS_WRITE, cmd,
 188                                I2C_SMBUS_WORD_DATA, &data);
 189}
 190
 191static int32_t i2c_smbus_write_block_data(int file, uint8_t cmd,
 192                                   uint8_t length, const uint8_t *values)
 193{
 194        union i2c_smbus_data data;
 195
 196        if (length > I2C_SMBUS_BLOCK_MAX)
 197                length = I2C_SMBUS_BLOCK_MAX;
 198
 199        memcpy(data.block+1, values, length);
 200        data.block[0] = length;
 201
 202        return i2c_smbus_access(file, I2C_SMBUS_WRITE, cmd,
 203                                I2C_SMBUS_BLOCK_DATA, &data);
 204}
 205
 206static int32_t i2c_smbus_write_i2c_block_data(int file, uint8_t cmd,
 207                                       uint8_t length, const uint8_t *values)
 208{
 209        union i2c_smbus_data data;
 210
 211        if (length > I2C_SMBUS_BLOCK_MAX)
 212                length = I2C_SMBUS_BLOCK_MAX;
 213
 214        memcpy(data.block+1, values, length);
 215        data.block[0] = length;
 216
 217        return i2c_smbus_access(file, I2C_SMBUS_WRITE, cmd,
 218                                I2C_SMBUS_I2C_BLOCK_BROKEN, &data);
 219}
 220#endif /* ENABLE_I2CSET */
 221
 222#if ENABLE_I2CDUMP
 223/*
 224 * Returns the number of bytes read, vals must hold at
 225 * least I2C_SMBUS_BLOCK_MAX bytes.
 226 */
 227static int32_t i2c_smbus_read_block_data(int fd, uint8_t cmd, uint8_t *vals)
 228{
 229        union i2c_smbus_data data;
 230        int i, err;
 231
 232        err = i2c_smbus_access(fd, I2C_SMBUS_READ, cmd,
 233                               I2C_SMBUS_BLOCK_DATA, &data);
 234        if (err < 0)
 235                return err;
 236
 237        for (i = 1; i <= data.block[0]; i++)
 238                *vals++ = data.block[i];
 239        return data.block[0];
 240}
 241
 242static int32_t i2c_smbus_read_i2c_block_data(int fd, uint8_t cmd,
 243                                             uint8_t len, uint8_t *vals)
 244{
 245        union i2c_smbus_data data;
 246        int i, err;
 247
 248        if (len > I2C_SMBUS_BLOCK_MAX)
 249                len = I2C_SMBUS_BLOCK_MAX;
 250        data.block[0] = len;
 251
 252        err = i2c_smbus_access(fd, I2C_SMBUS_READ, cmd,
 253                               len == 32 ? I2C_SMBUS_I2C_BLOCK_BROKEN :
 254                                           I2C_SMBUS_I2C_BLOCK_DATA, &data);
 255        if (err < 0)
 256                return err;
 257
 258        for (i = 1; i <= data.block[0]; i++)
 259                *vals++ = data.block[i];
 260        return data.block[0];
 261}
 262#endif /* ENABLE_I2CDUMP */
 263
 264#if ENABLE_I2CDETECT
 265static int32_t i2c_smbus_write_quick(int fd, uint8_t val)
 266{
 267        return i2c_smbus_access(fd, val, 0, I2C_SMBUS_QUICK, NULL);
 268}
 269#endif /* ENABLE_I2CDETECT */
 270
 271static int i2c_bus_lookup(const char *bus_str)
 272{
 273        return xstrtou_range(bus_str, 10, 0, 0xfffff);
 274}
 275
 276#if ENABLE_I2CGET || ENABLE_I2CSET || ENABLE_I2CDUMP
 277static int i2c_parse_bus_addr(const char *addr_str)
 278{
 279        /* Slave address must be in range 0x03 - 0x77. */
 280        return xstrtou_range(addr_str, 16, 0x03, 0x77);
 281}
 282
 283static void i2c_set_pec(int fd, int pec)
 284{
 285        ioctl_or_perror_and_die(fd, I2C_PEC,
 286                                itoptr(pec ? 1 : 0),
 287                                "can't set PEC");
 288}
 289#endif
 290
 291#if ENABLE_I2CGET || ENABLE_I2CSET || ENABLE_I2CDUMP || ENABLE_I2CTRANSFER
 292static void i2c_set_slave_addr(int fd, int addr, int force)
 293{
 294        ioctl_or_perror_and_die(fd, force ? I2C_SLAVE_FORCE : I2C_SLAVE,
 295                                itoptr(addr),
 296                                "can't set address to 0x%02x", addr);
 297}
 298#endif
 299
 300#if ENABLE_I2CGET || ENABLE_I2CSET
 301static int i2c_parse_data_addr(const char *data_addr)
 302{
 303        /* Data address must be an 8 bit integer. */
 304        return xstrtou_range(data_addr, 16, 0, 0xff);
 305}
 306#endif /* ENABLE_I2CGET || ENABLE_I2CSET */
 307
 308/*
 309 * Opens the device file associated with given i2c bus.
 310 *
 311 * Upstream i2c-tools also support opening devices by i2c bus name
 312 * but we drop it here for size reduction.
 313 */
 314static int i2c_dev_open(int i2cbus)
 315{
 316        char filename[sizeof("/dev/i2c-%d") + sizeof(int)*3];
 317        int fd;
 318
 319        sprintf(filename, "/dev/i2c-%d", i2cbus);
 320        fd = open(filename, O_RDWR);
 321        if (fd < 0) {
 322                if (errno == ENOENT) {
 323                        filename[8] = '/'; /* change to "/dev/i2c/%d" */
 324                        fd = xopen(filename, O_RDWR);
 325                } else {
 326                        bb_perror_msg_and_die("can't open '%s'", filename);
 327                }
 328        }
 329
 330        return fd;
 331}
 332
 333/* Size reducing helpers for xxx_check_funcs(). */
 334static void get_funcs_matrix(int fd, unsigned long *funcs)
 335{
 336        ioctl_or_perror_and_die(fd, I2C_FUNCS, funcs,
 337                        "can't get adapter functionality matrix");
 338}
 339
 340#if ENABLE_I2CGET || ENABLE_I2CSET || ENABLE_I2CDUMP
 341static void check_funcs_test_end(int funcs, int pec, const char *err)
 342{
 343        if (pec && !(funcs & (I2C_FUNC_SMBUS_PEC | I2C_FUNC_I2C)))
 344                bb_simple_error_msg("warning: adapter does not support PEC");
 345
 346        if (err)
 347                bb_error_msg_and_die(
 348                        "adapter has no %s capability", err);
 349}
 350#endif /* ENABLE_I2CGET || ENABLE_I2CSET || ENABLE_I2CDUMP */
 351
 352/*
 353 * The below functions emit an error message and exit if the adapter doesn't
 354 * support desired functionalities.
 355 */
 356#if ENABLE_I2CGET || ENABLE_I2CDUMP
 357static void check_read_funcs(int fd, int mode, int data_addr, int pec)
 358{
 359        unsigned long funcs;
 360        const char *err = NULL;
 361
 362        get_funcs_matrix(fd, &funcs);
 363        switch (mode) {
 364        case I2C_SMBUS_BYTE:
 365                if (!(funcs & I2C_FUNC_SMBUS_READ_BYTE)) {
 366                        err = "SMBus receive byte";
 367                        break;
 368                }
 369                if (data_addr >= 0 && !(funcs & I2C_FUNC_SMBUS_WRITE_BYTE))
 370                        err = "SMBus send byte";
 371                break;
 372        case I2C_SMBUS_BYTE_DATA:
 373                if (!(funcs & I2C_FUNC_SMBUS_READ_BYTE_DATA))
 374                        err = "SMBus read byte";
 375                break;
 376        case I2C_SMBUS_WORD_DATA:
 377                if (!(funcs & I2C_FUNC_SMBUS_READ_WORD_DATA))
 378                        err = "SMBus read word";
 379                break;
 380#if ENABLE_I2CDUMP
 381        case I2C_SMBUS_BLOCK_DATA:
 382                if (!(funcs & I2C_FUNC_SMBUS_READ_BLOCK_DATA))
 383                        err = "SMBus block read";
 384                break;
 385
 386        case I2C_SMBUS_I2C_BLOCK_DATA:
 387                if (!(funcs & I2C_FUNC_SMBUS_READ_I2C_BLOCK))
 388                        err = "I2C block read";
 389                break;
 390#endif /* ENABLE_I2CDUMP */
 391        default:
 392                bb_simple_error_msg_and_die("internal error");
 393        }
 394        check_funcs_test_end(funcs, pec, err);
 395}
 396#endif /* ENABLE_I2CGET || ENABLE_I2CDUMP */
 397
 398#if ENABLE_I2CSET
 399static void check_write_funcs(int fd, int mode, int pec)
 400{
 401        unsigned long funcs;
 402        const char *err = NULL;
 403
 404        get_funcs_matrix(fd, &funcs);
 405        switch (mode) {
 406        case I2C_SMBUS_BYTE:
 407                if (!(funcs & I2C_FUNC_SMBUS_WRITE_BYTE))
 408                        err = "SMBus send byte";
 409                break;
 410
 411        case I2C_SMBUS_BYTE_DATA:
 412                if (!(funcs & I2C_FUNC_SMBUS_WRITE_BYTE_DATA))
 413                        err = "SMBus write byte";
 414                break;
 415
 416        case I2C_SMBUS_WORD_DATA:
 417                if (!(funcs & I2C_FUNC_SMBUS_WRITE_WORD_DATA))
 418                        err = "SMBus write word";
 419                break;
 420
 421        case I2C_SMBUS_BLOCK_DATA:
 422                if (!(funcs & I2C_FUNC_SMBUS_WRITE_BLOCK_DATA))
 423                        err = "SMBus block write";
 424                break;
 425        case I2C_SMBUS_I2C_BLOCK_DATA:
 426                if (!(funcs & I2C_FUNC_SMBUS_WRITE_I2C_BLOCK))
 427                        err = "I2C block write";
 428                break;
 429        }
 430        check_funcs_test_end(funcs, pec, err);
 431}
 432#endif /* ENABLE_I2CSET */
 433
 434static void confirm_or_abort(void)
 435{
 436        fprintf(stderr, "Continue? [y/N] ");
 437        if (!bb_ask_y_confirmation())
 438                bb_simple_error_msg_and_die("aborting");
 439}
 440
 441/*
 442 * Return only if user confirms the action, abort otherwise.
 443 *
 444 * The messages displayed here are much less elaborate than their i2c-tools
 445 * counterparts - this is done for size reduction.
 446 */
 447static void confirm_action(int bus_addr, int mode, int data_addr, int pec)
 448{
 449        bb_simple_error_msg("WARNING! This program can confuse your I2C bus");
 450
 451        /* Don't let the user break his/her EEPROMs */
 452        if (bus_addr >= 0x50 && bus_addr <= 0x57 && pec) {
 453                bb_simple_error_msg_and_die("this is I2C not smbus - using PEC on I2C "
 454                        "devices may result in data loss, aborting");
 455        }
 456
 457        if (mode == I2C_SMBUS_BYTE && data_addr >= 0 && pec)
 458                bb_simple_error_msg("WARNING! May interpret a write byte command "
 459                        "with PEC as a write byte data command");
 460
 461        if (pec)
 462                bb_simple_error_msg("PEC checking enabled");
 463
 464        confirm_or_abort();
 465}
 466
 467#if ENABLE_I2CGET
 468//usage:#define i2cget_trivial_usage
 469//usage:       "[-fy] BUS CHIP-ADDRESS [DATA-ADDRESS [MODE]]"
 470//usage:#define i2cget_full_usage "\n\n"
 471//usage:       "Read from I2C/SMBus chip registers"
 472//usage:     "\n"
 473//usage:     "\n        I2CBUS  I2C bus number"
 474//usage:     "\n        ADDRESS 0x03-0x77"
 475//usage:     "\nMODE is:"
 476//usage:     "\n        b       Read byte data (default)"
 477//usage:     "\n        w       Read word data"
 478//usage:     "\n        c       Write byte/read byte"
 479//usage:     "\n        Append p for SMBus PEC"
 480//usage:     "\n"
 481//usage:     "\n        -f      Force access"
 482//usage:     "\n        -y      Disable interactive mode"
 483int i2cget_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
 484int i2cget_main(int argc UNUSED_PARAM, char **argv)
 485{
 486        const unsigned opt_f = (1 << 0), opt_y = (1 << 1);
 487
 488        int bus_num, bus_addr, data_addr = -1, status;
 489        int mode = I2C_SMBUS_BYTE, pec = 0, fd;
 490        unsigned opts;
 491
 492        opts = getopt32(argv, "^" "fy" "\0" "-2:?4"/*from 2 to 4 args*/);
 493        argv += optind;
 494
 495        bus_num = i2c_bus_lookup(argv[0]);
 496        bus_addr = i2c_parse_bus_addr(argv[1]);
 497
 498        if (argv[2]) {
 499                data_addr = i2c_parse_data_addr(argv[2]);
 500                mode = I2C_SMBUS_BYTE_DATA;
 501                if (argv[3]) {
 502                        switch (argv[3][0]) {
 503                        case 'b':       /* Already set */               break;
 504                        case 'w':       mode = I2C_SMBUS_WORD_DATA;     break;
 505                        case 'c':       mode = I2C_SMBUS_BYTE;          break;
 506                        default:
 507                                bb_simple_error_msg("invalid mode");
 508                                bb_show_usage();
 509                        }
 510                        pec = argv[3][1] == 'p';
 511                }
 512        }
 513
 514        fd = i2c_dev_open(bus_num);
 515        check_read_funcs(fd, mode, data_addr, pec);
 516        i2c_set_slave_addr(fd, bus_addr, opts & opt_f);
 517
 518        if (!(opts & opt_y))
 519                confirm_action(bus_addr, mode, data_addr, pec);
 520
 521        if (pec)
 522                i2c_set_pec(fd, 1);
 523
 524        switch (mode) {
 525        case I2C_SMBUS_BYTE:
 526                if (data_addr >= 0) {
 527                        status = i2c_smbus_write_byte(fd, data_addr);
 528                        if (status < 0)
 529                                bb_simple_error_msg("warning - write failed");
 530                }
 531                status = i2c_smbus_read_byte(fd);
 532                break;
 533        case I2C_SMBUS_WORD_DATA:
 534                status = i2c_smbus_read_word_data(fd, data_addr);
 535                break;
 536        default: /* I2C_SMBUS_BYTE_DATA */
 537                status = i2c_smbus_read_byte_data(fd, data_addr);
 538        }
 539        close(fd);
 540
 541        if (status < 0)
 542                bb_simple_perror_msg_and_die("read failed");
 543
 544        printf("0x%0*x\n", mode == I2C_SMBUS_WORD_DATA ? 4 : 2, status);
 545
 546        return 0;
 547}
 548#endif /* ENABLE_I2CGET */
 549
 550#if ENABLE_I2CSET
 551//usage:#define i2cset_trivial_usage
 552//usage:       "[-fy] [-m MASK] BUS CHIP-ADDRESS DATA-ADDRESS [VALUE] ... [MODE]"
 553//usage:#define i2cset_full_usage "\n\n"
 554//usage:       "Set I2C registers"
 555//usage:     "\n"
 556//usage:     "\n        I2CBUS  I2C bus number"
 557//usage:     "\n        ADDRESS 0x03-0x77"
 558//usage:     "\nMODE is:"
 559//usage:     "\n        c       Byte, no value"
 560//usage:     "\n        b       Byte data (default)"
 561//usage:     "\n        w       Word data"
 562//usage:     "\n        i       I2C block data"
 563//usage:     "\n        s       SMBus block data"
 564//usage:     "\n        Append p for SMBus PEC"
 565//usage:     "\n"
 566//usage:     "\n        -f      Force access"
 567//usage:     "\n        -y      Disable interactive mode"
 568//usage:     "\n        -r      Read back and compare the result"
 569//usage:     "\n        -m MASK Mask specifying which bits to write"
 570int i2cset_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
 571int i2cset_main(int argc, char **argv)
 572{
 573        const unsigned opt_f = (1 << 0), opt_y = (1 << 1),
 574                              opt_m = (1 << 2), opt_r = (1 << 3);
 575
 576        int bus_num, bus_addr, data_addr, mode = I2C_SMBUS_BYTE, pec = 0;
 577        int val, blen, mask, fd, status;
 578        unsigned char block[I2C_SMBUS_BLOCK_MAX];
 579        char *opt_m_arg = NULL;
 580        unsigned opts;
 581
 582        opts = getopt32(argv, "^"
 583                "fym:r"
 584                "\0" "-3", /* minimum 3 args */
 585                &opt_m_arg
 586        );
 587        argv += optind;
 588        argc -= optind;
 589        argc--; /* now argv[argc] is last arg */
 590
 591        bus_num = i2c_bus_lookup(argv[0]);
 592        bus_addr = i2c_parse_bus_addr(argv[1]);
 593        data_addr = i2c_parse_data_addr(argv[2]);
 594
 595        if (argv[3]) {
 596                if (!argv[4] && argv[3][0] != 'c') {
 597                        mode = I2C_SMBUS_BYTE_DATA; /* Implicit b */
 598                } else {
 599                        switch (argv[argc][0]) {
 600                        case 'c': /* Already set */
 601                                break;
 602                        case 'b': mode = I2C_SMBUS_BYTE_DATA;
 603                                break;
 604                        case 'w': mode = I2C_SMBUS_WORD_DATA;
 605                                break;
 606                        case 's': mode = I2C_SMBUS_BLOCK_DATA;
 607                                break;
 608                        case 'i': mode = I2C_SMBUS_I2C_BLOCK_DATA;
 609                                break;
 610                        default:
 611                                bb_simple_error_msg("invalid mode");
 612                                bb_show_usage();
 613                        }
 614
 615                        pec = (argv[argc][1] == 'p');
 616                        if (mode == I2C_SMBUS_BLOCK_DATA
 617                         || mode == I2C_SMBUS_I2C_BLOCK_DATA
 618                        ) {
 619                                if (pec && mode == I2C_SMBUS_I2C_BLOCK_DATA)
 620                                        bb_simple_error_msg_and_die(
 621                                                "PEC not supported for I2C "
 622                                                "block writes");
 623                                if (opts & opt_m)
 624                                        bb_simple_error_msg_and_die(
 625                                                "mask not supported for block "
 626                                                "writes");
 627                        }
 628                }
 629        }
 630
 631        /* Prepare the value(s) to be written according to current mode. */
 632        mask = 0;
 633        blen = 0;
 634        switch (mode) {
 635        case I2C_SMBUS_BYTE_DATA:
 636                val = xstrtou_range(argv[3], 0, 0, 0xff);
 637                break;
 638        case I2C_SMBUS_WORD_DATA:
 639                val = xstrtou_range(argv[3], 0, 0, 0xffff);
 640                break;
 641        case I2C_SMBUS_BLOCK_DATA:
 642        case I2C_SMBUS_I2C_BLOCK_DATA:
 643                for (blen = 3; blen < argc; blen++)
 644                        block[blen - 3] = xstrtou_range(argv[blen], 0, 0, 0xff);
 645                blen -= 3;
 646                val = -1;
 647                break;
 648        default:
 649                val = -1;
 650                break;
 651        }
 652
 653        if (opts & opt_m) {
 654                mask = xstrtou_range(opt_m_arg, 0, 0,
 655                                (mode == I2C_SMBUS_BYTE ||
 656                                 mode == I2C_SMBUS_BYTE_DATA) ? 0xff : 0xffff);
 657        }
 658
 659        fd = i2c_dev_open(bus_num);
 660        check_write_funcs(fd, mode, pec);
 661        i2c_set_slave_addr(fd, bus_addr, opts & opt_f);
 662
 663        if (!(opts & opt_y))
 664                confirm_action(bus_addr, mode, data_addr, pec);
 665
 666        /*
 667         * If we're using mask - read the current value here and adjust the
 668         * value to be written.
 669         */
 670        if (opts & opt_m) {
 671                int tmpval;
 672
 673                switch (mode) {
 674                case I2C_SMBUS_BYTE:
 675                        tmpval = i2c_smbus_read_byte(fd);
 676                        break;
 677                case I2C_SMBUS_WORD_DATA:
 678                        tmpval = i2c_smbus_read_word_data(fd, data_addr);
 679                        break;
 680                default:
 681                        tmpval = i2c_smbus_read_byte_data(fd, data_addr);
 682                }
 683
 684                if (tmpval < 0)
 685                        bb_simple_perror_msg_and_die("can't read old value");
 686
 687                val = (val & mask) | (tmpval & ~mask);
 688
 689                if (!(opts & opt_y)) {
 690                        bb_error_msg("old value 0x%0*x, write mask "
 691                                "0x%0*x, will write 0x%0*x to register "
 692                                "0x%02x",
 693                                mode == I2C_SMBUS_WORD_DATA ? 4 : 2, tmpval,
 694                                mode == I2C_SMBUS_WORD_DATA ? 4 : 2, mask,
 695                                mode == I2C_SMBUS_WORD_DATA ? 4 : 2, val,
 696                                data_addr);
 697                        confirm_or_abort();
 698                }
 699        }
 700
 701        if (pec)
 702                i2c_set_pec(fd, 1);
 703
 704        switch (mode) {
 705        case I2C_SMBUS_BYTE:
 706                status = i2c_smbus_write_byte(fd, data_addr);
 707                break;
 708        case I2C_SMBUS_WORD_DATA:
 709                status = i2c_smbus_write_word_data(fd, data_addr, val);
 710                break;
 711        case I2C_SMBUS_BLOCK_DATA:
 712                status = i2c_smbus_write_block_data(fd, data_addr,
 713                                                    blen, block);
 714                break;
 715        case I2C_SMBUS_I2C_BLOCK_DATA:
 716                status = i2c_smbus_write_i2c_block_data(fd, data_addr,
 717                                                        blen, block);
 718                break;
 719        default: /* I2C_SMBUS_BYTE_DATA */
 720                status = i2c_smbus_write_byte_data(fd, data_addr, val);
 721                break;
 722        }
 723        if (status < 0)
 724                bb_simple_perror_msg_and_die("write failed");
 725
 726        if (pec)
 727                i2c_set_pec(fd, 0); /* Clear PEC. */
 728
 729        /* No readback required - we're done. */
 730        if (!(opts & opt_r))
 731                return 0;
 732
 733        switch (mode) {
 734        case I2C_SMBUS_BYTE:
 735                status = i2c_smbus_read_byte(fd);
 736                val = data_addr;
 737                break;
 738        case I2C_SMBUS_WORD_DATA:
 739                status = i2c_smbus_read_word_data(fd, data_addr);
 740                break;
 741        default: /* I2C_SMBUS_BYTE_DATA */
 742                status = i2c_smbus_read_byte_data(fd, data_addr);
 743        }
 744
 745        if (status < 0) {
 746                puts("Warning - readback failed");
 747        } else
 748        if (status != val) {
 749                printf("Warning - data mismatch - wrote "
 750                       "0x%0*x, read back 0x%0*x\n",
 751                       mode == I2C_SMBUS_WORD_DATA ? 4 : 2, val,
 752                       mode == I2C_SMBUS_WORD_DATA ? 4 : 2, status);
 753        } else {
 754                printf("Value 0x%0*x written, readback matched\n",
 755                       mode == I2C_SMBUS_WORD_DATA ? 4 : 2, val);
 756        }
 757
 758        return 0;
 759}
 760#endif /* ENABLE_I2CSET */
 761
 762#if ENABLE_I2CDUMP
 763static int read_block_data(int buf_fd, int mode, int *block)
 764{
 765        uint8_t cblock[I2C_SMBUS_BLOCK_MAX + I2CDUMP_NUM_REGS];
 766        int res, blen = 0, tmp, i;
 767
 768        if (mode == I2C_SMBUS_BLOCK_DATA) {
 769                blen = i2c_smbus_read_block_data(buf_fd, 0, cblock);
 770                if (blen <= 0)
 771                        goto fail;
 772        } else {
 773                for (res = 0; res < I2CDUMP_NUM_REGS; res += tmp) {
 774                        tmp = i2c_smbus_read_i2c_block_data(
 775                                        buf_fd, res, I2C_SMBUS_BLOCK_MAX,
 776                                        cblock + res);
 777                        if (tmp <= 0) {
 778                                blen = tmp;
 779                                goto fail;
 780                        }
 781                }
 782
 783                if (res >= I2CDUMP_NUM_REGS)
 784                        res = I2CDUMP_NUM_REGS;
 785
 786                for (i = 0; i < res; i++)
 787                        block[i] = cblock[i];
 788
 789                if (mode != I2C_SMBUS_BLOCK_DATA)
 790                        for (i = res; i < I2CDUMP_NUM_REGS; i++)
 791                                block[i] = -1;
 792        }
 793
 794        return blen;
 795
 796 fail:
 797        bb_error_msg_and_die("block read failed: %d", blen);
 798}
 799
 800/* Dump all but word data. */
 801static void dump_data(int bus_fd, int mode, unsigned first,
 802                      unsigned last, int *block, int blen)
 803{
 804        int i, j, res;
 805
 806        puts("     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f"
 807             "    0123456789abcdef");
 808
 809        for (i = 0; i < I2CDUMP_NUM_REGS; i += 0x10) {
 810                if (mode == I2C_SMBUS_BLOCK_DATA && i >= blen)
 811                        break;
 812                if (i/16 < first/16)
 813                        continue;
 814                if (i/16 > last/16)
 815                        break;
 816
 817                printf("%02x: ", i);
 818                for (j = 0; j < 16; j++) {
 819                        fflush_all();
 820                        /* Skip unwanted registers */
 821                        if (i+j < first || i+j > last) {
 822                                printf("   ");
 823                                if (mode == I2C_SMBUS_WORD_DATA) {
 824                                        printf("   ");
 825                                        j++;
 826                                }
 827                                continue;
 828                        }
 829
 830                        switch (mode) {
 831                        case I2C_SMBUS_BYTE_DATA:
 832                                res = i2c_smbus_read_byte_data(bus_fd, i+j);
 833                                block[i+j] = res;
 834                                break;
 835                        case I2C_SMBUS_WORD_DATA:
 836                                res = i2c_smbus_read_word_data(bus_fd, i+j);
 837                                if (res < 0) {
 838                                        block[i+j] = res;
 839                                        block[i+j+1] = res;
 840                                } else {
 841                                        block[i+j] = res & 0xff;
 842                                        block[i+j+1] = res >> 8;
 843                                }
 844                                break;
 845                        case I2C_SMBUS_BYTE:
 846                                res = i2c_smbus_read_byte(bus_fd);
 847                                block[i+j] = res;
 848                                break;
 849                        default:
 850                                res = block[i+j];
 851                        }
 852
 853                        if (mode == I2C_SMBUS_BLOCK_DATA &&
 854                            i+j >= blen) {
 855                                printf("   ");
 856                        } else if (res < 0) {
 857                                printf("XX ");
 858                                if (mode == I2C_SMBUS_WORD_DATA)
 859                                        printf("XX ");
 860                        } else {
 861                                printf("%02x ", block[i+j]);
 862                                if (mode == I2C_SMBUS_WORD_DATA)
 863                                        printf("%02x ", block[i+j+1]);
 864                        }
 865
 866                        if (mode == I2C_SMBUS_WORD_DATA)
 867                                j++;
 868                }
 869                printf("   ");
 870
 871                for (j = 0; j < 16; j++) {
 872                        if (mode == I2C_SMBUS_BLOCK_DATA && i+j >= blen)
 873                                break;
 874                        /* Skip unwanted registers */
 875                        if (i+j < first || i+j > last) {
 876                                bb_putchar(' ');
 877                                continue;
 878                        }
 879
 880                        res = block[i+j];
 881                        if (res < 0) {
 882                                bb_putchar('X');
 883                        } else if (res == 0x00 || res == 0xff) {
 884                                bb_putchar('.');
 885                        } else if (res < 32 || res >= 127) {
 886                                bb_putchar('?');
 887                        } else {
 888                                bb_putchar(res);
 889                        }
 890                }
 891                bb_putchar('\n');
 892        }
 893}
 894
 895static void dump_word_data(int bus_fd, unsigned first, unsigned last)
 896{
 897        int i, j, rv;
 898
 899        /* Word data. */
 900        puts("     0,8  1,9  2,a  3,b  4,c  5,d  6,e  7,f");
 901        for (i = 0; i < 256; i += 8) {
 902                if (i/8 < first/8)
 903                        continue;
 904                if (i/8 > last/8)
 905                        break;
 906
 907                printf("%02x: ", i);
 908                for (j = 0; j < 8; j++) {
 909                        /* Skip unwanted registers. */
 910                        if (i+j < first || i+j > last) {
 911                                printf("     ");
 912                                continue;
 913                        }
 914
 915                        rv = i2c_smbus_read_word_data(bus_fd, i+j);
 916                        if (rv < 0)
 917                                printf("XXXX ");
 918                        else
 919                                printf("%04x ", rv & 0xffff);
 920                }
 921                bb_putchar('\n');
 922        }
 923}
 924
 925//usage:#define i2cdump_trivial_usage
 926//usage:       "[-fy] [-r FIRST-LAST] BUS ADDR [MODE]"
 927//usage:#define i2cdump_full_usage "\n\n"
 928//usage:       "Examine I2C registers"
 929//usage:     "\n"
 930//usage:     "\n        I2CBUS  I2C bus number"
 931//usage:     "\n        ADDRESS 0x03-0x77"
 932//usage:     "\nMODE is:"
 933//usage:     "\n        b       Byte (default)"
 934//usage:     "\n        w       Word"
 935//usage:     "\n        W       Word on even register addresses"
 936//usage:     "\n        i       I2C block"
 937//usage:     "\n        s       SMBus block"
 938//usage:     "\n        c       Consecutive byte"
 939//usage:     "\n        Append p for SMBus PEC"
 940//usage:     "\n"
 941//usage:     "\n        -f      Force access"
 942//usage:     "\n        -y      Disable interactive mode"
 943//usage:     "\n        -r      Limit the number of registers being accessed"
 944int i2cdump_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
 945int i2cdump_main(int argc UNUSED_PARAM, char **argv)
 946{
 947        const unsigned opt_f = (1 << 0), opt_y = (1 << 1),
 948                              opt_r = (1 << 2);
 949
 950        int bus_num, bus_addr, mode = I2C_SMBUS_BYTE_DATA, even = 0, pec = 0;
 951        unsigned first = 0x00, last = 0xff, opts;
 952        int block[I2CDUMP_NUM_REGS];
 953        char *opt_r_str, *dash;
 954        int fd, res;
 955
 956        opts = getopt32(argv, "^"
 957                "fyr:"
 958                "\0" "-2:?3" /* from 2 to 3 args */,
 959                &opt_r_str
 960        );
 961        argv += optind;
 962
 963        bus_num = i2c_bus_lookup(argv[0]);
 964        bus_addr = i2c_parse_bus_addr(argv[1]);
 965
 966        if (argv[2]) {
 967                switch (argv[2][0]) {
 968                case 'b': /* Already set. */                    break;
 969                case 'c': mode = I2C_SMBUS_BYTE;                break;
 970                case 'w': mode = I2C_SMBUS_WORD_DATA;           break;
 971                case 'W':
 972                        mode = I2C_SMBUS_WORD_DATA;
 973                        even = 1;
 974                        break;
 975                case 's': mode = I2C_SMBUS_BLOCK_DATA;          break;
 976                case 'i': mode = I2C_SMBUS_I2C_BLOCK_DATA;      break;
 977                default:
 978                        bb_simple_error_msg_and_die("invalid mode");
 979                }
 980
 981                if (argv[2][1] == 'p') {
 982                        if (argv[2][0] == 'W' || argv[2][0] == 'i') {
 983                                bb_simple_error_msg_and_die(
 984                                        "pec not supported for -W and -i");
 985                        } else {
 986                                pec = 1;
 987                        }
 988                }
 989        }
 990
 991        if (opts & opt_r) {
 992                first = strtol(opt_r_str, &dash, 0);
 993                if (dash == opt_r_str || *dash != '-' || first > 0xff)
 994                        bb_simple_error_msg_and_die("invalid range");
 995                last = xstrtou_range(++dash, 0, first, 0xff);
 996
 997                /* Range is not available for every mode. */
 998                switch (mode) {
 999                case I2C_SMBUS_BYTE:
1000                case I2C_SMBUS_BYTE_DATA:
1001                        break;
1002                case I2C_SMBUS_WORD_DATA:
1003                        if (!even || (!(first % 2) && last % 2))
1004                                break;
1005                        /* Fall through */
1006                default:
1007                        bb_simple_error_msg_and_die(
1008                                "range not compatible with selected mode");
1009                }
1010        }
1011
1012        fd = i2c_dev_open(bus_num);
1013        check_read_funcs(fd, mode, -1 /* data_addr */, pec);
1014        i2c_set_slave_addr(fd, bus_addr, opts & opt_f);
1015
1016        if (pec)
1017                i2c_set_pec(fd, 1);
1018
1019        if (!(opts & opt_y))
1020                confirm_action(bus_addr, mode, -1 /* data_addr */, pec);
1021
1022        /* All but word data. */
1023        if (mode != I2C_SMBUS_WORD_DATA || even) {
1024                int blen = 0;
1025
1026                if (mode == I2C_SMBUS_BLOCK_DATA || mode == I2C_SMBUS_I2C_BLOCK_DATA)
1027                        blen = read_block_data(fd, mode, block);
1028
1029                if (mode == I2C_SMBUS_BYTE) {
1030                        res = i2c_smbus_write_byte(fd, first);
1031                        if (res < 0)
1032                                bb_simple_perror_msg_and_die("write start address");
1033                }
1034
1035                dump_data(fd, mode, first, last, block, blen);
1036        } else {
1037                dump_word_data(fd, first, last);
1038        }
1039
1040        return 0;
1041}
1042#endif /* ENABLE_I2CDUMP */
1043
1044#if ENABLE_I2CDETECT
1045enum adapter_type {
1046        ADT_DUMMY = 0,
1047        ADT_ISA,
1048        ADT_I2C,
1049        ADT_SMBUS,
1050};
1051
1052struct adap_desc {
1053        const char *funcs;
1054        const char *algo;
1055};
1056
1057static const struct adap_desc adap_descs[] ALIGN_PTR = {
1058        { .funcs = "dummy", .algo = "Dummy bus", },
1059        { .funcs = "isa",   .algo = "ISA bus", },
1060        { .funcs = "i2c",   .algo = "I2C adapter", },
1061        { .funcs = "smbus", .algo = "SMBus adapter", },
1062};
1063
1064struct i2c_func {
1065        long value;
1066        const char* name;
1067};
1068
1069static const struct i2c_func i2c_funcs_tab[] ALIGN_PTR = {
1070        { .value = I2C_FUNC_I2C,
1071          .name = "I2C" },
1072        { .value = I2C_FUNC_SMBUS_QUICK,
1073          .name = "SMBus quick command" },
1074        { .value = I2C_FUNC_SMBUS_WRITE_BYTE,
1075          .name = "SMBus send byte" },
1076        { .value = I2C_FUNC_SMBUS_READ_BYTE,
1077          .name = "SMBus receive byte" },
1078        { .value = I2C_FUNC_SMBUS_WRITE_BYTE_DATA,
1079          .name = "SMBus write byte" },
1080        { .value = I2C_FUNC_SMBUS_READ_BYTE_DATA,
1081          .name = "SMBus read byte" },
1082        { .value = I2C_FUNC_SMBUS_WRITE_WORD_DATA,
1083          .name = "SMBus write word" },
1084        { .value = I2C_FUNC_SMBUS_READ_WORD_DATA,
1085          .name = "SMBus read word" },
1086        { .value = I2C_FUNC_SMBUS_PROC_CALL,
1087          .name = "SMBus process call" },
1088        { .value = I2C_FUNC_SMBUS_WRITE_BLOCK_DATA,
1089          .name = "SMBus block write" },
1090        { .value = I2C_FUNC_SMBUS_READ_BLOCK_DATA,
1091          .name = "SMBus block read" },
1092        { .value = I2C_FUNC_SMBUS_BLOCK_PROC_CALL,
1093          .name = "SMBus block process call" },
1094        { .value = I2C_FUNC_SMBUS_PEC,
1095          .name = "SMBus PEC" },
1096        { .value = I2C_FUNC_SMBUS_WRITE_I2C_BLOCK,
1097          .name = "I2C block write" },
1098        { .value = I2C_FUNC_SMBUS_READ_I2C_BLOCK,
1099          .name = "I2C block read" },
1100        { .value = 0, .name = NULL }
1101};
1102
1103static enum adapter_type i2cdetect_get_funcs(int bus)
1104{
1105        enum adapter_type ret;
1106        unsigned long funcs;
1107        int fd;
1108
1109        fd = i2c_dev_open(bus);
1110
1111        get_funcs_matrix(fd, &funcs);
1112        if (funcs & I2C_FUNC_I2C)
1113                ret = ADT_I2C;
1114        else if (funcs & (I2C_FUNC_SMBUS_BYTE |
1115                          I2C_FUNC_SMBUS_BYTE_DATA |
1116                          I2C_FUNC_SMBUS_WORD_DATA))
1117                ret = ADT_SMBUS;
1118        else
1119                ret = ADT_DUMMY;
1120
1121        close(fd);
1122
1123        return ret;
1124}
1125
1126static void NORETURN list_i2c_busses_and_exit(void)
1127{
1128        const char *const i2cdev_path = "/sys/class/i2c-dev";
1129
1130        char path[NAME_MAX], name[128];
1131        struct dirent *de, *subde;
1132        enum adapter_type adt;
1133        DIR *dir, *subdir;
1134        int rv, bus;
1135        char *pos;
1136        FILE *fp;
1137
1138        /*
1139         * XXX Upstream i2cdetect also looks for i2c bus info in /proc/bus/i2c,
1140         * but we won't bother since it's only useful on older kernels (before
1141         * 2.6.5). We expect sysfs to be present and mounted at /sys/.
1142         */
1143
1144        dir = xopendir(i2cdev_path);
1145        while ((de = readdir(dir))) {
1146                if (de->d_name[0] == '.')
1147                        continue;
1148
1149                /* Simple version for ISA chips. */
1150                snprintf(path, NAME_MAX, "%s/%s/name",
1151                         i2cdev_path, de->d_name);
1152                fp = fopen_for_read(path);
1153                if (fp == NULL) {
1154                        snprintf(path, NAME_MAX,
1155                                 "%s/%s/device/name",
1156                                 i2cdev_path, de->d_name);
1157                        fp = fopen_for_read(path);
1158                }
1159
1160                /* Non-ISA chips require the hard-way. */
1161                if (fp == NULL) {
1162                        snprintf(path, NAME_MAX,
1163                                 "%s/%s/device/name",
1164                                 i2cdev_path, de->d_name);
1165                        subdir = opendir(path);
1166                        if (subdir == NULL)
1167                                continue;
1168
1169                        while ((subde = readdir(subdir))) {
1170                                if (subde->d_name[0] == '.')
1171                                        continue;
1172
1173                                if (is_prefixed_with(subde->d_name, "i2c-")) {
1174                                        snprintf(path, NAME_MAX,
1175                                                 "%s/%s/device/%s/name",
1176                                                 i2cdev_path, de->d_name,
1177                                                 subde->d_name);
1178                                        fp = fopen_for_read(path);
1179                                        break;
1180                                }
1181                        }
1182                }
1183
1184                if (fp != NULL) {
1185                        /*
1186                         * Get the rest of the info and display a line
1187                         * for a single bus.
1188                         */
1189                        memset(name, 0, sizeof(name));
1190                        pos = fgets(name, sizeof(name), fp);
1191                        fclose(fp);
1192                        if (pos == NULL)
1193                                continue;
1194
1195                        pos = strchr(name, '\n');
1196                        if (pos != NULL)
1197                                *pos = '\0';
1198
1199                        rv = sscanf(de->d_name, "i2c-%d", &bus);
1200                        if (rv != 1)
1201                                continue;
1202
1203                        if (is_prefixed_with(name, "ISA"))
1204                                adt = ADT_ISA;
1205                        else
1206                                adt = i2cdetect_get_funcs(bus);
1207
1208                        printf(
1209                                "i2c-%d\t%-10s\t%-32s\t%s\n",
1210                                bus, adap_descs[adt].funcs,
1211                                name, adap_descs[adt].algo);
1212                }
1213        }
1214
1215        exit(EXIT_SUCCESS);
1216}
1217
1218static void NORETURN no_support(const char *cmd)
1219{
1220        bb_error_msg_and_die("bus doesn't support %s", cmd);
1221}
1222
1223static void will_skip(const char *cmd)
1224{
1225        bb_error_msg(
1226                "warning: can't use %s command, "
1227                "will skip some addresses", cmd);
1228}
1229
1230//usage:#define i2cdetect_trivial_usage
1231//usage:       "-l | -F I2CBUS | [-ya] [-q|-r] I2CBUS [FIRST LAST]"
1232//usage:#define i2cdetect_full_usage "\n\n"
1233//usage:       "Detect I2C chips"
1234//usage:     "\n"
1235//usage:     "\n        -l      List installed buses"
1236//usage:     "\n        -F BUS# List functionalities on this bus"
1237//usage:     "\n        -y      Disable interactive mode"
1238//usage:     "\n        -a      Force scanning of non-regular addresses"
1239//usage:     "\n        -q      Use smbus quick write commands for probing (default)"
1240//usage:     "\n        -r      Use smbus read byte commands for probing"
1241//usage:     "\n        FIRST and LAST limit probing range"
1242int i2cdetect_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
1243int i2cdetect_main(int argc UNUSED_PARAM, char **argv)
1244{
1245        const unsigned opt_y = (1 << 0), opt_a = (1 << 1),
1246                              opt_q = (1 << 2), opt_r = (1 << 3),
1247                              opt_F = (1 << 4), opt_l = (1 << 5);
1248
1249        int fd, bus_num, i, j, mode = I2CDETECT_MODE_AUTO, status, cmd;
1250        unsigned first = 0x03, last = 0x77, opts;
1251        unsigned long funcs;
1252
1253        opts = getopt32(argv, "^"
1254                        "yaqrFl"
1255                        "\0"
1256                        "q--r:r--q:"/*mutually exclusive*/
1257                        "?3"/*up to 3 args*/
1258        );
1259        argv += optind;
1260
1261        if (opts & opt_l)
1262                list_i2c_busses_and_exit();
1263
1264        if (!argv[0])
1265                bb_show_usage();
1266
1267        bus_num = i2c_bus_lookup(argv[0]);
1268        fd = i2c_dev_open(bus_num);
1269        get_funcs_matrix(fd, &funcs);
1270
1271        if (opts & opt_F) {
1272                /* Only list the functionalities. */
1273                printf("Functionalities implemented by bus #%d\n", bus_num);
1274                for (i = 0; i2c_funcs_tab[i].value; i++) {
1275                        printf("%-32s %s\n", i2c_funcs_tab[i].name,
1276                               funcs & i2c_funcs_tab[i].value ? "yes" : "no");
1277                }
1278
1279                return EXIT_SUCCESS;
1280        }
1281
1282        if (opts & opt_r)
1283                mode = I2CDETECT_MODE_READ;
1284        else if (opts & opt_q)
1285                mode = I2CDETECT_MODE_QUICK;
1286
1287        if (opts & opt_a) {
1288                first = 0x00;
1289                last = 0x7f;
1290        }
1291
1292        /* Read address range. */
1293        if (argv[1]) {
1294                first = xstrtou_range(argv[1], 16, first, last);
1295                if (argv[2])
1296                        last = xstrtou_range(argv[2], 16, first, last);
1297        }
1298
1299        if (!(funcs & (I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_READ_BYTE))) {
1300                no_support("detection commands");
1301        } else
1302        if (mode == I2CDETECT_MODE_QUICK && !(funcs & I2C_FUNC_SMBUS_QUICK)) {
1303                no_support("SMBus quick write");
1304        } else
1305        if (mode == I2CDETECT_MODE_READ && !(funcs & I2C_FUNC_SMBUS_READ_BYTE)) {
1306                no_support("SMBus receive byte");
1307        }
1308
1309        if (mode == I2CDETECT_MODE_AUTO) {
1310                if (!(funcs & I2C_FUNC_SMBUS_QUICK))
1311                        will_skip("SMBus quick write");
1312                if (!(funcs & I2C_FUNC_SMBUS_READ_BYTE))
1313                        will_skip("SMBus receive byte");
1314        }
1315
1316        if (!(opts & opt_y))
1317                confirm_action(-1, -1, -1, 0);
1318
1319        puts("     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f");
1320        for (i = 0; i < 128; i += 16) {
1321                printf("%02x: ", i);
1322                for (j = 0; j < 16; j++) {
1323                        fflush_all();
1324
1325                        cmd = mode;
1326                        if (mode == I2CDETECT_MODE_AUTO) {
1327                                if ((i+j >= 0x30 && i+j <= 0x37) ||
1328                                    (i+j >= 0x50 && i+j <= 0x5F))
1329                                        cmd = I2CDETECT_MODE_READ;
1330                                else
1331                                        cmd = I2CDETECT_MODE_QUICK;
1332                        }
1333
1334                        /* Skip unwanted addresses. */
1335                        if (i+j < first
1336                         || i+j > last
1337                         || (cmd == I2CDETECT_MODE_READ && !(funcs & I2C_FUNC_SMBUS_READ_BYTE))
1338                         || (cmd == I2CDETECT_MODE_QUICK && !(funcs & I2C_FUNC_SMBUS_QUICK)))
1339                        {
1340                                printf("   ");
1341                                continue;
1342                        }
1343
1344                        status = ioctl(fd, I2C_SLAVE, itoptr(i + j));
1345                        if (status < 0) {
1346                                if (errno == EBUSY) {
1347                                        printf("UU ");
1348                                        continue;
1349                                }
1350
1351                                bb_perror_msg_and_die(
1352                                        "can't set address to 0x%02x", i + j);
1353                        }
1354
1355                        switch (cmd) {
1356                        case I2CDETECT_MODE_READ:
1357                                /*
1358                                 * This is known to lock SMBus on various
1359                                 * write-only chips (mainly clock chips).
1360                                 */
1361                                status = i2c_smbus_read_byte(fd);
1362                                break;
1363                        default: /* I2CDETECT_MODE_QUICK: */
1364                                /*
1365                                 * This is known to corrupt the Atmel
1366                                 * AT24RF08 EEPROM.
1367                                 */
1368                                status = i2c_smbus_write_quick(fd,
1369                                                               I2C_SMBUS_WRITE);
1370                                break;
1371                        }
1372
1373                        if (status < 0)
1374                                printf("-- ");
1375                        else
1376                                printf("%02x ", i+j);
1377                }
1378                bb_putchar('\n');
1379        }
1380
1381        return 0;
1382}
1383#endif /* ENABLE_I2CDETECT */
1384
1385#if ENABLE_I2CTRANSFER
1386static void check_i2c_func(int fd)
1387{
1388        unsigned long funcs;
1389
1390        get_funcs_matrix(fd, &funcs);
1391
1392        if (!(funcs & I2C_FUNC_I2C))
1393                bb_simple_error_msg_and_die("adapter does not support I2C transfers");
1394}
1395
1396//usage:#define i2ctransfer_trivial_usage
1397//usage:       "[-fay] I2CBUS { rLENGTH[@ADDR] | wLENGTH[@ADDR] DATA...}..."
1398//usage:#define i2ctransfer_full_usage "\n\n"
1399//usage:       "Read/write I2C data in one transfer"
1400//usage:     "\n"
1401//usage:     "\n        -f      Force access to busy addresses"
1402//usage:     "\n        -a      Force access to non-regular addresses"
1403//usage:     "\n        -y      Disable interactive mode"
1404int i2ctransfer_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
1405int i2ctransfer_main(int argc UNUSED_PARAM, char **argv)
1406{
1407        enum {
1408                opt_f = (1 << 0),
1409                opt_y = (1 << 1),
1410                opt_a = (1 << 2),
1411        };
1412        int bus_num, bus_addr;
1413        int fd;
1414        unsigned opts, first, last;
1415        int nmsgs, nmsgs_sent, i;
1416        struct i2c_msg msgs[I2C_RDWR_IOCTL_MAX_MSGS];
1417        struct i2c_rdwr_ioctl_data rdwr;
1418
1419        memset(msgs, 0, sizeof(msgs));
1420
1421        opts = getopt32(argv, "^"
1422                "fya"
1423                "\0" "-2" /* minimum 2 args */
1424        );
1425        first = 0x03;
1426        last = 0x77;
1427        if (opts & opt_a) {
1428                first = 0x00;
1429                last = 0x7f;
1430        }
1431
1432        argv += optind;
1433        bus_num = i2c_bus_lookup(argv[0]);
1434        fd = i2c_dev_open(bus_num);
1435        check_i2c_func(fd);
1436
1437        bus_addr = -1;
1438        nmsgs = 0;
1439        while (*++argv) {
1440                char *arg_ptr;
1441                unsigned len;
1442                uint16_t flags;
1443                char *end;
1444
1445                if (nmsgs >= I2C_RDWR_IOCTL_MAX_MSGS)
1446                        bb_simple_error_msg_and_die("too many messages, max: "I2C_RDWR_IOCTL_MAX_MSGS_STR);
1447
1448                flags = 0;
1449                arg_ptr = *argv;
1450                switch (*arg_ptr++) {
1451                case 'r': flags |= I2C_M_RD; break;
1452                case 'w': break;
1453                default:
1454                        bb_show_usage();
1455                }
1456
1457                end = strchr(arg_ptr, '@');
1458                if (end) *end = '\0';
1459                len = xstrtou_range(arg_ptr, 0, 0, 0xffff);
1460                if (end) {
1461                        bus_addr = xstrtou_range(end + 1, 0, first, last);
1462                        i2c_set_slave_addr(fd, bus_addr, (opts & opt_f));
1463                } else {
1464                        /* Reuse last address if possible */
1465                        if (bus_addr < 0)
1466                                bb_error_msg_and_die("no address given in '%s'", *argv);
1467                }
1468
1469                msgs[nmsgs].addr = bus_addr;
1470                msgs[nmsgs].flags = flags;
1471                msgs[nmsgs].len = len;
1472                if (len)
1473                        msgs[nmsgs].buf = xzalloc(len);
1474
1475                if (!(flags & I2C_M_RD)) {
1476                        /* Consume DATA arg(s) */
1477                        unsigned buf_idx = 0;
1478
1479                        while (buf_idx < len) {
1480                                uint8_t data8;
1481                                unsigned long data;
1482
1483                                arg_ptr = *++argv;
1484                                if (!arg_ptr)
1485                                        bb_show_usage();
1486                                data = strtoul(arg_ptr, &end, 0);
1487                                if (data > 0xff || arg_ptr == end)
1488                                        bb_error_msg_and_die("invalid data byte '%s'", *argv);
1489
1490                                data8 = data;
1491                                while (buf_idx < len) {
1492                                        msgs[nmsgs].buf[buf_idx++] = data8;
1493                                        if (!*end)
1494                                                break;
1495                                        switch (*end) {
1496                                        /* Pseudo randomness (8 bit AXR with a=13 and b=27) */
1497                                        case 'p':
1498                                                data8 = (data8 ^ 27) + 13;
1499                                                data8 = (data8 << 1) | (data8 >> 7);
1500                                                break;
1501                                        case '+': data8++; break;
1502                                        case '-': data8--; break;
1503                                        case '=': break;
1504                                        default:
1505                                                bb_error_msg_and_die("invalid data byte suffix: '%s'",
1506                                                                     *argv);
1507                                        }
1508                                }
1509                        }
1510                }
1511                nmsgs++;
1512        }
1513
1514        if (!(opts & opt_y))
1515                confirm_action(bus_addr, 0, 0, 0);
1516
1517        rdwr.msgs = msgs;
1518        rdwr.nmsgs = nmsgs;
1519        nmsgs_sent = ioctl_or_perror_and_die(fd, I2C_RDWR, &rdwr, "I2C_RDWR");
1520        if (nmsgs_sent < nmsgs)
1521                bb_error_msg("warning: only %u/%u messages sent", nmsgs_sent, nmsgs);
1522
1523        for (i = 0; i < nmsgs_sent; i++) {
1524                if (msgs[i].len != 0 && (msgs[i].flags & I2C_M_RD)) {
1525                        int j;
1526                        for (j = 0; j < msgs[i].len - 1; j++)
1527                                printf("0x%02x ", msgs[i].buf[j]);
1528                        /* Print final byte with newline */
1529                        printf("0x%02x\n", msgs[i].buf[j]);
1530                }
1531        }
1532
1533# if ENABLE_FEATURE_CLEAN_UP
1534        close(fd);
1535        for (i = 0; i < nmsgs; i++)
1536                free(msgs[i].buf);
1537# endif
1538
1539        return 0;
1540}
1541#endif /* ENABLE_I2CTRANSFER */
1542