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

Revision 6048, 11.8 KB (checked in by khali, 3 years ago)

i2c-dev: Move SMBus helper functions to include/i2c/smbus.h

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