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

Revision 4417, 11.1 KB (checked in by khali, 7 years ago)

Support and use the new I2C block read with variable length which will
be available in Linux kernel 2.6.23. Binary compatibility is guaranteed,
source code compatibility isn't, but the incompatibility will be
spotted quickly as the prototype of the helper function
i2c_smbus_read_i2c_block_data() changed. The only problem would be if
a program is calling i2c_smbus_access() directly. Hopefully this should
be a rare case. The py-smbus binding code is in this case and will be
adjusted soon.

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