Logo Search packages:      
Sourcecode: i2c-tools version File versions  Download package

eeprom.c

/*
This program is hereby placed into the public domain.
Of course the program is provided without warranty of any kind.
*/
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <time.h>
#include <linux/i2c-dev.h>

/*
  this program can read 24C16 (and probably smaller ones, too)
  I wrote it as a quick and dirty hack because my satellite receiver
  hung again... so I had to reprogram the eeprom where is stores it's
  settings.
 */

#define DEFAULT_I2C_BUS      "/dev/i2c-0"
#define DEFAULT_EEPROM_ADDR  0x50         /* the 24C16 sits on i2c address 0x50 */
#define DEFAULT_NUM_PAGES    8            /* we default to a 24C16 eeprom which has 8 pages */
#define BYTES_PER_PAGE       256          /* one eeprom page is 256 byte */
#define MAX_BYTES            8            /* max number of bytes to write in one chunk */
       /* ... note: 24C02 and 24C01 only allow 8 bytes to be written in one chunk.   *
        *  if you are going to write 24C04,8,16 you can change this to 16            */

/* write len bytes (stored in buf) to eeprom at address addr, page-offset offset */
/* if len=0 (buf may be NULL in this case) you can reposition the eeprom's read-pointer */
/* return 0 on success, -1 on failure */
int eeprom_write(int fd,
             unsigned int addr,
             unsigned int offset,
             unsigned char *buf,
             unsigned char len
){
      struct i2c_rdwr_ioctl_data msg_rdwr;
      struct i2c_msg             i2cmsg;
      int i;
      char _buf[MAX_BYTES + 1];

      if(len>MAX_BYTES){
          fprintf(stderr,"I can only write MAX_BYTES bytes at a time!\n");
          return -1;
      }

      if(len+offset >256){
          fprintf(stderr,"Sorry, len(%d)+offset(%d) > 256 (page boundary)\n",
                  len,offset);
          return -1;
      }

      _buf[0]=offset;    /* _buf[0] is the offset into the eeprom page! */
      for(i=0;i<len;i++) /* copy buf[0..n] -> _buf[1..n+1] */
          _buf[1+i]=buf[i];

      msg_rdwr.msgs = &i2cmsg;
      msg_rdwr.nmsgs = 1;

      i2cmsg.addr  = addr;
      i2cmsg.flags = 0;
      i2cmsg.len   = 1+len;
      i2cmsg.buf   = _buf;

      if((i=ioctl(fd,I2C_RDWR,&msg_rdwr))<0){
          perror("ioctl()");
          fprintf(stderr,"ioctl returned %d\n",i);
          return -1;
      }

      if(len>0)
          fprintf(stderr,"Wrote %d bytes to eeprom at 0x%02x, offset %08x\n",
                len,addr,offset);
      else
          fprintf(stderr,"Positioned pointer in eeprom at 0x%02x to offset %08x\n",
                addr,offset);

      return 0;
}

/* read len bytes stored in eeprom at address addr, offset offset in array buf */
/* return -1 on error, 0 on success */
int eeprom_read(int fd,
             unsigned int addr,
             unsigned int offset,
             unsigned char *buf,
             unsigned char len
){
      struct i2c_rdwr_ioctl_data msg_rdwr;
      struct i2c_msg             i2cmsg;
      int i;

      if(len>MAX_BYTES){
          fprintf(stderr,"I can only write MAX_BYTES bytes at a time!\n");
          return -1;
      }

      if(eeprom_write(fd,addr,offset,NULL,0)<0)
          return -1;

      msg_rdwr.msgs = &i2cmsg;
      msg_rdwr.nmsgs = 1;

      i2cmsg.addr  = addr;
      i2cmsg.flags = I2C_M_RD;
      i2cmsg.len   = len;
      i2cmsg.buf   = buf;

      if((i=ioctl(fd,I2C_RDWR,&msg_rdwr))<0){
          perror("ioctl()");
          fprintf(stderr,"ioctl returned %d\n",i);
          return -1;
      }

      fprintf(stderr,"Read %d bytes from eeprom at 0x%02x, offset %08x\n",
            len,addr,offset);

      return 0;
}



