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