root/i2c-tools/trunk/tools/i2cdump.c

Revision 5242, 11.7 kB (checked in by khali, 7 months ago)

Use consistent transaction names (based on the SMBus specification)
when complaining about a missing adapter functionality.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1 /*
2     i2cdump.c - a user-space program to dump I2C registers
3     Copyright (C) 2002-2003  Frodo Looijaard <frodol@dds.nl>, and
4                              Mark D. Studebaker <mdsxyz123@yahoo.com>
5     Copyright (C) 2004-2008  Jean Delvare <khali@linux-fr.org>
6
7     This program is free software; you can redistribute it and/or modify
8     it under the terms of the GNU General Public License as published by
9     the Free Software Foundation; either version 2 of the License, or
10     (at your option) any later version.
11
12     This program is distributed in the hope that it will be useful,
13     but WITHOUT ANY WARRANTY; without even the implied warranty of
14     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15     GNU General Public License for more details.
16
17     You should have received a copy of the GNU General Public License
18     along with this program; if not, write to the Free Software
19     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
20     MA 02110-1301 USA.
21 */
22
23 #include <errno.h>
24 #include <string.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <unistd.h>
28 #include <linux/i2c-dev.h>
29 #include "i2cbusses.h"
30 #include "util.h"
31 #include "../version.h"
32
33 static void help(void)
34 {
35         fprintf(stderr,
36                 "Usage: i2cdump [-f] [-y] [-r first-last] I2CBUS ADDRESS [MODE [BANK [BANKREG]]]\n"
37                 "  I2CBUS is an integer or an I2C bus name\n"
38                 "  ADDRESS is an integer (0x03 - 0x77)\n"
39                 "  MODE is one of:\n"
40                 "    b (byte, default)\n"
41                 "    w (word)\n"
42                 "    W (word on even register addresses)\n"
43                 "    s (SMBus block)\n"
44                 "    i (I2C block)\n"
45                 "    c (consecutive byte)\n"
46                 "    Append p for SMBus PEC\n");
47 }
48
49 static int check_funcs(int file, int size, int pec)
50 {
51         unsigned long funcs;
52
53         /* check adapter functionality */
54         if (ioctl(file, I2C_FUNCS, &funcs) < 0) {
55                 fprintf(stderr, "Error: Could not get the adapter "
56                         "functionality matrix: %s\n", strerror(errno));
57                 return -1;
58         }
59
60         switch(size) {
61         case I2C_SMBUS_BYTE:
62                 if (!(funcs & I2C_FUNC_SMBUS_READ_BYTE)) {
63                         fprintf(stderr, MISSING_FUNC_FMT, "SMBus receive byte");
64                         return -1;
65                 }
66                 if (!(funcs & I2C_FUNC_SMBUS_WRITE_BYTE)) {
67                         fprintf(stderr, MISSING_FUNC_FMT, "SMBus send byte");
68                         return -1;
69                 }
70                 break;
71
72         case I2C_SMBUS_BYTE_DATA:
73                 if (!(funcs & I2C_FUNC_SMBUS_READ_BYTE_DATA)) {
74                         fprintf(stderr, MISSING_FUNC_FMT, "SMBus read byte");
75                         return -1;
76                 }
77                 break;
78
79         case I2C_SMBUS_WORD_DATA:
80                 if (!(funcs & I2C_FUNC_SMBUS_READ_WORD_DATA)) {
81                         fprintf(stderr, MISSING_FUNC_FMT, "SMBus read word");
82                         return -1;
83                 }
84                 break;
85
86         case I2C_SMBUS_BLOCK_DATA:
87                 if (!(funcs & I2C_FUNC_SMBUS_READ_BLOCK_DATA)) {
88                         fprintf(stderr, MISSING_FUNC_FMT, "SMBus block read");
89                         return -1;
90                 }
91                 break;
92
93         case I2C_SMBUS_I2C_BLOCK_DATA:
94                 if (!(funcs & I2C_FUNC_SMBUS_READ_I2C_BLOCK)) {
95                         fprintf(stderr, MISSING_FUNC_FMT, "I2C block read");
96                         return -1;
97                 }
98                 break;
99         }
100
101         if (pec
102          && !(funcs & (I2C_FUNC_SMBUS_PEC | I2C_FUNC_I2C))) {
103                 fprintf(stderr, "Warning: Adapter does "
104                         "not seem to support PEC\n");
105         }
106
107         return 0;
108 }
109
110 int main(int argc, char *argv[])
111 {
112         char *end;
113         int i, j, res, i2cbus, address, size, file;
114         int bank = 0, bankreg = 0x4E, old_bank = 0;
115         char filename[20];
116         int block[256], s_length = 0;
117         int pec = 0, even = 0;
118         int flags = 0;
119         int force = 0, yes = 0, version = 0;
120         const char *range = NULL;
121         int first = 0x00, last = 0xff;
122
123         /* handle (optional) flags first */
124         while (1+flags < argc && argv[1+flags][0] == '-') {
125                 switch (argv[1+flags][1]) {
126                 case 'V': version = 1; break;
127                 case 'f': force = 1; break;
128                 case 'r': range = argv[1+(++flags)]; break;
129                 case 'y': yes = 1; break;
130                 default:
131                         fprintf(stderr, "Error: Unsupported option "
132                                 "\"%s\"!\n", argv[1+flags]);
133                         help();
134                         exit(1);
135                 }
136                 flags++;
137         }
138
139         if (version) {
140                 fprintf(stderr, "i2cdump version %s\n", VERSION);
141                 exit(0);
142         }
143
144         if (argc < flags + 2) {
145                 fprintf(stderr, "Error: No i2c-bus specified!\n");
146                 help();
147                 exit(1);
148         }
149         i2cbus = lookup_i2c_bus(argv[flags+1]);
150         if (i2cbus < 0) {
151                 help();
152                 exit(1);
153         }
154
155         if (argc < flags + 3) {
156                 fprintf(stderr, "Error: No address specified!\n");
157                 help();
158                 exit(1);
159         }
160         address = parse_i2c_address(argv[flags+2]);
161         if (address < 0) {
162                 help();
163                 exit(1);
164         }
165
166         if (argc < flags + 4) {
167                 fprintf(stderr, "No size specified (using byte-data access)\n");
168                 size = I2C_SMBUS_BYTE_DATA;
169         } else if (!strncmp(argv[flags+3], "b", 1)) {
170                 size = I2C_SMBUS_BYTE_DATA;
171                 pec = argv[flags+3][1] == 'p';
172         } else if (!strncmp(argv[flags+3], "w", 1)) {
173                 size = I2C_SMBUS_WORD_DATA;
174                 pec = argv[flags+3][1] == 'p';
175         } else if (!strncmp(argv[flags+3], "W", 1)) {
176                 size = I2C_SMBUS_WORD_DATA;
177                 even = 1;
178         } else if (!strncmp(argv[flags+3], "s", 1)) {
179                 size = I2C_SMBUS_BLOCK_DATA;
180                 pec = argv[flags+3][1] == 'p';
181         } else if (!strncmp(argv[flags+3], "c", 1)) {
182                 size = I2C_SMBUS_BYTE;
183                 pec = argv[flags+3][1] == 'p';
184         } else if (!strcmp(argv[flags+3], "i"))
185                 size = I2C_SMBUS_I2C_BLOCK_DATA;
186         else {
187                 fprintf(stderr, "Error: Invalid mode!\n");
188                 help();
189                 exit(1);
190         }
191
192         if (argc > flags + 4) {
193                 bank = strtol(argv[flags+4], &end, 0);
194                 if (*end || size == I2C_SMBUS_I2C_BLOCK_DATA) {
195                         fprintf(stderr, "Error: Invalid bank number!\n");
196                         help();
197                         exit(1);
198                 }
199                 if ((size == I2C_SMBUS_BYTE_DATA || size == I2C_SMBUS_WORD_DATA)
200                  && (bank < 0 || bank > 15)) {
201                         fprintf(stderr, "Error: bank out of range!\n");
202                         help();
203                         exit(1);
204                 }
205                 if (size == I2C_SMBUS_BLOCK_DATA
206                  && (bank < 0 || bank > 0xff)) {
207                         fprintf(stderr, "Error: block command out of range!\n");
208                         help();
209                         exit(1);
210                 }
211
212                 if (argc > flags + 5) {
213                         bankreg = strtol(argv[flags+5], &end, 0);
214                         if (*end || size == I2C_SMBUS_BLOCK_DATA) {
215                                 fprintf(stderr, "Error: Invalid bank register "
216                                         "number!\n");
217                                 help();
218                                 exit(1);
219                         }
220                         if (bankreg < 0 || bankreg > 0xff) {
221                                 fprintf(stderr, "Error: bank out of range "
222                                         "(0-0xff)!\n");
223                                 help();
224                                 exit(1);
225                         }
226                 }
227         }
228
229         /* Parse optional range string */
230         if (range) {
231                 char *dash;
232
233                 first = strtol(range, &dash, 0);
234                 if (dash == range || *dash != '-'
235                  || first < 0 || first > 0xff) {
236                         fprintf(stderr, "Error: Invalid range parameter!\n");
237                         exit(1);
238                 }
239                 last = strtol(++dash, &end, 0);
240                 if (end == dash || *end != '\0'
241                  || last < first || last > 0xff) {
242                         fprintf(stderr, "Error: Invalid range parameter!\n");
243                         exit(1);
244                 }
245
246                 /* Check mode constraints */
247                 switch (size) {
248                 case I2C_SMBUS_BYTE:
249                 case I2C_SMBUS_BYTE_DATA:
250                         break;
251                 case I2C_SMBUS_WORD_DATA:
252                         if (!even || (!(first%2) && last%2))
253                                 break;
254                         /* Fall through */
255                 default:
256                         fprintf(stderr,
257                                 "Error: Range parameter not compatible with selected mode!\n");
258                         exit(1);
259                 }
260         }
261
262         file = open_i2c_dev(i2cbus, filename, 0);
263         if (file < 0
264          || check_funcs(file, size, pec)
265          || set_slave_addr(file, address, force))
266                 exit(1);
267
268         if (pec) {
269                 if (ioctl(file, I2C_PEC, 1) < 0) {
270                         fprintf(stderr, "Error: Could not set PEC: %s\n",
271                                 strerror(errno));
272                         exit(1);
273                 }
274         }
275
276         if (!yes) {
277                 fprintf(stderr, "WARNING! This program can confuse your I2C "
278                         "bus, cause data loss and worse!\n");
279
280                 fprintf(stderr, "I will probe file %s, address 0x%x, mode "
281                         "%s\n", filename, address,
282                         size == I2C_SMBUS_BLOCK_DATA ? "smbus block" :
283                         size == I2C_SMBUS_I2C_BLOCK_DATA ? "i2c block" :
284                         size == I2C_SMBUS_BYTE ? "byte consecutive read" :
285                         size == I2C_SMBUS_BYTE_DATA ? "byte" : "word");
286                 if (pec)
287                         fprintf(stderr, "PEC checking enabled.\n");
288                 if (even)
289                         fprintf(stderr, "Only probing even register "
290                                 "addresses.\n");
291                 if (bank) {
292                         if (size == I2C_SMBUS_BLOCK_DATA)
293                                 fprintf(stderr, "Using command 0x%02x.\n",
294                                         bank);
295                         else
296                                 fprintf(stderr, "Probing bank %d using bank "
297                                         "register 0x%02x.\n", bank, bankreg);
298                 }
299                 if (range) {
300                         fprintf(stderr,
301                                 "Probe range limited to 0x%02x-0x%02x.\n",
302                                 first, last);
303                 }
304
305                 fprintf(stderr, "Continue? [Y/n] ");
306                 fflush(stderr);
307                 if (!user_ack(1)) {
308                         fprintf(stderr, "Aborting on user request.\n");
309                         exit(0);
310                 }
311         }
312
313         /* See Winbond w83781d data sheet for bank details */
314         if (bank && size != I2C_SMBUS_BLOCK_DATA) {
315                 res = i2c_smbus_read_byte_data(file, bankreg);
316                 if (res >= 0) {
317                         old_bank = res;
318                         res = i2c_smbus_write_byte_data(file, bankreg,
319                                 bank | (old_bank & 0xf0));
320                 }
321                 if (res < 0) {
322                         fprintf(stderr, "Error: Bank switching failed\n");
323                         exit(1);
324                 }
325         }
326
327         /* handle all but word data */
328         if (size != I2C_SMBUS_WORD_DATA || even) {
329                 /* do the block transaction */
330                 if (size == I2C_SMBUS_BLOCK_DATA
331                  || size == I2C_SMBUS_I2C_BLOCK_DATA) {
332                         unsigned char cblock[288];
333
334                         if (size == I2C_SMBUS_BLOCK_DATA) {
335                                 res = i2c_smbus_read_block_data(file, bank,
336                                       cblock);
337                                 /* Remember returned block length for a nicer
338                                    display later */
339                                 s_length = res;
340                         } else {
341                                 for (res = 0; res < 256; res += i) {
342                                         i = i2c_smbus_read_i2c_block_data(file,
343                                                 res, 32, cblock + res);
344                                         if (i <= 0) {
345                                                 res = i;
346                                                 break;
347                                         }
348                                 }
349                         }
350                         if (res <= 0) {
351                                 fprintf(stderr, "Error: Block read failed, "
352                                         "return code %d\n", res);
353                                 exit(1);
354                         }
355                         if (res >= 256)
356                                 res = 256;
357                         for (i = 0; i < res; i++)
358                                 block[i] = cblock[i];
359                         if (size != I2C_SMBUS_BLOCK_DATA)
360                                 for (i = res; i < 256; i++)
361                                         block[i] = -1;
362                 }
363
364                 if (size == I2C_SMBUS_BYTE) {
365                         res = i2c_smbus_write_byte(file, first);
366                         if(res != 0) {
367                                 fprintf(stderr, "Error: Write start address "
368                                         "failed, return code %d\n", res);
369                                 exit(1);
370                         }
371                 }
372
373                 printf("     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f"
374                        "    0123456789abcdef\n");
375                 for (i = 0; i < 256; i+=16) {
376                         if (size == I2C_SMBUS_BLOCK_DATA && i >= s_length)
377                                 break;
378                         if (i/16 < first/16)
379                                 continue;
380                         if (i/16 > last/16)
381                                 break;
382
383                         printf("%02x: ", i);
384                         for (j = 0; j < 16; j++) {
385                                 fflush(stdout);
386                                 /* Skip unwanted registers */
387                                 if (i+j < first || i+j > last) {
388                                         printf("   ");
389                                         if (size == I2C_SMBUS_WORD_DATA) {
390                                                 printf("   ");
391                                                 j++;
392                                         }
393                                         continue;
394                                 }
395
396                                 if (size == I2C_SMBUS_BYTE_DATA) {
397                                         block[i+j] = res =
398                                           i2c_smbus_read_byte_data(file, i+j);
399                                 } else if (size == I2C_SMBUS_WORD_DATA) {
400                                         res = i2c_smbus_read_word_data(file,
401                                                                        i+j);
402                                         if (res < 0) {
403                                                 block[i+j] = res;
404                                                 block[i+j+1] = res;
405                                         } else {
406                                                 block[i+j] = res & 0xff;
407                                                 block[i+j+1] = res >> 8;
408                                         }
409                                 } else if (size == I2C_SMBUS_BYTE) {
410                                         block[i+j] = res =
411                                           i2c_smbus_read_byte(file);
412                                 } else
413                                         res = block[i+j];
414
415                                 if (size == I2C_SMBUS_BLOCK_DATA
416                                  && i+j >= s_length) {
417                                         printf("   ");
418                                 } else if (res < 0) {
419                                         printf("XX ");
420                                         if (size == I2C_SMBUS_WORD_DATA)
421                                                 printf("XX ");
422                                 } else {
423                                         printf("%02x ", block[i+j]);
424                                         if (size == I2C_SMBUS_WORD_DATA)
425                                                 printf("%02x ", block[i+j+1]);
426                                 }
427                                 if (size == I2C_SMBUS_WORD_DATA)
428                                         j++;
429                         }
430                         printf("   ");
431
432                         for (j = 0; j < 16; j++) {
433                                 if (size == I2C_SMBUS_BLOCK_DATA
434                                  && i+j >= s_length)
435                                         break;
436                                 /* Skip unwanted registers */
437                                 if (i+j < first || i+j > last) {
438                                         printf(" ");
439                                         continue;
440                                 }
441
442                                 res = block[i+j];
443                                 if (res < 0)
444                                         printf("X");
445                                 else
446                                 if ((res & 0xff) == 0x00
447                                  || (res & 0xff) == 0xff)
448                                         printf(".");
449                                 else
450                                 if ((res & 0xff) < 32
451                                  || (res & 0xff) >= 127)
452                                         printf("?");
453                                 else
454                                         printf("%c", res & 0xff);
455                         }
456                         printf("\n");
457                 }
458         } else {
459                 printf("     0,8  1,9  2,a  3,b  4,c  5,d  6,e  7,f\n");
460                 for (i = 0; i < 256; i+=8) {
461                         if (i/8 < first/8)
462                                 continue;
463                         if (i/8 > last/8)
464                                 break;
465
466                         printf("%02x: ", i);
467                         for (j = 0; j < 8; j++) {
468                                 /* Skip unwanted registers */
469                                 if (i+j < first || i+j > last) {
470                                         printf("     ");
471                                         continue;
472                                 }
473
474                                 res = i2c_smbus_read_word_data(file, i+j);
475                                 if (res < 0)
476                                         printf("XXXX ");
477                                 else
478                                         printf("%04x ", res & 0xffff);
479                         }
480                         printf("\n");
481                 }
482         }
483         if (bank && size != I2C_SMBUS_BLOCK_DATA) {
484                 i2c_smbus_write_byte_data(file, bankreg, old_bank);
485         }
486         exit(0);
487 }
Note: See TracBrowser for help on using the browser.