blob: 82a559f74a2be2426ebfea1a506d8aaa09bc0a11 [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
14//config: select PLATFORM_LINUX
15//config: help
Denys Vlasenko72089cf2017-07-21 09:50:55 +020016//config: Read from I2C/SMBus chip registers.
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +010017//config:
18//config:config I2CSET
Denys Vlasenkob097a842018-12-28 03:20:17 +010019//config: bool "i2cset (6.7 kb)"
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +010020//config: default y
21//config: select PLATFORM_LINUX
22//config: help
Denys Vlasenko72089cf2017-07-21 09:50:55 +020023//config: Set I2C registers.
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +010024//config:
25//config:config I2CDUMP
Denys Vlasenkob097a842018-12-28 03:20:17 +010026//config: bool "i2cdump (7.1 kb)"
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +010027//config: default y
28//config: select PLATFORM_LINUX
29//config: help
Denys Vlasenko72089cf2017-07-21 09:50:55 +020030//config: Examine I2C registers.
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +010031//config:
32//config:config I2CDETECT
Denys Vlasenkob097a842018-12-28 03:20:17 +010033//config: bool "i2cdetect (7.1 kb)"
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +010034//config: default y
35//config: select PLATFORM_LINUX
36//config: help
Denys Vlasenko72089cf2017-07-21 09:50:55 +020037//config: Detect I2C chips.
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +010038//config:
Nikolaus Vossdac8f5e2019-02-10 19:56:41 +010039//config:config I2CTRANSFER
40//config: bool "i2ctransfer (4.0 kb)"
41//config: default y
42//config: select PLATFORM_LINUX
43//config: help
44//config: Send user-defined I2C messages in one transfer.
45//config:
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +010046
47//applet:IF_I2CGET(APPLET(i2cget, BB_DIR_USR_SBIN, BB_SUID_DROP))
48//applet:IF_I2CSET(APPLET(i2cset, BB_DIR_USR_SBIN, BB_SUID_DROP))
49//applet:IF_I2CDUMP(APPLET(i2cdump, BB_DIR_USR_SBIN, BB_SUID_DROP))
50//applet:IF_I2CDETECT(APPLET(i2cdetect, BB_DIR_USR_SBIN, BB_SUID_DROP))
Nikolaus Vossdac8f5e2019-02-10 19:56:41 +010051//applet:IF_I2CTRANSFER(APPLET(i2ctransfer, BB_DIR_USR_SBIN, BB_SUID_DROP))
Denys Vlasenko1a1203f2017-08-07 16:47:34 +020052/* not NOEXEC: if hw operation stalls, use less memory in "hung" process */
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +010053
54//kbuild:lib-$(CONFIG_I2CGET) += i2c_tools.o
55//kbuild:lib-$(CONFIG_I2CSET) += i2c_tools.o
56//kbuild:lib-$(CONFIG_I2CDUMP) += i2c_tools.o
57//kbuild:lib-$(CONFIG_I2CDETECT) += i2c_tools.o
Nikolaus Vossdac8f5e2019-02-10 19:56:41 +010058//kbuild:lib-$(CONFIG_I2CTRANSFER) += i2c_tools.o
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +010059
60/*
61 * Unsupported stuff:
62 *
63 * - upstream i2c-tools can also look-up i2c busses by name, we only accept
64 * numbers,
65 * - bank and bankreg parameters for i2cdump are not supported because of
66 * their limited usefulness (see i2cdump manual entry for more info),
67 * - i2cdetect doesn't look for bus info in /proc as it does in upstream, but
68 * it shouldn't be a problem in modern kernels.
69 */
70
71#include "libbb.h"
72
Bartosz Golaszewskid9892fa2015-09-04 10:35:22 +020073#include <linux/i2c.h>
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +010074
Bartosz Golaszewski2beb5242015-09-04 10:38:48 +020075#define I2CDUMP_NUM_REGS 256
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +010076
Bartosz Golaszewski2beb5242015-09-04 10:38:48 +020077#define I2CDETECT_MODE_AUTO 0
78#define I2CDETECT_MODE_QUICK 1
79#define I2CDETECT_MODE_READ 2
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +010080
Bartosz Golaszewski0d1eaf42017-08-29 12:31:22 +020081/* linux/i2c-dev.h from i2c-tools overwrites the one from linux uapi
82 * and defines symbols already defined by linux/i2c.h.
83 * Also, it defines a bunch of static inlines which we would rather NOT
84 * inline. What a mess.
85 * We need only these definitions from linux/i2c-dev.h:
86 */
87#define I2C_SLAVE 0x0703
88#define I2C_SLAVE_FORCE 0x0706
89#define I2C_FUNCS 0x0705
90#define I2C_PEC 0x0708
91#define I2C_SMBUS 0x0720
Nikolaus Vossdac8f5e2019-02-10 19:56:41 +010092#define I2C_RDWR 0x0707
93#define I2C_RDWR_IOCTL_MAX_MSGS 42
94#define I2C_RDWR_IOCTL_MAX_MSGS_STR "42"
Bartosz Golaszewski0d1eaf42017-08-29 12:31:22 +020095struct i2c_smbus_ioctl_data {
96 __u8 read_write;
97 __u8 command;
98 __u32 size;
99 union i2c_smbus_data *data;
100};
Nikolaus Vossdac8f5e2019-02-10 19:56:41 +0100101struct i2c_rdwr_ioctl_data {
102 struct i2c_msg *msgs; /* pointers to i2c_msgs */
103 __u32 nmsgs; /* number of i2c_msgs */
104};
Bartosz Golaszewski0d1eaf42017-08-29 12:31:22 +0200105/* end linux/i2c-dev.h */
106
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100107/*
108 * This is needed for ioctl_or_perror_and_die() since it only accepts pointers.
109 */
110static ALWAYS_INLINE void *itoptr(int i)
111{
112 return (void*)(intptr_t)i;
113}
114
115static int32_t i2c_smbus_access(int fd, char read_write, uint8_t cmd,
116 int size, union i2c_smbus_data *data)
117{
118 struct i2c_smbus_ioctl_data args;
119
120 args.read_write = read_write;
121 args.command = cmd;
122 args.size = size;
123 args.data = data;
124
125 return ioctl(fd, I2C_SMBUS, &args);
126}
127
128static int32_t i2c_smbus_read_byte(int fd)
129{
130 union i2c_smbus_data data;
131 int err;
132
133 err = i2c_smbus_access(fd, I2C_SMBUS_READ, 0, I2C_SMBUS_BYTE, &data);
134 if (err < 0)
135 return err;
136
137 return data.byte;
138}
139
140#if ENABLE_I2CGET || ENABLE_I2CSET || ENABLE_I2CDUMP
141static int32_t i2c_smbus_write_byte(int fd, uint8_t val)
142{
143 return i2c_smbus_access(fd, I2C_SMBUS_WRITE,
144 val, I2C_SMBUS_BYTE, NULL);
145}
146
147static int32_t i2c_smbus_read_byte_data(int fd, uint8_t cmd)
148{
149 union i2c_smbus_data data;
150 int err;
151
152 err = i2c_smbus_access(fd, I2C_SMBUS_READ, cmd,
153 I2C_SMBUS_BYTE_DATA, &data);
154 if (err < 0)
155 return err;
156
157 return data.byte;
158}
159
160static int32_t i2c_smbus_read_word_data(int fd, uint8_t cmd)
161{
162 union i2c_smbus_data data;
163 int err;
164
165 err = i2c_smbus_access(fd, I2C_SMBUS_READ, cmd,
166 I2C_SMBUS_WORD_DATA, &data);
167 if (err < 0)
168 return err;
169
170 return data.word;
171}
172#endif /* ENABLE_I2CGET || ENABLE_I2CSET || ENABLE_I2CDUMP */
173
174#if ENABLE_I2CSET
175static int32_t i2c_smbus_write_byte_data(int file,
176 uint8_t cmd, uint8_t value)
177{
178 union i2c_smbus_data data;
179
180 data.byte = value;
181
182 return i2c_smbus_access(file, I2C_SMBUS_WRITE, cmd,
183 I2C_SMBUS_BYTE_DATA, &data);
184}
185
186static int32_t i2c_smbus_write_word_data(int file, uint8_t cmd, uint16_t value)
187{
188 union i2c_smbus_data data;
189
190 data.word = value;
191
192 return i2c_smbus_access(file, I2C_SMBUS_WRITE, cmd,
193 I2C_SMBUS_WORD_DATA, &data);
194}
195
196static int32_t i2c_smbus_write_block_data(int file, uint8_t cmd,
197 uint8_t length, const uint8_t *values)
198{
199 union i2c_smbus_data data;
200
201 if (length > I2C_SMBUS_BLOCK_MAX)
202 length = I2C_SMBUS_BLOCK_MAX;
203
204 memcpy(data.block+1, values, length);
205 data.block[0] = length;
206
207 return i2c_smbus_access(file, I2C_SMBUS_WRITE, cmd,
208 I2C_SMBUS_BLOCK_DATA, &data);
209}
210
211static int32_t i2c_smbus_write_i2c_block_data(int file, uint8_t cmd,
212 uint8_t length, const uint8_t *values)
213{
214 union i2c_smbus_data data;
215
216 if (length > I2C_SMBUS_BLOCK_MAX)
217 length = I2C_SMBUS_BLOCK_MAX;
218
219 memcpy(data.block+1, values, length);
220 data.block[0] = length;
221
222 return i2c_smbus_access(file, I2C_SMBUS_WRITE, cmd,
223 I2C_SMBUS_I2C_BLOCK_BROKEN, &data);
224}
225#endif /* ENABLE_I2CSET */
226
227#if ENABLE_I2CDUMP
228/*
229 * Returns the number of bytes read, vals must hold at
230 * least I2C_SMBUS_BLOCK_MAX bytes.
231 */
232static int32_t i2c_smbus_read_block_data(int fd, uint8_t cmd, uint8_t *vals)
233{
234 union i2c_smbus_data data;
235 int i, err;
236
237 err = i2c_smbus_access(fd, I2C_SMBUS_READ, cmd,
238 I2C_SMBUS_BLOCK_DATA, &data);
239 if (err < 0)
240 return err;
241
242 for (i = 1; i <= data.block[0]; i++)
243 *vals++ = data.block[i];
244 return data.block[0];
245}
246
247static int32_t i2c_smbus_read_i2c_block_data(int fd, uint8_t cmd,
248 uint8_t len, uint8_t *vals)
249{
250 union i2c_smbus_data data;
251 int i, err;
252
253 if (len > I2C_SMBUS_BLOCK_MAX)
254 len = I2C_SMBUS_BLOCK_MAX;
255 data.block[0] = len;
256
257 err = i2c_smbus_access(fd, I2C_SMBUS_READ, cmd,
258 len == 32 ? I2C_SMBUS_I2C_BLOCK_BROKEN :
259 I2C_SMBUS_I2C_BLOCK_DATA, &data);
260 if (err < 0)
261 return err;
262
263 for (i = 1; i <= data.block[0]; i++)
264 *vals++ = data.block[i];
265 return data.block[0];
266}
267#endif /* ENABLE_I2CDUMP */
268
269#if ENABLE_I2CDETECT
270static int32_t i2c_smbus_write_quick(int fd, uint8_t val)
271{
272 return i2c_smbus_access(fd, val, 0, I2C_SMBUS_QUICK, NULL);
273}
274#endif /* ENABLE_I2CDETECT */
275
276static int i2c_bus_lookup(const char *bus_str)
277{
278 return xstrtou_range(bus_str, 10, 0, 0xfffff);
279}
280
Nikolaus Vossdac8f5e2019-02-10 19:56:41 +0100281#if ENABLE_I2CGET || ENABLE_I2CSET || ENABLE_I2CDUMP || ENABLE_I2CTRANSFER
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100282static int i2c_parse_bus_addr(const char *addr_str)
283{
284 /* Slave address must be in range 0x03 - 0x77. */
285 return xstrtou_range(addr_str, 16, 0x03, 0x77);
286}
287
288static void i2c_set_pec(int fd, int pec)
289{
290 ioctl_or_perror_and_die(fd, I2C_PEC,
291 itoptr(pec ? 1 : 0),
292 "can't set PEC");
293}
Bartosz Golaszewski31474272015-06-05 10:27:28 +0200294
295static void i2c_set_slave_addr(int fd, int addr, int force)
296{
297 ioctl_or_perror_and_die(fd, force ? I2C_SLAVE_FORCE : I2C_SLAVE,
298 itoptr(addr),
299 "can't set address to 0x%02x", addr);
300}
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100301#endif /* ENABLE_I2CGET || ENABLE_I2CSET || ENABLE_I2CDUMP */
302
303#if ENABLE_I2CGET || ENABLE_I2CSET
304static int i2c_parse_data_addr(const char *data_addr)
305{
306 /* Data address must be an 8 bit integer. */
307 return xstrtou_range(data_addr, 16, 0, 0xff);
308}
309#endif /* ENABLE_I2CGET || ENABLE_I2CSET */
310
311/*
312 * Opens the device file associated with given i2c bus.
313 *
314 * Upstream i2c-tools also support opening devices by i2c bus name
315 * but we drop it here for size reduction.
316 */
317static int i2c_dev_open(int i2cbus)
318{
319 char filename[sizeof("/dev/i2c-%d") + sizeof(int)*3];
320 int fd;
321
322 sprintf(filename, "/dev/i2c-%d", i2cbus);
323 fd = open(filename, O_RDWR);
324 if (fd < 0) {
Bartosz Golaszewski7ca5c512015-05-11 17:26:27 +0200325 if (errno == ENOENT) {
326 filename[8] = '/'; /* change to "/dev/i2c/%d" */
327 fd = xopen(filename, O_RDWR);
328 } else {
329 bb_perror_msg_and_die("can't open '%s'", filename);
330 }
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100331 }
332
333 return fd;
334}
335
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100336/* Size reducing helpers for xxx_check_funcs(). */
337static void get_funcs_matrix(int fd, unsigned long *funcs)
338{
339 ioctl_or_perror_and_die(fd, I2C_FUNCS, funcs,
340 "can't get adapter functionality matrix");
341}
342
343#if ENABLE_I2CGET || ENABLE_I2CSET || ENABLE_I2CDUMP
344static void check_funcs_test_end(int funcs, int pec, const char *err)
345{
346 if (pec && !(funcs & (I2C_FUNC_SMBUS_PEC | I2C_FUNC_I2C)))
James Byrne69374872019-07-02 11:35:03 +0200347 bb_simple_error_msg("warning: adapter does not support PEC");
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100348
349 if (err)
350 bb_error_msg_and_die(
351 "adapter has no %s capability", err);
352}
353#endif /* ENABLE_I2CGET || ENABLE_I2CSET || ENABLE_I2CDUMP */
354
355/*
356 * The below functions emit an error message and exit if the adapter doesn't
357 * support desired functionalities.
358 */
359#if ENABLE_I2CGET || ENABLE_I2CDUMP
360static void check_read_funcs(int fd, int mode, int data_addr, int pec)
361{
362 unsigned long funcs;
363 const char *err = NULL;
364
365 get_funcs_matrix(fd, &funcs);
366 switch (mode) {
367 case I2C_SMBUS_BYTE:
368 if (!(funcs & I2C_FUNC_SMBUS_READ_BYTE)) {
369 err = "SMBus receive byte";
370 break;
371 }
372 if (data_addr >= 0 && !(funcs & I2C_FUNC_SMBUS_WRITE_BYTE))
373 err = "SMBus send byte";
374 break;
375 case I2C_SMBUS_BYTE_DATA:
376 if (!(funcs & I2C_FUNC_SMBUS_READ_BYTE_DATA))
377 err = "SMBus read byte";
378 break;
379 case I2C_SMBUS_WORD_DATA:
380 if (!(funcs & I2C_FUNC_SMBUS_READ_WORD_DATA))
381 err = "SMBus read word";
382 break;
383#if ENABLE_I2CDUMP
384 case I2C_SMBUS_BLOCK_DATA:
385 if (!(funcs & I2C_FUNC_SMBUS_READ_BLOCK_DATA))
386 err = "SMBus block read";
387 break;
388
389 case I2C_SMBUS_I2C_BLOCK_DATA:
390 if (!(funcs & I2C_FUNC_SMBUS_READ_I2C_BLOCK))
391 err = "I2C block read";
392 break;
393#endif /* ENABLE_I2CDUMP */
394 default:
James Byrne69374872019-07-02 11:35:03 +0200395 bb_simple_error_msg_and_die("internal error");
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100396 }
397 check_funcs_test_end(funcs, pec, err);
398}
399#endif /* ENABLE_I2CGET || ENABLE_I2CDUMP */
400
401#if ENABLE_I2CSET
402static void check_write_funcs(int fd, int mode, int pec)
403{
404 unsigned long funcs;
405 const char *err = NULL;
406
407 get_funcs_matrix(fd, &funcs);
408 switch (mode) {
409 case I2C_SMBUS_BYTE:
410 if (!(funcs & I2C_FUNC_SMBUS_WRITE_BYTE))
411 err = "SMBus send byte";
412 break;
413
414 case I2C_SMBUS_BYTE_DATA:
415 if (!(funcs & I2C_FUNC_SMBUS_WRITE_BYTE_DATA))
416 err = "SMBus write byte";
417 break;
418
419 case I2C_SMBUS_WORD_DATA:
420 if (!(funcs & I2C_FUNC_SMBUS_WRITE_WORD_DATA))
421 err = "SMBus write word";
422 break;
423
424 case I2C_SMBUS_BLOCK_DATA:
425 if (!(funcs & I2C_FUNC_SMBUS_WRITE_BLOCK_DATA))
426 err = "SMBus block write";
427 break;
428 case I2C_SMBUS_I2C_BLOCK_DATA:
429 if (!(funcs & I2C_FUNC_SMBUS_WRITE_I2C_BLOCK))
430 err = "I2C block write";
431 break;
432 }
433 check_funcs_test_end(funcs, pec, err);
434}
435#endif /* ENABLE_I2CSET */
436
437static void confirm_or_abort(void)
438{
439 fprintf(stderr, "Continue? [y/N] ");
Denys Vlasenko77cb6b92018-04-07 15:08:12 +0200440 if (!bb_ask_y_confirmation())
James Byrne69374872019-07-02 11:35:03 +0200441 bb_simple_error_msg_and_die("aborting");
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100442}
443
444/*
445 * Return only if user confirms the action, abort otherwise.
446 *
447 * The messages displayed here are much less elaborate than their i2c-tools
448 * counterparts - this is done for size reduction.
449 */
450static void confirm_action(int bus_addr, int mode, int data_addr, int pec)
451{
James Byrne69374872019-07-02 11:35:03 +0200452 bb_simple_error_msg("WARNING! This program can confuse your I2C bus");
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100453
454 /* Don't let the user break his/her EEPROMs */
455 if (bus_addr >= 0x50 && bus_addr <= 0x57 && pec) {
James Byrne69374872019-07-02 11:35:03 +0200456 bb_simple_error_msg_and_die("this is I2C not smbus - using PEC on I2C "
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100457 "devices may result in data loss, aborting");
458 }
459
460 if (mode == I2C_SMBUS_BYTE && data_addr >= 0 && pec)
James Byrne69374872019-07-02 11:35:03 +0200461 bb_simple_error_msg("WARNING! May interpret a write byte command "
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100462 "with PEC as a write byte data command");
463
464 if (pec)
James Byrne69374872019-07-02 11:35:03 +0200465 bb_simple_error_msg("PEC checking enabled");
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100466
467 confirm_or_abort();
468}
469
470#if ENABLE_I2CGET
471//usage:#define i2cget_trivial_usage
Denys Vlasenkof27e1502017-08-29 15:44:01 +0200472//usage: "[-fy] BUS CHIP-ADDRESS [DATA-ADDRESS [MODE]]"
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100473//usage:#define i2cget_full_usage "\n\n"
Denys Vlasenkof27e1502017-08-29 15:44:01 +0200474//usage: "Read from I2C/SMBus chip registers"
475//usage: "\n"
476//usage: "\n I2CBUS I2C bus number"
477//usage: "\n ADDRESS 0x03-0x77"
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100478//usage: "\nMODE is:"
Denys Vlasenkof27e1502017-08-29 15:44:01 +0200479//usage: "\n b Read byte data (default)"
480//usage: "\n w Read word data"
481//usage: "\n c Write byte/read byte"
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100482//usage: "\n Append p for SMBus PEC"
483//usage: "\n"
Denys Vlasenkof27e1502017-08-29 15:44:01 +0200484//usage: "\n -f Force access"
485//usage: "\n -y Disable interactive mode"
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100486int i2cget_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
487int i2cget_main(int argc UNUSED_PARAM, char **argv)
488{
489 const unsigned opt_f = (1 << 0), opt_y = (1 << 1);
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100490
491 int bus_num, bus_addr, data_addr = -1, status;
492 int mode = I2C_SMBUS_BYTE, pec = 0, fd;
493 unsigned opts;
494
Denys Vlasenko22542ec2017-08-08 21:55:02 +0200495 opts = getopt32(argv, "^" "fy" "\0" "-2:?4"/*from 2 to 4 args*/);
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100496 argv += optind;
497
498 bus_num = i2c_bus_lookup(argv[0]);
499 bus_addr = i2c_parse_bus_addr(argv[1]);
500
501 if (argv[2]) {
502 data_addr = i2c_parse_data_addr(argv[2]);
503 mode = I2C_SMBUS_BYTE_DATA;
504 if (argv[3]) {
505 switch (argv[3][0]) {
506 case 'b': /* Already set */ break;
507 case 'w': mode = I2C_SMBUS_WORD_DATA; break;
508 case 'c': mode = I2C_SMBUS_BYTE; break;
509 default:
James Byrne69374872019-07-02 11:35:03 +0200510 bb_simple_error_msg("invalid mode");
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100511 bb_show_usage();
512 }
513 pec = argv[3][1] == 'p';
514 }
515 }
516
517 fd = i2c_dev_open(bus_num);
518 check_read_funcs(fd, mode, data_addr, pec);
519 i2c_set_slave_addr(fd, bus_addr, opts & opt_f);
520
521 if (!(opts & opt_y))
522 confirm_action(bus_addr, mode, data_addr, pec);
523
524 if (pec)
525 i2c_set_pec(fd, 1);
526
527 switch (mode) {
528 case I2C_SMBUS_BYTE:
529 if (data_addr >= 0) {
530 status = i2c_smbus_write_byte(fd, data_addr);
531 if (status < 0)
James Byrne69374872019-07-02 11:35:03 +0200532 bb_simple_error_msg("warning - write failed");
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100533 }
534 status = i2c_smbus_read_byte(fd);
535 break;
536 case I2C_SMBUS_WORD_DATA:
537 status = i2c_smbus_read_word_data(fd, data_addr);
538 break;
539 default: /* I2C_SMBUS_BYTE_DATA */
540 status = i2c_smbus_read_byte_data(fd, data_addr);
541 }
542 close(fd);
543
544 if (status < 0)
James Byrne69374872019-07-02 11:35:03 +0200545 bb_simple_perror_msg_and_die("read failed");
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100546
547 printf("0x%0*x\n", mode == I2C_SMBUS_WORD_DATA ? 4 : 2, status);
548
549 return 0;
550}
551#endif /* ENABLE_I2CGET */
552
553#if ENABLE_I2CSET
554//usage:#define i2cset_trivial_usage
Denys Vlasenkof27e1502017-08-29 15:44:01 +0200555//usage: "[-fy] [-m MASK] BUS CHIP-ADDRESS DATA-ADDRESS [VALUE] ... [MODE]"
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100556//usage:#define i2cset_full_usage "\n\n"
Denys Vlasenkof27e1502017-08-29 15:44:01 +0200557//usage: "Set I2C registers"
558//usage: "\n"
559//usage: "\n I2CBUS I2C bus number"
560//usage: "\n ADDRESS 0x03-0x77"
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100561//usage: "\nMODE is:"
Denys Vlasenkof27e1502017-08-29 15:44:01 +0200562//usage: "\n c Byte, no value"
563//usage: "\n b Byte data (default)"
564//usage: "\n w Word data"
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100565//usage: "\n i I2C block data"
566//usage: "\n s SMBus block data"
567//usage: "\n Append p for SMBus PEC"
568//usage: "\n"
Denys Vlasenkof27e1502017-08-29 15:44:01 +0200569//usage: "\n -f Force access"
570//usage: "\n -y Disable interactive mode"
571//usage: "\n -r Read back and compare the result"
572//usage: "\n -m MASK Mask specifying which bits to write"
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100573int i2cset_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
574int i2cset_main(int argc, char **argv)
575{
576 const unsigned opt_f = (1 << 0), opt_y = (1 << 1),
577 opt_m = (1 << 2), opt_r = (1 << 3);
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100578
579 int bus_num, bus_addr, data_addr, mode = I2C_SMBUS_BYTE, pec = 0;
Avi Fishmanb5d9ba82017-10-05 11:25:16 +0200580 int val, blen, mask, fd, status;
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100581 unsigned char block[I2C_SMBUS_BLOCK_MAX];
582 char *opt_m_arg = NULL;
583 unsigned opts;
584
Avi Fishmanb5d9ba82017-10-05 11:25:16 +0200585 opts = getopt32(argv, "^"
586 "fym:r"
587 "\0" "-3", /* minimum 3 args */
588 &opt_m_arg
589 );
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100590 argv += optind;
591 argc -= optind;
Avi Fishmanb5d9ba82017-10-05 11:25:16 +0200592 argc--; /* now argv[argc] is last arg */
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100593
594 bus_num = i2c_bus_lookup(argv[0]);
595 bus_addr = i2c_parse_bus_addr(argv[1]);
596 data_addr = i2c_parse_data_addr(argv[2]);
597
598 if (argv[3]) {
599 if (!argv[4] && argv[3][0] != 'c') {
600 mode = I2C_SMBUS_BYTE_DATA; /* Implicit b */
601 } else {
Avi Fishmanb5d9ba82017-10-05 11:25:16 +0200602 switch (argv[argc][0]) {
603 case 'c': /* Already set */
604 break;
605 case 'b': mode = I2C_SMBUS_BYTE_DATA;
606 break;
607 case 'w': mode = I2C_SMBUS_WORD_DATA;
608 break;
609 case 's': mode = I2C_SMBUS_BLOCK_DATA;
610 break;
611 case 'i': mode = I2C_SMBUS_I2C_BLOCK_DATA;
612 break;
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100613 default:
James Byrne69374872019-07-02 11:35:03 +0200614 bb_simple_error_msg("invalid mode");
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100615 bb_show_usage();
616 }
617
Avi Fishmanb5d9ba82017-10-05 11:25:16 +0200618 pec = (argv[argc][1] == 'p');
619 if (mode == I2C_SMBUS_BLOCK_DATA
620 || mode == I2C_SMBUS_I2C_BLOCK_DATA
621 ) {
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100622 if (pec && mode == I2C_SMBUS_I2C_BLOCK_DATA)
James Byrne69374872019-07-02 11:35:03 +0200623 bb_simple_error_msg_and_die(
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100624 "PEC not supported for I2C "
625 "block writes");
626 if (opts & opt_m)
James Byrne69374872019-07-02 11:35:03 +0200627 bb_simple_error_msg_and_die(
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100628 "mask not supported for block "
629 "writes");
630 }
631 }
632 }
633
634 /* Prepare the value(s) to be written according to current mode. */
Avi Fishmanb5d9ba82017-10-05 11:25:16 +0200635 mask = 0;
636 blen = 0;
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100637 switch (mode) {
638 case I2C_SMBUS_BYTE_DATA:
639 val = xstrtou_range(argv[3], 0, 0, 0xff);
640 break;
641 case I2C_SMBUS_WORD_DATA:
642 val = xstrtou_range(argv[3], 0, 0, 0xffff);
643 break;
644 case I2C_SMBUS_BLOCK_DATA:
645 case I2C_SMBUS_I2C_BLOCK_DATA:
Avi Fishmanb5d9ba82017-10-05 11:25:16 +0200646 for (blen = 3; blen < argc; blen++)
647 block[blen - 3] = xstrtou_range(argv[blen], 0, 0, 0xff);
648 blen -= 3;
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100649 val = -1;
650 break;
651 default:
652 val = -1;
653 break;
654 }
655
656 if (opts & opt_m) {
657 mask = xstrtou_range(opt_m_arg, 0, 0,
658 (mode == I2C_SMBUS_BYTE ||
659 mode == I2C_SMBUS_BYTE_DATA) ? 0xff : 0xffff);
660 }
661
662 fd = i2c_dev_open(bus_num);
663 check_write_funcs(fd, mode, pec);
664 i2c_set_slave_addr(fd, bus_addr, opts & opt_f);
665
666 if (!(opts & opt_y))
667 confirm_action(bus_addr, mode, data_addr, pec);
668
669 /*
670 * If we're using mask - read the current value here and adjust the
671 * value to be written.
672 */
673 if (opts & opt_m) {
674 int tmpval;
675
676 switch (mode) {
677 case I2C_SMBUS_BYTE:
678 tmpval = i2c_smbus_read_byte(fd);
679 break;
680 case I2C_SMBUS_WORD_DATA:
681 tmpval = i2c_smbus_read_word_data(fd, data_addr);
682 break;
683 default:
684 tmpval = i2c_smbus_read_byte_data(fd, data_addr);
685 }
686
687 if (tmpval < 0)
James Byrne69374872019-07-02 11:35:03 +0200688 bb_simple_perror_msg_and_die("can't read old value");
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100689
690 val = (val & mask) | (tmpval & ~mask);
691
692 if (!(opts & opt_y)) {
693 bb_error_msg("old value 0x%0*x, write mask "
694 "0x%0*x, will write 0x%0*x to register "
695 "0x%02x",
696 mode == I2C_SMBUS_WORD_DATA ? 4 : 2, tmpval,
697 mode == I2C_SMBUS_WORD_DATA ? 4 : 2, mask,
698 mode == I2C_SMBUS_WORD_DATA ? 4 : 2, val,
699 data_addr);
700 confirm_or_abort();
701 }
702 }
703
704 if (pec)
705 i2c_set_pec(fd, 1);
706
707 switch (mode) {
708 case I2C_SMBUS_BYTE:
709 status = i2c_smbus_write_byte(fd, data_addr);
710 break;
711 case I2C_SMBUS_WORD_DATA:
712 status = i2c_smbus_write_word_data(fd, data_addr, val);
713 break;
714 case I2C_SMBUS_BLOCK_DATA:
715 status = i2c_smbus_write_block_data(fd, data_addr,
716 blen, block);
717 break;
718 case I2C_SMBUS_I2C_BLOCK_DATA:
719 status = i2c_smbus_write_i2c_block_data(fd, data_addr,
720 blen, block);
721 break;
722 default: /* I2C_SMBUS_BYTE_DATA */
723 status = i2c_smbus_write_byte_data(fd, data_addr, val);
724 break;
725 }
726 if (status < 0)
James Byrne69374872019-07-02 11:35:03 +0200727 bb_simple_perror_msg_and_die("write failed");
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100728
729 if (pec)
730 i2c_set_pec(fd, 0); /* Clear PEC. */
731
732 /* No readback required - we're done. */
733 if (!(opts & opt_r))
734 return 0;
735
736 switch (mode) {
737 case I2C_SMBUS_BYTE:
738 status = i2c_smbus_read_byte(fd);
739 val = data_addr;
740 break;
741 case I2C_SMBUS_WORD_DATA:
742 status = i2c_smbus_read_word_data(fd, data_addr);
743 break;
744 default: /* I2C_SMBUS_BYTE_DATA */
745 status = i2c_smbus_read_byte_data(fd, data_addr);
746 }
747
748 if (status < 0) {
Denys Vlasenkod60752f2015-10-07 22:42:45 +0200749 puts("Warning - readback failed");
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100750 } else
751 if (status != val) {
752 printf("Warning - data mismatch - wrote "
753 "0x%0*x, read back 0x%0*x\n",
754 mode == I2C_SMBUS_WORD_DATA ? 4 : 2, val,
755 mode == I2C_SMBUS_WORD_DATA ? 4 : 2, status);
756 } else {
757 printf("Value 0x%0*x written, readback matched\n",
758 mode == I2C_SMBUS_WORD_DATA ? 4 : 2, val);
759 }
760
761 return 0;
762}
763#endif /* ENABLE_I2CSET */
764
765#if ENABLE_I2CDUMP
Bartosz Golaszewskiaeb11a92015-06-05 10:27:31 +0200766static int read_block_data(int buf_fd, int mode, int *block)
767{
Bartosz Golaszewski2beb5242015-09-04 10:38:48 +0200768 uint8_t cblock[I2C_SMBUS_BLOCK_MAX + I2CDUMP_NUM_REGS];
Bartosz Golaszewskiaeb11a92015-06-05 10:27:31 +0200769 int res, blen = 0, tmp, i;
770
Bartosz Golaszewski1fe75b82015-10-27 17:15:03 +0100771 if (mode == I2C_SMBUS_BLOCK_DATA) {
Bartosz Golaszewski74bb9d52015-10-27 17:15:04 +0100772 blen = i2c_smbus_read_block_data(buf_fd, 0, cblock);
773 if (blen <= 0)
774 goto fail;
Bartosz Golaszewskiaeb11a92015-06-05 10:27:31 +0200775 } else {
Bartosz Golaszewski2beb5242015-09-04 10:38:48 +0200776 for (res = 0; res < I2CDUMP_NUM_REGS; res += tmp) {
Bartosz Golaszewskiaeb11a92015-06-05 10:27:31 +0200777 tmp = i2c_smbus_read_i2c_block_data(
778 buf_fd, res, I2C_SMBUS_BLOCK_MAX,
779 cblock + res);
Bartosz Golaszewski5ed69892015-10-27 17:15:05 +0100780 if (tmp <= 0) {
781 blen = tmp;
Bartosz Golaszewski74bb9d52015-10-27 17:15:04 +0100782 goto fail;
Bartosz Golaszewski5ed69892015-10-27 17:15:05 +0100783 }
Bartosz Golaszewskiaeb11a92015-06-05 10:27:31 +0200784 }
785
Bartosz Golaszewski2beb5242015-09-04 10:38:48 +0200786 if (res >= I2CDUMP_NUM_REGS)
787 res = I2CDUMP_NUM_REGS;
Bartosz Golaszewskiaeb11a92015-06-05 10:27:31 +0200788
789 for (i = 0; i < res; i++)
790 block[i] = cblock[i];
791
792 if (mode != I2C_SMBUS_BLOCK_DATA)
Bartosz Golaszewski2beb5242015-09-04 10:38:48 +0200793 for (i = res; i < I2CDUMP_NUM_REGS; i++)
Bartosz Golaszewskiaeb11a92015-06-05 10:27:31 +0200794 block[i] = -1;
795 }
796
797 return blen;
Bartosz Golaszewski74bb9d52015-10-27 17:15:04 +0100798
799 fail:
Bartosz Golaszewski5ed69892015-10-27 17:15:05 +0100800 bb_error_msg_and_die("block read failed: %d", blen);
Bartosz Golaszewskiaeb11a92015-06-05 10:27:31 +0200801}
802
803/* Dump all but word data. */
804static void dump_data(int bus_fd, int mode, unsigned first,
805 unsigned last, int *block, int blen)
806{
807 int i, j, res;
808
Denys Vlasenkod60752f2015-10-07 22:42:45 +0200809 puts(" 0 1 2 3 4 5 6 7 8 9 a b c d e f"
810 " 0123456789abcdef");
Bartosz Golaszewskiaeb11a92015-06-05 10:27:31 +0200811
Bartosz Golaszewski2beb5242015-09-04 10:38:48 +0200812 for (i = 0; i < I2CDUMP_NUM_REGS; i += 0x10) {
Bartosz Golaszewskiaeb11a92015-06-05 10:27:31 +0200813 if (mode == I2C_SMBUS_BLOCK_DATA && i >= blen)
814 break;
815 if (i/16 < first/16)
816 continue;
817 if (i/16 > last/16)
818 break;
819
820 printf("%02x: ", i);
821 for (j = 0; j < 16; j++) {
822 fflush_all();
823 /* Skip unwanted registers */
824 if (i+j < first || i+j > last) {
825 printf(" ");
826 if (mode == I2C_SMBUS_WORD_DATA) {
827 printf(" ");
828 j++;
829 }
830 continue;
831 }
832
833 switch (mode) {
834 case I2C_SMBUS_BYTE_DATA:
835 res = i2c_smbus_read_byte_data(bus_fd, i+j);
836 block[i+j] = res;
837 break;
838 case I2C_SMBUS_WORD_DATA:
839 res = i2c_smbus_read_word_data(bus_fd, i+j);
840 if (res < 0) {
841 block[i+j] = res;
842 block[i+j+1] = res;
843 } else {
844 block[i+j] = res & 0xff;
845 block[i+j+1] = res >> 8;
846 }
847 break;
848 case I2C_SMBUS_BYTE:
849 res = i2c_smbus_read_byte(bus_fd);
850 block[i+j] = res;
851 break;
852 default:
853 res = block[i+j];
854 }
855
856 if (mode == I2C_SMBUS_BLOCK_DATA &&
857 i+j >= blen) {
858 printf(" ");
859 } else if (res < 0) {
860 printf("XX ");
861 if (mode == I2C_SMBUS_WORD_DATA)
862 printf("XX ");
863 } else {
864 printf("%02x ", block[i+j]);
865 if (mode == I2C_SMBUS_WORD_DATA)
866 printf("%02x ", block[i+j+1]);
867 }
868
869 if (mode == I2C_SMBUS_WORD_DATA)
870 j++;
871 }
872 printf(" ");
873
874 for (j = 0; j < 16; j++) {
875 if (mode == I2C_SMBUS_BLOCK_DATA && i+j >= blen)
876 break;
877 /* Skip unwanted registers */
878 if (i+j < first || i+j > last) {
Denys Vlasenkod60752f2015-10-07 22:42:45 +0200879 bb_putchar(' ');
Bartosz Golaszewskiaeb11a92015-06-05 10:27:31 +0200880 continue;
881 }
882
883 res = block[i+j];
884 if (res < 0) {
Denys Vlasenkod60752f2015-10-07 22:42:45 +0200885 bb_putchar('X');
Bartosz Golaszewskiaeb11a92015-06-05 10:27:31 +0200886 } else if (res == 0x00 || res == 0xff) {
Denys Vlasenkod60752f2015-10-07 22:42:45 +0200887 bb_putchar('.');
Bartosz Golaszewskiaeb11a92015-06-05 10:27:31 +0200888 } else if (res < 32 || res >= 127) {
Denys Vlasenkod60752f2015-10-07 22:42:45 +0200889 bb_putchar('?');
Bartosz Golaszewskiaeb11a92015-06-05 10:27:31 +0200890 } else {
Denys Vlasenkod60752f2015-10-07 22:42:45 +0200891 bb_putchar(res);
Bartosz Golaszewskiaeb11a92015-06-05 10:27:31 +0200892 }
893 }
Denys Vlasenkod60752f2015-10-07 22:42:45 +0200894 bb_putchar('\n');
Bartosz Golaszewskiaeb11a92015-06-05 10:27:31 +0200895 }
896}
897
898static void dump_word_data(int bus_fd, unsigned first, unsigned last)
899{
900 int i, j, rv;
901
902 /* Word data. */
Denys Vlasenkod60752f2015-10-07 22:42:45 +0200903 puts(" 0,8 1,9 2,a 3,b 4,c 5,d 6,e 7,f");
Bartosz Golaszewskiaeb11a92015-06-05 10:27:31 +0200904 for (i = 0; i < 256; i += 8) {
905 if (i/8 < first/8)
906 continue;
907 if (i/8 > last/8)
908 break;
909
910 printf("%02x: ", i);
911 for (j = 0; j < 8; j++) {
912 /* Skip unwanted registers. */
913 if (i+j < first || i+j > last) {
914 printf(" ");
915 continue;
916 }
917
918 rv = i2c_smbus_read_word_data(bus_fd, i+j);
919 if (rv < 0)
920 printf("XXXX ");
921 else
922 printf("%04x ", rv & 0xffff);
923 }
Denys Vlasenkod60752f2015-10-07 22:42:45 +0200924 bb_putchar('\n');
Bartosz Golaszewskiaeb11a92015-06-05 10:27:31 +0200925 }
926}
927
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100928//usage:#define i2cdump_trivial_usage
Denys Vlasenkof27e1502017-08-29 15:44:01 +0200929//usage: "[-fy] [-r FIRST-LAST] BUS ADDR [MODE]"
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100930//usage:#define i2cdump_full_usage "\n\n"
Denys Vlasenkof27e1502017-08-29 15:44:01 +0200931//usage: "Examine I2C registers"
932//usage: "\n"
933//usage: "\n I2CBUS I2C bus number"
934//usage: "\n ADDRESS 0x03-0x77"
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100935//usage: "\nMODE is:"
Denys Vlasenkof27e1502017-08-29 15:44:01 +0200936//usage: "\n b Byte (default)"
937//usage: "\n w Word"
938//usage: "\n W Word on even register addresses"
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100939//usage: "\n i I2C block"
940//usage: "\n s SMBus block"
Denys Vlasenkof27e1502017-08-29 15:44:01 +0200941//usage: "\n c Consecutive byte"
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100942//usage: "\n Append p for SMBus PEC"
943//usage: "\n"
Denys Vlasenkof27e1502017-08-29 15:44:01 +0200944//usage: "\n -f Force access"
945//usage: "\n -y Disable interactive mode"
946//usage: "\n -r Limit the number of registers being accessed"
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100947int i2cdump_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
948int i2cdump_main(int argc UNUSED_PARAM, char **argv)
949{
950 const unsigned opt_f = (1 << 0), opt_y = (1 << 1),
951 opt_r = (1 << 2);
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100952
953 int bus_num, bus_addr, mode = I2C_SMBUS_BYTE_DATA, even = 0, pec = 0;
Bartosz Golaszewskiaeb11a92015-06-05 10:27:31 +0200954 unsigned first = 0x00, last = 0xff, opts;
Bartosz Golaszewski59f81972016-06-23 17:19:50 +0200955 int block[I2CDUMP_NUM_REGS];
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100956 char *opt_r_str, *dash;
Denys Vlasenko2cf45912015-11-01 20:57:34 +0100957 int fd, res;
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100958
Denys Vlasenko22542ec2017-08-08 21:55:02 +0200959 opts = getopt32(argv, "^"
960 "fyr:"
961 "\0" "-2:?3" /* from 2 to 3 args */,
962 &opt_r_str
963 );
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100964 argv += optind;
965
966 bus_num = i2c_bus_lookup(argv[0]);
967 bus_addr = i2c_parse_bus_addr(argv[1]);
968
969 if (argv[2]) {
970 switch (argv[2][0]) {
Bartosz Golaszewskiaeb11a92015-06-05 10:27:31 +0200971 case 'b': /* Already set. */ break;
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100972 case 'c': mode = I2C_SMBUS_BYTE; break;
973 case 'w': mode = I2C_SMBUS_WORD_DATA; break;
974 case 'W':
975 mode = I2C_SMBUS_WORD_DATA;
976 even = 1;
977 break;
978 case 's': mode = I2C_SMBUS_BLOCK_DATA; break;
979 case 'i': mode = I2C_SMBUS_I2C_BLOCK_DATA; break;
980 default:
James Byrne69374872019-07-02 11:35:03 +0200981 bb_simple_error_msg_and_die("invalid mode");
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100982 }
983
984 if (argv[2][1] == 'p') {
985 if (argv[2][0] == 'W' || argv[2][0] == 'i') {
James Byrne69374872019-07-02 11:35:03 +0200986 bb_simple_error_msg_and_die(
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100987 "pec not supported for -W and -i");
988 } else {
989 pec = 1;
990 }
991 }
992 }
993
994 if (opts & opt_r) {
995 first = strtol(opt_r_str, &dash, 0);
996 if (dash == opt_r_str || *dash != '-' || first > 0xff)
James Byrne69374872019-07-02 11:35:03 +0200997 bb_simple_error_msg_and_die("invalid range");
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +0100998 last = xstrtou_range(++dash, 0, first, 0xff);
999
Bartosz Golaszewskiaeb11a92015-06-05 10:27:31 +02001000 /* Range is not available for every mode. */
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001001 switch (mode) {
1002 case I2C_SMBUS_BYTE:
1003 case I2C_SMBUS_BYTE_DATA:
1004 break;
1005 case I2C_SMBUS_WORD_DATA:
1006 if (!even || (!(first % 2) && last % 2))
1007 break;
1008 /* Fall through */
1009 default:
James Byrne69374872019-07-02 11:35:03 +02001010 bb_simple_error_msg_and_die(
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001011 "range not compatible with selected mode");
1012 }
1013 }
1014
1015 fd = i2c_dev_open(bus_num);
1016 check_read_funcs(fd, mode, -1 /* data_addr */, pec);
1017 i2c_set_slave_addr(fd, bus_addr, opts & opt_f);
1018
1019 if (pec)
1020 i2c_set_pec(fd, 1);
1021
1022 if (!(opts & opt_y))
1023 confirm_action(bus_addr, mode, -1 /* data_addr */, pec);
1024
Bartosz Golaszewskiaeb11a92015-06-05 10:27:31 +02001025 /* All but word data. */
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001026 if (mode != I2C_SMBUS_WORD_DATA || even) {
Denys Vlasenko2cf45912015-11-01 20:57:34 +01001027 int blen = 0;
1028
Bartosz Golaszewski1cde5f72015-10-27 17:15:02 +01001029 if (mode == I2C_SMBUS_BLOCK_DATA || mode == I2C_SMBUS_I2C_BLOCK_DATA)
1030 blen = read_block_data(fd, mode, block);
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001031
1032 if (mode == I2C_SMBUS_BYTE) {
1033 res = i2c_smbus_write_byte(fd, first);
1034 if (res < 0)
James Byrne69374872019-07-02 11:35:03 +02001035 bb_simple_perror_msg_and_die("write start address");
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001036 }
1037
Bartosz Golaszewskiaeb11a92015-06-05 10:27:31 +02001038 dump_data(fd, mode, first, last, block, blen);
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001039 } else {
Bartosz Golaszewskiaeb11a92015-06-05 10:27:31 +02001040 dump_word_data(fd, first, last);
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001041 }
1042
1043 return 0;
1044}
1045#endif /* ENABLE_I2CDUMP */
1046
1047#if ENABLE_I2CDETECT
1048enum adapter_type {
1049 ADT_DUMMY = 0,
1050 ADT_ISA,
1051 ADT_I2C,
1052 ADT_SMBUS,
1053};
1054
1055struct adap_desc {
1056 const char *funcs;
1057 const char *algo;
1058};
1059
1060static const struct adap_desc adap_descs[] = {
1061 { .funcs = "dummy",
1062 .algo = "Dummy bus", },
1063 { .funcs = "isa",
1064 .algo = "ISA bus", },
1065 { .funcs = "i2c",
1066 .algo = "I2C adapter", },
1067 { .funcs = "smbus",
1068 .algo = "SMBus adapter", },
1069};
1070
1071struct i2c_func
1072{
1073 long value;
1074 const char* name;
1075};
1076
1077static const struct i2c_func i2c_funcs_tab[] = {
1078 { .value = I2C_FUNC_I2C,
1079 .name = "I2C" },
1080 { .value = I2C_FUNC_SMBUS_QUICK,
Denys Vlasenko7f3a2a22015-10-08 11:24:44 +02001081 .name = "SMBus quick command" },
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001082 { .value = I2C_FUNC_SMBUS_WRITE_BYTE,
Denys Vlasenko7f3a2a22015-10-08 11:24:44 +02001083 .name = "SMBus send byte" },
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001084 { .value = I2C_FUNC_SMBUS_READ_BYTE,
Denys Vlasenko7f3a2a22015-10-08 11:24:44 +02001085 .name = "SMBus receive byte" },
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001086 { .value = I2C_FUNC_SMBUS_WRITE_BYTE_DATA,
Denys Vlasenko7f3a2a22015-10-08 11:24:44 +02001087 .name = "SMBus write byte" },
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001088 { .value = I2C_FUNC_SMBUS_READ_BYTE_DATA,
Denys Vlasenko7f3a2a22015-10-08 11:24:44 +02001089 .name = "SMBus read byte" },
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001090 { .value = I2C_FUNC_SMBUS_WRITE_WORD_DATA,
Denys Vlasenko7f3a2a22015-10-08 11:24:44 +02001091 .name = "SMBus write word" },
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001092 { .value = I2C_FUNC_SMBUS_READ_WORD_DATA,
Denys Vlasenko7f3a2a22015-10-08 11:24:44 +02001093 .name = "SMBus read word" },
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001094 { .value = I2C_FUNC_SMBUS_PROC_CALL,
Denys Vlasenko7f3a2a22015-10-08 11:24:44 +02001095 .name = "SMBus process call" },
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001096 { .value = I2C_FUNC_SMBUS_WRITE_BLOCK_DATA,
Denys Vlasenko7f3a2a22015-10-08 11:24:44 +02001097 .name = "SMBus block write" },
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001098 { .value = I2C_FUNC_SMBUS_READ_BLOCK_DATA,
Denys Vlasenko7f3a2a22015-10-08 11:24:44 +02001099 .name = "SMBus block read" },
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001100 { .value = I2C_FUNC_SMBUS_BLOCK_PROC_CALL,
Denys Vlasenko7f3a2a22015-10-08 11:24:44 +02001101 .name = "SMBus block process call" },
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001102 { .value = I2C_FUNC_SMBUS_PEC,
1103 .name = "SMBus PEC" },
1104 { .value = I2C_FUNC_SMBUS_WRITE_I2C_BLOCK,
Denys Vlasenko7f3a2a22015-10-08 11:24:44 +02001105 .name = "I2C block write" },
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001106 { .value = I2C_FUNC_SMBUS_READ_I2C_BLOCK,
Denys Vlasenko7f3a2a22015-10-08 11:24:44 +02001107 .name = "I2C block read" },
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001108 { .value = 0, .name = NULL }
1109};
1110
1111static enum adapter_type i2cdetect_get_funcs(int bus)
1112{
1113 enum adapter_type ret;
1114 unsigned long funcs;
1115 int fd;
1116
1117 fd = i2c_dev_open(bus);
1118
1119 get_funcs_matrix(fd, &funcs);
1120 if (funcs & I2C_FUNC_I2C)
1121 ret = ADT_I2C;
1122 else if (funcs & (I2C_FUNC_SMBUS_BYTE |
1123 I2C_FUNC_SMBUS_BYTE_DATA |
1124 I2C_FUNC_SMBUS_WORD_DATA))
1125 ret = ADT_SMBUS;
1126 else
1127 ret = ADT_DUMMY;
1128
1129 close(fd);
1130
1131 return ret;
1132}
1133
1134static void NORETURN list_i2c_busses_and_exit(void)
1135{
1136 const char *const i2cdev_path = "/sys/class/i2c-dev";
1137
1138 char path[NAME_MAX], name[128];
1139 struct dirent *de, *subde;
1140 enum adapter_type adt;
1141 DIR *dir, *subdir;
1142 int rv, bus;
1143 char *pos;
1144 FILE *fp;
1145
1146 /*
1147 * XXX Upstream i2cdetect also looks for i2c bus info in /proc/bus/i2c,
1148 * but we won't bother since it's only useful on older kernels (before
1149 * 2.6.5). We expect sysfs to be present and mounted at /sys/.
1150 */
1151
1152 dir = xopendir(i2cdev_path);
1153 while ((de = readdir(dir))) {
1154 if (de->d_name[0] == '.')
1155 continue;
1156
1157 /* Simple version for ISA chips. */
1158 snprintf(path, NAME_MAX, "%s/%s/name",
1159 i2cdev_path, de->d_name);
1160 fp = fopen(path, "r");
1161 if (fp == NULL) {
1162 snprintf(path, NAME_MAX,
1163 "%s/%s/device/name",
1164 i2cdev_path, de->d_name);
1165 fp = fopen(path, "r");
1166 }
1167
1168 /* Non-ISA chips require the hard-way. */
1169 if (fp == NULL) {
1170 snprintf(path, NAME_MAX,
1171 "%s/%s/device/name",
1172 i2cdev_path, de->d_name);
1173 subdir = opendir(path);
1174 if (subdir == NULL)
1175 continue;
1176
1177 while ((subde = readdir(subdir))) {
1178 if (subde->d_name[0] == '.')
1179 continue;
1180
Denys Vlasenko8dff01d2015-03-12 17:48:34 +01001181 if (is_prefixed_with(subde->d_name, "i2c-")) {
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001182 snprintf(path, NAME_MAX,
1183 "%s/%s/device/%s/name",
1184 i2cdev_path, de->d_name,
1185 subde->d_name);
1186 fp = fopen(path, "r");
Bartosz Golaszewskid9089922015-06-05 10:27:32 +02001187 break;
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001188 }
1189 }
1190 }
1191
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001192 if (fp != NULL) {
1193 /*
1194 * Get the rest of the info and display a line
1195 * for a single bus.
1196 */
1197 memset(name, 0, sizeof(name));
1198 pos = fgets(name, sizeof(name), fp);
1199 fclose(fp);
1200 if (pos == NULL)
1201 continue;
1202
1203 pos = strchr(name, '\n');
1204 if (pos != NULL)
1205 *pos = '\0';
1206
1207 rv = sscanf(de->d_name, "i2c-%d", &bus);
1208 if (rv != 1)
1209 continue;
1210
Denys Vlasenko8dff01d2015-03-12 17:48:34 +01001211 if (is_prefixed_with(name, "ISA"))
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001212 adt = ADT_ISA;
1213 else
1214 adt = i2cdetect_get_funcs(bus);
1215
1216 printf(
1217 "i2c-%d\t%-10s\t%-32s\t%s\n",
1218 bus, adap_descs[adt].funcs,
1219 name, adap_descs[adt].algo);
1220 }
1221 }
1222
1223 exit(EXIT_SUCCESS);
1224}
1225
1226static void NORETURN no_support(const char *cmd)
1227{
1228 bb_error_msg_and_die("bus doesn't support %s", cmd);
1229}
1230
1231static void will_skip(const char *cmd)
1232{
1233 bb_error_msg(
1234 "warning: can't use %s command, "
1235 "will skip some addresses", cmd);
1236}
1237
1238//usage:#define i2cdetect_trivial_usage
Bartosz Golaszewski0d1eaf42017-08-29 12:31:22 +02001239//usage: "-l | -F I2CBUS | [-ya] [-q|-r] I2CBUS [FIRST LAST]"
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001240//usage:#define i2cdetect_full_usage "\n\n"
Bartosz Golaszewski0d1eaf42017-08-29 12:31:22 +02001241//usage: "Detect I2C chips"
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001242//usage: "\n"
Denys Vlasenkof27e1502017-08-29 15:44:01 +02001243//usage: "\n -l List installed buses"
1244//usage: "\n -F BUS# List functionalities on this bus"
Bartosz Golaszewski0d1eaf42017-08-29 12:31:22 +02001245//usage: "\n -y Disable interactive mode"
1246//usage: "\n -a Force scanning of non-regular addresses"
1247//usage: "\n -q Use smbus quick write commands for probing (default)"
1248//usage: "\n -r Use smbus read byte commands for probing"
1249//usage: "\n FIRST and LAST limit probing range"
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001250int i2cdetect_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
1251int i2cdetect_main(int argc UNUSED_PARAM, char **argv)
1252{
1253 const unsigned opt_y = (1 << 0), opt_a = (1 << 1),
1254 opt_q = (1 << 2), opt_r = (1 << 3),
1255 opt_F = (1 << 4), opt_l = (1 << 5);
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001256
Bartosz Golaszewski99f025a2015-10-27 17:15:00 +01001257 int fd, bus_num, i, j, mode = I2CDETECT_MODE_AUTO, status, cmd;
Bartosz Golaszewskie545bf62015-06-05 10:27:29 +02001258 unsigned first = 0x03, last = 0x77, opts;
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001259 unsigned long funcs;
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001260
Denys Vlasenko22542ec2017-08-08 21:55:02 +02001261 opts = getopt32(argv, "^"
1262 "yaqrFl"
1263 "\0"
Bartosz Golaszewski0d1eaf42017-08-29 12:31:22 +02001264 "q--r:r--q:"/*mutually exclusive*/
1265 "?3"/*up to 3 args*/
Denys Vlasenko22542ec2017-08-08 21:55:02 +02001266 );
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001267 argv += optind;
1268
1269 if (opts & opt_l)
1270 list_i2c_busses_and_exit();
1271
Bartosz Golaszewskib2cca322015-05-11 17:22:10 +02001272 if (!argv[0])
1273 bb_show_usage();
1274
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001275 bus_num = i2c_bus_lookup(argv[0]);
1276 fd = i2c_dev_open(bus_num);
1277 get_funcs_matrix(fd, &funcs);
1278
1279 if (opts & opt_F) {
1280 /* Only list the functionalities. */
1281 printf("Functionalities implemented by bus #%d\n", bus_num);
1282 for (i = 0; i2c_funcs_tab[i].value; i++) {
1283 printf("%-32s %s\n", i2c_funcs_tab[i].name,
1284 funcs & i2c_funcs_tab[i].value ? "yes" : "no");
1285 }
1286
1287 return EXIT_SUCCESS;
1288 }
1289
1290 if (opts & opt_r)
Bartosz Golaszewski2beb5242015-09-04 10:38:48 +02001291 mode = I2CDETECT_MODE_READ;
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001292 else if (opts & opt_q)
Bartosz Golaszewski2beb5242015-09-04 10:38:48 +02001293 mode = I2CDETECT_MODE_QUICK;
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001294
Bartosz Golaszewskie545bf62015-06-05 10:27:29 +02001295 if (opts & opt_a) {
1296 first = 0x00;
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001297 last = 0x7f;
Bartosz Golaszewskie545bf62015-06-05 10:27:29 +02001298 }
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001299
1300 /* Read address range. */
1301 if (argv[1]) {
1302 first = xstrtou_range(argv[1], 16, first, last);
1303 if (argv[2])
1304 last = xstrtou_range(argv[2], 16, first, last);
1305 }
1306
1307 if (!(funcs & (I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_READ_BYTE))) {
1308 no_support("detection commands");
1309 } else
Bartosz Golaszewski2beb5242015-09-04 10:38:48 +02001310 if (mode == I2CDETECT_MODE_QUICK && !(funcs & I2C_FUNC_SMBUS_QUICK)) {
Denys Vlasenko7f3a2a22015-10-08 11:24:44 +02001311 no_support("SMBus quick write");
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001312 } else
Bartosz Golaszewski2beb5242015-09-04 10:38:48 +02001313 if (mode == I2CDETECT_MODE_READ && !(funcs & I2C_FUNC_SMBUS_READ_BYTE)) {
Denys Vlasenko7f3a2a22015-10-08 11:24:44 +02001314 no_support("SMBus receive byte");
Bartosz Golaszewski22044722015-06-05 10:27:30 +02001315 }
1316
Bartosz Golaszewski2beb5242015-09-04 10:38:48 +02001317 if (mode == I2CDETECT_MODE_AUTO) {
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001318 if (!(funcs & I2C_FUNC_SMBUS_QUICK))
Denys Vlasenko7f3a2a22015-10-08 11:24:44 +02001319 will_skip("SMBus quick write");
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001320 if (!(funcs & I2C_FUNC_SMBUS_READ_BYTE))
Denys Vlasenko7f3a2a22015-10-08 11:24:44 +02001321 will_skip("SMBus receive byte");
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001322 }
1323
1324 if (!(opts & opt_y))
1325 confirm_action(-1, -1, -1, 0);
1326
Denys Vlasenkod60752f2015-10-07 22:42:45 +02001327 puts(" 0 1 2 3 4 5 6 7 8 9 a b c d e f");
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001328 for (i = 0; i < 128; i += 16) {
1329 printf("%02x: ", i);
Bartosz Golaszewskifc8eb052015-10-27 17:15:01 +01001330 for (j = 0; j < 16; j++) {
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001331 fflush_all();
1332
Bartosz Golaszewski99f025a2015-10-27 17:15:00 +01001333 cmd = mode;
Bartosz Golaszewski2beb5242015-09-04 10:38:48 +02001334 if (mode == I2CDETECT_MODE_AUTO) {
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001335 if ((i+j >= 0x30 && i+j <= 0x37) ||
1336 (i+j >= 0x50 && i+j <= 0x5F))
Bartosz Golaszewski99f025a2015-10-27 17:15:00 +01001337 cmd = I2CDETECT_MODE_READ;
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001338 else
Bartosz Golaszewski99f025a2015-10-27 17:15:00 +01001339 cmd = I2CDETECT_MODE_QUICK;
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001340 }
1341
1342 /* Skip unwanted addresses. */
1343 if (i+j < first
1344 || i+j > last
Bartosz Golaszewski99f025a2015-10-27 17:15:00 +01001345 || (cmd == I2CDETECT_MODE_READ && !(funcs & I2C_FUNC_SMBUS_READ_BYTE))
1346 || (cmd == I2CDETECT_MODE_QUICK && !(funcs & I2C_FUNC_SMBUS_QUICK)))
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001347 {
1348 printf(" ");
1349 continue;
1350 }
1351
Bartosz Golaszewski31474272015-06-05 10:27:28 +02001352 status = ioctl(fd, I2C_SLAVE, itoptr(i + j));
1353 if (status < 0) {
1354 if (errno == EBUSY) {
1355 printf("UU ");
1356 continue;
1357 }
1358
1359 bb_perror_msg_and_die(
1360 "can't set address to 0x%02x", i + j);
1361 }
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001362
Bartosz Golaszewski99f025a2015-10-27 17:15:00 +01001363 switch (cmd) {
Bartosz Golaszewski2beb5242015-09-04 10:38:48 +02001364 case I2CDETECT_MODE_READ:
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001365 /*
1366 * This is known to lock SMBus on various
1367 * write-only chips (mainly clock chips).
1368 */
1369 status = i2c_smbus_read_byte(fd);
1370 break;
Bartosz Golaszewski2beb5242015-09-04 10:38:48 +02001371 default: /* I2CDETECT_MODE_QUICK: */
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001372 /*
1373 * This is known to corrupt the Atmel
1374 * AT24RF08 EEPROM.
1375 */
1376 status = i2c_smbus_write_quick(fd,
1377 I2C_SMBUS_WRITE);
1378 break;
1379 }
1380
1381 if (status < 0)
1382 printf("-- ");
1383 else
1384 printf("%02x ", i+j);
1385 }
Denys Vlasenkod60752f2015-10-07 22:42:45 +02001386 bb_putchar('\n');
Bartosz Golaszewski622a7aa2015-02-10 03:16:25 +01001387 }
1388
1389 return 0;
1390}
1391#endif /* ENABLE_I2CDETECT */
Nikolaus Vossdac8f5e2019-02-10 19:56:41 +01001392
1393#if ENABLE_I2CTRANSFER
1394static void check_i2c_func(int fd)
1395{
1396 unsigned long funcs;
1397
1398 get_funcs_matrix(fd, &funcs);
1399
1400 if (!(funcs & I2C_FUNC_I2C))
James Byrne69374872019-07-02 11:35:03 +02001401 bb_simple_error_msg_and_die("adapter does not support I2C transfers");
Nikolaus Vossdac8f5e2019-02-10 19:56:41 +01001402}
1403
1404//usage:#define i2ctransfer_trivial_usage
1405//usage: "[-fay] I2CBUS {rLENGTH[@ADDR] | wLENGTH[@ADDR] DATA...}..."
1406//usage:#define i2ctransfer_full_usage "\n\n"
1407//usage: "Read/write I2C data in one transfer"
1408//usage: "\n"
Nikolaus Vossf81e0122019-02-11 11:30:52 +01001409//usage: "\n -f Force access to busy addresses"
1410//usage: "\n -a Force access to non-regular addresses"
Nikolaus Vossdac8f5e2019-02-10 19:56:41 +01001411//usage: "\n -y Disable interactive mode"
1412int i2ctransfer_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
1413int i2ctransfer_main(int argc UNUSED_PARAM, char **argv)
1414{
1415 enum {
1416 opt_f = (1 << 0),
1417 opt_y = (1 << 1),
1418 opt_a = (1 << 2),
1419 };
1420 int bus_num, bus_addr;
1421 int fd;
1422 unsigned opts, first, last;
1423 int nmsgs, nmsgs_sent, i;
1424 struct i2c_msg msgs[I2C_RDWR_IOCTL_MAX_MSGS];
1425 struct i2c_rdwr_ioctl_data rdwr;
1426
1427 memset(msgs, 0, sizeof(msgs));
1428
1429 opts = getopt32(argv, "^"
1430 "fya"
1431 "\0" "-2" /* minimum 2 args */
1432 );
1433 first = 0x03;
1434 last = 0x77;
1435 if (opts & opt_a) {
1436 first = 0x00;
1437 last = 0x7f;
1438 }
1439
1440 argv += optind;
1441 bus_num = i2c_bus_lookup(argv[0]);
1442 fd = i2c_dev_open(bus_num);
1443 check_i2c_func(fd);
1444
1445 bus_addr = -1;
1446 nmsgs = 0;
1447 while (*++argv) {
1448 char *arg_ptr;
1449 unsigned len;
1450 uint16_t flags;
1451 char *end;
1452
1453 if (nmsgs >= I2C_RDWR_IOCTL_MAX_MSGS)
James Byrne69374872019-07-02 11:35:03 +02001454 bb_simple_error_msg_and_die("too many messages, max: "I2C_RDWR_IOCTL_MAX_MSGS_STR);
Nikolaus Vossdac8f5e2019-02-10 19:56:41 +01001455
1456 flags = 0;
1457 arg_ptr = *argv;
1458 switch (*arg_ptr++) {
1459 case 'r': flags |= I2C_M_RD; break;
1460 case 'w': break;
1461 default:
1462 bb_show_usage();
1463 }
1464
1465 end = strchr(arg_ptr, '@');
1466 if (end) *end = '\0';
1467 len = xstrtou_range(arg_ptr, 0, 0, 0xffff);
1468 if (end) {
1469 bus_addr = xstrtou_range(end + 1, 0, first, last);
Nikolaus Vossf81e0122019-02-11 11:30:52 +01001470 i2c_set_slave_addr(fd, bus_addr, (opts & opt_f));
Nikolaus Vossdac8f5e2019-02-10 19:56:41 +01001471 } else {
1472 /* Reuse last address if possible */
1473 if (bus_addr < 0)
1474 bb_error_msg_and_die("no address given in '%s'", *argv);
1475 }
1476
1477 msgs[nmsgs].addr = bus_addr;
1478 msgs[nmsgs].flags = flags;
1479 msgs[nmsgs].len = len;
1480 if (len)
1481 msgs[nmsgs].buf = xzalloc(len);
1482
1483 if (!(flags & I2C_M_RD)) {
1484 /* Consume DATA arg(s) */
1485 unsigned buf_idx = 0;
1486
1487 while (buf_idx < len) {
1488 uint8_t data8;
1489 unsigned long data;
1490
1491 arg_ptr = *++argv;
1492 if (!arg_ptr)
1493 bb_show_usage();
1494 data = strtoul(arg_ptr, &end, 0);
1495 if (data > 0xff || arg_ptr == end)
1496 bb_error_msg_and_die("invalid data byte '%s'", *argv);
1497
1498 data8 = data;
1499 while (buf_idx < len) {
1500 msgs[nmsgs].buf[buf_idx++] = data8;
1501 if (!*end)
1502 break;
1503 switch (*end) {
1504 /* Pseudo randomness (8 bit AXR with a=13 and b=27) */
1505 case 'p':
1506 data8 = (data8 ^ 27) + 13;
1507 data8 = (data8 << 1) | (data8 >> 7);
1508 break;
1509 case '+': data8++; break;
1510 case '-': data8--; break;
1511 case '=': break;
1512 default:
1513 bb_error_msg_and_die("invalid data byte suffix: '%s'",
1514 *argv);
1515 }
1516 }
1517 }
1518 }
1519 nmsgs++;
1520 }
1521
1522 if (!(opts & opt_y))
1523 confirm_action(bus_addr, 0, 0, 0);
1524
1525 rdwr.msgs = msgs;
1526 rdwr.nmsgs = nmsgs;
1527 nmsgs_sent = ioctl_or_perror_and_die(fd, I2C_RDWR, &rdwr, "I2C_RDWR");
1528 if (nmsgs_sent < nmsgs)
1529 bb_error_msg("warning: only %u/%u messages sent", nmsgs_sent, nmsgs);
1530
1531 for (i = 0; i < nmsgs_sent; i++) {
1532 if (msgs[i].len != 0 && (msgs[i].flags & I2C_M_RD)) {
1533 int j;
1534 for (j = 0; j < msgs[i].len - 1; j++)
1535 printf("0x%02x ", msgs[i].buf[j]);
1536 /* Print final byte with newline */
1537 printf("0x%02x\n", msgs[i].buf[j]);
1538 }
1539 }
1540
1541# if ENABLE_FEATURE_CLEAN_UP
1542 close(fd);
1543 for (i = 0; i < nmsgs; i++)
1544 free(msgs[i].buf);
1545# endif
1546
1547 return 0;
1548}
1549#endif /* ENABLE_I2CTRANSFER */