Add eeprog

This commit is contained in:
Jeremy Soller
2020-12-01 09:52:26 -07:00
parent ddbe02ec37
commit 78ee2df236
17 changed files with 1789 additions and 315 deletions

View File

@@ -0,0 +1,203 @@
/***************************************************************************
copyright : (C) by 2003-2004 Stefano Barbato
email : stefano@codesink.org
Copyright (C) 2011 by Kris Rusocki <kszysiu@gmail.com>
- support for user-defined write cycle time
$Id: 24cXX.c,v 1.5 2004/02/29 11:05:28 tat Exp $
***************************************************************************/
/***************************************************************************
* *
* 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, int write_cycle_time, struct eeprom* e)
{
int funcs, fd, r;
e->fd = e->addr = 0;
e->dev = 0;
fd = open(dev_fqn, O_RDWR);
if(fd <= 0)
{
fprintf(stderr, "Error eeprom_open: %s\n", strerror(errno));
return -1;
}
// get funcs list
if((r = ioctl(fd, I2C_FUNCS, &funcs) < 0))
{
fprintf(stderr, "Error eeprom_open: %s\n", strerror(errno));
return -1;
}
// 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)
{
fprintf(stderr, "Error eeprom_open: %s\n", strerror(errno));
return -1;
}
e->fd = fd;
e->addr = addr;
e->dev = dev_fqn;
e->type = type;
e->write_cycle_time = write_cycle_time;
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)
{
int ret;
if(e->type == EEPROM_TYPE_8BIT_ADDR) {
__u8 buf[2] = { mem_addr & 0x00ff, data };
ret = i2c_write_2b(e, buf);
if (ret == 0 && e->write_cycle_time != 0) {
usleep(1000 * e->write_cycle_time);
}
return ret;
} else if(e->type == EEPROM_TYPE_16BIT_ADDR) {
__u8 buf[3] =
{ (mem_addr >> 8) & 0x00ff, mem_addr & 0x00ff, data };
ret = i2c_write_3b(e, buf);
if (ret == 0 && e->write_cycle_time != 0) {
usleep(1000 * e->write_cycle_time);
}
return ret;
}
fprintf(stderr, "ERR: unknown eeprom type\n");
return -1;
}

View File

@@ -0,0 +1,62 @@
/***************************************************************************
copyright : (C) by 2003-2004 Stefano Barbato
email : stefano@codesink.org
Copyright (C) 2011 by Kris Rusocki <kszysiu@gmail.com>
- support for user-defined write cycle time
$Id: 24cXX.h,v 1.6 2004/02/29 11:05:28 tat Exp $
***************************************************************************/
/***************************************************************************
* *
* 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
int write_cycle_time;
};
/*
* 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, int delay, 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

View File

@@ -0,0 +1,21 @@
29.02.2004, 0.7.6
- better error handling
- read_from_eeprom bug fixed, thanks to Marek Michalkiewicz
02.12.2003, 0.7.5
- help switch (-h) added
- 8bit addressing is now the default (safest)
- 16bit mode switch added (-16)
- quiet mode has been added (-q)
28.11.2003, 0.7.4
- force switch added (-f)
- big warning will be displayed before reading/writing, user must
confirm
- i2c-dev.h has been (re)included into the distribution package because
user space functions have been removed from the original i2c-dev.h
by the dev team.
21.11.2003, 0.7.3
- ChangeLog added
- WARNING file added
- support for 8bit addressing EEPROMs (-8 command line switch)
- better code documentation
- i2c-dev.h is no more included into the dist package.

View File

@@ -0,0 +1,32 @@
CFLAGS=-g -Wall -O2
PREFIX=/usr/bin
all: eeprog
eeprog: eeprog.o 24cXX.o
eeprog-static: eeprog.o 24cXX.o
$(CC) -static -o $@ $?
clean:
$(RM) eeprog eeprog.o 24cXX.o
distclean: clean
$(RM) *~
$(RM) dist/*~
install: eeprog
install -ps eeprog $(PREFIX)/eeprog-tear
install -p dist/eeprog-spd-dump $(PREFIX)
install -p dist/eeprog-spd-flash $(PREFIX)
install -p dist/eeprog-spd-dump-g34 $(PREFIX)
install -p dist/eeprog-spd-flash-g34 $(PREFIX)
uninstall:
$(RM) $(PREFIX)/eeprog-tear
$(RM) $(PREFIX)/eeprog-spd-dump
$(RM) $(PREFIX)/eeprog-spd-flash
$(RM) $(PREFIX)/eeprog-spd-dump-g34
$(RM) $(PREFIX)/eeprog-spd-flash-g34
.PHONY: all clean distclean install uninstall

View File

@@ -0,0 +1,12 @@
Important! See the WARNING file.
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 -16 switch for EEPROMs larger than 24C16 (16bit addressing mode).
Again, it's really important that you read the WARNING file.
Type "make" to compile.

View File

@@ -0,0 +1,20 @@
Writing to unknown EEPROMs can break your computer.
DIMMs contain an EEPROM and if you overwrite it, your computer
may not boot anymore.
Reading 8bit EEPROM using 16bit addressing may actually WRITE
to the EEPROM. Be careful.
The following chips use 8bit mode:
24C01
24C02
24C04
24C08
24C16
Bigger ones use 16bit addressing so you must use -16.
When in doubt, check data sheets.
If you are not sure what you're doing, DO NOT use this tool.

View File

@@ -0,0 +1 @@
eeprog-spd-dump-0.11

View File

@@ -0,0 +1,115 @@
#!/bin/bash
#
# eeprog-spd-dump 0.11, SPD dump utility
#
# Copyright (c) 2010-2014 by Kris Rusocki <kszysiu@gmail.com>
# Licensed under GPLv2
#
# Boards supported: generic utility, YMMV
#
check_for()
{
[ -z $1 ] && return 1
which $1 > /dev/null 2>&1 || return 1
return 0
}
missing_tool()
{
echo
echo ERROR: \'$1\' is not available on your system. Please install package providing \'$1\'.
}
usage()
{
echo Usage:
echo -e \\t"$0" \<index\>
echo -e \\t\\tdumps SPD at I2C address 0x50 + \<index\>
echo
echo -e \\t"$0" all
echo -e \\t\\tdumps all SPDs \(I2C addresses 0x50 through 0x57\)
exit 1
}
[ -z "$1" ] && usage
INDEX=$1
if [ "$INDEX" = "all" ]; then
START=0
END=7
else
[ "$INDEX" != "$(echo $INDEX | tr -cd 0-9)" ] && INDEX=x
if [ "$INDEX" != $(($INDEX)) -o $(($INDEX)) -lt 0 -o $(($INDEX)) -gt 7 ]; then
echo \<index\> must be a number \(0-7\) or \"all\"
exit 1
fi
INDEX=$(($INDEX))
START=$INDEX
END=$INDEX
fi
DMIDECODE=dmidecode
MODPROBE=modprobe
EEPROG=eeprog-tear
PREREQUISITES="id head $DMIDECODE $MODPROBE $EEPROG"
ERRORS=0
MISSING=1
for i in $PREREQUISITES ; do
[ $MISSING -ne 0 ] && echo -n Checking for
echo -n \ $i
MISSING=0
if ! check_for $i ; then
MISSING=1
missing_tool $i
ERRORS=1
fi
done
echo \ ...done.
if [ $ERRORS -ne 0 ]; then
exit 1
fi
if [ "$(id -ru)" != "0" ]; then
echo ERROR: need root privileges.
exit 1
fi
BOARD=$($DMIDECODE -s baseboard-product-name | head -1)
if [ "$BOARD" = "H8QG6" -o "$BOARD" = "H8QGL" ]; then
$MODPROBE ipmi_si
if ls -d /sys/devices/platform/ipmi_bmc* > /dev/null 2>&1 ; then
echo ERROR: BMC\(s\) found. Please disable IPMI and try again.
exit 1
fi
fi
$MODPROBE -r eeprom 2> /dev/null
$MODPROBE i2c_dev
[ -z "$EEPROG_DEV" ] && EEPROG_DEV=/dev/i2c-0
echo Processing ...
for i in $(seq $((0x50+$START)) $((0x50+$END))) ; do
IHEX=0x$(printf '%x' $i)
OUT=spd-$BOARD-$IHEX.bin
echo -n Reading DIMM at address $IHEX ...
$EEPROG -8 -f -r 0:256 $EEPROG_DEV $i > "$OUT" 2> /dev/null
RET=$?
if [ $RET -eq 2 ]; then
echo
echo ERROR: cannot access $EEPROG_DEV
exit 1
fi
if [ $RET -ne 0 ]; then
echo
echo DIMM at address $IHEX not populated \(or encountered I2C error\)
rm "$OUT"
else
echo done.
fi
done

View File

@@ -0,0 +1 @@
eeprog-spd-dump-g34-0.11

View File

@@ -0,0 +1,200 @@
#!/bin/bash
#
# eeprog-spd-dump-g34 0.11, SPD dump utility for G34 boards
#
# Copyright (c) 2010-2014 by Kris Rusocki <kszysiu@gmail.com>
# Licensed under GPLv2
#
# Boards supported: Tyan S8812, Supermicro H8QGi/H8QG6/H8QGL series
#
SMBUS=/proc/bus/pci/00/14.0
read_smbus()
{
local out
[ -z $1 ] && return 1
[ -z $SMBUS ] && return 1
[ $(($1 % 4)) -ne 0 ] && return 1
out=0x$(dd bs=4 if=$SMBUS skip=$(($1/4)) count=1 status=noxfer 2> /dev/null | od -tx1 -An | tr -d ' ')
[ $? -ne 0 ] && return 1
echo $out
return 0
}
write_smbus()
{
[ -z $1 ] && return 1
[ -z $2 ] && return 1
[ -z $SMBUS ] && return 1
[ $(($1 % 4)) -ne 0 ] && return 1
echo -en $(printf '%08x' $2 | sed -e s/../\\\\x\&/g) | dd bs=4 of=$SMBUS conv=notrunc seek=$(($1/4)) status=noxfer 2> /dev/null
return $?
}
dimm_bank()
{
[ -z $1 ] && return 1
[ -z "$BOARD" ] && return 1
[ -z "$I2CSET" ] && return 1
if [ "$BOARD" = "S8812" ]; then
$I2CSET -y 0 0x71 $(($1+4))
return $?
fi
if [ "$BOARD" = "H8QG6" -o "$BOARD" = "H8QGL" ]; then
local GPIO
GPIO=$(read_smbus 0x50)
[ $? -ne 0 ] && return 1
GPIO=$((($GPIO & 0xFFFFFCFF) | ($1 << 8)))
write_smbus 0x50 $GPIO
[ $? -ne 0 ] && return 1
return 0
fi
return 1
}
check_for()
{
[ -z $1 ] && return 1
which $1 > /dev/null 2>&1 || return 1
return 0
}
missing_tool()
{
echo
echo ERROR: \'$1\' is not available on your system. Please install package providing \'$1\'.
}
usage()
{
echo Usage:
echo -e \\t"$0" \<cpu\>
echo -e \\t\\tdumps SPDs of all DIMM modules of given CPU
echo
echo -e \\t"$0" all
echo -e \\t\\tdumps SPDs of all DIMM modules
exit 1
}
[ -z "$1" ] && usage
CPU=$1
CPUMASK=0
if [ "$CPU" = "all" ]; then
CPUMASK=15
else
[ "$CPU" != "$(echo $CPU | tr -cd 0-9)" ] && CPU=x
if [ "$CPU" != $(($CPU)) -o $(($CPU)) -lt 0 -o $(($CPU)) -gt 3 ]; then
echo \<cpu\> must be a number \(0-3\) or \"all\"
exit 1
fi
CPU=$(($CPU))
CPUMASK=$((1 << $CPU))
fi
DMIDECODE=dmidecode
MODPROBE=modprobe
I2CSET=i2cset
EEPROG=eeprog-tear
PREREQUISITES="id head sed od tr seq dd find awk lspci $DMIDECODE $MODPROBE $I2CSET $EEPROG"
ERRORS=0
MISSING=1
for i in $PREREQUISITES ; do
[ $MISSING -ne 0 ] && echo -n Checking for
echo -n \ $i
MISSING=0
if ! check_for $i ; then
MISSING=1
missing_tool $i
ERRORS=1
fi
done
echo \ ...done.
if [ $ERRORS -ne 0 ]; then
exit 1
fi
if [ "$(id -ru)" != "0" ]; then
echo ERROR: need root privileges.
exit 1
fi
BOARD=$($DMIDECODE -s baseboard-product-name | head -1)
if [ "$BOARD" != "S8812" -a "$BOARD" != "H8QG6" -a "$BOARD" != "H8QGL" ]; then
echo ERROR: unsupported board: \""$BOARD"\"
fi
if [ "$BOARD" = "H8QG6" -o "$BOARD" = "H8QGL" ]; then
$MODPROBE ipmi_si
if ls -d /sys/devices/platform/ipmi_bmc* > /dev/null 2>&1 ; then
echo ERROR: BMC\(s\) found. Please disable IPMI and try again.
exit 1
fi
fi
INCREMENT=1
if [ "$BOARD" = "H8QGL" ]; then
INCREMENT=2
fi
$MODPROBE -r eeprom 2> /dev/null
$MODPROBE i2c_dev
if [ -z "$EEPROG_DEV" ]; then
echo Discovering i2c bus ...
# EEPROG_DEV=$(ls /sys/bus/pci/devices/0000:00:14.0/i2c-*/i2c-dev 2> /dev/null)
# EEPROG_DEV=$(ls /sys/bus/pci/devices/0000:$(lspci -nm | awk '/ "1002" "4385" / { print $1 }')/i2c-*/i2c-dev 2> /dev/null)
EEPROG_DEV=$(find /sys/bus/pci/devices/0000:$(lspci -nm | awk '/ "1002" "4385" / { print $1 }')/i2c-*/i2c-dev -mindepth 1 -maxdepth 1 -printf '%f ' | (read -a A ; if [ ${#A[*]} -gt 1 ]; then echo WARNING: multiple matching I2C interfaces found: ${A[*]}. Using ${A[0]}. Override with EEPROG_DEV if necessary. >&2 ; fi ; echo ${A[0]}))
fi
if [ -z "$EEPROG_DEV" ]; then
echo WARNING: PCI device 1002:4385 not found or has no I2C busses! Using i2c-0. >&2
EEPROG_DEV=i2c-0
fi
EEPROG_DEV=/dev/$EEPROG_DEV
echo Using i2c bus at $EEPROG_DEV
if [ "$BOARD" = "S8812" ]; then
# pre-set the Tyan
$I2CSET -y 0 0x72 0
fi
bit=1
cpu=0
while [ $cpu -lt 4 ]; do
if [ $(($bit & $CPUMASK)) -ne 0 ]; then
echo Processing CPU $cpu ...
dimm_bank $cpu
if [ $? -ne 0 ]; then
echo ERROR: dimm_bank $cpu failed
exit 1
fi
for i in $(seq $((0x50)) $INCREMENT $((0x57))) ; do
IHEX=0x$(printf '%x' $i)
OUT=spd-$BOARD-CPU-$cpu-$IHEX.bin
echo -n Reading DIMM at address $IHEX ...
$EEPROG -8 -f -r 0:256 $EEPROG_DEV $i > "$OUT" 2> /dev/null
RET=$?
if [ $RET -eq 2 ]; then
echo
echo ERROR: cannot access $EEPROG_DEV
exit 1
fi
if [ $RET -ne 0 ]; then
echo
echo DIMM at address $IHEX not populated \(or encountered I2C error\)
rm "$OUT"
else
echo done.
fi
done
fi
cpu=$(($cpu+1))
bit=$(($bit << 1))
done

View File

@@ -0,0 +1 @@
eeprog-spd-flash-0.11

View File

@@ -0,0 +1,143 @@
#!/bin/bash
#
# eeprog-spd-flash 0.11, SPD flash utility
#
# Copyright (c) 2010-2014 by Kris Rusocki <kszysiu@gmail.com>
# Licensed under GPLv2
#
# Boards supported: generic utility, YMMV
#
check_for()
{
[ -z $1 ] && return 1
which $1 > /dev/null 2>&1 || return 1
return 0
}
missing_tool()
{
echo
echo ERROR: \'$1\' is not available on your system. Please install package providing \'$1\'.
}
usage()
{
echo Usage:
echo -e \\t"$0" all \<file\>
echo -e \\t\\tflashes all SPDs \(I2C addresses 0x50 through 0x57\) with given file
echo
echo -e \\t"$0" \<index\> \<file\>
echo -e \\t\\tflashes SPD at address 0x50 + \<index\> with given file
echo
echo -e \\t"$0" all
echo -e \\t\\tflashes SPDs with files, names of which follow the scheme:
echo -e \\t\\t\ \ spd-\<board model\>-0x\<I2C address in hex\>.bin
echo -e \\t\\tin other words, it does reverse of eeprog-spd-dump
echo
exit 1
}
[ -z "$1" ] && usage
INDEX=$1
FILE=$2
if [ "$INDEX" = "all" ]; then
START=0
END=7
else
[ -z "$FILE" ] && usage
[ "$INDEX" != "$(echo $INDEX | tr -cd 0-9)" ] && INDEX=x
if [ "$INDEX" != $(($INDEX)) -o $(($INDEX)) -lt 0 -o $(($INDEX)) -gt 7 ]; then
echo \<index\> must be a number \(0-7\) or \"all\"
exit 1
fi
INDEX=$(($INDEX))
START=$INDEX
END=$INDEX
fi
DMIDECODE=dmidecode
MODPROBE=modprobe
EEPROG=eeprog-tear
PREREQUISITES="id head $DMIDECODE $MODPROBE $EEPROG"
ERRORS=0
MISSING=1
for i in $PREREQUISITES ; do
[ $MISSING -ne 0 ] && echo -n Checking for
echo -n \ $i
MISSING=0
if ! check_for $i ; then
MISSING=1
missing_tool $i
ERRORS=1
fi
done
echo \ ...done.
if [ $ERRORS -ne 0 ]; then
exit 1
fi
if [ "$(id -ru)" != "0" ]; then
echo ERROR: need root privileges.
exit 1
fi
BOARD=$($DMIDECODE -s baseboard-product-name | head -1)
if [ "$BOARD" = "H8QG6" -o "$BOARD" = "H8QGL" ]; then
$MODPROBE ipmi_si
if ls -d /sys/devices/platform/ipmi_bmc* > /dev/null 2>&1 ; then
echo ERROR: BMC\(s\) found. Please disable IPMI and try again.
exit 1
fi
fi
echo
echo Requested flashing of
echo -en \\t
[ "$INDEX" = "all" ] && echo -n all DIMMs || echo -n DIMM at index $INDEX
echo
echo with
echo -en \\t
[ -z "$FILE" ] && echo -n spd-$BOARD-\<I2C address in hex\>.bin files || echo -n "$FILE"
echo
echo
echo OK to proceed? Press ENTER to continue or Ctrl+C to exit.
read CONFIRM
$MODPROBE -r eeprom 2> /dev/null
$MODPROBE i2c_dev
[ -z "$EEPROG_DEV" ] && EEPROG_DEV=/dev/i2c-0
flashed=0
echo Processing ...
for i in $(seq $((0x50+$START)) $((0x50+$END))) ; do
IHEX=0x$(printf '%x' $i)
[ -z "$FILE" ] && IN=spd-$BOARD-$IHEX.bin || IN=$FILE
if [ ! -r "$IN" ]; then
echo "$IN" does not exist or is not readable. Skipping DIMM at address $IHEX.
continue
fi
echo -n Writing "$IN" to DIMM at address $IHEX ...
$EEPROG -8 -f -w 0 -t 15 $EEPROG_DEV $i < "$IN" 2> /dev/null
RET=$?
if [ $RET -eq 2 ]; then
echo
echo ERROR: cannot access $EEPROG_DEV
exit 1
fi
if [ $RET -ne 0 ]; then
echo
echo DIMM at address $IHEX not populated \(or encountered I2C error\)
else
flashed=$(($flashed+1))
echo done.
fi
done
echo
echo Flashed $flashed DIMM\(s\).

View File

@@ -0,0 +1 @@
eeprog-spd-flash-g34-0.11

View File

@@ -0,0 +1,230 @@
#!/bin/bash
#
# eeprog-spd-flash-g34 0.11, SPD flash utility for 4p G34 boards
#
# Copyright (c) 2010-2014 by Kris Rusocki <kszysiu@gmail.com>
# Licensed under GPLv2
#
# Boards supported: Tyan S8812, Supermicro H8QGi/H8QG6/H8QGL series
#
SMBUS=/proc/bus/pci/00/14.0
read_smbus()
{
local out
[ -z $1 ] && return 1
[ -z $SMBUS ] && return 1
[ $(($1 % 4)) -ne 0 ] && return 1
out=0x$(dd bs=4 if=$SMBUS skip=$(($1/4)) count=1 status=noxfer 2> /dev/null | od -tx1 -An | tr -d ' ')
[ $? -ne 0 ] && return 1
echo $out
return 0
}
write_smbus()
{
[ -z $1 ] && return 1
[ -z $2 ] && return 1
[ -z $SMBUS ] && return 1
[ $(($1 % 4)) -ne 0 ] && return 1
echo -en $(printf '%08x' $2 | sed -e s/../\\\\x\&/g) | dd bs=4 of=$SMBUS conv=notrunc seek=$(($1/4)) status=noxfer 2> /dev/null
return $?
}
dimm_bank()
{
[ -z $1 ] && return 1
[ -z "$BOARD" ] && return 1
[ -z "$I2CSET" ] && return 1
if [ "$BOARD" = "S8812" ]; then
$I2CSET -y 0 0x71 $(($1+4))
return $?
fi
if [ "$BOARD" = "H8QG6" -o "$BOARD" = "H8QGL" ]; then
local GPIO
GPIO=$(read_smbus 0x50)
[ $? -ne 0 ] && return 1
GPIO=$((($GPIO & 0xFFFFFCFF) | ($1 << 8)))
write_smbus 0x50 $GPIO
[ $? -ne 0 ] && return 1
return 0
fi
return 1
}
check_for()
{
[ -z $1 ] && return 1
which $1 > /dev/null 2>&1 || return 1
return 0
}
missing_tool()
{
echo
echo ERROR: \'$1\' is not available on your system. Please install package providing \'$1\'.
}
usage()
{
echo Usage:
echo -e \\t"$0" all \<file\>
echo -e \\t\\tflashes SPDs of all DIMM modules with given file
echo
echo -e \\t"$0" \<cpu\> \<file\>
echo -e \\t\\tflashes SPDs of all DIMM modules of given CPU with given file
echo
echo -e \\t"$0" all
echo -e \\t\\tflashes SPDs with files, names of which follow the scheme:
echo -e \\t\\t\ \ spd-\<board model\>-CPU-\<cpu\>-0x\<I2C address in hex\>.bin
echo -e \\t\\tin other words, it does reverse of eeprog-spd-dump-g34
echo
echo -e \\t"$0" \<cpu\>
echo -e \\t\\tsame as above but only flashes SPDs of DIMM modules of given CPU
echo
exit 1
}
[ -z "$1" ] && usage
CPU=$1
FILE=$2
CPUMASK=0
if [ "$CPU" = "all" ]; then
CPUMASK=15
else
[ "$CPU" != "$(echo $CPU | tr -cd 0-9)" ] && CPU=x
if [ "$CPU" != $(($CPU)) -o $(($CPU)) -lt 0 -o $(($CPU)) -gt 3 ]; then
echo \<cpu\> must be a number \(0-3\) or \"all\"
exit 1
fi
CPU=$(($CPU))
CPUMASK=$((1 << $CPU))
fi
DMIDECODE=dmidecode
MODPROBE=modprobe
I2CSET=i2cset
EEPROG=eeprog-tear
PREREQUISITES="id head sed od tr seq dd find awk lspci $DMIDECODE $MODPROBE $I2CSET $EEPROG"
ERRORS=0
MISSING=1
for i in $PREREQUISITES ; do
[ $MISSING -ne 0 ] && echo -n Checking for
echo -n \ $i
MISSING=0
if ! check_for $i ; then
MISSING=1
missing_tool $i
ERRORS=1
fi
done
echo \ ...done.
if [ $ERRORS -ne 0 ]; then
exit 1
fi
if [ "$(id -ru)" != "0" ]; then
echo ERROR: need root privileges.
exit 1
fi
BOARD=$($DMIDECODE -s baseboard-product-name | head -1)
if [ "$BOARD" != "S8812" -a "$BOARD" != "H8QG6" -a "$BOARD" != "H8QGL" ]; then
echo ERROR: unsupported board: \""$BOARD"\"
fi
if [ "$BOARD" = "H8QG6" -o "$BOARD" = "H8QGL" ]; then
$MODPROBE ipmi_si
if ls -d /sys/devices/platform/ipmi_bmc* > /dev/null 2>&1 ; then
echo ERROR: BMC\(s\) found. Please disable IPMI and try again.
exit 1
fi
fi
echo
echo Requested flashing of
echo -en \\t
[ "$CPU" = "all" ] && echo -n all DIMMs || echo -n CPU$CPU\'s DIMMs
echo
echo with
echo -en \\t
[ -z "$FILE" ] && echo -n spd-$BOARD-CPU-\<cpu\>-\<I2C address in hex\>.bin files || echo -n "$FILE"
echo
echo
echo OK to proceed? Press ENTER to continue or Ctrl+C to exit.
read CONFIRM
INCREMENT=1
if [ "$BOARD" = "H8QGL" ]; then
INCREMENT=2
fi
$MODPROBE -r eeprom 2> /dev/null
$MODPROBE i2c_dev
if [ -z "$EEPROG_DEV" ]; then
echo Discovering i2c bus ...
# EEPROG_DEV=$(ls /sys/bus/pci/devices/0000:00:14.0/i2c-*/i2c-dev 2> /dev/null)
# EEPROG_DEV=$(ls /sys/bus/pci/devices/0000:$(lspci -nm | awk '/ "1002" "4385" / { print $1 }')/i2c-*/i2c-dev 2> /dev/null)
EEPROG_DEV=$(find /sys/bus/pci/devices/0000:$(lspci -nm | awk '/ "1002" "4385" / { print $1 }')/i2c-*/i2c-dev -mindepth 1 -maxdepth 1 -printf '%f ' | (read -a A ; if [ ${#A[*]} -gt 1 ]; then echo WARNING: multiple matching I2C interfaces found: ${A[*]}. Using ${A[0]}. Override with EEPROG_DEV if necessary. >&2 ; fi ; echo ${A[0]}))
fi
if [ -z "$EEPROG_DEV" ]; then
echo WARNING: PCI device 1002:4385 not found or has no I2C busses! Using i2c-0. >&2
EEPROG_DEV=i2c-0
fi
EEPROG_DEV=/dev/$EEPROG_DEV
echo Using i2c bus at $EEPROG_DEV
if [ "$BOARD" = "S8812" ]; then
# pre-set the Tyan
$I2CSET -y 0 0x72 0
fi
bit=1
cpu=0
flashed=0
while [ $cpu -lt 4 ]; do
if [ $(($bit & $CPUMASK)) -ne 0 ]; then
echo Processing CPU $cpu ...
dimm_bank $cpu
if [ $? -ne 0 ]; then
echo ERROR: dimm_bank $cpu failed
exit 1
fi
for i in $(seq $((0x50)) $INCREMENT $((0x57))) ; do
IHEX=0x$(printf '%x' $i)
[ -z "$FILE" ] && IN=spd-$BOARD-CPU-$cpu-$IHEX.bin || IN=$FILE
if [ ! -r "$IN" ]; then
echo "$IN" does not exist or is not readable. Skipping DIMM at address $IHEX.
continue
fi
echo -n Writing "$IN" to DIMM at address $IHEX ...
$EEPROG -8 -f -w 0 -t 15 $EEPROG_DEV $i < "$IN" 2> /dev/null
RET=$?
if [ $RET -eq 2 ]; then
echo
echo ERROR: cannot access $EEPROG_DEV
exit 1
fi
if [ $RET -ne 0 ]; then
echo
echo DIMM at address $IHEX not populated \(or encountered I2C error\)
else
flashed=$(($flashed+1))
echo done.
fi
done
fi
cpu=$(($cpu+1))
bit=$(($bit << 1))
done
echo
echo Flashed $flashed DIMM\(s\).

View File

@@ -0,0 +1,386 @@
/***************************************************************************
copyright : (C) by 2003-2004 Stefano Barbato
email : stefano@codesink.org
Copyright (C) 2011 by Kris Rusocki <kszysiu@gmail.com>
- usage/strings cleanup
- misc cleanup: use "static" keyword where appropriate
- misc cleanup: have confirm_action() return void
- support custom input and output files
- support user-defined write cycle time
- ensure that stdin is a terminal when operating w/o -f
- do not allow reading data from a terminal w/o -f
- perform complete input validation before taking action
- use dedicated exit code when opening I2C device fails
$Id: eeprog.c,v 1.28 2004/02/29 11:06:41 tat Exp $
***************************************************************************/
/***************************************************************************
* *
* 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.6-tear12"
#define ENV_DEV "EEPROG_DEV"
#define ENV_I2C_ADDR "EEPROG_I2C_ADDR"
static int g_quiet;
#define usage_if(a) do { do_usage_if( a , __LINE__); } while(0);
static void do_usage_if(int b, int line)
{
const static char *eeprog_usage =
"eeprog " VERSION ", a 24Cxx EEPROM reader/writer\n"
"Copyright (c) 2003-2004 by Stefano Barbato - All rights reserved.\n"
"Copyright (c) 2011 by Kris Rusocki - All rights reserved.\n"
"Usage:\n"
"\teeprog [-fqxd] [-16|-8] -r addr[:count] [-o file] /dev/i2c-N i2c-address\n"
"\teeprog [-fqd] [-16|-8] -w addr [-i file] [-t tWC] /dev/i2c-N i2c-address\n"
"\teeprog -h\n"
"\n"
" Address modes: \n"
" -8 Use 8bit address mode for 24c0x...24C16 [default]\n"
" -16 Use 16bit address mode for 24c32...24C256\n"
" Actions: \n"
" -r addr[:count] Read [count] (1 if omitted) bytes from [addr]\n"
" and print them to the standard output (or file\n"
" specified by -o)\n"
" -w addr Write stdin (or file specified by -i) starting\n"
" at address [addr] of the EEPROM\n"
" -h Print this help\n"
" Options: \n"
" -i file Read input from [file] (for use with -w)\n"
" -o file Write output to [file] (for use with -r)\n"
" -x Set hex output mode\n"
" -d Dummy mode, display what *would* have been done\n"
" -f Disable warnings and don't ask confirmation\n"
" -q Quiet mode\n"
" -t tWC Define chip's write cycle time to [tWC] miliseconds\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 -f\n";
if(!b)
return;
fprintf(stderr, "%s\n[line %d]\n", eeprog_usage, line);
exit(1);
}
#define die_if3(a, msg, code) do { do_die_if( a , msg, __LINE__, code); } while(0)
#define die_if(a, msg) die_if3(a, msg, 1)
static void do_die_if(int b, char* msg, int line, int exitcode)
{
if(!b)
return;
fprintf(stderr, "Error at line %d: %s\n", line, msg);
//fprintf(stderr, " sysmsg: %s\n", strerror(errno));
exit(exitcode);
}
#define print_info(args...) do { if(!g_quiet) fprintf(stderr, args); } while(0)
static int parse_arg(char *arg, int* paddr, int *psize)
{
char *end;
unsigned int out_paddr, out_psize;
if(arg[0] == '\0')
return -1;
out_paddr = strtol(arg, &end, 0);
if(*end == '\0')
{
if(paddr)
*paddr = out_paddr;
return 1;
}
if(*end != ':')
return -1;
if(end[1] == '\0')
return -1;
out_psize = strtol(end + 1, &end, 0);
if(*end == '\0')
{
if (paddr)
*paddr = out_paddr;
if (psize)
*psize = out_psize;
return 2;
}
return -1;
}
static void confirm_action()
{
fprintf(stderr,
"\n"
"____________________________WARNING____________________________\n"
"Erroneously writing to a system EEPROM (like DIMM SPD modules)\n"
"may break your system. In such event, it will NOT boot anymore\n"
"and you may not be able to fix it.\n"
"\n"
"Reading from 8bit EEPROMs (like that in your DIMM) while using\n"
"-16 option can also UNEXPECTEDLY write to them so be sure to\n"
"use -16 option ONLY when 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();
}
static int read_from_eeprom(struct eeprom *e, FILE *fp, int addr, int size, int hex)
{
int ch, i;
for(i = 0; i < size; ++i, ++addr)
{
die_if((ch = eeprom_read_byte(e, addr)) < 0, "read error");
if(hex)
{
if( (i % 16) == 0 )
fprintf(fp, "\n %.4x| ", addr);
else if( (i % 8) == 0 )
fprintf(fp, " ");
fprintf(fp, "%.2x ", ch);
} else
putc(ch, fp);
}
if(hex)
fprintf(fp, "\n\n");
fflush(fp);
return 0;
}
static int write_to_eeprom(struct eeprom *e, FILE *fp, int addr)
{
int c;
while((c = fgetc(fp)) != EOF)
{
print_info(".");
fflush(stdout);
die_if(eeprom_write_byte(e, addr++, c), "write error");
}
print_info("\n\n");
return 0;
}
int main(int argc, char** argv)
{
struct eeprom e;
int ret, op, i2c_addr, memaddr, size, want_hex, dummy, force, sixteen, write_cycle_time;
char *input_file, *output_file;
FILE *input_fp, *output_fp;
char *device, *arg = 0, *i2c_addr_s;
struct stat st;
int eeprom_type = 0;
op = want_hex = dummy = force = sixteen = write_cycle_time = 0;
size = 1; // default
g_quiet = 0;
input_file = output_file = NULL;
input_fp = stdin;
output_fp = stdout;
while((ret = getopt(argc, argv, "1:8fr:qhw:xdt:i:o:")) != -1)
{
switch(ret)
{
case '1':
usage_if(*optarg != '6' || strlen(optarg) != 1);
die_if(eeprom_type, "EEPROM type switch (-8 or -16) used twice");
eeprom_type = EEPROM_TYPE_16BIT_ADDR;
break;
case 'x':
want_hex++;
break;
case 'd':
dummy++;
break;
case '8':
die_if(eeprom_type, "EEPROM type switch (-8 or -16) used twice");
eeprom_type = EEPROM_TYPE_8BIT_ADDR;
break;
case 'f':
force++;
break;
case 'q':
g_quiet++;
break;
case 'h':
usage_if(1);
break;
case 't':
die_if(parse_arg(optarg, &write_cycle_time, NULL) != 1 || write_cycle_time < 0, "-t -- invalid argument");
break;
case 'i':
input_file = optarg;
break;
case 'o':
output_file = optarg;
break;
default:
die_if(op != 0, "Both read and write requested");
arg = optarg;
op = ret;
}
}
if(!eeprom_type)
eeprom_type = EEPROM_TYPE_8BIT_ADDR; // default
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);
die_if(parse_arg(i2c_addr_s, &i2c_addr, NULL) != 1 || i2c_addr < 0, "I2C address -- invalid argument");
ret = parse_arg(arg, &memaddr, &size);
die_if(op == 'r' && (ret == -1 || memaddr < 0 || size < 0), "-r -- invalid argument");
die_if(op == 'w' && (ret != 1 || memaddr < 0), "-w -- invalid argument");
print_info("eeprog %s, a 24Cxx EEPROM reader/writer\n", VERSION);
print_info("Copyright (c) 2003-2004 by Stefano Barbato - All rights reserved.\n");
print_info("Copyright (c) 2011 by Kris Rusocki - All rights reserved.\n");
print_info(" Bus: %s, Address: 0x%02x, Mode: %dbit\n",
device, i2c_addr,
(eeprom_type == EEPROM_TYPE_8BIT_ADDR ? 8 : 16) );
if(op == 'r')
{
print_info(" Operation: read %d bytes from offset %d, Output file: %s\n",
size, memaddr, output_file ? output_file : "<stdout>");
} else {
print_info(" Operation: write at offset %d, Input file: %s\n",
memaddr, input_file ? input_file : "<stdin>");
if(write_cycle_time != 0)
print_info(" Write cycle time: %d milliseconds\n", write_cycle_time);
}
if(dummy)
{
fprintf(stderr, "Dummy mode selected, nothing done.\n");
return 0;
}
if (input_file) {
die_if((input_fp = fopen(input_file, "rb")) == NULL,
"unable to open input file "
"(check that the file exists and that it's readable)");
} else {
input_file = "<stdin>";
}
if (output_file) {
die_if((output_fp = fopen(output_file, "wb")) == NULL,
"unable to create output file "
"(check that you have permissions to write the file)");
} else {
output_file = "<stdout>";
}
die_if3(eeprom_open(device, i2c_addr, eeprom_type, write_cycle_time, &e) < 0,
"unable to open eeprom device file "
"(check that the file exists and that it's readable)",
2);
switch(op)
{
case 'r':
if(force == 0) {
/* Confirmation must come from a terminal */
die_if(isatty(0) == 0,
"stdin is not a terminal"
);
confirm_action();
}
print_info(" Reading %d bytes from 0x%x\n", size, memaddr);
read_from_eeprom(&e, output_fp, memaddr, size, want_hex);
break;
case 'w':
if(force == 0) {
/* Don't read data from a terminal */
die_if(isatty(fileno(input_fp)) == 1,
"refusing to read data from a terminal\n"
"\n"
"Use -i to provide input file or -f to force."
);
/* Confirmation must come from a terminal */
die_if(isatty(0) == 0,
"stdin is not a terminal"
"\n"
"Use -f to force."
);
confirm_action();
}
print_info(" Writing %s starting at address 0x%x\n",
input_file, memaddr);
write_to_eeprom(&e, input_fp, memaddr);
break;
default:
usage_if(1);
exit(1);
}
eeprom_close(&e);
return 0;
}

View File

@@ -0,0 +1,361 @@
/*
i2c-dev.h - i2c-bus driver, char device interface
Copyright (C) 1995-97 Simon G. Vogl
Copyright (C) 1998-99 Frodo Looijaard <frodol@dds.nl>
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.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/* $Id: i2c-dev.h,v 1.4 2003/11/27 23:08:06 tat Exp $ */
#ifndef LIB_I2CDEV_H
#define LIB_I2CDEV_H
#include <linux/types.h>
#include <sys/ioctl.h>
/* -- i2c.h -- */
/*
* I2C Message - used for pure i2c transaction, also from /dev interface
*/
struct i2c_msg {
__u16 addr; /* slave address */
unsigned short flags;
#define I2C_M_TEN 0x10 /* we have a ten bit chip address */
#define I2C_M_RD 0x01
#define I2C_M_NOSTART 0x4000
#define I2C_M_REV_DIR_ADDR 0x2000
#define I2C_M_IGNORE_NAK 0x1000
#define I2C_M_NO_RD_ACK 0x0800
short len; /* msg length */
char *buf; /* pointer to msg data */
int err;
short done;
};
/* To determine what functionality is present */
#define I2C_FUNC_I2C 0x00000001
#define I2C_FUNC_10BIT_ADDR 0x00000002
#define I2C_FUNC_PROTOCOL_MANGLING 0x00000004 /* I2C_M_{REV_DIR_ADDR,NOSTART,..} */
#define I2C_FUNC_SMBUS_HWPEC_CALC 0x00000008 /* SMBus 2.0 */
#define I2C_FUNC_SMBUS_READ_WORD_DATA_PEC 0x00000800 /* SMBus 2.0 */
#define I2C_FUNC_SMBUS_WRITE_WORD_DATA_PEC 0x00001000 /* SMBus 2.0 */
#define I2C_FUNC_SMBUS_PROC_CALL_PEC 0x00002000 /* SMBus 2.0 */
#define I2C_FUNC_SMBUS_BLOCK_PROC_CALL_PEC 0x00004000 /* SMBus 2.0 */
#define I2C_FUNC_SMBUS_BLOCK_PROC_CALL 0x00008000 /* SMBus 2.0 */
#define I2C_FUNC_SMBUS_QUICK 0x00010000
#define I2C_FUNC_SMBUS_READ_BYTE 0x00020000
#define I2C_FUNC_SMBUS_WRITE_BYTE 0x00040000
#define I2C_FUNC_SMBUS_READ_BYTE_DATA 0x00080000
#define I2C_FUNC_SMBUS_WRITE_BYTE_DATA 0x00100000
#define I2C_FUNC_SMBUS_READ_WORD_DATA 0x00200000
#define I2C_FUNC_SMBUS_WRITE_WORD_DATA 0x00400000
#define I2C_FUNC_SMBUS_PROC_CALL 0x00800000
#define I2C_FUNC_SMBUS_READ_BLOCK_DATA 0x01000000
#define I2C_FUNC_SMBUS_WRITE_BLOCK_DATA 0x02000000
#define I2C_FUNC_SMBUS_READ_I2C_BLOCK 0x04000000 /* I2C-like block xfer */
#define I2C_FUNC_SMBUS_WRITE_I2C_BLOCK 0x08000000 /* w/ 1-byte reg. addr. */
#define I2C_FUNC_SMBUS_READ_I2C_BLOCK_2 0x10000000 /* I2C-like block xfer */
#define I2C_FUNC_SMBUS_WRITE_I2C_BLOCK_2 0x20000000 /* w/ 2-byte reg. addr. */
#define I2C_FUNC_SMBUS_READ_BLOCK_DATA_PEC 0x40000000 /* SMBus 2.0 */
#define I2C_FUNC_SMBUS_WRITE_BLOCK_DATA_PEC 0x80000000 /* SMBus 2.0 */
#define I2C_FUNC_SMBUS_BYTE I2C_FUNC_SMBUS_READ_BYTE | \
I2C_FUNC_SMBUS_WRITE_BYTE
#define I2C_FUNC_SMBUS_BYTE_DATA I2C_FUNC_SMBUS_READ_BYTE_DATA | \
I2C_FUNC_SMBUS_WRITE_BYTE_DATA
#define I2C_FUNC_SMBUS_WORD_DATA I2C_FUNC_SMBUS_READ_WORD_DATA | \
I2C_FUNC_SMBUS_WRITE_WORD_DATA
#define I2C_FUNC_SMBUS_BLOCK_DATA I2C_FUNC_SMBUS_READ_BLOCK_DATA | \
I2C_FUNC_SMBUS_WRITE_BLOCK_DATA
#define I2C_FUNC_SMBUS_I2C_BLOCK I2C_FUNC_SMBUS_READ_I2C_BLOCK | \
I2C_FUNC_SMBUS_WRITE_I2C_BLOCK
#define I2C_FUNC_SMBUS_I2C_BLOCK_2 I2C_FUNC_SMBUS_READ_I2C_BLOCK_2 | \
I2C_FUNC_SMBUS_WRITE_I2C_BLOCK_2
#define I2C_FUNC_SMBUS_BLOCK_DATA_PEC I2C_FUNC_SMBUS_READ_BLOCK_DATA_PEC | \
I2C_FUNC_SMBUS_WRITE_BLOCK_DATA_PEC
#define I2C_FUNC_SMBUS_WORD_DATA_PEC I2C_FUNC_SMBUS_READ_WORD_DATA_PEC | \
I2C_FUNC_SMBUS_WRITE_WORD_DATA_PEC
#define I2C_FUNC_SMBUS_READ_BYTE_PEC I2C_FUNC_SMBUS_READ_BYTE_DATA
#define I2C_FUNC_SMBUS_WRITE_BYTE_PEC I2C_FUNC_SMBUS_WRITE_BYTE_DATA
#define I2C_FUNC_SMBUS_READ_BYTE_DATA_PEC I2C_FUNC_SMBUS_READ_WORD_DATA
#define I2C_FUNC_SMBUS_WRITE_BYTE_DATA_PEC I2C_FUNC_SMBUS_WRITE_WORD_DATA
#define I2C_FUNC_SMBUS_BYTE_PEC I2C_FUNC_SMBUS_BYTE_DATA
#define I2C_FUNC_SMBUS_BYTE_DATA_PEC I2C_FUNC_SMBUS_WORD_DATA
#define I2C_FUNC_SMBUS_EMUL I2C_FUNC_SMBUS_QUICK | \
I2C_FUNC_SMBUS_BYTE | \
I2C_FUNC_SMBUS_BYTE_DATA | \
I2C_FUNC_SMBUS_WORD_DATA | \
I2C_FUNC_SMBUS_PROC_CALL | \
I2C_FUNC_SMBUS_WRITE_BLOCK_DATA | \
I2C_FUNC_SMBUS_WRITE_BLOCK_DATA_PEC | \
I2C_FUNC_SMBUS_I2C_BLOCK
/*
* Data for SMBus Messages
*/
#define I2C_SMBUS_BLOCK_MAX 32 /* As specified in SMBus standard */
#define I2C_SMBUS_I2C_BLOCK_MAX 32 /* Not specified but we use same structure */
union i2c_smbus_data {
__u8 byte;
__u16 word;
__u8 block[I2C_SMBUS_BLOCK_MAX + 3]; /* block[0] is used for length */
/* one more for read length in block process call */
/* and one more for PEC */
};
/* smbus_access read or write markers */
#define I2C_SMBUS_READ 1
#define I2C_SMBUS_WRITE 0
/* SMBus transaction types (size parameter in the above functions)
Note: these no longer correspond to the (arbitrary) PIIX4 internal codes! */
#define I2C_SMBUS_QUICK 0
#define I2C_SMBUS_BYTE 1
#define I2C_SMBUS_BYTE_DATA 2
#define I2C_SMBUS_WORD_DATA 3
#define I2C_SMBUS_PROC_CALL 4
#define I2C_SMBUS_BLOCK_DATA 5
#define I2C_SMBUS_I2C_BLOCK_DATA 6
#define I2C_SMBUS_BLOCK_PROC_CALL 7 /* SMBus 2.0 */
#define I2C_SMBUS_BLOCK_DATA_PEC 8 /* SMBus 2.0 */
#define I2C_SMBUS_PROC_CALL_PEC 9 /* SMBus 2.0 */
#define I2C_SMBUS_BLOCK_PROC_CALL_PEC 10 /* SMBus 2.0 */
#define I2C_SMBUS_WORD_DATA_PEC 11 /* SMBus 2.0 */
/* ----- commands for the ioctl like i2c_command call:
* note that additional calls are defined in the algorithm and hw
* dependent layers - these can be listed here, or see the
* corresponding header files.
*/
/* -> bit-adapter specific ioctls */
#define I2C_RETRIES 0x0701 /* number of times a device address */
/* should be polled when not */
/* acknowledging */
#define I2C_TIMEOUT 0x0702 /* set timeout - call with int */
/* this is for i2c-dev.c */
#define I2C_SLAVE 0x0703 /* Change slave address */
/* Attn.: Slave address is 7 or 10 bits */
#define I2C_SLAVE_FORCE 0x0706 /* Change slave address */
/* Attn.: Slave address is 7 or 10 bits */
/* This changes the address, even if it */
/* is already taken! */
#define I2C_TENBIT 0x0704 /* 0 for 7 bit addrs, != 0 for 10 bit */
#define I2C_FUNCS 0x0705 /* Get the adapter functionality */
#define I2C_RDWR 0x0707 /* Combined R/W transfer (one stop only)*/
#define I2C_PEC 0x0708 /* != 0 for SMBus PEC */
#if 0
#define I2C_ACK_TEST 0x0710 /* See if a slave is at a specific address */
#endif
#define I2C_SMBUS 0x0720 /* SMBus-level access */
/* -- i2c.h -- */
/* Note: 10-bit addresses are NOT supported! */
/* This is the structure as used in the I2C_SMBUS ioctl call */
struct i2c_smbus_ioctl_data {
char read_write;
__u8 command;
int size;
union i2c_smbus_data *data;
};
/* This is the structure as used in the I2C_RDWR ioctl call */
struct i2c_rdwr_ioctl_data {
struct i2c_msg *msgs; /* pointers to i2c_msgs */
int nmsgs; /* number of i2c_msgs */
};
static inline __s32 i2c_smbus_access(int file, char read_write, __u8 command,
int size, union i2c_smbus_data *data)
{
struct i2c_smbus_ioctl_data args;
args.read_write = read_write;
args.command = command;
args.size = size;
args.data = data;
return ioctl(file,I2C_SMBUS,&args);
}
static inline __s32 i2c_smbus_write_quick(int file, __u8 value)
{
return i2c_smbus_access(file,value,0,I2C_SMBUS_QUICK,NULL);
}
static inline __s32 i2c_smbus_read_byte(int file)
{
union i2c_smbus_data data;
if (i2c_smbus_access(file,I2C_SMBUS_READ,0,I2C_SMBUS_BYTE,&data))
return -1;
else
return 0x0FF & data.byte;
}
static inline __s32 i2c_smbus_write_byte(int file, __u8 value)
{
return i2c_smbus_access(file,I2C_SMBUS_WRITE,value,
I2C_SMBUS_BYTE,NULL);
}
static inline __s32 i2c_smbus_read_byte_data(int file, __u8 command)
{
union i2c_smbus_data data;
if (i2c_smbus_access(file,I2C_SMBUS_READ,command,
I2C_SMBUS_BYTE_DATA,&data))
return -1;
else
return 0x0FF & data.byte;
}
static inline __s32 i2c_smbus_write_byte_data(int file, __u8 command,
__u8 value)
{
union i2c_smbus_data data;
data.byte = value;
return i2c_smbus_access(file,I2C_SMBUS_WRITE,command,
I2C_SMBUS_BYTE_DATA, &data);
}
static inline __s32 i2c_smbus_read_word_data(int file, __u8 command)
{
union i2c_smbus_data data;
if (i2c_smbus_access(file,I2C_SMBUS_READ,command,
I2C_SMBUS_WORD_DATA,&data))
return -1;
else
return 0x0FFFF & data.word;
}
static inline __s32 i2c_smbus_write_word_data(int file, __u8 command,
__u16 value)
{
union i2c_smbus_data data;
data.word = value;
return i2c_smbus_access(file,I2C_SMBUS_WRITE,command,
I2C_SMBUS_WORD_DATA, &data);
}
static inline __s32 i2c_smbus_process_call(int file, __u8 command, __u16 value)
{
union i2c_smbus_data data;
data.word = value;
if (i2c_smbus_access(file,I2C_SMBUS_WRITE,command,
I2C_SMBUS_PROC_CALL,&data))
return -1;
else
return 0x0FFFF & data.word;
}
/* Returns the number of read bytes */
static inline __s32 i2c_smbus_read_block_data(int file, __u8 command,
__u8 *values)
{
union i2c_smbus_data data;
int i;
if (i2c_smbus_access(file,I2C_SMBUS_READ,command,
I2C_SMBUS_BLOCK_DATA,&data))
return -1;
else {
for (i = 1; i <= data.block[0]; i++)
values[i-1] = data.block[i];
return data.block[0];
}
}
static inline __s32 i2c_smbus_write_block_data(int file, __u8 command,
__u8 length, __u8 *values)
{
union i2c_smbus_data data;
int i;
if (length > 32)
length = 32;
for (i = 1; i <= length; i++)
data.block[i] = values[i-1];
data.block[0] = length;
return i2c_smbus_access(file,I2C_SMBUS_WRITE,command,
I2C_SMBUS_BLOCK_DATA, &data);
}
/* Returns the number of read bytes */
static inline __s32 i2c_smbus_read_i2c_block_data(int file, __u8 command,
__u8 *values)
{
union i2c_smbus_data data;
int i;
if (i2c_smbus_access(file,I2C_SMBUS_READ,command,
I2C_SMBUS_I2C_BLOCK_DATA,&data))
return -1;
else {
for (i = 1; i <= data.block[0]; i++)
values[i-1] = data.block[i];
return data.block[0];
}
}
static inline __s32 i2c_smbus_write_i2c_block_data(int file, __u8 command,
__u8 length, __u8 *values)
{
union i2c_smbus_data data;
int i;
if (length > 32)
length = 32;
for (i = 1; i <= length; i++)
data.block[i] = values[i-1];
data.block[0] = length;
return i2c_smbus_access(file,I2C_SMBUS_WRITE,command,
I2C_SMBUS_I2C_BLOCK_DATA, &data);
}
/* Returns the number of read bytes */
static inline __s32 i2c_smbus_block_process_call(int file, __u8 command,
__u8 length, __u8 *values)
{
union i2c_smbus_data data;
int i;
if (length > 32)
length = 32;
for (i = 1; i <= length; i++)
data.block[i] = values[i-1];
data.block[0] = length;
if (i2c_smbus_access(file,I2C_SMBUS_WRITE,command,
I2C_SMBUS_BLOCK_PROC_CALL,&data))
return -1;
else {
for (i = 1; i <= data.block[0]; i++)
values[i-1] = data.block[i];
return data.block[0];
}
}
#endif /* LIB_I2CDEV_H */

View File

@@ -1,315 +0,0 @@
/*
This program is hereby placed into the public domain.
Of course the program is provided without warranty of any kind.
Downloaded from http://www.lm-sensors.org/browser/i2c-tools/trunk/eepromer/eeprom.c
*/
#include <sys/ioctl.h>
#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 16 /* 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){
if ( len > 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);
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! */
int wait = 0;
int acked = 0;
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 separate 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);
fprintf(stderr,".");
for ( wait = 0; wait < 10; wait ++ ) {
acked = eeprom_write(d,addr+i,j*MAX_BYTES,NULL,0);
if ( acked == 0 )
break;
fprintf(stderr,".");
usleep( 100 );
}
if ( acked != 0 ) {
fprintf(stderr,"Ack of write operation timedout");
exit ( 1 );
}
fprintf(stderr," acked \n");
}
} 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);
}