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