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

Revision 1445, 11.7 KB (checked in by mds, 11 years ago)

add PEC support

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1/*
2    i2cdump.c - Part of i2cdump, a user-space program to dump I2C registers
3    Copyright (c) 2002  Frodo Looijaard <frodol@dds.nl>, and
4    Mark D. Studebaker <mdsxyz123@yahoo.com>
5
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 2 of the License, or
9    (at your option) any later version.
10
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, write to the Free Software
18    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19*/
20
21#include <errno.h>
22#include <string.h>
23#include <stdio.h>
24#include <stdlib.h>
25#include <unistd.h>
26#include <fcntl.h>
27#include <linux/i2c-dev.h>
28
29/*
30   We don't use this #define but it was put into i2c.h at the same time as
31   i2c_smbus_read_i2c_block_data() was implemented (i2c 2.6.3),
32   so we use it as a version check.
33*/
34#ifdef I2C_FUNC_SMBUS_READ_I2C_BLOCK_2
35#define USE_I2C_BLOCK 1
36#else
37#define USE_I2C_BLOCK 0
38#endif
39
40#ifdef I2C_FUNC_SMBUS_BLOCK_DATA_PEC
41#define HAVE_PEC 1
42#endif
43
44void help(void)
45{
46  FILE *fptr;
47  char s[100];
48
49  fprintf(stderr,"Syntax: i2cdump I2CBUS ADDRESS [MODE] [BANK [BANKREG]]\n");
50  fprintf(stderr,"  MODE is 'b[yte]', 'w[ord]', 's[mbusblock], or 'i[2cblock]' (default b)\n");
51  fprintf(stderr,"  Append MODE with 'p' for PEC checking\n");
52  fprintf(stderr,"  I2CBUS is an integer\n");
53  fprintf(stderr,"  ADDRESS is an integer 0x00 - 0x7f\n");
54  fprintf(stderr,"  BANK and BANKREG are for byte and word accesses (default bank 0, reg 0x4e)\n");
55  fprintf(stderr,"  BANK is the command for smbusblock accesses (default 0)\n");
56  if((fptr = fopen("/proc/bus/i2c", "r"))) {
57    fprintf(stderr,"  Installed I2C busses:\n");
58    while(fgets(s, 100, fptr))
59      fprintf(stderr, "    %s", s);     
60    fclose(fptr);
61  }
62}
63
64int main(int argc, char *argv[])
65{
66  char *end;
67  int i,j,res,res2,i2cbus,address,size,file;
68  int e1, e2, e3;
69  int bank = 0, bankreg = 0x4E;
70  char filename1[20];
71  char filename2[20];
72  char filename3[20];
73  char *filename;
74  long funcs;
75  unsigned char cblock[256]; 
76  int block[256]; 
77  int pec = 0;
78
79  if (argc < 2) {
80    fprintf(stderr,"Error: No i2c-bus specified!\n");
81    help();
82    exit(1);
83  }
84
85  i2cbus = strtol(argv[1],&end,0);
86  if (*end) {
87    fprintf(stderr,"Error: First argument not a number!\n");
88    help();
89    exit(1);
90  }
91  if ((i2cbus < 0) || (i2cbus > 0xff)) {
92    fprintf(stderr,"Error: I2CBUS argument out of range!\n");
93    help();
94  }
95
96  if (argc < 3) {
97    fprintf(stderr,"Error: No address specified!\n");
98    help();
99    exit(1);
100  }
101  address = strtol(argv[2],&end,0);
102  if (*end) {
103    fprintf(stderr,"Error: Second argument not a number!\n");
104    help();
105    exit(1);
106  }
107  if ((address < 0) || (address > 0x7f)) {
108    fprintf(stderr,"Error: Address out of range!\n");
109    help();
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 (!strcmp(argv[3],"i"))
125    size = I2C_SMBUS_I2C_BLOCK_DATA;
126  else {
127    fprintf(stderr,"Error: Invalid mode!\n");
128    help();
129    exit(1);
130  }
131
132  if(argc > 4) {
133    bank = strtol(argv[4],&end,0);
134    if (*end || size == I2C_SMBUS_I2C_BLOCK_DATA) {
135      fprintf(stderr,"Error: Invalid bank number!\n");
136      help();
137      exit(1);
138    }
139    if (((size == I2C_SMBUS_BYTE_DATA) || (size == I2C_SMBUS_WORD_DATA)) &&
140        ((bank < 0) || (bank > 15))) {
141      fprintf(stderr,"Error: bank out of range!\n");
142      help();
143      exit(1);
144    }
145    if (((size == I2C_SMBUS_BLOCK_DATA)) &&
146        ((bank < 0) || (bank > 0xff))) {
147      fprintf(stderr,"Error: block command out of range!\n");
148      help();
149      exit(1);
150    }
151
152    if(argc > 5) {
153      bankreg = strtol(argv[5],&end,0);
154      if (*end || size == I2C_SMBUS_BLOCK_DATA) {
155        fprintf(stderr,"Error: Invalid bank register number!\n");
156        help();
157        exit(1);
158      }
159      if ((bankreg < 0) || (bankreg > 0xff)) {
160        fprintf(stderr,"Error: bank out of range (0-0xff)!\n");
161        help();
162        exit(1);
163      }
164    }
165  }
166
167/*
168 * Try all three variants and give the correct error message
169 * upon failure
170 */
171
172  sprintf(filename1,"/dev/i2c-%d",i2cbus);
173  sprintf(filename2,"/dev/i2c%d",i2cbus);
174  sprintf(filename3,"/dev/i2c/%d",i2cbus);
175  if ((file = open(filename1,O_RDWR)) < 0) {
176    e1 = errno;
177    if ((file = open(filename2,O_RDWR)) < 0) {
178      e2 = errno;
179      if ((file = open(filename3,O_RDWR)) < 0) {
180        e3 = errno;
181        if(e1 == ENOENT && e2 == ENOENT && e3 == ENOENT) {
182          fprintf(stderr,"Error: Could not open file `%s', `%s', or `%s': %s\n",
183                     filename1,filename2,filename3,strerror(ENOENT));
184        }
185        if (e1 != ENOENT) {
186          fprintf(stderr,"Error: Could not open file `%s' : %s\n",
187                     filename1,strerror(e1));
188          if(e1 == EACCES)
189            fprintf(stderr,"Run as root?\n");
190        }
191        if (e2 != ENOENT) {
192          fprintf(stderr,"Error: Could not open file `%s' : %s\n",
193                     filename2,strerror(e2));
194          if(e2 == EACCES)
195            fprintf(stderr,"Run as root?\n");
196        }
197        if (e3 != ENOENT) {
198          fprintf(stderr,"Error: Could not open file `%s' : %s\n",
199                     filename3,strerror(e3));
200          if(e3 == EACCES)
201            fprintf(stderr,"Run as root?\n");
202        }
203        exit(1);
204      } else {
205         filename = filename3;
206      }
207    } else {
208       filename = filename2;
209    }
210  } else {
211    filename = filename1;
212  }
213 
214  /* check adapter functionality */
215  if (ioctl(file,I2C_FUNCS,&funcs) < 0) {
216    fprintf(stderr,
217            "Error: Could not get the adapter functionality matrix: %s\n",
218            strerror(errno));
219    exit(1);
220  }
221
222  switch(size) {
223     case I2C_SMBUS_BYTE_DATA:
224#ifdef HAVE_PEC
225        if(pec) {
226          if (! (funcs & I2C_FUNC_SMBUS_READ_BYTE_DATA_PEC)) {
227             fprintf(stderr, "Error: Adapter for i2c bus %d", i2cbus);
228             fprintf(stderr, " does not have byte read w/ PEC capability\n");
229             exit(1);
230          }       
231        } else
232#endif
233        {
234          if (! (funcs & I2C_FUNC_SMBUS_READ_BYTE_DATA)) {
235             fprintf(stderr, "Error: Adapter for i2c bus %d", i2cbus);
236             fprintf(stderr, " does not have byte read capability\n");
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 %d", i2cbus);
247             fprintf(stderr, " does not have word read w/ PEC capability\n");
248             exit(1);
249          }       
250        } else
251#endif
252        {
253          if (! (funcs & I2C_FUNC_SMBUS_READ_WORD_DATA)) {
254             fprintf(stderr, "Error: Adapter for i2c bus %d", i2cbus);
255             fprintf(stderr, " does not have word read capability\n");
256             exit(1);
257          }       
258        }
259        break;
260
261     case I2C_SMBUS_BLOCK_DATA:
262#ifdef HAVE_PEC
263        if(pec) {
264          if (! (funcs & I2C_FUNC_SMBUS_READ_BLOCK_DATA_PEC)) {
265             fprintf(stderr, "Error: Adapter for i2c bus %d", i2cbus);
266             fprintf(stderr, " does not have smbus block read capability\n");
267             exit(1);
268          }       
269        } else
270#endif
271        {
272          if (! (funcs & I2C_FUNC_SMBUS_READ_BLOCK_DATA)) {
273             fprintf(stderr, "Error: Adapter for i2c bus %d", i2cbus);
274             fprintf(stderr, " does not have smbus block read w/ PEC capability\n");
275             exit(1);
276          }       
277        }
278        break;
279
280     case I2C_SMBUS_I2C_BLOCK_DATA:
281        if (! (funcs & I2C_FUNC_SMBUS_READ_I2C_BLOCK)) {
282           fprintf(stderr, "Error: Adapter for i2c bus %d", i2cbus);
283           fprintf(stderr, " does not have i2c block read capability\n");
284           exit(1);
285        }       
286        break;
287
288  }
289  /* use FORCE so that we can look at registers even when
290     a driver is also running */
291  if (ioctl(file,I2C_SLAVE_FORCE,address) < 0) {
292    fprintf(stderr,"Error: Could not set address to %d: %s\n",address,
293            strerror(errno));
294    exit(1);
295  }
296 
297  if(pec) {
298#ifdef HAVE_PEC
299    if (ioctl(file,I2C_PEC, 1) < 0) {
300      fprintf(stderr,"Error: Could not set PEC: %s\n", strerror(errno));
301      exit(1);
302    }
303#else
304    fprintf(stderr,"Error: PEC not supported in your kernel\n");
305    exit(1);
306#endif
307  }
308
309  fprintf(stderr,"  WARNING! This program can confuse your I2C bus, "
310          "cause data loss and worse!\n");
311  fprintf(stderr,"  I will probe file %s, address 0x%x, mode %s\n",
312          filename,address,size == I2C_SMBUS_BLOCK_DATA ? "smbus block" :
313                           size == I2C_SMBUS_I2C_BLOCK_DATA ? "i2c block" :
314                           size == I2C_SMBUS_BYTE_DATA ? "byte" : "word");
315  if(pec)
316    fprintf(stderr,"  with PEC checking.\n", bank);
317  if(bank) {   
318    if(size == I2C_SMBUS_BLOCK_DATA)
319      fprintf(stderr,"  Using command 0x%02x.\n", bank);
320    else
321      fprintf(stderr,"  Probing bank %d using bank register 0x%02x.\n",
322              bank, bankreg);
323  }
324  fprintf(stderr,"  You have five seconds to reconsider and press CTRL-C!\n\n");
325  sleep(5);
326
327  /* See Winbond w83781d data sheet for bank details */
328  if(bank && size != I2C_SMBUS_BLOCK_DATA) {
329    i2c_smbus_write_byte_data(file,bankreg,bank | 0x80);
330  }
331
332  /* handle all but word data */
333  if (size != I2C_SMBUS_WORD_DATA) {
334
335    /* do the block transaction */
336    if(size == I2C_SMBUS_BLOCK_DATA || size == I2C_SMBUS_I2C_BLOCK_DATA) {
337      if(size == I2C_SMBUS_BLOCK_DATA) {
338        res = i2c_smbus_read_block_data(file, bank, cblock);
339      } else if(size == I2C_SMBUS_I2C_BLOCK_DATA) {
340#if USE_I2C_BLOCK
341        res = 0;
342        for (i = 0; i < 256; i+=32) {
343          res2 = i2c_smbus_read_i2c_block_data(file, i, cblock+i);
344          if(res2 <= 0)
345            break;
346          res += res2;
347        }
348#else
349        fprintf(stderr, "Error: I2C block read unsupported in i2c-core\n");
350        exit(1);
351#endif
352      }
353      if(res <= 0) {
354        fprintf(stderr, "Error: Block read failed, return code %d\n", res);
355        exit(1);
356      }
357      if(res >= 256)
358        res = 256;
359      for (i = 0; i < res; i++)
360        block[i] = cblock[i];
361      for (i = res; i < 256; i++)
362        block[i] = -1;
363    }
364
365    printf("     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f    0123456789abcdef\n");
366    for (i = 0; i < 256; i+=16) {
367      printf("%02x: ",i);
368      for(j = 0; j < 16; j++) {
369        if(size == I2C_SMBUS_BYTE_DATA) {
370          res = i2c_smbus_read_byte_data(file,i+j);
371          block[i+j] = res;
372        } else
373          res = block[i+j];
374        if (res < 0)
375          printf("XX ");
376        else
377          printf("%02x ",res & 0xff);
378      }
379      printf("   ");
380      for(j = 0; j < 16; j++) {
381        res = block[i+j];
382        if (res < 0)
383          printf("X");
384        else if (((res & 0xff) == 0x00) || ((res & 0xff) == 0xff))
385          printf(".");
386        else if (((res & 0xff) < 32) || ((res & 0xff) >= 127))
387          printf("?");
388        else
389          printf("%c",res & 0xff);
390      }
391      printf("\n");
392    if(size == I2C_SMBUS_BLOCK_DATA && i == 16)
393      break;           
394    }
395  } else {
396    printf("     0,8  1,9  2,a  3,b  4,c  5,d  6,e  7,f\n");
397    for (i = 0; i < 256; i+=8) {
398      printf("%02x: ",i);
399      for(j = 0; j < 8; j++) {
400        res = i2c_smbus_read_word_data(file,i+j);
401        if (res < 0)
402          printf("XXXX ");
403        else
404          printf("%04x ",res & 0xffff);
405      }
406      printf("\n");
407    }
408  }
409  if(bank && size != I2C_SMBUS_BLOCK_DATA) {
410    i2c_smbus_write_byte_data(file,bankreg,0x80);
411  }
412  exit(0);
413}
Note: See TracBrowser for help on using the browser.