1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70#define FOR_i2cdetect
71#define TT this.i2ctools
72#include "toys.h"
73
74#include <linux/i2c.h>
75#include <linux/i2c-dev.h>
76
77printf_format static void confirm(const char *fmt, ...)
78{
79 va_list va;
80
81 if (FLAG(y)) return;
82
83 va_start(va, fmt);
84 vfprintf(stderr, fmt, va);
85 va_end(va);
86 if (!yesno(1)) error_exit("Exiting");
87}
88
89static int i2c_open(int bus, int slave, int chip)
90{
91 int fd;
92
93 snprintf(toybuf, sizeof(toybuf), "/dev/i2c-%d", bus);
94 fd = xopen(toybuf, O_RDONLY);
95 if (slave) xioctl(fd, slave, (void *)(long)chip);
96 return fd;
97}
98
99static unsigned long i2c_get_funcs(int bus)
100{
101 int fd = i2c_open(bus, 0, 0);
102 unsigned long result;
103
104 xioctl(fd, I2C_FUNCS, &result);
105 close(fd);
106 return result;
107}
108
109static int i2c_read_byte(int fd, int addr, int *byte)
110{
111 union i2c_smbus_data data;
112 struct i2c_smbus_ioctl_data ioctl_data = { .read_write = I2C_SMBUS_READ,
113 .size = I2C_SMBUS_BYTE_DATA, .command = addr, .data = &data };
114
115 memset(&data, 0, sizeof(data));
116 if (ioctl(fd, I2C_SMBUS, &ioctl_data)==-1) return -1;
117 *byte = data.byte;
118 return 0;
119}
120
121static int i2c_quick_write(int fd, int addr)
122{
123 struct i2c_smbus_ioctl_data ioctl_data = { .read_write = I2C_SMBUS_QUICK,
124 .size = 0, .command = addr };
125
126 return ioctl(fd, I2C_SMBUS, &ioctl_data);
127}
128
129static void i2cdetect_dash_F(int bus)
130{
131 struct { int mask; const char *name; } funcs[] = {
132 {I2C_FUNC_I2C, "I2C"},
133 {I2C_FUNC_SMBUS_QUICK, "SMBus Quick Command"},
134 {I2C_FUNC_SMBUS_WRITE_BYTE, "SMBus Send Byte"},
135 {I2C_FUNC_SMBUS_READ_BYTE, "SMBus Receive Byte"},
136 {I2C_FUNC_SMBUS_WRITE_BYTE_DATA, "SMBus Write Byte"},
137 {I2C_FUNC_SMBUS_READ_BYTE_DATA, "SMBus Read Byte"},
138 {I2C_FUNC_SMBUS_WRITE_WORD_DATA, "SMBus Write Word"},
139 {I2C_FUNC_SMBUS_READ_WORD_DATA, "SMBus Read Word"},
140 {I2C_FUNC_SMBUS_PROC_CALL, "SMBus Process Call"},
141 {I2C_FUNC_SMBUS_WRITE_BLOCK_DATA, "SMBus Write Block"},
142 {I2C_FUNC_SMBUS_READ_BLOCK_DATA, "SMBus Read Block"},
143 {I2C_FUNC_SMBUS_BLOCK_PROC_CALL, "SMBus Block Process Call"},
144 {I2C_FUNC_SMBUS_PEC, "SMBus PEC"},
145 {I2C_FUNC_SMBUS_WRITE_I2C_BLOCK, "I2C Write Block"},
146 {I2C_FUNC_SMBUS_READ_I2C_BLOCK, "I2C Read Block"},
147 };
148 unsigned long sup = i2c_get_funcs(bus);
149 int i;
150
151 printf("Functionalities implemented by %s:\n", toybuf);
152 for (i = 0; i < ARRAY_LEN(funcs); ++i)
153 printf("%-32s %s\n", funcs[i].name, (sup & funcs[i].mask) ? "yes" : "no");
154}
155
156static int i2cdetect_dash_l(struct dirtree *node)
157{
158 int suffix_len = strlen("/name");
159 int bus;
160 char *fname, *p;
161 unsigned long funcs;
162
163 if (!node->parent) return DIRTREE_RECURSE;
164
165 if (sscanf(node->name, "i2c-%d", &bus)!=1) return 0;
166 funcs = i2c_get_funcs(bus);
167
168 fname = dirtree_path(node, &suffix_len);
169 strcat(fname, "/name");
170 xreadfile(fname, toybuf, sizeof(toybuf));
171 free(fname);
172 if ((p = strchr(toybuf, '\n'))) *p = 0;
173
174
175 printf("%s\t%-10s\t%-32s\t%s\n", node->name,
176 (funcs & I2C_FUNC_I2C) ? "i2c" : "?", toybuf,
177 (funcs & I2C_FUNC_I2C) ? "I2C Adapter" : "?");
178
179 return 0;
180}
181
182void i2cdetect_main(void)
183{
184 if (FLAG(l)) {
185 if (toys.optc) error_exit("-l doesn't take arguments");
186 dirtree_flagread("/sys/class/i2c-dev", DIRTREE_SHUTUP, i2cdetect_dash_l);
187 } else if (FLAG(F)) {
188 if (toys.optc != 1) error_exit("-F BUS");
189 i2cdetect_dash_F(atolx_range(*toys.optargs, 0, INT_MAX));
190 } else {
191 int bus, first = 0x03, last = 0x77, fd, row, addr, byte;
192
193 if (FLAG(a)) {
194 first = 0x00;
195 last = 0x7f;
196 }
197
198 if (toys.optc!=1 && toys.optc!=3) help_exit("Needs 1 or 3 arguments");
199 bus = atolx_range(*toys.optargs, 0, INT_MAX);
200 if (toys.optc==3) {
201 first = atolx_range(toys.optargs[1], 0, 0x7f);
202 last = atolx_range(toys.optargs[2], 0, 0x7f);
203 if (first > last) error_exit("first > last");
204 }
205
206 confirm("Probe chips 0x%02x-0x%02x on bus %d?", first, last, bus);
207
208 fd = i2c_open(bus, 0, 0);
209 printf(" 0 1 2 3 4 5 6 7 8 9 a b c d e f\n");
210 for (row = 0; row <= 0x70; row += 16) {
211 xprintf("%02x:", row & 0xf0);
212 for (addr = row; addr<row+16; ++addr) {
213 if (addr<first || addr>last) printf(" ");
214 else {
215 if (ioctl(fd, I2C_SLAVE, addr) == -1) {
216 if (errno == EBUSY) {
217 xprintf(" UU");
218 continue;
219 }
220 perror_exit("ioctl(I2C_SLAVE)");
221 }
222 if ((FLAG(r) ? i2c_read_byte(fd, addr, &byte)
223 : i2c_quick_write(fd, addr)) == -1) xprintf(" --");
224 else xprintf(" %02x", addr);
225 }
226 }
227 putchar('\n');
228 }
229 close(fd);
230 }
231}
232
233#define FOR_i2cdump
234#include "generated/flags.h"
235
236void i2cdump_main(void)
237{
238 int bus = atolx_range(toys.optargs[0], 0, INT_MAX);
239 int chip = atolx_range(toys.optargs[1], 0, 0x7f);
240 int fd, row, addr, byte;
241
242 confirm("Dump chip 0x%02x on bus %d?", chip, bus);
243
244 fd = i2c_open(bus, FLAG(f) ? I2C_SLAVE_FORCE : I2C_SLAVE, chip);
245 printf(" 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef\n");
246 for (row = 0; row<=0xf0; row += 16) {
247 xprintf("%02x:", row & 0xf0);
248 for (addr = row; addr<row+16; ++addr) {
249 if (!i2c_read_byte(fd, addr, &byte)) printf(" %02x", byte);
250 else {
251 printf(" XX");
252 byte = 'X';
253 }
254 toybuf[addr-row] = isprint(byte) ? byte : (byte ? '?' : '.');
255 }
256 printf(" %16.16s\n", toybuf);
257 }
258 close(fd);
259}
260
261#define FOR_i2cget
262#include "generated/flags.h"
263
264void i2cget_main(void)
265{
266 int bus = atolx_range(toys.optargs[0], 0, INT_MAX);
267 int chip = atolx_range(toys.optargs[1], 0, 0x7f);
268 int addr = atolx_range(toys.optargs[2], 0, 0xff);
269 int fd, byte;
270
271 confirm("Read register 0x%02x from chip 0x%02x on bus %d?", addr, chip, bus);
272
273 fd = i2c_open(bus, FLAG(f) ? I2C_SLAVE_FORCE : I2C_SLAVE, chip);
274 if (i2c_read_byte(fd, addr, &byte)==-1) perror_exit("i2c_read_byte");
275 printf("0x%02x\n", byte);
276 close(fd);
277}
278
279#define FOR_i2cset
280#include "generated/flags.h"
281
282void i2cset_main(void)
283{
284 int bus = atolx_range(toys.optargs[0], 0, INT_MAX);
285 int chip = atolx_range(toys.optargs[1], 0, 0x7f);
286 int addr = atolx_range(toys.optargs[2], 0, 0xff);
287 char *mode = toys.optargs[toys.optc-1];
288 int fd, i;
289 struct i2c_smbus_ioctl_data ioctl_data;
290 union i2c_smbus_data data;
291
292 memset(&data, 0, sizeof(data));
293 if (strlen(mode)!=1) help_exit("mode too long");
294 if (*mode=='b' && toys.optc==5) {
295 ioctl_data.size = I2C_SMBUS_BYTE_DATA;
296 data.byte = atolx_range(toys.optargs[3], 0, 0xff);
297 } else if (*mode=='w' && toys.optc==5) {
298 ioctl_data.size = I2C_SMBUS_WORD_DATA;
299 data.word = atolx_range(toys.optargs[3], 0, 0xffff);
300 } else if (*mode=='i' && toys.optc>=5) {
301 if (toys.optc-4>I2C_SMBUS_BLOCK_MAX) error_exit("too much data");
302 ioctl_data.size = I2C_SMBUS_I2C_BLOCK_DATA;
303 for (i = 0; i<toys.optc-4; ++i)
304 data.block[i+1] = atolx_range(toys.optargs[3+i], 0, 0xff);
305 data.block[0] = toys.optc-4;
306 } else help_exit("syntax error");
307
308 confirm("Write register 0x%02x from chip 0x%02x on bus %d?", addr, chip, bus);
309
310 fd = i2c_open(bus, FLAG(f) ? I2C_SLAVE_FORCE : I2C_SLAVE, chip);
311 ioctl_data.read_write = I2C_SMBUS_WRITE;
312 ioctl_data.command = addr;
313 ioctl_data.data = &data;
314 xioctl(fd, I2C_SMBUS, &ioctl_data);
315 close(fd);
316}
317