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

Revision 2675, 10.8 KB (checked in by khali, 9 years ago)

Refactor i2c device opening.

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