blob: cc8b99a924b5953b3cbaf3b7246791a11893997f [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 */
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +010011//config:config I2CGET
Denys Vlasenkob097a842018-12-28 03:20:17 +010012//config: bool "i2cget (5.5 kb)"
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +010013//config: default y
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +010014//config: help
Denys Vlasenko72089cf2017-07-21 09:50:55 +020015//config: Read from I2C/SMBus chip registers.
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +010016//config:
17//config:config I2CSET
Denys Vlasenkob097a842018-12-28 03:20:17 +010018//config: bool "i2cset (6.7 kb)"
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +010019//config: default y
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +010020//config: help
Denys Vlasenko72089cf2017-07-21 09:50:55 +020021//config: Set I2C registers.
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +010022//config:
23//config:config I2CDUMP
Denys Vlasenkob097a842018-12-28 03:20:17 +010024//config: bool "i2cdump (7.1 kb)"
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +010025//config: default y
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +010026//config: help
Denys Vlasenko72089cf2017-07-21 09:50:55 +020027//config: Examine I2C registers.
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +010028//config:
29//config:config I2CDETECT
Denys Vlasenkob097a842018-12-28 03:20:17 +010030//config: bool "i2cdetect (7.1 kb)"
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +010031//config: default y
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +010032//config: help
Denys Vlasenko72089cf2017-07-21 09:50:55 +020033//config: Detect I2C chips.
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +010034//config:
Nikolaus Vossdac8f5e2019-02-10 19:56:41 +010035//config:config I2CTRANSFER
36//config: bool "i2ctransfer (4.0 kb)"
37//config: default y
Nikolaus Vossdac8f5e2019-02-10 19:56:41 +010038//config: help
39//config: Send user-defined I2C messages in one transfer.
40//config:
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +010041
42//applet:IF_I2CGET(APPLET(i2cget, BB_DIR_USR_SBIN, BB_SUID_DROP))
43//applet:IF_I2CSET(APPLET(i2cset, BB_DIR_USR_SBIN, BB_SUID_DROP))
44//applet:IF_I2CDUMP(APPLET(i2cdump, BB_DIR_USR_SBIN, BB_SUID_DROP))
45//applet:IF_I2CDETECT(APPLET(i2cdetect, BB_DIR_USR_SBIN, BB_SUID_DROP))
Nikolaus Vossdac8f5e2019-02-10 19:56:41 +010046//applet:IF_I2CTRANSFER(APPLET(i2ctransfer, BB_DIR_USR_SBIN, BB_SUID_DROP))
Denys Vlasenko1a1203f2017-08-07 16:47:34 +020047/* not NOEXEC: if hw operation stalls, use less memory in "hung" process */
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +010048
49//kbuild:lib-$(CONFIG_I2CGET) += i2c_tools.o
50//kbuild:lib-$(CONFIG_I2CSET) += i2c_tools.o
51//kbuild:lib-$(CONFIG_I2CDUMP) += i2c_tools.o
52//kbuild:lib-$(CONFIG_I2CDETECT) += i2c_tools.o
Nikolaus Vossdac8f5e2019-02-10 19:56:41 +010053//kbuild:lib-$(CONFIG_I2CTRANSFER) += i2c_tools.o
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +010054
55/*
56 * Unsupported stuff:
57 *
58 * - upstream i2c-tools can also look-up i2c busses by name, we only accept
59 * numbers,
60 * - bank and bankreg parameters for i2cdump are not supported because of
61 * their limited usefulness (see i2cdump manual entry for more info),
62 * - i2cdetect doesn't look for bus info in /proc as it does in upstream, but
63 * it shouldn't be a problem in modern kernels.
64 */
65
66#include "libbb.h"
67
Bartosz Golaszewskid9892fa2015-09-04 10:35:22 +020068#include <linux/i2c.h>
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +010069
Bartosz Golaszewski2beb5242015-09-04 10:38:48 +020070#define I2CDUMP_NUM_REGS 256
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +010071
Bartosz Golaszewski2beb5242015-09-04 10:38:48 +020072#define I2CDETECT_MODE_AUTO 0
73#define I2CDETECT_MODE_QUICK 1
74#define I2CDETECT_MODE_READ 2
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +010075
Bartosz Golaszewski0d1eaf42017-08-29 12:31:22 +020076/* linux/i2c-dev.h from i2c-tools overwrites the one from linux uapi
77 * and defines symbols already defined by linux/i2c.h.
78 * Also, it defines a bunch of static inlines which we would rather NOT
79 * inline. What a mess.
80 * We need only these definitions from linux/i2c-dev.h:
81 */
82#define I2C_SLAVE 0x0703
83#define I2C_SLAVE_FORCE 0x0706
84#define I2C_FUNCS 0x0705
85#define I2C_PEC 0x0708
86#define I2C_SMBUS 0x0720
Nikolaus Vossdac8f5e2019-02-10 19:56:41 +010087#define I2C_RDWR 0x0707
88#define I2C_RDWR_IOCTL_MAX_MSGS 42
89#define I2C_RDWR_IOCTL_MAX_MSGS_STR "42"
Bartosz Golaszewski0d1eaf42017-08-29 12:31:22 +020090struct i2c_smbus_ioctl_data {
91 __u8 read_write;
92 __u8 command;
93 __u32 size;
94 union i2c_smbus_data *data;
95};
Nikolaus Vossdac8f5e2019-02-10 19:56:41 +010096struct i2c_rdwr_ioctl_data {
97 struct i2c_msg *msgs; /* pointers to i2c_msgs */
98 __u32 nmsgs; /* number of i2c_msgs */
99};
Bartosz Golaszewski0d1eaf42017-08-29 12:31:22 +0200100/* end linux/i2c-dev.h */
101
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100102/*
103 * This is needed for ioctl_or_perror_and_die() since it only accepts pointers.
104 */
105static ALWAYS_INLINE void *itoptr(int i)
106{
107 return (void*)(intptr_t)i;
108}
109
110static int32_t i2c_smbus_access(int fd, char read_write, uint8_t cmd,
111 int size, union i2c_smbus_data *data)
112{
113 struct i2c_smbus_ioctl_data args;
114
115 args.read_write = read_write;
116 args.command = cmd;
117 args.size = size;
118 args.data = data;
119
120 return ioctl(fd, I2C_SMBUS, &args);
121}
122
123static int32_t i2c_smbus_read_byte(int fd)
124{
125 union i2c_smbus_data data;
126 int err;
127
128 err = i2c_smbus_access(fd, I2C_SMBUS_READ, 0, I2C_SMBUS_BYTE, &data);
129 if (err < 0)
130 return err;
131
132 return data.byte;
133}
134
135#if ENABLE_I2CGET || ENABLE_I2CSET || ENABLE_I2CDUMP
136static int32_t i2c_smbus_write_byte(int fd, uint8_t val)
137{
138 return i2c_smbus_access(fd, I2C_SMBUS_WRITE,
139 val, I2C_SMBUS_BYTE, NULL);
140}
141
142static int32_t i2c_smbus_read_byte_data(int fd, uint8_t cmd)
143{
144 union i2c_smbus_data data;
145 int err;
146
147 err = i2c_smbus_access(fd, I2C_SMBUS_READ, cmd,
148 I2C_SMBUS_BYTE_DATA, &data);
149 if (err < 0)
150 return err;
151
152 return data.byte;
153}
154
155static int32_t i2c_smbus_read_word_data(int fd, uint8_t cmd)
156{
157 union i2c_smbus_data data;
158 int err;
159
160 err = i2c_smbus_access(fd, I2C_SMBUS_READ, cmd,
161 I2C_SMBUS_WORD_DATA, &data);
162 if (err < 0)
163 return err;
164
165 return data.word;
166}
167#endif /* ENABLE_I2CGET || ENABLE_I2CSET || ENABLE_I2CDUMP */
168
169#if ENABLE_I2CSET
170static int32_t i2c_smbus_write_byte_data(int file,
171 uint8_t cmd, uint8_t value)
172{
173 union i2c_smbus_data data;
174
175 data.byte = value;
176
177 return i2c_smbus_access(file, I2C_SMBUS_WRITE, cmd,
178 I2C_SMBUS_BYTE_DATA, &data);
179}
180
181static int32_t i2c_smbus_write_word_data(int file, uint8_t cmd, uint16_t value)
182{
183 union i2c_smbus_data data;
184
185 data.word = value;
186
187 return i2c_smbus_access(file, I2C_SMBUS_WRITE, cmd,
188 I2C_SMBUS_WORD_DATA, &data);
189}
190
191static int32_t i2c_smbus_write_block_data(int file, uint8_t cmd,
192 uint8_t length, const uint8_t *values)
193{
194 union i2c_smbus_data data;
195
196 if (length > I2C_SMBUS_BLOCK_MAX)
197 length = I2C_SMBUS_BLOCK_MAX;
198
199 memcpy(data.block+1, values, length);
200 data.block[0] = length;
201
202 return i2c_smbus_access(file, I2C_SMBUS_WRITE, cmd,
203 I2C_SMBUS_BLOCK_DATA, &data);
204}
205
206static int32_t i2c_smbus_write_i2c_block_data(int file, uint8_t cmd,
207 uint8_t length, const uint8_t *values)
208{
209 union i2c_smbus_data data;
210
211 if (length > I2C_SMBUS_BLOCK_MAX)
212 length = I2C_SMBUS_BLOCK_MAX;
213
214 memcpy(data.block+1, values, length);
215 data.block[0] = length;
216
217 return i2c_smbus_access(file, I2C_SMBUS_WRITE, cmd,
218 I2C_SMBUS_I2C_BLOCK_BROKEN, &data);
219}
220#endif /* ENABLE_I2CSET */
221
222#if ENABLE_I2CDUMP
223/*
224 * Returns the number of bytes read, vals must hold at
225 * least I2C_SMBUS_BLOCK_MAX bytes.
226 */
227static int32_t i2c_smbus_read_block_data(int fd, uint8_t cmd, uint8_t *vals)
228{
229 union i2c_smbus_data data;
230 int i, err;
231
232 err = i2c_smbus_access(fd, I2C_SMBUS_READ, cmd,
233 I2C_SMBUS_BLOCK_DATA, &data);
234 if (err < 0)
235 return err;
236
237 for (i = 1; i <= data.block[0]; i++)
238 *vals++ = data.block[i];
239 return data.block[0];
240}
241
242static int32_t i2c_smbus_read_i2c_block_data(int fd, uint8_t cmd,
243 uint8_t len, uint8_t *vals)
244{
245 union i2c_smbus_data data;
246 int i, err;
247
248 if (len > I2C_SMBUS_BLOCK_MAX)
249 len = I2C_SMBUS_BLOCK_MAX;
250 data.block[0] = len;
251
252 err = i2c_smbus_access(fd, I2C_SMBUS_READ, cmd,
253 len == 32 ? I2C_SMBUS_I2C_BLOCK_BROKEN :
254 I2C_SMBUS_I2C_BLOCK_DATA, &data);
255 if (err < 0)
256 return err;
257
258 for (i = 1; i <= data.block[0]; i++)
259 *vals++ = data.block[i];
260 return data.block[0];
261}
262#endif /* ENABLE_I2CDUMP */
263
264#if ENABLE_I2CDETECT
265static int32_t i2c_smbus_write_quick(int fd, uint8_t val)
266{
267 return i2c_smbus_access(fd, val, 0, I2C_SMBUS_QUICK, NULL);
268}
269#endif /* ENABLE_I2CDETECT */
270
271static int i2c_bus_lookup(const char *bus_str)
272{
273 return xstrtou_range(bus_str, 10, 0, 0xfffff);
274}
275
Nikolaus Vossdac8f5e2019-02-10 19:56:41 +0100276#if ENABLE_I2CGET || ENABLE_I2CSET || ENABLE_I2CDUMP || ENABLE_I2CTRANSFER
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100277static int i2c_parse_bus_addr(const char *addr_str)
278{
279 /* Slave address must be in range 0x03 - 0x77. */
280 return xstrtou_range(addr_str, 16, 0x03, 0x77);
281}
282
283static void i2c_set_pec(int fd, int pec)
284{
285 ioctl_or_perror_and_die(fd, I2C_PEC,
286 itoptr(pec ? 1 : 0),
287 "can't set PEC");
288}
Bartosz Golaszewski31474272015-06-05 10:27:28 +0200289
290static void i2c_set_slave_addr(int fd, int addr, int force)
291{
292 ioctl_or_perror_and_die(fd, force ? I2C_SLAVE_FORCE : I2C_SLAVE,
293 itoptr(addr),
294 "can't set address to 0x%02x", addr);
295}
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100296#endif /* ENABLE_I2CGET || ENABLE_I2CSET || ENABLE_I2CDUMP */
297
298#if ENABLE_I2CGET || ENABLE_I2CSET
299static int i2c_parse_data_addr(const char *data_addr)
300{
301 /* Data address must be an 8 bit integer. */
302 return xstrtou_range(data_addr, 16, 0, 0xff);
303}
304#endif /* ENABLE_I2CGET || ENABLE_I2CSET */
305
306/*
307 * Opens the device file associated with given i2c bus.
308 *
309 * Upstream i2c-tools also support opening devices by i2c bus name
310 * but we drop it here for size reduction.
311 */
312static int i2c_dev_open(int i2cbus)
313{
314 char filename[sizeof("/dev/i2c-%d") + sizeof(int)*3];
315 int fd;
316
317 sprintf(filename, "/dev/i2c-%d", i2cbus);
318 fd = open(filename, O_RDWR);
319 if (fd < 0) {
Bartosz Golaszewski7ca5c512015-05-11 17:26:27 +0200320 if (errno == ENOENT) {
321 filename[8] = '/'; /* change to "/dev/i2c/%d" */
322 fd = xopen(filename, O_RDWR);
323 } else {
324 bb_perror_msg_and_die("can't open '%s'", filename);
325 }
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100326 }
327
328 return fd;
329}
330
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100331/* Size reducing helpers for xxx_check_funcs(). */
332static void get_funcs_matrix(int fd, unsigned long *funcs)
333{
334 ioctl_or_perror_and_die(fd, I2C_FUNCS, funcs,
335 "can't get adapter functionality matrix");
336}
337
338#if ENABLE_I2CGET || ENABLE_I2CSET || ENABLE_I2CDUMP
339static void check_funcs_test_end(int funcs, int pec, const char *err)
340{
341 if (pec && !(funcs & (I2C_FUNC_SMBUS_PEC | I2C_FUNC_I2C)))
James Byrne69374872019-07-02 11:35:03 +0200342 bb_simple_error_msg("warning: adapter does not support PEC");
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100343
344 if (err)
345 bb_error_msg_and_die(
346 "adapter has no %s capability", err);
347}
348#endif /* ENABLE_I2CGET || ENABLE_I2CSET || ENABLE_I2CDUMP */
349
350/*
351 * The below functions emit an error message and exit if the adapter doesn't
352 * support desired functionalities.
353 */
354#if ENABLE_I2CGET || ENABLE_I2CDUMP
355static void check_read_funcs(int fd, int mode, int data_addr, int pec)
356{
357 unsigned long funcs;
358 const char *err = NULL;
359
360 get_funcs_matrix(fd, &funcs);
361 switch (mode) {
362 case I2C_SMBUS_BYTE:
363 if (!(funcs & I2C_FUNC_SMBUS_READ_BYTE)) {
364 err = "SMBus receive byte";
365 break;
366 }
367 if (data_addr >= 0 && !(funcs & I2C_FUNC_SMBUS_WRITE_BYTE))
368 err = "SMBus send byte";
369 break;
370 case I2C_SMBUS_BYTE_DATA:
371 if (!(funcs & I2C_FUNC_SMBUS_READ_BYTE_DATA))
372 err = "SMBus read byte";
373 break;
374 case I2C_SMBUS_WORD_DATA:
375 if (!(funcs & I2C_FUNC_SMBUS_READ_WORD_DATA))
376 err = "SMBus read word";
377 break;
378#if ENABLE_I2CDUMP
379 case I2C_SMBUS_BLOCK_DATA:
380 if (!(funcs & I2C_FUNC_SMBUS_READ_BLOCK_DATA))
381 err = "SMBus block read";
382 break;
383
384 case I2C_SMBUS_I2C_BLOCK_DATA:
385 if (!(funcs & I2C_FUNC_SMBUS_READ_I2C_BLOCK))
386 err = "I2C block read";
387 break;
388#endif /* ENABLE_I2CDUMP */
389 default:
James Byrne69374872019-07-02 11:35:03 +0200390 bb_simple_error_msg_and_die("internal error");
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100391 }
392 check_funcs_test_end(funcs, pec, err);
393}
394#endif /* ENABLE_I2CGET || ENABLE_I2CDUMP */
395
396#if ENABLE_I2CSET
397static void check_write_funcs(int fd, int mode, int pec)
398{
399 unsigned long funcs;
400 const char *err = NULL;
401
402 get_funcs_matrix(fd, &funcs);
403 switch (mode) {
404 case I2C_SMBUS_BYTE:
405 if (!(funcs & I2C_FUNC_SMBUS_WRITE_BYTE))
406 err = "SMBus send byte";
407 break;
408
409 case I2C_SMBUS_BYTE_DATA:
410 if (!(funcs & I2C_FUNC_SMBUS_WRITE_BYTE_DATA))
411 err = "SMBus write byte";
412 break;
413
414 case I2C_SMBUS_WORD_DATA:
415 if (!(funcs & I2C_FUNC_SMBUS_WRITE_WORD_DATA))
416 err = "SMBus write word";
417 break;
418
419 case I2C_SMBUS_BLOCK_DATA:
420 if (!(funcs & I2C_FUNC_SMBUS_WRITE_BLOCK_DATA))
421 err = "SMBus block write";
422 break;
423 case I2C_SMBUS_I2C_BLOCK_DATA:
424 if (!(funcs & I2C_FUNC_SMBUS_WRITE_I2C_BLOCK))
425 err = "I2C block write";
426 break;
427 }
428 check_funcs_test_end(funcs, pec, err);
429}
430#endif /* ENABLE_I2CSET */
431
432static void confirm_or_abort(void)
433{
434 fprintf(stderr, "Continue? [y/N] ");
Denys Vlasenko77cb6b92018-04-07 15:08:12 +0200435 if (!bb_ask_y_confirmation())
James Byrne69374872019-07-02 11:35:03 +0200436 bb_simple_error_msg_and_die("aborting");
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100437}
438
439/*
440 * Return only if user confirms the action, abort otherwise.
441 *
442 * The messages displayed here are much less elaborate than their i2c-tools
443 * counterparts - this is done for size reduction.
444 */
445static void confirm_action(int bus_addr, int mode, int data_addr, int pec)
446{
James Byrne69374872019-07-02 11:35:03 +0200447 bb_simple_error_msg("WARNING! This program can confuse your I2C bus");
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100448
449 /* Don't let the user break his/her EEPROMs */
450 if (bus_addr >= 0x50 && bus_addr <= 0x57 && pec) {
James Byrne69374872019-07-02 11:35:03 +0200451 bb_simple_error_msg_and_die("this is I2C not smbus - using PEC on I2C "
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100452 "devices may result in data loss, aborting");
453 }
454
455 if (mode == I2C_SMBUS_BYTE && data_addr >= 0 && pec)
James Byrne69374872019-07-02 11:35:03 +0200456 bb_simple_error_msg("WARNING! May interpret a write byte command "
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100457 "with PEC as a write byte data command");
458
459 if (pec)
James Byrne69374872019-07-02 11:35:03 +0200460 bb_simple_error_msg("PEC checking enabled");
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100461
462 confirm_or_abort();
463}
464
465#if ENABLE_I2CGET
466//usage:#define i2cget_trivial_usage
Denys Vlasenkof27e1502017-08-29 15:44:01 +0200467//usage: "[-fy] BUS CHIP-ADDRESS [DATA-ADDRESS [MODE]]"
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100468//usage:#define i2cget_full_usage "\n\n"
Denys Vlasenkof27e1502017-08-29 15:44:01 +0200469//usage: "Read from I2C/SMBus chip registers"
470//usage: "\n"
471//usage: "\n I2CBUS I2C bus number"
472//usage: "\n ADDRESS 0x03-0x77"
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100473//usage: "\nMODE is:"
Denys Vlasenkof27e1502017-08-29 15:44:01 +0200474//usage: "\n b Read byte data (default)"
475//usage: "\n w Read word data"
476//usage: "\n c Write byte/read byte"
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100477//usage: "\n Append p for SMBus PEC"
478//usage: "\n"
Denys Vlasenkof27e1502017-08-29 15:44:01 +0200479//usage: "\n -f Force access"
480//usage: "\n -y Disable interactive mode"
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100481int i2cget_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
482int i2cget_main(int argc UNUSED_PARAM, char **argv)
483{
484 const unsigned opt_f = (1 << 0), opt_y = (1 << 1);
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100485
486 int bus_num, bus_addr, data_addr = -1, status;
487 int mode = I2C_SMBUS_BYTE, pec = 0, fd;
488 unsigned opts;
489
Denys Vlasenko22542ec2017-08-08 21:55:02 +0200490 opts = getopt32(argv, "^" "fy" "\0" "-2:?4"/*from 2 to 4 args*/);
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100491 argv += optind;
492
493 bus_num = i2c_bus_lookup(argv[0]);
494 bus_addr = i2c_parse_bus_addr(argv[1]);
495
496 if (argv[2]) {
497 data_addr = i2c_parse_data_addr(argv[2]);
498 mode = I2C_SMBUS_BYTE_DATA;
499 if (argv[3]) {
500 switch (argv[3][0]) {
501 case 'b': /* Already set */ break;
502 case 'w': mode = I2C_SMBUS_WORD_DATA; break;
503 case 'c': mode = I2C_SMBUS_BYTE; break;
504 default:
James Byrne69374872019-07-02 11:35:03 +0200505 bb_simple_error_msg("invalid mode");
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100506 bb_show_usage();
507 }
508 pec = argv[3][1] == 'p';
509 }
510 }
511
512 fd = i2c_dev_open(bus_num);
513 check_read_funcs(fd, mode, data_addr, pec);
514 i2c_set_slave_addr(fd, bus_addr, opts & opt_f);
515
516 if (!(opts & opt_y))
517 confirm_action(bus_addr, mode, data_addr, pec);
518
519 if (pec)
520 i2c_set_pec(fd, 1);
521
522 switch (mode) {
523 case I2C_SMBUS_BYTE:
524 if (data_addr >= 0) {
525 status = i2c_smbus_write_byte(fd, data_addr);
526 if (status < 0)
James Byrne69374872019-07-02 11:35:03 +0200527 bb_simple_error_msg("warning - write failed");
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100528 }
529 status = i2c_smbus_read_byte(fd);
530 break;
531 case I2C_SMBUS_WORD_DATA:
532 status = i2c_smbus_read_word_data(fd, data_addr);
533 break;
534 default: /* I2C_SMBUS_BYTE_DATA */
535 status = i2c_smbus_read_byte_data(fd, data_addr);
536 }
537 close(fd);
538
539 if (status < 0)
James Byrne69374872019-07-02 11:35:03 +0200540 bb_simple_perror_msg_and_die("read failed");
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100541
542 printf("0x%0*x\n", mode == I2C_SMBUS_WORD_DATA ? 4 : 2, status);
543
544 return 0;
545}
546#endif /* ENABLE_I2CGET */
547
548#if ENABLE_I2CSET
549//usage:#define i2cset_trivial_usage
Denys Vlasenkof27e1502017-08-29 15:44:01 +0200550//usage: "[-fy] [-m MASK] BUS CHIP-ADDRESS DATA-ADDRESS [VALUE] ... [MODE]"
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100551//usage:#define i2cset_full_usage "\n\n"
Denys Vlasenkof27e1502017-08-29 15:44:01 +0200552//usage: "Set I2C registers"
553//usage: "\n"
554//usage: "\n I2CBUS I2C bus number"
555//usage: "\n ADDRESS 0x03-0x77"
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100556//usage: "\nMODE is:"
Denys Vlasenkof27e1502017-08-29 15:44:01 +0200557//usage: "\n c Byte, no value"
558//usage: "\n b Byte data (default)"
559//usage: "\n w Word data"
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100560//usage: "\n i I2C block data"
561//usage: "\n s SMBus block data"
562//usage: "\n Append p for SMBus PEC"
563//usage: "\n"
Denys Vlasenkof27e1502017-08-29 15:44:01 +0200564//usage: "\n -f Force access"
565//usage: "\n -y Disable interactive mode"
566//usage: "\n -r Read back and compare the result"
567//usage: "\n -m MASK Mask specifying which bits to write"
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100568int i2cset_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
569int i2cset_main(int argc, char **argv)
570{
571 const unsigned opt_f = (1 << 0), opt_y = (1 << 1),
572 opt_m = (1 << 2), opt_r = (1 << 3);
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100573
574 int bus_num, bus_addr, data_addr, mode = I2C_SMBUS_BYTE, pec = 0;
Avi Fishmanb5d9ba82017-10-05 11:25:16 +0200575 int val, blen, mask, fd, status;
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100576 unsigned char block[I2C_SMBUS_BLOCK_MAX];
577 char *opt_m_arg = NULL;
578 unsigned opts;
579
Avi Fishmanb5d9ba82017-10-05 11:25:16 +0200580 opts = getopt32(argv, "^"
581 "fym:r"
582 "\0" "-3", /* minimum 3 args */
583 &opt_m_arg
584 );
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100585 argv += optind;
586 argc -= optind;
Avi Fishmanb5d9ba82017-10-05 11:25:16 +0200587 argc--; /* now argv[argc] is last arg */
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100588
589 bus_num = i2c_bus_lookup(argv[0]);
590 bus_addr = i2c_parse_bus_addr(argv[1]);
591 data_addr = i2c_parse_data_addr(argv[2]);
592
593 if (argv[3]) {
594 if (!argv[4] && argv[3][0] != 'c') {
595 mode = I2C_SMBUS_BYTE_DATA; /* Implicit b */
596 } else {
Avi Fishmanb5d9ba82017-10-05 11:25:16 +0200597 switch (argv[argc][0]) {
598 case 'c': /* Already set */
599 break;
600 case 'b': mode = I2C_SMBUS_BYTE_DATA;
601 break;
602 case 'w': mode = I2C_SMBUS_WORD_DATA;
603 break;
604 case 's': mode = I2C_SMBUS_BLOCK_DATA;
605 break;
606 case 'i': mode = I2C_SMBUS_I2C_BLOCK_DATA;
607 break;
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100608 default:
James Byrne69374872019-07-02 11:35:03 +0200609 bb_simple_error_msg("invalid mode");
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100610 bb_show_usage();
611 }
612
Avi Fishmanb5d9ba82017-10-05 11:25:16 +0200613 pec = (argv[argc][1] == 'p');
614 if (mode == I2C_SMBUS_BLOCK_DATA
615 || mode == I2C_SMBUS_I2C_BLOCK_DATA
616 ) {
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100617 if (pec && mode == I2C_SMBUS_I2C_BLOCK_DATA)
James Byrne69374872019-07-02 11:35:03 +0200618 bb_simple_error_msg_and_die(
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100619 "PEC not supported for I2C "
620 "block writes");
621 if (opts & opt_m)
James Byrne69374872019-07-02 11:35:03 +0200622 bb_simple_error_msg_and_die(
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100623 "mask not supported for block "
624 "writes");
625 }
626 }
627 }
628
629 /* Prepare the value(s) to be written according to current mode. */
Avi Fishmanb5d9ba82017-10-05 11:25:16 +0200630 mask = 0;
631 blen = 0;
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100632 switch (mode) {
633 case I2C_SMBUS_BYTE_DATA:
634 val = xstrtou_range(argv[3], 0, 0, 0xff);
635 break;
636 case I2C_SMBUS_WORD_DATA:
637 val = xstrtou_range(argv[3], 0, 0, 0xffff);
638 break;
639 case I2C_SMBUS_BLOCK_DATA:
640 case I2C_SMBUS_I2C_BLOCK_DATA:
Avi Fishmanb5d9ba82017-10-05 11:25:16 +0200641 for (blen = 3; blen < argc; blen++)
642 block[blen - 3] = xstrtou_range(argv[blen], 0, 0, 0xff);
643 blen -= 3;
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100644 val = -1;
645 break;
646 default:
647 val = -1;
648 break;
649 }
650
651 if (opts & opt_m) {
652 mask = xstrtou_range(opt_m_arg, 0, 0,
653 (mode == I2C_SMBUS_BYTE ||
654 mode == I2C_SMBUS_BYTE_DATA) ? 0xff : 0xffff);
655 }
656
657 fd = i2c_dev_open(bus_num);
658 check_write_funcs(fd, mode, pec);
659 i2c_set_slave_addr(fd, bus_addr, opts & opt_f);
660
661 if (!(opts & opt_y))
662 confirm_action(bus_addr, mode, data_addr, pec);
663
664 /*
665 * If we're using mask - read the current value here and adjust the
666 * value to be written.
667 */
668 if (opts & opt_m) {
669 int tmpval;
670
671 switch (mode) {
672 case I2C_SMBUS_BYTE:
673 tmpval = i2c_smbus_read_byte(fd);
674 break;
675 case I2C_SMBUS_WORD_DATA:
676 tmpval = i2c_smbus_read_word_data(fd, data_addr);
677 break;
678 default:
679 tmpval = i2c_smbus_read_byte_data(fd, data_addr);
680 }
681
682 if (tmpval < 0)
James Byrne69374872019-07-02 11:35:03 +0200683 bb_simple_perror_msg_and_die("can't read old value");
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100684
685 val = (val & mask) | (tmpval & ~mask);
686
687 if (!(opts & opt_y)) {
688 bb_error_msg("old value 0x%0*x, write mask "
689 "0x%0*x, will write 0x%0*x to register "
690 "0x%02x",
691 mode == I2C_SMBUS_WORD_DATA ? 4 : 2, tmpval,
692 mode == I2C_SMBUS_WORD_DATA ? 4 : 2, mask,
693 mode == I2C_SMBUS_WORD_DATA ? 4 : 2, val,
694 data_addr);
695 confirm_or_abort();
696 }
697 }
698
699 if (pec)
700 i2c_set_pec(fd, 1);
701
702 switch (mode) {
703 case I2C_SMBUS_BYTE:
704 status = i2c_smbus_write_byte(fd, data_addr);
705 break;
706 case I2C_SMBUS_WORD_DATA:
707 status = i2c_smbus_write_word_data(fd, data_addr, val);
708 break;
709 case I2C_SMBUS_BLOCK_DATA:
710 status = i2c_smbus_write_block_data(fd, data_addr,
711 blen, block);
712 break;
713 case I2C_SMBUS_I2C_BLOCK_DATA:
714 status = i2c_smbus_write_i2c_block_data(fd, data_addr,
715 blen, block);
716 break;
717 default: /* I2C_SMBUS_BYTE_DATA */
718 status = i2c_smbus_write_byte_data(fd, data_addr, val);
719 break;
720 }
721 if (status < 0)
James Byrne69374872019-07-02 11:35:03 +0200722 bb_simple_perror_msg_and_die("write failed");
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100723
724 if (pec)
725 i2c_set_pec(fd, 0); /* Clear PEC. */
726
727 /* No readback required - we're done. */
728 if (!(opts & opt_r))
729 return 0;
730
731 switch (mode) {
732 case I2C_SMBUS_BYTE:
733 status = i2c_smbus_read_byte(fd);
734 val = data_addr;
735 break;
736 case I2C_SMBUS_WORD_DATA:
737 status = i2c_smbus_read_word_data(fd, data_addr);
738 break;
739 default: /* I2C_SMBUS_BYTE_DATA */
740 status = i2c_smbus_read_byte_data(fd, data_addr);
741 }
742
743 if (status < 0) {
Denys Vlasenkod60752f2015-10-07 22:42:45 +0200744 puts("Warning - readback failed");
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100745 } else
746 if (status != val) {
747 printf("Warning - data mismatch - wrote "
748 "0x%0*x, read back 0x%0*x\n",
749 mode == I2C_SMBUS_WORD_DATA ? 4 : 2, val,
750 mode == I2C_SMBUS_WORD_DATA ? 4 : 2, status);
751 } else {
752 printf("Value 0x%0*x written, readback matched\n",
753 mode == I2C_SMBUS_WORD_DATA ? 4 : 2, val);
754 }
755
756 return 0;
757}
758#endif /* ENABLE_I2CSET */
759
760#if ENABLE_I2CDUMP
Bartosz Golaszewskiaeb11a92015-06-05 10:27:31 +0200761static int read_block_data(int buf_fd, int mode, int *block)
762{
Bartosz Golaszewski2beb5242015-09-04 10:38:48 +0200763 uint8_t cblock[I2C_SMBUS_BLOCK_MAX + I2CDUMP_NUM_REGS];
Bartosz Golaszewskiaeb11a92015-06-05 10:27:31 +0200764 int res, blen = 0, tmp, i;
765
Bartosz Golaszewski1fe75b82015-10-27 17:15:03 +0100766 if (mode == I2C_SMBUS_BLOCK_DATA) {
Bartosz Golaszewski74bb9d52015-10-27 17:15:04 +0100767 blen = i2c_smbus_read_block_data(buf_fd, 0, cblock);
768 if (blen <= 0)
769 goto fail;
Bartosz Golaszewskiaeb11a92015-06-05 10:27:31 +0200770 } else {
Bartosz Golaszewski2beb5242015-09-04 10:38:48 +0200771 for (res = 0; res < I2CDUMP_NUM_REGS; res += tmp) {
Bartosz Golaszewskiaeb11a92015-06-05 10:27:31 +0200772 tmp = i2c_smbus_read_i2c_block_data(
773 buf_fd, res, I2C_SMBUS_BLOCK_MAX,
774 cblock + res);
Bartosz Golaszewski5ed69892015-10-27 17:15:05 +0100775 if (tmp <= 0) {
776 blen = tmp;
Bartosz Golaszewski74bb9d52015-10-27 17:15:04 +0100777 goto fail;
Bartosz Golaszewski5ed69892015-10-27 17:15:05 +0100778 }
Bartosz Golaszewskiaeb11a92015-06-05 10:27:31 +0200779 }
780
Bartosz Golaszewski2beb5242015-09-04 10:38:48 +0200781 if (res >= I2CDUMP_NUM_REGS)
782 res = I2CDUMP_NUM_REGS;
Bartosz Golaszewskiaeb11a92015-06-05 10:27:31 +0200783
784 for (i = 0; i < res; i++)
785 block[i] = cblock[i];
786
787 if (mode != I2C_SMBUS_BLOCK_DATA)
Bartosz Golaszewski2beb5242015-09-04 10:38:48 +0200788 for (i = res; i < I2CDUMP_NUM_REGS; i++)
Bartosz Golaszewskiaeb11a92015-06-05 10:27:31 +0200789 block[i] = -1;
790 }
791
792 return blen;
Bartosz Golaszewski74bb9d52015-10-27 17:15:04 +0100793
794 fail:
Bartosz Golaszewski5ed69892015-10-27 17:15:05 +0100795 bb_error_msg_and_die("block read failed: %d", blen);
Bartosz Golaszewskiaeb11a92015-06-05 10:27:31 +0200796}
797
798/* Dump all but word data. */
799static void dump_data(int bus_fd, int mode, unsigned first,
800 unsigned last, int *block, int blen)
801{
802 int i, j, res;
803
Denys Vlasenkod60752f2015-10-07 22:42:45 +0200804 puts(" 0 1 2 3 4 5 6 7 8 9 a b c d e f"
805 " 0123456789abcdef");
Bartosz Golaszewskiaeb11a92015-06-05 10:27:31 +0200806
Bartosz Golaszewski2beb5242015-09-04 10:38:48 +0200807 for (i = 0; i < I2CDUMP_NUM_REGS; i += 0x10) {
Bartosz Golaszewskiaeb11a92015-06-05 10:27:31 +0200808 if (mode == I2C_SMBUS_BLOCK_DATA && i >= blen)
809 break;
810 if (i/16 < first/16)
811 continue;
812 if (i/16 > last/16)
813 break;
814
815 printf("%02x: ", i);
816 for (j = 0; j < 16; j++) {
817 fflush_all();
818 /* Skip unwanted registers */
819 if (i+j < first || i+j > last) {
820 printf(" ");
821 if (mode == I2C_SMBUS_WORD_DATA) {
822 printf(" ");
823 j++;
824 }
825 continue;
826 }
827
828 switch (mode) {
829 case I2C_SMBUS_BYTE_DATA:
830 res = i2c_smbus_read_byte_data(bus_fd, i+j);
831 block[i+j] = res;
832 break;
833 case I2C_SMBUS_WORD_DATA:
834 res = i2c_smbus_read_word_data(bus_fd, i+j);
835 if (res < 0) {
836 block[i+j] = res;
837 block[i+j+1] = res;
838 } else {
839 block[i+j] = res & 0xff;
840 block[i+j+1] = res >> 8;
841 }
842 break;
843 case I2C_SMBUS_BYTE:
844 res = i2c_smbus_read_byte(bus_fd);
845 block[i+j] = res;
846 break;
847 default:
848 res = block[i+j];
849 }
850
851 if (mode == I2C_SMBUS_BLOCK_DATA &&
852 i+j >= blen) {
853 printf(" ");
854 } else if (res < 0) {
855 printf("XX ");
856 if (mode == I2C_SMBUS_WORD_DATA)
857 printf("XX ");
858 } else {
859 printf("%02x ", block[i+j]);
860 if (mode == I2C_SMBUS_WORD_DATA)
861 printf("%02x ", block[i+j+1]);
862 }
863
864 if (mode == I2C_SMBUS_WORD_DATA)
865 j++;
866 }
867 printf(" ");
868
869 for (j = 0; j < 16; j++) {
870 if (mode == I2C_SMBUS_BLOCK_DATA && i+j >= blen)
871 break;
872 /* Skip unwanted registers */
873 if (i+j < first || i+j > last) {
Denys Vlasenkod60752f2015-10-07 22:42:45 +0200874 bb_putchar(' ');
Bartosz Golaszewskiaeb11a92015-06-05 10:27:31 +0200875 continue;
876 }
877
878 res = block[i+j];
879 if (res < 0) {
Denys Vlasenkod60752f2015-10-07 22:42:45 +0200880 bb_putchar('X');
Bartosz Golaszewskiaeb11a92015-06-05 10:27:31 +0200881 } else if (res == 0x00 || res == 0xff) {
Denys Vlasenkod60752f2015-10-07 22:42:45 +0200882 bb_putchar('.');
Bartosz Golaszewskiaeb11a92015-06-05 10:27:31 +0200883 } else if (res < 32 || res >= 127) {
Denys Vlasenkod60752f2015-10-07 22:42:45 +0200884 bb_putchar('?');
Bartosz Golaszewskiaeb11a92015-06-05 10:27:31 +0200885 } else {
Denys Vlasenkod60752f2015-10-07 22:42:45 +0200886 bb_putchar(res);
Bartosz Golaszewskiaeb11a92015-06-05 10:27:31 +0200887 }
888 }
Denys Vlasenkod60752f2015-10-07 22:42:45 +0200889 bb_putchar('\n');
Bartosz Golaszewskiaeb11a92015-06-05 10:27:31 +0200890 }
891}
892
893static void dump_word_data(int bus_fd, unsigned first, unsigned last)
894{
895 int i, j, rv;
896
897 /* Word data. */
Denys Vlasenkod60752f2015-10-07 22:42:45 +0200898 puts(" 0,8 1,9 2,a 3,b 4,c 5,d 6,e 7,f");
Bartosz Golaszewskiaeb11a92015-06-05 10:27:31 +0200899 for (i = 0; i < 256; i += 8) {
900 if (i/8 < first/8)
901 continue;
902 if (i/8 > last/8)
903 break;
904
905 printf("%02x: ", i);
906 for (j = 0; j < 8; j++) {
907 /* Skip unwanted registers. */
908 if (i+j < first || i+j > last) {
909 printf(" ");
910 continue;
911 }
912
913 rv = i2c_smbus_read_word_data(bus_fd, i+j);
914 if (rv < 0)
915 printf("XXXX ");
916 else
917 printf("%04x ", rv & 0xffff);
918 }
Denys Vlasenkod60752f2015-10-07 22:42:45 +0200919 bb_putchar('\n');
Bartosz Golaszewskiaeb11a92015-06-05 10:27:31 +0200920 }
921}
922
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100923//usage:#define i2cdump_trivial_usage
Denys Vlasenkof27e1502017-08-29 15:44:01 +0200924//usage: "[-fy] [-r FIRST-LAST] BUS ADDR [MODE]"
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100925//usage:#define i2cdump_full_usage "\n\n"
Denys Vlasenkof27e1502017-08-29 15:44:01 +0200926//usage: "Examine I2C registers"
927//usage: "\n"
928//usage: "\n I2CBUS I2C bus number"
929//usage: "\n ADDRESS 0x03-0x77"
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100930//usage: "\nMODE is:"
Denys Vlasenkof27e1502017-08-29 15:44:01 +0200931//usage: "\n b Byte (default)"
932//usage: "\n w Word"
933//usage: "\n W Word on even register addresses"
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100934//usage: "\n i I2C block"
935//usage: "\n s SMBus block"
Denys Vlasenkof27e1502017-08-29 15:44:01 +0200936//usage: "\n c Consecutive byte"
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100937//usage: "\n Append p for SMBus PEC"
938//usage: "\n"
Denys Vlasenkof27e1502017-08-29 15:44:01 +0200939//usage: "\n -f Force access"
940//usage: "\n -y Disable interactive mode"
941//usage: "\n -r Limit the number of registers being accessed"
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100942int i2cdump_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
943int i2cdump_main(int argc UNUSED_PARAM, char **argv)
944{
945 const unsigned opt_f = (1 << 0), opt_y = (1 << 1),
946 opt_r = (1 << 2);
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100947
948 int bus_num, bus_addr, mode = I2C_SMBUS_BYTE_DATA, even = 0, pec = 0;
Bartosz Golaszewskiaeb11a92015-06-05 10:27:31 +0200949 unsigned first = 0x00, last = 0xff, opts;
Bartosz Golaszewski59f81972016-06-23 17:19:50 +0200950 int block[I2CDUMP_NUM_REGS];
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100951 char *opt_r_str, *dash;
Denys Vlasenko2cf45912015-11-01 20:57:34 +0100952 int fd, res;
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100953
Denys Vlasenko22542ec2017-08-08 21:55:02 +0200954 opts = getopt32(argv, "^"
955 "fyr:"
956 "\0" "-2:?3" /* from 2 to 3 args */,
957 &opt_r_str
958 );
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100959 argv += optind;
960
961 bus_num = i2c_bus_lookup(argv[0]);
962 bus_addr = i2c_parse_bus_addr(argv[1]);
963
964 if (argv[2]) {
965 switch (argv[2][0]) {
Bartosz Golaszewskiaeb11a92015-06-05 10:27:31 +0200966 case 'b': /* Already set. */ break;
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100967 case 'c': mode = I2C_SMBUS_BYTE; break;
968 case 'w': mode = I2C_SMBUS_WORD_DATA; break;
969 case 'W':
970 mode = I2C_SMBUS_WORD_DATA;
971 even = 1;
972 break;
973 case 's': mode = I2C_SMBUS_BLOCK_DATA; break;
974 case 'i': mode = I2C_SMBUS_I2C_BLOCK_DATA; break;
975 default:
James Byrne69374872019-07-02 11:35:03 +0200976 bb_simple_error_msg_and_die("invalid mode");
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100977 }
978
979 if (argv[2][1] == 'p') {
980 if (argv[2][0] == 'W' || argv[2][0] == 'i') {
James Byrne69374872019-07-02 11:35:03 +0200981 bb_simple_error_msg_and_die(
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100982 "pec not supported for -W and -i");
983 } else {
984 pec = 1;
985 }
986 }
987 }
988
989 if (opts & opt_r) {
990 first = strtol(opt_r_str, &dash, 0);
991 if (dash == opt_r_str || *dash != '-' || first > 0xff)
James Byrne69374872019-07-02 11:35:03 +0200992 bb_simple_error_msg_and_die("invalid range");
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100993 last = xstrtou_range(++dash, 0, first, 0xff);
994
Bartosz Golaszewskiaeb11a92015-06-05 10:27:31 +0200995 /* Range is not available for every mode. */
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100996 switch (mode) {
997 case I2C_SMBUS_BYTE:
998 case I2C_SMBUS_BYTE_DATA:
999 break;
1000 case I2C_SMBUS_WORD_DATA:
1001 if (!even || (!(first % 2) && last % 2))
1002 break;
1003 /* Fall through */
1004 default:
James Byrne69374872019-07-02 11:35:03 +02001005 bb_simple_error_msg_and_die(
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001006 "range not compatible with selected mode");
1007 }
1008 }
1009
1010 fd = i2c_dev_open(bus_num);
1011 check_read_funcs(fd, mode, -1 /* data_addr */, pec);
1012 i2c_set_slave_addr(fd, bus_addr, opts & opt_f);
1013
1014 if (pec)
1015 i2c_set_pec(fd, 1);
1016
1017 if (!(opts & opt_y))
1018 confirm_action(bus_addr, mode, -1 /* data_addr */, pec);
1019
Bartosz Golaszewskiaeb11a92015-06-05 10:27:31 +02001020 /* All but word data. */
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001021 if (mode != I2C_SMBUS_WORD_DATA || even) {
Denys Vlasenko2cf45912015-11-01 20:57:34 +01001022 int blen = 0;
1023
Bartosz Golaszewski1cde5f72015-10-27 17:15:02 +01001024 if (mode == I2C_SMBUS_BLOCK_DATA || mode == I2C_SMBUS_I2C_BLOCK_DATA)
1025 blen = read_block_data(fd, mode, block);
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001026
1027 if (mode == I2C_SMBUS_BYTE) {
1028 res = i2c_smbus_write_byte(fd, first);
1029 if (res < 0)
James Byrne69374872019-07-02 11:35:03 +02001030 bb_simple_perror_msg_and_die("write start address");
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001031 }
1032
Bartosz Golaszewskiaeb11a92015-06-05 10:27:31 +02001033 dump_data(fd, mode, first, last, block, blen);
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001034 } else {
Bartosz Golaszewskiaeb11a92015-06-05 10:27:31 +02001035 dump_word_data(fd, first, last);
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001036 }
1037
1038 return 0;
1039}
1040#endif /* ENABLE_I2CDUMP */
1041
1042#if ENABLE_I2CDETECT
1043enum adapter_type {
1044 ADT_DUMMY = 0,
1045 ADT_ISA,
1046 ADT_I2C,
1047 ADT_SMBUS,
1048};
1049
1050struct adap_desc {
1051 const char *funcs;
1052 const char *algo;
1053};
1054
1055static const struct adap_desc adap_descs[] = {
1056 { .funcs = "dummy",
1057 .algo = "Dummy bus", },
1058 { .funcs = "isa",
1059 .algo = "ISA bus", },
1060 { .funcs = "i2c",
1061 .algo = "I2C adapter", },
1062 { .funcs = "smbus",
1063 .algo = "SMBus adapter", },
1064};
1065
1066struct i2c_func
1067{
1068 long value;
1069 const char* name;
1070};
1071
1072static const struct i2c_func i2c_funcs_tab[] = {
1073 { .value = I2C_FUNC_I2C,
1074 .name = "I2C" },
1075 { .value = I2C_FUNC_SMBUS_QUICK,
Denys Vlasenko7f3a2a22015-10-08 11:24:44 +02001076 .name = "SMBus quick command" },
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001077 { .value = I2C_FUNC_SMBUS_WRITE_BYTE,
Denys Vlasenko7f3a2a22015-10-08 11:24:44 +02001078 .name = "SMBus send byte" },
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001079 { .value = I2C_FUNC_SMBUS_READ_BYTE,
Denys Vlasenko7f3a2a22015-10-08 11:24:44 +02001080 .name = "SMBus receive byte" },
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001081 { .value = I2C_FUNC_SMBUS_WRITE_BYTE_DATA,
Denys Vlasenko7f3a2a22015-10-08 11:24:44 +02001082 .name = "SMBus write byte" },
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001083 { .value = I2C_FUNC_SMBUS_READ_BYTE_DATA,
Denys Vlasenko7f3a2a22015-10-08 11:24:44 +02001084 .name = "SMBus read byte" },
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001085 { .value = I2C_FUNC_SMBUS_WRITE_WORD_DATA,
Denys Vlasenko7f3a2a22015-10-08 11:24:44 +02001086 .name = "SMBus write word" },
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001087 { .value = I2C_FUNC_SMBUS_READ_WORD_DATA,
Denys Vlasenko7f3a2a22015-10-08 11:24:44 +02001088 .name = "SMBus read word" },
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001089 { .value = I2C_FUNC_SMBUS_PROC_CALL,
Denys Vlasenko7f3a2a22015-10-08 11:24:44 +02001090 .name = "SMBus process call" },
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001091 { .value = I2C_FUNC_SMBUS_WRITE_BLOCK_DATA,
Denys Vlasenko7f3a2a22015-10-08 11:24:44 +02001092 .name = "SMBus block write" },
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001093 { .value = I2C_FUNC_SMBUS_READ_BLOCK_DATA,
Denys Vlasenko7f3a2a22015-10-08 11:24:44 +02001094 .name = "SMBus block read" },
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001095 { .value = I2C_FUNC_SMBUS_BLOCK_PROC_CALL,
Denys Vlasenko7f3a2a22015-10-08 11:24:44 +02001096 .name = "SMBus block process call" },
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001097 { .value = I2C_FUNC_SMBUS_PEC,
1098 .name = "SMBus PEC" },
1099 { .value = I2C_FUNC_SMBUS_WRITE_I2C_BLOCK,
Denys Vlasenko7f3a2a22015-10-08 11:24:44 +02001100 .name = "I2C block write" },
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001101 { .value = I2C_FUNC_SMBUS_READ_I2C_BLOCK,
Denys Vlasenko7f3a2a22015-10-08 11:24:44 +02001102 .name = "I2C block read" },
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001103 { .value = 0, .name = NULL }
1104};
1105
1106static enum adapter_type i2cdetect_get_funcs(int bus)
1107{
1108 enum adapter_type ret;
1109 unsigned long funcs;
1110 int fd;
1111
1112 fd = i2c_dev_open(bus);
1113
1114 get_funcs_matrix(fd, &funcs);
1115 if (funcs & I2C_FUNC_I2C)
1116 ret = ADT_I2C;
1117 else if (funcs & (I2C_FUNC_SMBUS_BYTE |
1118 I2C_FUNC_SMBUS_BYTE_DATA |
1119 I2C_FUNC_SMBUS_WORD_DATA))
1120 ret = ADT_SMBUS;
1121 else
1122 ret = ADT_DUMMY;
1123
1124 close(fd);
1125
1126 return ret;
1127}
1128
1129static void NORETURN list_i2c_busses_and_exit(void)
1130{
1131 const char *const i2cdev_path = "/sys/class/i2c-dev";
1132
1133 char path[NAME_MAX], name[128];
1134 struct dirent *de, *subde;
1135 enum adapter_type adt;
1136 DIR *dir, *subdir;
1137 int rv, bus;
1138 char *pos;
1139 FILE *fp;
1140
1141 /*
1142 * XXX Upstream i2cdetect also looks for i2c bus info in /proc/bus/i2c,
1143 * but we won't bother since it's only useful on older kernels (before
1144 * 2.6.5). We expect sysfs to be present and mounted at /sys/.
1145 */
1146
1147 dir = xopendir(i2cdev_path);
1148 while ((de = readdir(dir))) {
1149 if (de->d_name[0] == '.')
1150 continue;
1151
1152 /* Simple version for ISA chips. */
1153 snprintf(path, NAME_MAX, "%s/%s/name",
1154 i2cdev_path, de->d_name);
1155 fp = fopen(path, "r");
1156 if (fp == NULL) {
1157 snprintf(path, NAME_MAX,
1158 "%s/%s/device/name",
1159 i2cdev_path, de->d_name);
1160 fp = fopen(path, "r");
1161 }
1162
1163 /* Non-ISA chips require the hard-way. */
1164 if (fp == NULL) {
1165 snprintf(path, NAME_MAX,
1166 "%s/%s/device/name",
1167 i2cdev_path, de->d_name);
1168 subdir = opendir(path);
1169 if (subdir == NULL)
1170 continue;
1171
1172 while ((subde = readdir(subdir))) {
1173 if (subde->d_name[0] == '.')
1174 continue;
1175
Denys Vlasenko8dff01d2015-03-12 17:48:34 +01001176 if (is_prefixed_with(subde->d_name, "i2c-")) {
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001177 snprintf(path, NAME_MAX,
1178 "%s/%s/device/%s/name",
1179 i2cdev_path, de->d_name,
1180 subde->d_name);
1181 fp = fopen(path, "r");
Bartosz Golaszewskid9089922015-06-05 10:27:32 +02001182 break;
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001183 }
1184 }
1185 }
1186
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001187 if (fp != NULL) {
1188 /*
1189 * Get the rest of the info and display a line
1190 * for a single bus.
1191 */
1192 memset(name, 0, sizeof(name));
1193 pos = fgets(name, sizeof(name), fp);
1194 fclose(fp);
1195 if (pos == NULL)
1196 continue;
1197
1198 pos = strchr(name, '\n');
1199 if (pos != NULL)
1200 *pos = '\0';
1201
1202 rv = sscanf(de->d_name, "i2c-%d", &bus);
1203 if (rv != 1)
1204 continue;
1205
Denys Vlasenko8dff01d2015-03-12 17:48:34 +01001206 if (is_prefixed_with(name, "ISA"))
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001207 adt = ADT_ISA;
1208 else
1209 adt = i2cdetect_get_funcs(bus);
1210
1211 printf(
1212 "i2c-%d\t%-10s\t%-32s\t%s\n",
1213 bus, adap_descs[adt].funcs,
1214 name, adap_descs[adt].algo);
1215 }
1216 }
1217
1218 exit(EXIT_SUCCESS);
1219}
1220
1221static void NORETURN no_support(const char *cmd)
1222{
1223 bb_error_msg_and_die("bus doesn't support %s", cmd);
1224}
1225
1226static void will_skip(const char *cmd)
1227{
1228 bb_error_msg(
1229 "warning: can't use %s command, "
1230 "will skip some addresses", cmd);
1231}
1232
1233//usage:#define i2cdetect_trivial_usage
Bartosz Golaszewski0d1eaf42017-08-29 12:31:22 +02001234//usage: "-l | -F I2CBUS | [-ya] [-q|-r] I2CBUS [FIRST LAST]"
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001235//usage:#define i2cdetect_full_usage "\n\n"
Bartosz Golaszewski0d1eaf42017-08-29 12:31:22 +02001236//usage: "Detect I2C chips"
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001237//usage: "\n"
Denys Vlasenkof27e1502017-08-29 15:44:01 +02001238//usage: "\n -l List installed buses"
1239//usage: "\n -F BUS# List functionalities on this bus"
Bartosz Golaszewski0d1eaf42017-08-29 12:31:22 +02001240//usage: "\n -y Disable interactive mode"
1241//usage: "\n -a Force scanning of non-regular addresses"
1242//usage: "\n -q Use smbus quick write commands for probing (default)"
1243//usage: "\n -r Use smbus read byte commands for probing"
1244//usage: "\n FIRST and LAST limit probing range"
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001245int i2cdetect_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
1246int i2cdetect_main(int argc UNUSED_PARAM, char **argv)
1247{
1248 const unsigned opt_y = (1 << 0), opt_a = (1 << 1),
1249 opt_q = (1 << 2), opt_r = (1 << 3),
1250 opt_F = (1 << 4), opt_l = (1 << 5);
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001251
Bartosz Golaszewski99f025a2015-10-27 17:15:00 +01001252 int fd, bus_num, i, j, mode = I2CDETECT_MODE_AUTO, status, cmd;
Bartosz Golaszewskie545bf62015-06-05 10:27:29 +02001253 unsigned first = 0x03, last = 0x77, opts;
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001254 unsigned long funcs;
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001255
Denys Vlasenko22542ec2017-08-08 21:55:02 +02001256 opts = getopt32(argv, "^"
1257 "yaqrFl"
1258 "\0"
Bartosz Golaszewski0d1eaf42017-08-29 12:31:22 +02001259 "q--r:r--q:"/*mutually exclusive*/
1260 "?3"/*up to 3 args*/
Denys Vlasenko22542ec2017-08-08 21:55:02 +02001261 );
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001262 argv += optind;
1263
1264 if (opts & opt_l)
1265 list_i2c_busses_and_exit();
1266
Bartosz Golaszewskib2cca322015-05-11 17:22:10 +02001267 if (!argv[0])
1268 bb_show_usage();
1269
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001270 bus_num = i2c_bus_lookup(argv[0]);
1271 fd = i2c_dev_open(bus_num);
1272 get_funcs_matrix(fd, &funcs);
1273
1274 if (opts & opt_F) {
1275 /* Only list the functionalities. */
1276 printf("Functionalities implemented by bus #%d\n", bus_num);
1277 for (i = 0; i2c_funcs_tab[i].value; i++) {
1278 printf("%-32s %s\n", i2c_funcs_tab[i].name,
1279 funcs & i2c_funcs_tab[i].value ? "yes" : "no");
1280 }
1281
1282 return EXIT_SUCCESS;
1283 }
1284
1285 if (opts & opt_r)
Bartosz Golaszewski2beb5242015-09-04 10:38:48 +02001286 mode = I2CDETECT_MODE_READ;
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001287 else if (opts & opt_q)
Bartosz Golaszewski2beb5242015-09-04 10:38:48 +02001288 mode = I2CDETECT_MODE_QUICK;
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001289
Bartosz Golaszewskie545bf62015-06-05 10:27:29 +02001290 if (opts & opt_a) {
1291 first = 0x00;
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001292 last = 0x7f;
Bartosz Golaszewskie545bf62015-06-05 10:27:29 +02001293 }
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001294
1295 /* Read address range. */
1296 if (argv[1]) {
1297 first = xstrtou_range(argv[1], 16, first, last);
1298 if (argv[2])
1299 last = xstrtou_range(argv[2], 16, first, last);
1300 }
1301
1302 if (!(funcs & (I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_READ_BYTE))) {
1303 no_support("detection commands");
1304 } else
Bartosz Golaszewski2beb5242015-09-04 10:38:48 +02001305 if (mode == I2CDETECT_MODE_QUICK && !(funcs & I2C_FUNC_SMBUS_QUICK)) {
Denys Vlasenko7f3a2a22015-10-08 11:24:44 +02001306 no_support("SMBus quick write");
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001307 } else
Bartosz Golaszewski2beb5242015-09-04 10:38:48 +02001308 if (mode == I2CDETECT_MODE_READ && !(funcs & I2C_FUNC_SMBUS_READ_BYTE)) {
Denys Vlasenko7f3a2a22015-10-08 11:24:44 +02001309 no_support("SMBus receive byte");
Bartosz Golaszewski22044722015-06-05 10:27:30 +02001310 }
1311
Bartosz Golaszewski2beb5242015-09-04 10:38:48 +02001312 if (mode == I2CDETECT_MODE_AUTO) {
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001313 if (!(funcs & I2C_FUNC_SMBUS_QUICK))
Denys Vlasenko7f3a2a22015-10-08 11:24:44 +02001314 will_skip("SMBus quick write");
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001315 if (!(funcs & I2C_FUNC_SMBUS_READ_BYTE))
Denys Vlasenko7f3a2a22015-10-08 11:24:44 +02001316 will_skip("SMBus receive byte");
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001317 }
1318
1319 if (!(opts & opt_y))
1320 confirm_action(-1, -1, -1, 0);
1321
Denys Vlasenkod60752f2015-10-07 22:42:45 +02001322 puts(" 0 1 2 3 4 5 6 7 8 9 a b c d e f");
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001323 for (i = 0; i < 128; i += 16) {
1324 printf("%02x: ", i);
Bartosz Golaszewskifc8eb052015-10-27 17:15:01 +01001325 for (j = 0; j < 16; j++) {
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001326 fflush_all();
1327
Bartosz Golaszewski99f025a2015-10-27 17:15:00 +01001328 cmd = mode;
Bartosz Golaszewski2beb5242015-09-04 10:38:48 +02001329 if (mode == I2CDETECT_MODE_AUTO) {
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001330 if ((i+j >= 0x30 && i+j <= 0x37) ||
1331 (i+j >= 0x50 && i+j <= 0x5F))
Bartosz Golaszewski99f025a2015-10-27 17:15:00 +01001332 cmd = I2CDETECT_MODE_READ;
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001333 else
Bartosz Golaszewski99f025a2015-10-27 17:15:00 +01001334 cmd = I2CDETECT_MODE_QUICK;
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001335 }
1336
1337 /* Skip unwanted addresses. */
1338 if (i+j < first
1339 || i+j > last
Bartosz Golaszewski99f025a2015-10-27 17:15:00 +01001340 || (cmd == I2CDETECT_MODE_READ && !(funcs & I2C_FUNC_SMBUS_READ_BYTE))
1341 || (cmd == I2CDETECT_MODE_QUICK && !(funcs & I2C_FUNC_SMBUS_QUICK)))
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001342 {
1343 printf(" ");
1344 continue;
1345 }
1346
Bartosz Golaszewski31474272015-06-05 10:27:28 +02001347 status = ioctl(fd, I2C_SLAVE, itoptr(i + j));
1348 if (status < 0) {
1349 if (errno == EBUSY) {
1350 printf("UU ");
1351 continue;
1352 }
1353
1354 bb_perror_msg_and_die(
1355 "can't set address to 0x%02x", i + j);
1356 }
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001357
Bartosz Golaszewski99f025a2015-10-27 17:15:00 +01001358 switch (cmd) {
Bartosz Golaszewski2beb5242015-09-04 10:38:48 +02001359 case I2CDETECT_MODE_READ:
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001360 /*
1361 * This is known to lock SMBus on various
1362 * write-only chips (mainly clock chips).
1363 */
1364 status = i2c_smbus_read_byte(fd);
1365 break;
Bartosz Golaszewski2beb5242015-09-04 10:38:48 +02001366 default: /* I2CDETECT_MODE_QUICK: */
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001367 /*
1368 * This is known to corrupt the Atmel
1369 * AT24RF08 EEPROM.
1370 */
1371 status = i2c_smbus_write_quick(fd,
1372 I2C_SMBUS_WRITE);
1373 break;
1374 }
1375
1376 if (status < 0)
1377 printf("-- ");
1378 else
1379 printf("%02x ", i+j);
1380 }
Denys Vlasenkod60752f2015-10-07 22:42:45 +02001381 bb_putchar('\n');
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001382 }
1383
1384 return 0;
1385}
1386#endif /* ENABLE_I2CDETECT */
Nikolaus Vossdac8f5e2019-02-10 19:56:41 +01001387
1388#if ENABLE_I2CTRANSFER
1389static void check_i2c_func(int fd)
1390{
1391 unsigned long funcs;
1392
1393 get_funcs_matrix(fd, &funcs);
1394
1395 if (!(funcs & I2C_FUNC_I2C))
James Byrne69374872019-07-02 11:35:03 +02001396 bb_simple_error_msg_and_die("adapter does not support I2C transfers");
Nikolaus Vossdac8f5e2019-02-10 19:56:41 +01001397}
1398
1399//usage:#define i2ctransfer_trivial_usage
1400//usage: "[-fay] I2CBUS {rLENGTH[@ADDR] | wLENGTH[@ADDR] DATA...}..."
1401//usage:#define i2ctransfer_full_usage "\n\n"
1402//usage: "Read/write I2C data in one transfer"
1403//usage: "\n"
Nikolaus Vossf81e0122019-02-11 11:30:52 +01001404//usage: "\n -f Force access to busy addresses"
1405//usage: "\n -a Force access to non-regular addresses"
Nikolaus Vossdac8f5e2019-02-10 19:56:41 +01001406//usage: "\n -y Disable interactive mode"
1407int i2ctransfer_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
1408int i2ctransfer_main(int argc UNUSED_PARAM, char **argv)
1409{
1410 enum {
1411 opt_f = (1 << 0),
1412 opt_y = (1 << 1),
1413 opt_a = (1 << 2),
1414 };
1415 int bus_num, bus_addr;
1416 int fd;
1417 unsigned opts, first, last;
1418 int nmsgs, nmsgs_sent, i;
1419 struct i2c_msg msgs[I2C_RDWR_IOCTL_MAX_MSGS];
1420 struct i2c_rdwr_ioctl_data rdwr;
1421
1422 memset(msgs, 0, sizeof(msgs));
1423
1424 opts = getopt32(argv, "^"
1425 "fya"
1426 "\0" "-2" /* minimum 2 args */
1427 );
1428 first = 0x03;
1429 last = 0x77;
1430 if (opts & opt_a) {
1431 first = 0x00;
1432 last = 0x7f;
1433 }
1434
1435 argv += optind;
1436 bus_num = i2c_bus_lookup(argv[0]);
1437 fd = i2c_dev_open(bus_num);
1438 check_i2c_func(fd);
1439
1440 bus_addr = -1;
1441 nmsgs = 0;
1442 while (*++argv) {
1443 char *arg_ptr;
1444 unsigned len;
1445 uint16_t flags;
1446 char *end;
1447
1448 if (nmsgs >= I2C_RDWR_IOCTL_MAX_MSGS)
James Byrne69374872019-07-02 11:35:03 +02001449 bb_simple_error_msg_and_die("too many messages, max: "I2C_RDWR_IOCTL_MAX_MSGS_STR);
Nikolaus Vossdac8f5e2019-02-10 19:56:41 +01001450
1451 flags = 0;
1452 arg_ptr = *argv;
1453 switch (*arg_ptr++) {
1454 case 'r': flags |= I2C_M_RD; break;
1455 case 'w': break;
1456 default:
1457 bb_show_usage();
1458 }
1459
1460 end = strchr(arg_ptr, '@');
1461 if (end) *end = '\0';
1462 len = xstrtou_range(arg_ptr, 0, 0, 0xffff);
1463 if (end) {
1464 bus_addr = xstrtou_range(end + 1, 0, first, last);
Nikolaus Vossf81e0122019-02-11 11:30:52 +01001465 i2c_set_slave_addr(fd, bus_addr, (opts & opt_f));
Nikolaus Vossdac8f5e2019-02-10 19:56:41 +01001466 } else {
1467 /* Reuse last address if possible */
1468 if (bus_addr < 0)
1469 bb_error_msg_and_die("no address given in '%s'", *argv);
1470 }
1471
1472 msgs[nmsgs].addr = bus_addr;
1473 msgs[nmsgs].flags = flags;
1474 msgs[nmsgs].len = len;
1475 if (len)
1476 msgs[nmsgs].buf = xzalloc(len);
1477
1478 if (!(flags & I2C_M_RD)) {
1479 /* Consume DATA arg(s) */
1480 unsigned buf_idx = 0;
1481
1482 while (buf_idx < len) {
1483 uint8_t data8;
1484 unsigned long data;
1485
1486 arg_ptr = *++argv;
1487 if (!arg_ptr)
1488 bb_show_usage();
1489 data = strtoul(arg_ptr, &end, 0);
1490 if (data > 0xff || arg_ptr == end)
1491 bb_error_msg_and_die("invalid data byte '%s'", *argv);
1492
1493 data8 = data;
1494 while (buf_idx < len) {
1495 msgs[nmsgs].buf[buf_idx++] = data8;
1496 if (!*end)
1497 break;
1498 switch (*end) {
1499 /* Pseudo randomness (8 bit AXR with a=13 and b=27) */
1500 case 'p':
1501 data8 = (data8 ^ 27) + 13;
1502 data8 = (data8 << 1) | (data8 >> 7);
1503 break;
1504 case '+': data8++; break;
1505 case '-': data8--; break;
1506 case '=': break;
1507 default:
1508 bb_error_msg_and_die("invalid data byte suffix: '%s'",
1509 *argv);
1510 }
1511 }
1512 }
1513 }
1514 nmsgs++;
1515 }
1516
1517 if (!(opts & opt_y))
1518 confirm_action(bus_addr, 0, 0, 0);
1519
1520 rdwr.msgs = msgs;
1521 rdwr.nmsgs = nmsgs;
1522 nmsgs_sent = ioctl_or_perror_and_die(fd, I2C_RDWR, &rdwr, "I2C_RDWR");
1523 if (nmsgs_sent < nmsgs)
1524 bb_error_msg("warning: only %u/%u messages sent", nmsgs_sent, nmsgs);
1525
1526 for (i = 0; i < nmsgs_sent; i++) {
1527 if (msgs[i].len != 0 && (msgs[i].flags & I2C_M_RD)) {
1528 int j;
1529 for (j = 0; j < msgs[i].len - 1; j++)
1530 printf("0x%02x ", msgs[i].buf[j]);
1531 /* Print final byte with newline */
1532 printf("0x%02x\n", msgs[i].buf[j]);
1533 }
1534 }
1535
1536# if ENABLE_FEATURE_CLEAN_UP
1537 close(fd);
1538 for (i = 0; i < nmsgs; i++)
1539 free(msgs[i].buf);
1540# endif
1541
1542 return 0;
1543}
1544#endif /* ENABLE_I2CTRANSFER */