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