root/lm-sensors/trunk/prog/dump/i2cdump.c @ 3077

Revision 3077, 11.3 KB (checked in by khali, 9 years ago)

Add a "quiet" parameter to open_i2c_dev() to prevent it from
displaying error messages.

  • 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       The lm_sensors group
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., 675 Mass Ave, Cambridge, MA 02139, USA.
20*/
21
22#include <errno.h>
23#include <string.h>
24#include <stdio.h>
25#include <stdlib.h>
26#include <unistd.h>
27#include "i2cbusses.h"
28#include "i2c-dev.h"
29#include "version.h"
30
31/*
32   We don't use this #define but it was put into i2c.h at the same time as
33   i2c_smbus_read_i2c_block_data() was implemented (i2c 2.6.3),
34   so we use it as a version check.
35*/
36#ifdef I2C_FUNC_SMBUS_READ_I2C_BLOCK_2
37#define USE_I2C_BLOCK 1
38#else
39#define USE_I2C_BLOCK 0
40#endif
41
42#ifdef I2C_FUNC_SMBUS_BLOCK_DATA_PEC
43#define HAVE_PEC 1
44#endif
45
46void help(void)
47{
48        fprintf(stderr, "Syntax: i2cdump [-y] I2CBUS ADDRESS [MODE] [BANK "
49                "[BANKREG]]\n"
50                "        i2cdump -V\n"
51                "  MODE is 'b[yte]', 'w[ord]', 's[mbusblock], 'i[2cblock]',\n"
52                "       or 'c[onsecutive byte address mode]' (default b)\n"
53                "  Append MODE with 'p' for PEC checking\n"
54                "  I2CBUS is an integer\n"
55                "  ADDRESS is an integer 0x00 - 0x7f\n"
56                "  BANK and BANKREG are for byte and word accesses (default "
57                "bank 0, reg 0x4e)\n"
58                "  BANK is the command for smbusblock accesses (default 0)\n");
59        print_i2c_busses(0);
60}
61
62int main(int argc, char *argv[])
63{
64        char *end;
65        int i, j, res, i2cbus, address, size, file;
66        int bank = 0, bankreg = 0x4E;
67        char filename[20];
68        long funcs;
69        int block[256];
70        int pec = 0;
71        int flags = 0;
72        int yes = 0, version = 0;
73
74        /* handle (optional) flags first */
75        while (1+flags < argc && argv[1+flags][0] == '-') {
76                switch (argv[1+flags][1]) {
77                case 'V': version = 1; break;
78                case 'y': yes = 1; break;
79                default:
80                        fprintf(stderr, "Warning: Unsupported flag "
81                                "\"-%c\"!\n", argv[1+flags][1]);
82                        help();
83                        exit(1);
84                }
85                flags++;
86        }
87
88        if (version) {
89                fprintf(stderr, "i2cdump version %s\n", LM_VERSION);
90                exit(0);
91        }
92
93        if (argc < flags + 2) {
94                fprintf(stderr, "Error: No i2c-bus specified!\n");
95                help();
96                exit(1);
97        }
98        i2cbus = strtol(argv[flags+1], &end, 0);
99        if (*end) {
100                fprintf(stderr, "Error: First argument not a number!\n");
101                help();
102                exit(1);
103        }
104        if (i2cbus < 0 || i2cbus > 0xff) {
105                fprintf(stderr, "Error: I2CBUS argument out of range!\n");
106                help();
107                exit(1);
108        }
109
110        if (argc < flags + 3) {
111                fprintf(stderr, "Error: No address specified!\n");
112                help();
113                exit(1);
114        }
115        address = strtol(argv[flags+2], &end, 0);
116        if (*end) {
117                fprintf(stderr, "Error: Second argument not a number!\n");
118                help();
119                exit(1);
120        }
121        if (address < 0 || address > 0x7f) {
122                fprintf(stderr, "Error: Address out of range!\n");
123                help();
124                exit(1);
125        }
126
127        if (argc < flags + 4) {
128                fprintf(stderr, "No size specified (using byte-data access)\n");
129                size = I2C_SMBUS_BYTE_DATA;
130        } else if (!strncmp(argv[flags+3], "b", 1)) {
131                size = I2C_SMBUS_BYTE_DATA;
132                pec = argv[flags+3][1] == 'p';
133        } else if (!strncmp(argv[flags+3], "w", 1)) {
134                size = I2C_SMBUS_WORD_DATA;
135                pec = argv[flags+3][1] == 'p';
136        } else if (!strncmp(argv[flags+3], "s", 1)) {
137                size = I2C_SMBUS_BLOCK_DATA;
138                pec = argv[flags+3][1] == 'p';
139        } else if (!strncmp(argv[flags+3], "c", 1)) {
140                size = I2C_SMBUS_BYTE;
141                pec = argv[flags+3][1] == 'p';
142        } else if (!strcmp(argv[flags+3], "i"))
143                size = I2C_SMBUS_I2C_BLOCK_DATA;
144        else {
145                fprintf(stderr, "Error: Invalid mode!\n");
146                help();
147                exit(1);
148        }
149
150        if (argc > flags + 4) {
151                bank = strtol(argv[flags+4], &end, 0);
152                if (*end || size == I2C_SMBUS_I2C_BLOCK_DATA) {
153                        fprintf(stderr, "Error: Invalid bank number!\n");
154                        help();
155                        exit(1);
156                }
157                if ((size == I2C_SMBUS_BYTE_DATA || size == I2C_SMBUS_WORD_DATA)
158                 && (bank < 0 || bank > 15)) {
159                        fprintf(stderr, "Error: bank out of range!\n");
160                        help();
161                        exit(1);
162                }
163                if (size == I2C_SMBUS_BLOCK_DATA
164                 && (bank < 0 || bank > 0xff)) {
165                        fprintf(stderr, "Error: block command out of range!\n");
166                        help();
167                        exit(1);
168                }
169
170                if (argc > flags + 5) {
171                        bankreg = strtol(argv[flags+5], &end, 0);
172                        if (*end || size == I2C_SMBUS_BLOCK_DATA) {
173                                fprintf(stderr, "Error: Invalid bank register "
174                                        "number!\n");
175                                help();
176                                exit(1);
177                        }
178                        if (bankreg < 0 || bankreg > 0xff) {
179                                fprintf(stderr, "Error: bank out of range "
180                                        "(0-0xff)!\n");
181                                help();
182                                exit(1);
183                        }
184                }
185        }
186
187        file = open_i2c_dev(i2cbus, filename, 0);
188        if (file < 0) {
189                exit(1);
190        }
191
192        /* check adapter functionality */
193        if (ioctl(file, I2C_FUNCS, &funcs) < 0) {
194                fprintf(stderr, "Error: Could not get the adapter "
195                        "functionality matrix: %s\n", strerror(errno));
196                exit(1);
197        }
198
199        switch(size) {
200        case I2C_SMBUS_BYTE:
201#ifdef HAVE_PEC
202                if (pec) {
203                        if (!(funcs & I2C_FUNC_SMBUS_READ_BYTE_PEC)) {
204                                fprintf(stderr, "Error: Adapter for i2c bus "
205                                        "%d does not have read w/ PEC "
206                                        "capability\n", i2cbus);
207                                exit(1);
208                        }
209                } else
210#endif
211                {
212                        if (!(funcs & I2C_FUNC_SMBUS_READ_BYTE)) {
213                                fprintf(stderr, "Error: Adapter for i2c bus "
214                                        "%d does not have read capability\n",
215                                        i2cbus);
216                                exit(1);
217                        }
218                }
219                break;
220
221        case I2C_SMBUS_BYTE_DATA:
222#ifdef HAVE_PEC
223                if (pec) {
224                        if (!(funcs & I2C_FUNC_SMBUS_READ_BYTE_DATA_PEC)) {
225                                fprintf(stderr, "Error: Adapter for i2c bus "
226                                        "%d does not have byte read w/ PEC "
227                                        "capability\n", i2cbus);
228                                exit(1);
229                        }
230                } else
231#endif
232                {
233                        if (!(funcs & I2C_FUNC_SMBUS_READ_BYTE_DATA)) {
234                                fprintf(stderr, "Error: Adapter for i2c bus "
235                                        "%d does not have byte read "
236                                        "capability\n", i2cbus);
237                                exit(1);
238                        }
239                }
240                break;
241
242        case I2C_SMBUS_WORD_DATA:
243#ifdef HAVE_PEC
244                if (pec) {
245                        if (!(funcs & I2C_FUNC_SMBUS_READ_WORD_DATA_PEC)) {
246                                fprintf(stderr, "Error: Adapter for i2c bus "
247                                        "%d does not have word read w/ PEC "
248                                        "capability\n", i2cbus);
249                                exit(1);
250                        }
251                } else
252#endif
253                {
254                        if (!(funcs & I2C_FUNC_SMBUS_READ_WORD_DATA)) {
255                                fprintf(stderr, "Error: Adapter for i2c bus "
256                                        "%d does not have word read "
257                                        "capability\n", i2cbus);
258                                exit(1);
259                        }
260                }
261                break;
262
263        case I2C_SMBUS_BLOCK_DATA:
264#ifdef HAVE_PEC
265                if (pec) {
266                        if (!(funcs & I2C_FUNC_SMBUS_READ_BLOCK_DATA_PEC)) {
267                                fprintf(stderr, "Error: Adapter for i2c bus "
268                                        "%d does not have smbus block read "
269                                        "w/ PEC capability\n", i2cbus);
270                                exit(1);
271                        }
272                } else
273#endif
274                {
275                        if (!(funcs & I2C_FUNC_SMBUS_READ_BLOCK_DATA)) {
276                                fprintf(stderr, "Error: Adapter for i2c bus "
277                                        "%d does not have smbus block read "
278                                        "capability\n", i2cbus);
279                                exit(1);
280                        }
281                }
282                break;
283
284        case I2C_SMBUS_I2C_BLOCK_DATA:
285                if (!(funcs & I2C_FUNC_SMBUS_READ_I2C_BLOCK)) {
286                        fprintf(stderr, "Error: Adapter for i2c bus %d does "
287                                "not have i2c block read capability\n",
288                                i2cbus);
289                        exit(1);
290                }
291                break;
292        }
293
294        /* use FORCE so that we can look at registers even when
295           a driver is also running */
296        if (ioctl(file, I2C_SLAVE_FORCE, address) < 0) {
297                fprintf(stderr, "Error: Could not set address to %d: %s\n",
298                        address, strerror(errno));
299                exit(1);
300        }
301
302        if (pec) {
303#ifdef HAVE_PEC
304                if (ioctl(file, I2C_PEC, 1) < 0) {
305                        fprintf(stderr, "Error: Could not set PEC: %s\n",
306                                strerror(errno));
307                        exit(1);
308                }
309#else
310                fprintf(stderr, "Error: PEC not supported in your kernel\n");
311                exit(1);
312#endif
313        }
314
315        if (!yes) {
316                char s[2];
317
318                fprintf(stderr, "WARNING! This program can confuse your I2C "
319                        "bus, cause data loss and worse!\n");
320
321                fprintf(stderr, "I will probe file %s, address 0x%x, mode "
322                        "%s\n", filename, address,
323                        size == I2C_SMBUS_BLOCK_DATA ? "smbus block" :
324                        size == I2C_SMBUS_I2C_BLOCK_DATA ? "i2c block" :
325                        size == I2C_SMBUS_BYTE ? "byte consecutive read" :
326                        size == I2C_SMBUS_BYTE_DATA ? "byte" : "word");
327                if (pec)
328                        fprintf(stderr, "PEC checking enabled.\n");
329                if (bank) {
330                        if (size == I2C_SMBUS_BLOCK_DATA)
331                                fprintf(stderr, "Using command 0x%02x.\n",
332                                        bank);
333                        else
334                                fprintf(stderr, "Probing bank %d using bank "
335                                        "register 0x%02x.\n", bank, bankreg);
336                }
337
338                fprintf(stderr, "Continue? [Y/n] ");
339                fflush(stderr);
340                fgets(s, 2, stdin);
341                if (s[0] != '\n' && s[0] != 'y' && s[0] != 'Y') {
342                        fprintf(stderr, "Aborting on user request.\n");
343                        exit(0);
344                }
345        }
346
347        /* See Winbond w83781d data sheet for bank details */
348        if (bank && size != I2C_SMBUS_BLOCK_DATA) {
349                i2c_smbus_write_byte_data(file, bankreg, bank | 0x80);
350        }
351
352        /* handle all but word data */
353        if (size != I2C_SMBUS_WORD_DATA) {
354
355                /* do the block transaction */
356                if (size == I2C_SMBUS_BLOCK_DATA
357                 || size == I2C_SMBUS_I2C_BLOCK_DATA) {
358                        unsigned char cblock[288];
359
360                        if (size == I2C_SMBUS_BLOCK_DATA) {
361                                res = i2c_smbus_read_block_data(file, bank,
362                                      cblock);
363                        } else {
364#if USE_I2C_BLOCK
365                                for (res = 0; res < 256; res += i) {
366                                        i = i2c_smbus_read_i2c_block_data(file,
367                                                res, cblock + res);
368                                        if (i <= 0)
369                                                break;
370                                }
371#else
372                                fprintf(stderr, "Error: I2C block read "
373                                        "unsupported in i2c-core\n");
374                                exit(1);
375#endif
376                        }
377                        if (res <= 0) {
378                                fprintf(stderr, "Error: Block read failed, "
379                                        "return code %d\n", res);
380                                exit(1);
381                        }
382                        if (res >= 256)
383                                res = 256;
384                        for (i = 0; i < res; i++)
385                                block[i] = cblock[i];
386                        for (i = res; i < 256; i++)
387                                block[i] = -1;
388                }
389
390                if (size == I2C_SMBUS_BYTE) {
391                        res = i2c_smbus_write_byte(file, 0);
392                        if(res != 0) {
393                                fprintf(stderr, "Error: Write start address "
394                                        "failed, return code %d\n", res);
395                                exit(1);
396                        }
397                }
398
399                printf("     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f"
400                       "    0123456789abcdef\n");
401                for (i = 0; i < 256; i+=16) {
402                        printf("%02x: ", i);
403                        for (j = 0; j < 16; j++) {
404                                if (size == I2C_SMBUS_BYTE_DATA) {
405                                        block[i+j] = res =
406                                          i2c_smbus_read_byte_data(file, i+j);
407                                } else if (size == I2C_SMBUS_BYTE) {
408                                        block[i+j] = res =
409                                          i2c_smbus_read_byte(file);
410                                } else
411                                        res = block[i+j];
412                                if (res < 0)
413                                        printf("XX ");
414                                else
415                                        printf("%02x ", res & 0xff);
416                        }
417                        printf("   ");
418                        for (j = 0; j < 16; j++) {
419                                res = block[i+j];
420                                if (res < 0)
421                                        printf("X");
422                                else
423                                if ((res & 0xff) == 0x00
424                                 || (res & 0xff) == 0xff)
425                                        printf(".");
426                                else
427                                if ((res & 0xff) < 32
428                                 || (res & 0xff) >= 127)
429                                        printf("?");
430                                else
431                                        printf("%c", res & 0xff);
432                        }
433                        printf("\n");
434                        if (size == I2C_SMBUS_BLOCK_DATA && i == 16)
435                                break;
436                }
437        } else {
438                printf("     0,8  1,9  2,a  3,b  4,c  5,d  6,e  7,f\n");
439                for (i = 0; i < 256; i+=8) {
440                        printf("%02x: ", i);
441                        for (j = 0; j < 8; j++) {
442                                res = i2c_smbus_read_word_data(file, i+j);
443                                if (res < 0)
444                                        printf("XXXX ");
445                                else
446                                        printf("%04x ", res & 0xffff);
447                        }
448                        printf("\n");
449                }
450        }
451        if (bank && size != I2C_SMBUS_BLOCK_DATA) {
452                i2c_smbus_write_byte_data(file, bankreg, 0x80);
453        }
454        exit(0);
455}
Note: See TracBrowser for help on using the browser.