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

Revision 5885, 11.7 KB (checked in by khali, 3 years ago)

Use a 20-bit limit for the i2c bus number.
Use snprintf for the i2c dev node name.
Update copyright years.

  • 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-2010  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
33static 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
49static 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
110int 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, sizeof(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.