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

Revision 1390, 10.3 KB (checked in by mds, 11 years ago)

add ability to specify the "command" on a smbus block read

(previously forced to zero). Limit smbus block read printout to 32 bytes.

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