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 */