eeprog program from

Stefano Barbato
	stefano@codesink.org


git-svn-id: http://lm-sensors.org/svn/lm-sensors/trunk@2099 7894878c-1315-0410-8ee3-d5d059ff63e0
This commit is contained in:
Mark D. Studebaker committed 2003-11-28 03:07:48 +00:00
1 parent 713f3eddb7
commit 0872117cb9
6 files changed
+514 -2

No files matched your search

+181
View File
@@ -0,0 +1,181 @@
/***************************************************************************
copyright : (C) by 2002-2003 Stefano Barbato
email : stefano@codesink.org
$Id$
***************************************************************************/
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <linux/fs.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <errno.h>
#include <assert.h>
#include <string.h>
#include "24cXX.h"
static int i2c_write_1b(struct eeprom *e, __u8 buf)
{
int r;
// we must simulate a plain I2C byte write with SMBus functions
r = i2c_smbus_write_byte(e->fd, buf);
if(r < 0)
fprintf(stderr, "Error i2c_write_1b: %s\n", strerror(errno));
usleep(10);
return r;
}
static int i2c_write_2b(struct eeprom *e, __u8 buf[2])
{
int r;
// we must simulate a plain I2C byte write with SMBus functions
r = i2c_smbus_write_byte_data(e->fd, buf[0], buf[1]);
if(r < 0)
fprintf(stderr, "Error i2c_write_2b: %s\n", strerror(errno));
usleep(10);
return r;
}
static int i2c_write_3b(struct eeprom *e, __u8 buf[3])
{
int r;
// we must simulate a plain I2C byte write with SMBus functions
// the __u16 data field will be byte swapped by the SMBus protocol
r = i2c_smbus_write_word_data(e->fd, buf[0], buf[2] << 8 | buf[1]);
if(r < 0)
fprintf(stderr, "Error i2c_write_3b: %s\n", strerror(errno));
usleep(10);
return r;
}
#define CHECK_I2C_FUNC( var, label ) \
do { if(0 == (var & label)) { \
fprintf(stderr, "\nError: " \
#label " function is required. Program halted.\n\n"); \
exit(1); } \
} while(0);
int eeprom_open(char *dev_fqn, int addr, int type, struct eeprom* e)
{
int funcs, fd, r;
e->fd = e->addr = 0;
e->dev = 0;
fd = open(dev_fqn, O_RDWR);
if(fd <= 0)
return -1;
// get funcs list
if((r = ioctl(fd, I2C_FUNCS, &funcs) < 0))
return r;
// check for req funcs
CHECK_I2C_FUNC( funcs, I2C_FUNC_SMBUS_READ_BYTE );
CHECK_I2C_FUNC( funcs, I2C_FUNC_SMBUS_WRITE_BYTE );
CHECK_I2C_FUNC( funcs, I2C_FUNC_SMBUS_READ_BYTE_DATA );
CHECK_I2C_FUNC( funcs, I2C_FUNC_SMBUS_WRITE_BYTE_DATA );
CHECK_I2C_FUNC( funcs, I2C_FUNC_SMBUS_READ_WORD_DATA );
CHECK_I2C_FUNC( funcs, I2C_FUNC_SMBUS_WRITE_WORD_DATA );
// set working device
if( ( r = ioctl(fd, I2C_SLAVE, addr)) < 0)
return r;
e->fd = fd;
e->addr = addr;
e->dev = dev_fqn;
e->type = type;
return 0;
}
int eeprom_close(struct eeprom *e)
{
close(e->fd);
e->fd = -1;
e->dev = 0;
e->type = EEPROM_TYPE_UNKNOWN;
return 0;
}
#if 0
int eeprom_24c32_write_byte(struct eeprom *e, __u16 mem_addr, __u8 data)
{
__u8 buf[3] = { (mem_addr >> 8) & 0x00ff, mem_addr & 0x00ff, data };
return i2c_write_3b(e, buf);
}
int eeprom_24c32_read_current_byte(struct eeprom* e)
{
ioctl(e->fd, BLKFLSBUF); // clear kernel read buffer
return i2c_smbus_read_byte(e->fd);
}
int eeprom_24c32_read_byte(struct eeprom* e, __u16 mem_addr)
{
int r;
ioctl(e->fd, BLKFLSBUF); // clear kernel read buffer
__u8 buf[2] = { (mem_addr >> 8) & 0x0ff, mem_addr & 0x0ff };
r = i2c_write_2b(e, buf);
if (r < 0)
return r;
r = i2c_smbus_read_byte(e->fd);
return r;
}
#endif
int eeprom_read_current_byte(struct eeprom* e)
{
ioctl(e->fd, BLKFLSBUF); // clear kernel read buffer
return i2c_smbus_read_byte(e->fd);
}
int eeprom_read_byte(struct eeprom* e, __u16 mem_addr)
{
int r;
ioctl(e->fd, BLKFLSBUF); // clear kernel read buffer
if(e->type == EEPROM_TYPE_8BIT_ADDR)
{
__u8 buf = mem_addr & 0x0ff;
r = i2c_write_1b(e, buf);
} else if(e->type == EEPROM_TYPE_16BIT_ADDR) {
__u8 buf[2] = { (mem_addr >> 8) & 0x0ff, mem_addr & 0x0ff };
r = i2c_write_2b(e, buf);
} else {
fprintf(stderr, "ERR: unknown eeprom type\n");
return -1;
}
if (r < 0)
return r;
r = i2c_smbus_read_byte(e->fd);
return r;
}
int eeprom_write_byte(struct eeprom *e, __u16 mem_addr, __u8 data)
{
if(e->type == EEPROM_TYPE_8BIT_ADDR) {
__u8 buf[2] = { mem_addr & 0x00ff, data };
return i2c_write_2b(e, buf);
} else if(e->type == EEPROM_TYPE_16BIT_ADDR) {
__u8 buf[3] =
{ (mem_addr >> 8) & 0x00ff, mem_addr & 0x00ff, data };
return i2c_write_3b(e, buf);
} else {
fprintf(stderr, "ERR: unknown eeprom type\n");
return -1;
}
}
+58
View File
@@ -0,0 +1,58 @@
/***************************************************************************
copyright : (C) by 2002-2003 Stefano Barbato
email : stefano@codesink.org
$Id$
***************************************************************************/
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#ifndef _24CXX_H_
#define _24CXX_H_
#include "i2c-dev.h"
#define EEPROM_TYPE_UNKNOWN 0
#define EEPROM_TYPE_8BIT_ADDR 1
#define EEPROM_TYPE_16BIT_ADDR 2
struct eeprom
{
char *dev; // device file i.e. /dev/i2c-N
int addr; // i2c address
int fd; // file descriptor
int type; // eeprom type
};
/*
* opens the eeprom device at [dev_fqn] (i.e. /dev/i2c-N) whose address is
* [addr] and set the eeprom_24c32 [e]
*/
int eeprom_open(char *dev_fqn, int addr, int type, struct eeprom*);
/*
* closees the eeprom device [e]
*/
int eeprom_close(struct eeprom *e);
/*
* read and returns the eeprom byte at memory address [mem_addr]
* Note: eeprom must have been selected by ioctl(fd,I2C_SLAVE,address)
*/
int eeprom_read_byte(struct eeprom* e, __u16 mem_addr);
/*
* read the current byte
* Note: eeprom must have been selected by ioctl(fd,I2C_SLAVE,address)
*/
int eeprom_read_current_byte(struct eeprom *e);
/*
* writes [data] at memory address [mem_addr]
* Note: eeprom must have been selected by ioctl(fd,I2C_SLAVE,address)
*/
int eeprom_write_byte(struct eeprom *e, __u16 mem_addr, __u8 data);
#endif
+4 -2
View File
@@ -2,11 +2,13 @@
CFLAGS = -O2 -I../../kernel/include
all: eepromer eeprom
all: eepromer eeprom eeprog
eepromer: eepromer.o
eeprom: eeprom.o
eeprog: eeprog.o 24cXX.o
clean:
rm -rf *~ *.o eepromer eeprom
rm -rf *~ *.o eepromer eeprom eeprog
+7
View File
@@ -2,12 +2,19 @@ These programs are used to read and write eeproms.
Use eeprom for small eeproms with one-byte addresses:
24C01, 24C01A, 24C02, 24C04, 24C08, and 24C16
It works only on true i2c bus adapters.
See README.eeprom for details.
Use eepromer for large eeproms with two-byte addresses:
24C32, 24C64, 24C128, 24C256, and 24C512
It works only on true i2c bus adapters.
See README.eepromer for details.
Use eeprog for either small or large eeproms.
Use the -8 switch for small eeproms.
It works on both i2c and smbus bus adapters.
See README.eeprog for details.
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! Warning !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!!! !
+12
View File
@@ -0,0 +1,12 @@
Important! See the README file for important warnings.
eeprog reads and writes 24Cxx EEPROMs connected to I2C serial bus.
It uses the SMBus protocol used by most of the recent chipsets. Don't forget to load
your i2c chipset and the i2c-dev drivers.
Use -8 switch for EEPROM smaller then 24C16 (8bit addressing mode).
Again, it's really important that you read the README file.
Type "make" to compile.
+252
View File
@@ -0,0 +1,252 @@
/***************************************************************************
copyright : (C) by 2002-2003 Stefano Barbato
email : stefano@codesink.org
$Id$
***************************************************************************/
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#include <stdio.h>
#include <fcntl.h>
#include <getopt.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "24cXX.h"
#define VERSION "0.7.4"
#define ENV_DEV "EEPROG_DEV"
#define ENV_I2C_ADDR "EEPROG_I2C_ADDR"
#define usage_if(a) do { do_usage_if( a , __LINE__); } while(0);
void do_usage_if(int b, int line)
{
const static char *eeprog_usage =
"Usage: eeprog [ -r addr[:count] | -w addr ] /dev/i2c-N i2c-address\n"
" -8 Use 8bit address mode for 24c0x...24C16\n"
" -r addr[:count] Read [count] (1 if omitted) bytes from [addr]\n"
" and print them to the standard output\n"
" -w addr Write input (stdin) at mem address [addr]\n"
" -x Set the hex output mode\n"
" -d Dummy mode, display what *would* have been done\n"
" -f Disable warnings and don't ask confirmation\n"
"\n"
"The following environment variables could be set instead of the command\n"
"line arguments:\n"
" EEPROG_DEV device name(/dev/i2c-N)\n"
" EEPROG_I2C_ADDR i2c-address\n"
"\n"
" Examples\n"
" 1- read 64 bytes from the EEPROM at address 0x54 on bus 0 starting\n"
" at address 123 (decimal)\n"
" eeprog /dev/i2c-0 0x54 -r 123:64\n"
" 2- prints the hex codes of the first 32 bytes read from bus 1 \n"
" at address 0x22\n"
" eeprog /dev/i2c-1 0x51 -x -r 0x22:0x20\n"
" 3- write the current timestamp at address 0x200 of the EEPROM on \n"
" bus 0 at address 0x33 \n"
" date | eeprog /dev/i2c-0 0x33 -w 0x200\n";
if(!b)
return;
fprintf(stderr, "%s\n[line %d]\n", eeprog_usage, line);
exit(1);
}
#define die_if(a, msg) do { do_die_if( a , msg, __LINE__); } while(0);
void do_die_if(int b, char* msg, int line)
{
if(!b)
return;
fprintf(stderr, "Error at line %d: %s\n", line, msg);
//fprintf(stderr, " sysmsg: %s\n", strerror(errno));
exit(1);
}
void parse_arg(char *arg, int* paddr, int *psize)
{
char *end;
*paddr = strtoul(arg, &end, 0);
if(*end == ':')
*psize = strtoul(++end, 0, 0);
}
int confirm_action()
{
fprintf(stderr,
"\n"
"__________________________________WARNING_______________________________\n"
"Erroneously writing to a system EEPROM (like DIMM SPD modules) can break your\n"
"system. It will NOT boot any more so you'll not be able to fix it.\n"
"\n"
"Reading from 8bit EEPROMs (like that in your DIMM) without using the -8 switch\n"
"can also UNEXPECTEDLY write to them, so be sure to use the -8 command param when\n"
"required.\n"
"\n"
"Use -f to disable this warning message\n"
"\n"
"Press ENTER to continue or hit CTRL-C to exit\n"
"\n"
);
getchar();
return 1;
}
int read_from_eeprom(struct eeprom *e, int addr, int size, int hex)
{
int c=1;
if(!hex)
{
putchar(eeprom_read_byte(e, addr));
while(--size)
{
putchar(eeprom_read_current_byte(e));
fflush(stdout);
}
return 0;
}
// hex print out
printf("\n %.4x| %.2x ", addr, eeprom_read_byte(e, addr));
while(--size)
{
addr++;
if( (c % 16) == 0 )
printf("\n %.4x| ", addr);
else if( (c % 8) == 0 )
printf(" ");
c++;
printf("%.2x ", eeprom_read_current_byte(e));
}
printf("\n\n");
return 0;
}
int write_to_eeprom(struct eeprom *e, int addr)
{
int c;
while((c = getchar()) != EOF)
{
fprintf(stderr, ".");
fflush(stdout);
eeprom_write_byte(e, addr++, c);
}
printf("\n\n");
return 0;
}
int main(int argc, char** argv)
{
struct eeprom e;
int ret, op, i2c_addr, memaddr, size, want_hex, dummy, force;
char *device, *arg = 0, *i2c_addr_s;
struct stat st;
int eeprom_type = EEPROM_TYPE_16BIT_ADDR;
op = want_hex = dummy = force = 0;
fprintf(stderr, "eeprog %s, a 24Cxx EEPROM reader/writer\n", VERSION);
fprintf(stderr,
"Copyright (c) 2003 by Stefano Barbato - All rights reserved.\n");
while((ret = getopt(argc, argv, "8fr:w:xd")) != -1)
{
switch(ret)
{
case 'x':
want_hex++;
break;
case 'd':
dummy++;
break;
case '8':
eeprom_type = EEPROM_TYPE_8BIT_ADDR;
break;
case 'f':
force++;
break;
default:
die_if(op != 0, "Both read and write requested");
arg = optarg;
op = ret;
}
}
usage_if(op == 0); // no switches
// set device and i2c_addr reading from cmdline or env
device = i2c_addr_s = 0;
switch(argc - optind)
{
case 0:
device = getenv(ENV_DEV);
i2c_addr_s = getenv(ENV_I2C_ADDR);
break;
case 1:
if(stat(argv[optind], &st) != -1)
{
device = argv[optind];
i2c_addr_s = getenv(ENV_I2C_ADDR);
} else {
device = getenv(ENV_DEV);
i2c_addr_s = argv[optind];
}
break;
case 2:
device = argv[optind++];
i2c_addr_s = argv[optind];
break;
default:
usage_if(1);
}
usage_if(!device || !i2c_addr_s);
i2c_addr = strtoul(i2c_addr_s, 0, 0);
fprintf(stderr, " Bus: %s, Address: 0x%x, Mode: %dbit\n",
device, i2c_addr,
(eeprom_type == EEPROM_TYPE_8BIT_ADDR ? 8 : 16) );
if(dummy)
{
fprintf(stderr, "Dummy mode selected, nothing done.\n");
return 0;
}
die_if(eeprom_open(device, i2c_addr, eeprom_type, &e) < 0,
"unable to open eeprom device file (check that the file exists and that it's readable)");
switch(op)
{
case 'r':
if(force == 0)
confirm_action();
size = 1; // default
parse_arg(arg, &memaddr, &size);
fprintf(stderr,
" Reading %d bytes from 0x%x\n", size, memaddr);
read_from_eeprom(&e, memaddr, size, want_hex);
break;
case 'w':
if(force == 0)
confirm_action();
parse_arg(arg, &memaddr, &size);
fprintf(stderr,
" Writing stdin starting at address 0x%x\n", memaddr);
write_to_eeprom(&e, memaddr);
break;
default:
usage_if(1);
exit(1);
}
eeprom_close(&e);
return 0;
}