From f1be58afdf522132e1eab2ff6362654626d87999 Mon Sep 17 00:00:00 2001 From: Jan Sarenik Date: Thu, 21 Apr 2016 15:34:52 +0200 Subject: [PATCH] Import from eeprog-0.7.6.tar.gz http://www.codesink.org/eeprog.html http://www.codesink.org/download/eeprog-0.7.6.tar.gz --- 24cXX.c | 189 ++++++++++++++++++++++++++++ 24cXX.h | 58 +++++++++ ChangeLog | 21 ++++ Makefile | 11 ++ README | 12 ++ WARNING | 20 +++ eeprog.c | 272 ++++++++++++++++++++++++++++++++++++++++ i2c-dev.h | 361 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 8 files changed, 944 insertions(+) create mode 100644 24cXX.c create mode 100644 24cXX.h create mode 100644 ChangeLog create mode 100644 Makefile create mode 100644 README create mode 100644 WARNING create mode 100644 eeprog.c create mode 100644 i2c-dev.h diff --git a/24cXX.c b/24cXX.c new file mode 100644 index 0000000..cf1726e --- /dev/null +++ b/24cXX.c @@ -0,0 +1,189 @@ +/*************************************************************************** + copyright : (C) by 2003-2004 Stefano Barbato + email : stefano@codesink.org + + $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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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) + { + 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; + 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); + } + fprintf(stderr, "ERR: unknown eeprom type\n"); + return -1; +} + diff --git a/24cXX.h b/24cXX.h new file mode 100644 index 0000000..e6f10ef --- /dev/null +++ b/24cXX.h @@ -0,0 +1,58 @@ +/*************************************************************************** + copyright : (C) by 2003-2004 Stefano Barbato + email : stefano@codesink.org + + $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 +}; + +/* + * 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 + diff --git a/ChangeLog b/ChangeLog new file mode 100644 index 0000000..deeb5fb --- /dev/null +++ b/ChangeLog @@ -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. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..234110e --- /dev/null +++ b/Makefile @@ -0,0 +1,11 @@ +CFLAGS=-g -I. -Wall -O2 + +all: eeprog + +clean: + rm -f eeprog 24cXX.o + +eeprog: eeprog.o 24cXX.o + +eeprog-static: eeprog.o 24cXX.o + $(CC) -static -o $@ $? diff --git a/README b/README new file mode 100644 index 0000000..ed4e264 --- /dev/null +++ b/README @@ -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 -8 switch for EEPROM smaller then 24C16 (8bit addressing mode). + +Again, it's really important that you read the WARNING file. + +Type "make" to compile. diff --git a/WARNING b/WARNING new file mode 100644 index 0000000..103e16a --- /dev/null +++ b/WARNING @@ -0,0 +1,20 @@ +Writing on unknown EEPROMs can brake your computer. + +DIMMs contain an EEPROM and if you overwrite it somehow your computer +will not boot anymore. + +Reading using 16bit addressing (i.e. not using the -8 switch) on a 8bit EEPROM +can 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 not use -8. + +More could need it, check data sheets. + +If you are not sure about what you're doing DON'T use this tool. diff --git a/eeprog.c b/eeprog.c new file mode 100644 index 0000000..f2f3bc4 --- /dev/null +++ b/eeprog.c @@ -0,0 +1,272 @@ +/*************************************************************************** + copyright : (C) by 2003-2004 Stefano Barbato + email : stefano@codesink.org + + $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 +#include +#include +#include +#include +#include +#include +#include +#include +#include "24cXX.h" + +#define VERSION "0.7.6" + +#define ENV_DEV "EEPROG_DEV" +#define ENV_I2C_ADDR "EEPROG_I2C_ADDR" + +int g_quiet; + +#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 = +"eeprog " VERSION ", a 24Cxx EEPROM reader/writer\n" +"Copyright (c) 2003-2004 by Stefano Barbato - All rights reserved.\n" +"Usage: eeprog [-fqxdh] [-16|-8] [ -r addr[:count] | -w addr ] /dev/i2c-N i2c-address\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\n" +" -w addr Write input (stdin) at address [addr] of the EEPROM\n" +" -h Print this help\n" +" Options: \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" +"\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); +} + +#define print_info(args...) do { if(!g_quiet) fprintf(stderr, args); } while(0); + +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)\n" + "can break your system. It will NOT boot anymore so you'll not\n" + "be able to fix it.\n" + "\n" + "Reading from 8bit EEPROMs (like that in your DIMM) without using\n" + "the -8 switch can also UNEXPECTEDLY write to them, so be sure to\n" + "use the -8 command param 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(); + return 1; +} + +int read_from_eeprom(struct eeprom *e, 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 ) + printf("\n %.4x| ", addr); + else if( (i % 8) == 0 ) + printf(" "); + printf("%.2x ", ch); + } else + putchar(ch); + } + if(hex) + printf("\n\n"); + fflush(stdout); + return 0; +} + +int write_to_eeprom(struct eeprom *e, int addr) +{ + int c; + while((c = getchar()) != 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; + char *device, *arg = 0, *i2c_addr_s; + struct stat st; + int eeprom_type = 0; + + op = want_hex = dummy = force = sixteen = 0; + g_quiet = 0; + + while((ret = getopt(argc, argv, "1:8fr:qhw:xd")) != -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; + 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); + i2c_addr = strtoul(i2c_addr_s, 0, 0); + + 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(" 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); + print_info(" 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); + print_info(" 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; +} + diff --git a/i2c-dev.h b/i2c-dev.h new file mode 100644 index 0000000..415ab45 --- /dev/null +++ b/i2c-dev.h @@ -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 + + 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 +#include + + +/* -- 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 */