int main(int argc, char **argv){
    int i,j;

    /* filedescriptor and name of device */
    int d; 
    char *dn=DEFAULT_I2C_BUS;

    /* filedescriptor and name of data file */
    int f=-1;
    char *fn=NULL;

    unsigned int addr=DEFAULT_EEPROM_ADDR;
    int rwmode=0;
    int pages=DEFAULT_NUM_PAGES;

    int force=0; /* suppress warning on write! */
    
    while((i=getopt(argc,argv,"d:a:p:wyf:h"))>=0){
      switch(i){
      case 'h':
          fprintf(stderr,"%s [-d dev] [-a adr] [-p pgs] [-w] [-y] [-f file]\n",argv[0]);
          fprintf(stderr,"\tdev: device, e.g. /dev/i2c-0    (def)\n");
          fprintf(stderr,"\tadr: base address of eeprom, eg 0xA0 (def)\n");
          fprintf(stderr,"\tpgs: number of pages to read, eg 8 (def)\n");
          fprintf(stderr,"\t-w : write to eeprom (default is reading!)\n");
          fprintf(stderr,"\t-y : suppress warning when writing (default is to warn!)\n");
          fprintf(stderr,"\t-f file: copy eeprom contents to/from file\n");
          fprintf(stderr,"\t         (default for read is test only; for write is all zeros)\n");
          fprintf(stderr,"Note on pages/addresses:\n");
          fprintf(stderr,"\teeproms with more than 256 byte appear as if they\n");
          fprintf(stderr,"\twere several eeproms with consecutive addresses on the bus\n");
          fprintf(stderr,"\tso we might as well address several seperate eeproms with\n");
          fprintf(stderr,"\tincreasing addresses....\n\n");
          exit(1);
          break;
      case 'd':
          dn=optarg;
          break;
      case 'a':
          if(sscanf(optarg,"0x%x",&addr)!=1){
            fprintf(stderr,"Cannot parse '%s' as addrs., example: 0xa0\n",
                  optarg);
            exit(1);
          }
          break;
      case 'p':
          if(sscanf(optarg,"%d",&pages)!=1){
            fprintf(stderr,"Cannot parse '%s' as number of pages, example: 8\n",
                  optarg);
            exit(1);
          }
          break;
      case 'w':
          rwmode++;
          break;
      case 'f':
          fn=optarg;
          break;
      case 'y':
          force++;
          break;
      }

    }
   
    fprintf(stderr,"base-address of eeproms       : 0x%02x\n",addr);
    fprintf(stderr,"number of pages to read       : %d (0x%02x .. 0x%02x)\n",
                pages,addr,addr+pages-1);

    if(fn){
      if(!rwmode) /* if we are reading, *WRITE* to file */
          f=open(fn,O_WRONLY|O_CREAT,0666);
      else /* if we are writing to eeprom, *READ* from file */
          f=open(fn,O_RDONLY);
      if(f<0){
          fprintf(stderr,"Could not open data-file %s for reading or writing\n",fn);
          perror(fn);
          exit(1);
      }
      fprintf(stderr,"file opened for %7s       : %s\n",rwmode?"reading":"writing",fn);
      fprintf(stderr,"            on filedescriptor : %d\n",f);
    }

    if((d=open(dn,O_RDWR))<0){
      fprintf(stderr,"Could not open i2c at %s\n",dn);
      perror(dn);
      exit(1);
    }

    fprintf(stderr,"i2c-devicenode is             : %s\n",dn);
    fprintf(stderr,"            on filedescriptor : %d\n\n",d);

    /***
     *** I'm not the one to blame of you screw your computer!
     ***/
    if(rwmode && ! force){
      unsigned char warnbuf[4];
      fprintf(stderr,"**WARNING**\n");
      fprintf(stderr," - \tYou have chosen to WRITE to this eeprom.\n");
      fprintf(stderr,"\tMake sure that this tiny chip is *NOT* vital to the\n");
      fprintf(stderr,"\toperation of your computer as you can easily corrupt\n");
      fprintf(stderr,"\tthe configuration memory of your SDRAM-memory-module,\n");
      fprintf(stderr,"\tyour IBM ThinkPad or whatnot...! Fixing these errors can be\n");
      fprintf(stderr,"\ta time-consuming and very costly process!\n\n");
      fprintf(stderr,"Things to consider:\n");
      fprintf(stderr," - \tYou can have more than one i2c-bus, check in /proc/bus/i2c\n");
      fprintf(stderr,"\tand specify the correct one with -d\n");
      fprintf(stderr,"\tright now you have chosen to use '%s'\n",dn);
      fprintf(stderr," - \tA eeprom can occupy several i2c-addresses (one per page)\n");
      fprintf(stderr,"\tso please make sure that there is no vital eeprom in your computer\n");
      fprintf(stderr,"\tsitting at addresses between 0x%02x and 0x%02x\n",addr,addr+pages-1);

      fprintf(stderr,"Enter 'yes' to continue:");
      fflush(stderr);
      if(!fgets(warnbuf,sizeof(warnbuf),stdin)){
          fprintf(stderr,"\nCould not read confirmation from stdin!\n");
          exit(1);
      }
      if(strncmp(warnbuf,"yes",3)){
          fprintf(stderr,"\n** ABORTING WRITE! **, you did not answer 'yes'\n");
          exit(1);
      }
    }

    for(i=0;i<pages;i++){
      unsigned char buf[BYTES_PER_PAGE];

      if(rwmode){

          if(f>=0){
            j=read(f,buf,sizeof(buf));
            if(j<0){
                fprintf(stderr,"Cannot read from file '%s'\n",fn);
                perror(fn);
                exit(1);
            }
            if(j!=sizeof(buf)){
                fprintf(stderr,"File '%s' is too small, padding eeprom with zeroes\n",fn);
                while(j<sizeof(buf))
                  buf[j++]=0;
            }
          } else {
            for(j=0;j<sizeof(buf);j++)
                buf[j]=0;
          }
            for(j=0;j<(BYTES_PER_PAGE/MAX_BYTES);j++)
            if(eeprom_write(d,addr+i,j*MAX_BYTES,buf+(j*MAX_BYTES),MAX_BYTES)<0)
                exit(1);
      } else {
            for(j=0;j<(BYTES_PER_PAGE/MAX_BYTES);j++)
            if(eeprom_read(d,addr+i,j*MAX_BYTES,buf+(j*MAX_BYTES),MAX_BYTES)<0)
                exit(1);
      }


      if(!rwmode && f>=0){
          j=write(f,buf,sizeof(buf));
          if(j!=sizeof(buf)){
            fprintf(stderr,"Cannot write to file '%s'\n",fn);
            perror(fn);
            exit(1);
          }
      }

    }

    if(f>=0)
      close(f);

    close(d);

    exit(0);

}

Generated by  Doxygen 1.6.0   Back to index