i2c: increase BUFLEN/CMDLEN to 128, add page flag.

128 byte reads are much more common than 32 byte reads. The message
passing + setup/teardown for a read is much more expensive, in terms
of time, than the reading itself. A slightly bigger struct is well
worth the time savings. This reduces read times for /dev/eeprom
from 57 seconds per 4KB to 14 seconds.

Additionally, make sending the page address in the eeprom driver
and utility optional. This can save a little time when reading
within the same page and allows support for smaller devices that
don't support pages (example: chips containing EDID).

Change-Id: Ie48087caee40c11fa241d1555fce9309ddd27b43
This commit is contained in:
Thomas Cort 2013-07-26 19:44:52 -04:00
parent 11be35a165
commit 437177b028
7 changed files with 94 additions and 59 deletions

View file

@ -18,7 +18,7 @@
* In the future, this could be expanded to support cape EEPROMs.
*/
static int board_info_beaglebone(int fd, i2c_addr_t address);
static int board_info_beaglebone(int fd, i2c_addr_t address, int flags);
/* Memory Layout of the BeagleBone and BeagleBone Black EEPROM */
typedef struct beaglebone_info
@ -32,7 +32,7 @@ typedef struct beaglebone_info
} beaglebone_info_t;
static int
board_info_beaglebone(int fd, i2c_addr_t address)
board_info_beaglebone(int fd, i2c_addr_t address, int flags)
{
int r;
int i, j;
@ -40,7 +40,7 @@ board_info_beaglebone(int fd, i2c_addr_t address)
beaglebone_info_t boneinfo;
r = eeprom_read(fd, address, 0x0000, &boneinfo,
sizeof(beaglebone_info_t));
sizeof(beaglebone_info_t), flags);
if (r == -1) {
fprintf(stderr, "Failed to read BeagleBone info r=%d\n", r);
return -1;
@ -65,12 +65,12 @@ board_info_beaglebone(int fd, i2c_addr_t address)
}
int
board_info(int fd, i2c_addr_t address)
board_info(int fd, i2c_addr_t address, int flags)
{
int r;
uint8_t magic_number[4];
r = eeprom_read(fd, address, 0x0000, &magic_number, 4);
r = eeprom_read(fd, address, 0x0000, &magic_number, 4, flags);
if (r == -1) {
printf("%-16s: %s\n", "BOARD_NAME", "UNKNOWN");
return 0;
@ -78,7 +78,7 @@ board_info(int fd, i2c_addr_t address)
if (magic_number[0] == 0xaa && magic_number[1] == 0x55 &&
magic_number[2] == 0x33 && magic_number[3] == 0xee) {
board_info_beaglebone(fd, address);
board_info_beaglebone(fd, address, flags);
} else {
printf("%-16s: %s\n", "BOARD_NAME", "UNKNOWN");
}

View file

@ -3,6 +3,7 @@
eepromread \- read data from an EEPROM
.SH SYNOPSIS
\fBeepromread\fR [\fB\-i\fR] [\fB\-f\fR \fIdev\fR] [\fB\-a\fR \fIslave_addr\fR]
[\fB\-n\fR]
.br
.de FL
.TP
@ -24,6 +25,11 @@ eepromread \- read data from an EEPROM
.TP 5
.B \-a
# Use \fIslave_address\fR instead of \fI0x50\fR.
.TP 5
.B \-n
# Do not send the page number when addressing the memory on the EEPROM. Some
smaller EEPROM chips aren't organized into pages and get confused if a page
number is sent with the memory address. Use this when reading EDID.
.SH EXAMPLES
.TP 20
.B eepromread -i
@ -34,6 +40,9 @@ eepromread \- read data from an EEPROM
.TP 20
.B eepromread -f /dev/i2c-3 -a 0x54
# display the first 256 bytes of the EEPROM on I2C bus 3, slave address 0x54.
.TP 20
.B eepromread -f /dev/i2c-3 -n
# read the EDID info from the display on I2C bus 3 on the BeagleBoard-xM.
.SH DESCRIPTION
.PP
\fIeepromread\fR is a simple tool for viewing the contents of an EEPROM.

View file

@ -1,4 +1,5 @@
#include <minix/i2c.h>
#include <minix/com.h>
#include <sys/types.h>
#include <sys/stat.h>
@ -13,17 +14,17 @@
#include "eepromread.h"
static int __eeprom_read32(int fd, i2c_addr_t addr, uint16_t memaddr,
void *buf, size_t buflen);
static int eeprom_dump(int fd, i2c_addr_t addr);
static int __eeprom_read128(int fd, i2c_addr_t addr, uint16_t memaddr,
void *buf, size_t buflen, int flags);
static int eeprom_dump(int fd, i2c_addr_t addr, int flags);
#define DEFAULT_I2C_DEVICE "/dev/i2c-1"
#define DEFAULT_I2C_ADDRESS 0x50
/*
* The /dev interface only supports 32 byte reads/writes and the EEPROM is
* larger, so to read the whole EEPROM, the task is broken down into 32 byte
* chunks in eeprom_read(). __eeprom_read32() does the actual ioctl() to do
* The /dev interface only supports 128 byte reads/writes and the EEPROM is
* larger, so to read the whole EEPROM, the task is broken down into 128 byte
* chunks in eeprom_read(). __eeprom_read128() does the actual ioctl() to do
* the read.
*
* A future enhancement might be to add support for the /dev/eeprom interface
@ -33,8 +34,8 @@ static int eeprom_dump(int fd, i2c_addr_t addr);
*/
static int
__eeprom_read32(int fd, i2c_addr_t addr, uint16_t memaddr, void *buf,
size_t buflen)
__eeprom_read128(int fd, i2c_addr_t addr, uint16_t memaddr, void *buf,
size_t buflen, int flags)
{
int r;
minix_i2c_ioctl_exec_t ioctl_exec;
@ -51,10 +52,16 @@ __eeprom_read32(int fd, i2c_addr_t addr, uint16_t memaddr, void *buf,
ioctl_exec.iie_addr = addr;
/* set the address to read from */
ioctl_exec.iie_cmd[0] = ((memaddr >> 8) & 0xff);
ioctl_exec.iie_cmd[1] = (memaddr & 0xff);
ioctl_exec.iie_cmdlen = 2;
if ((BDEV_NOPAGE & flags) == BDEV_NOPAGE) {
/* reading within the current page */
ioctl_exec.iie_cmd[0] = (memaddr & 0xff);
ioctl_exec.iie_cmdlen = 1;
} else {
/* reading from device with multiple pages */
ioctl_exec.iie_cmd[0] = ((memaddr >> 8) & 0xff);
ioctl_exec.iie_cmd[1] = (memaddr & 0xff);
ioctl_exec.iie_cmdlen = 2;
}
ioctl_exec.iie_buflen = buflen;
r = ioctl(fd, MINIX_I2C_IOCTL_EXEC, &ioctl_exec);
@ -70,7 +77,7 @@ __eeprom_read32(int fd, i2c_addr_t addr, uint16_t memaddr, void *buf,
int
eeprom_read(int fd, i2c_addr_t addr, uint16_t memaddr, void *buf,
size_t buflen)
size_t buflen, int flags)
{
int r;
uint16_t i;
@ -80,10 +87,11 @@ eeprom_read(int fd, i2c_addr_t addr, uint16_t memaddr, void *buf,
return -1;
}
for (i = 0; i < buflen; i += 32) {
r = __eeprom_read32(fd, addr, memaddr + i, buf + i,
((buflen - i) < 32) ? (buflen - i) : 32);
for (i = 0; i < buflen; i += 128) {
r = __eeprom_read128(fd, addr, memaddr + i, buf + i,
((buflen - i) < 128) ? (buflen - i) : 128, flags);
if (r == -1) {
return -1;
}
@ -96,14 +104,14 @@ eeprom_read(int fd, i2c_addr_t addr, uint16_t memaddr, void *buf,
* Read 256 bytes and print it to the screen in HEX and ASCII.
*/
static int
eeprom_dump(int fd, i2c_addr_t addr)
eeprom_dump(int fd, i2c_addr_t addr, int flags)
{
int i, j, r;
uint8_t buf[256];
memset(buf, '\0', 256);
r = eeprom_read(fd, addr, 0x0000, buf, 256);
r = eeprom_read(fd, addr, 0x0000, buf, 256, flags);
if (r == -1) {
return r;
}
@ -152,13 +160,13 @@ int
main(int argc, char *argv[])
{
int r, fd;
int ch, iflag = 0;
int ch, iflag = 0, read_flags = 0;
char *device = DEFAULT_I2C_DEVICE;
i2c_addr_t address = DEFAULT_I2C_ADDRESS;
setprogname(*argv);
while ((ch = getopt(argc, argv, "a:f:i")) != -1) {
while ((ch = getopt(argc, argv, "a:f:in")) != -1) {
switch (ch) {
case 'a':
address = strtol(optarg, NULL, 0x10);
@ -169,6 +177,9 @@ main(int argc, char *argv[])
case 'i':
iflag = 1;
break;
case 'n':
read_flags |= BDEV_NOPAGE;
break;
default:
break;
}
@ -181,13 +192,13 @@ main(int argc, char *argv[])
}
if (iflag == 1) {
r = board_info(fd, address);
r = board_info(fd, address, read_flags);
if (r == -1) {
fprintf(stderr, "board_info(): %s\n", strerror(errno));
return 1;
}
} else {
r = eeprom_dump(fd, address);
r = eeprom_dump(fd, address, read_flags);
if (r == -1) {
fprintf(stderr, "eeprom_dump(): %s\n", strerror(errno));
return 1;

View file

@ -2,7 +2,7 @@
#define __EEPROMREAD_H
int eeprom_read(int fd, i2c_addr_t addr, uint16_t memaddr, void *buf,
size_t buflen);
int board_info(int fd, i2c_addr_t address);
size_t buflen, int flags);
int board_info(int fd, i2c_addr_t address, int flags);
#endif /* __EEPROMREAD_H */

View file

@ -1,4 +1,5 @@
#include <minix/blockdriver.h>
#include <minix/com.h>
#include <minix/drivers.h>
#include <minix/ds.h>
#include <minix/i2c.h>
@ -53,10 +54,10 @@ struct blockdriver cat24c256_tab = {
.bdr_device = NULL /* 1 insance per bus, threads not needed */
};
static int cat24c256_read32(uint16_t memaddr, void *buf, size_t buflen);
static int cat24c256_read(uint16_t memaddr, void *buf, size_t buflen);
static int cat24c256_write16(uint16_t memaddr, void *buf, size_t buflen);
static int cat24c256_write(uint16_t memaddr, void *buf, size_t buflen);
static int cat24c256_read128(uint16_t memaddr, void *buf, size_t buflen, int flags);
static int cat24c256_read(uint16_t memaddr, void *buf, size_t buflen, int flags);
static int cat24c256_write16(uint16_t memaddr, void *buf, size_t buflen, int flags);
static int cat24c256_write(uint16_t memaddr, void *buf, size_t buflen, int flags);
/* globals */
@ -176,13 +177,13 @@ cat24c256_blk_transfer(dev_t minor, int do_write, u64_t pos64,
return EINVAL;
}
r = cat24c256_write(position, copybuf, count);
r = cat24c256_write(position, copybuf, count, flags);
if (r != OK) {
log_warn(&log, "write failed (r=%d)\n", r);
return r;
}
} else {
r = cat24c256_read(position, copybuf, count);
r = cat24c256_read(position, copybuf, count, flags);
if (r != OK) {
log_warn(&log, "read failed (r=%d)\n", r);
return r;
@ -259,16 +260,16 @@ cat24c256_blk_other(message * m)
return r;
}
/* The lower level i2c interface can only read/write 32 bytes at a time.
/* The lower level i2c interface can only read/write 128 bytes at a time.
* One might want to do more I/O than that at once w/EEPROM, so there is
* cat24c256_read() and cat24c256_read32(). cat24c256_read32() does the
* actual reading in chunks up to 32 bytes. cat24c256_read() splits
* the request up into chunks and repeatedly calls cat24c256_read32()
* cat24c256_read() and cat24c256_read128(). cat24c256_read128() does the
* actual reading in chunks up to 128 bytes. cat24c256_read() splits
* the request up into chunks and repeatedly calls cat24c256_read128()
* until all of the requested EEPROM locations have been read.
*/
static int
cat24c256_read32(uint16_t memaddr, void *buf, size_t buflen)
cat24c256_read128(uint16_t memaddr, void *buf, size_t buflen, int flags)
{
int r;
minix_i2c_ioctl_exec_t ioctl_exec;
@ -286,9 +287,15 @@ cat24c256_read32(uint16_t memaddr, void *buf, size_t buflen)
ioctl_exec.iie_addr = address;
/* set the memory address to read from */
ioctl_exec.iie_cmd[0] = ((memaddr >> 8) & 0xff);
ioctl_exec.iie_cmd[1] = (memaddr & 0xff);
ioctl_exec.iie_cmdlen = 2;
if ((BDEV_NOPAGE & flags) == BDEV_NOPAGE) {
/* reading within the current page */
ioctl_exec.iie_cmd[0] = (memaddr & 0xff);
ioctl_exec.iie_cmdlen = 1;
} else {
ioctl_exec.iie_cmd[0] = ((memaddr >> 8) & 0xff);
ioctl_exec.iie_cmd[1] = (memaddr & 0xff);
ioctl_exec.iie_cmdlen = 2;
}
ioctl_exec.iie_buflen = buflen;
@ -307,7 +314,7 @@ cat24c256_read32(uint16_t memaddr, void *buf, size_t buflen)
}
int
cat24c256_read(uint16_t memaddr, void *buf, size_t buflen)
cat24c256_read(uint16_t memaddr, void *buf, size_t buflen, int flags)
{
int r;
uint16_t i;
@ -317,25 +324,26 @@ cat24c256_read(uint16_t memaddr, void *buf, size_t buflen)
return -1;
}
for (i = 0; i < buflen; i += 32) {
for (i = 0; i < buflen; i += 128) {
r = cat24c256_read32(memaddr + i, buf + i,
((buflen - i) < 32) ? (buflen - i) : 32);
r = cat24c256_read128(memaddr + i, buf + i,
((buflen - i) < 128) ? (buflen - i) : 128, flags);
if (r != OK) {
return r;
}
log_trace(&log, "read %d bytes starting at 0x%x\n",
((buflen - i) < 32) ? (buflen - i) : 32, memaddr + i);
((buflen - i) < 128) ? (buflen - i) : 128, memaddr + i);
}
return OK;
}
static int
cat24c256_write16(uint16_t memaddr, void *buf, size_t buflen)
cat24c256_write16(uint16_t memaddr, void *buf, size_t buflen, int flags)
{
int r;
int addrlen;
minix_i2c_ioctl_exec_t ioctl_exec;
if (buflen > (I2C_EXEC_MAX_BUFLEN - 2) || buf == NULL
@ -352,11 +360,17 @@ cat24c256_write16(uint16_t memaddr, void *buf, size_t buflen)
ioctl_exec.iie_cmdlen = 0;
/* set the memory address to write to */
ioctl_exec.iie_buf[0] = ((memaddr >> 8) & 0xff);
ioctl_exec.iie_buf[1] = (memaddr & 0xff);
memcpy(ioctl_exec.iie_buf + 2, buf, buflen);
ioctl_exec.iie_buflen = buflen + 2;
if ((BDEV_NOPAGE & flags) == BDEV_NOPAGE) {
/* writing within the current page */
ioctl_exec.iie_buf[0] = (memaddr & 0xff); /* address */
addrlen = 1;
} else {
ioctl_exec.iie_buf[0] = ((memaddr >> 8) & 0xff);/* page */
ioctl_exec.iie_buf[1] = (memaddr & 0xff); /* address */
addrlen = 2;
}
memcpy(ioctl_exec.iie_buf + addrlen, buf, buflen);
ioctl_exec.iie_buflen = buflen + addrlen;
r = i2cdriver_exec(bus_endpoint, &ioctl_exec);
if (r != OK) {
@ -371,7 +385,7 @@ cat24c256_write16(uint16_t memaddr, void *buf, size_t buflen)
}
int
cat24c256_write(uint16_t memaddr, void *buf, size_t buflen)
cat24c256_write(uint16_t memaddr, void *buf, size_t buflen, int flags)
{
int r;
uint16_t i;
@ -384,7 +398,7 @@ cat24c256_write(uint16_t memaddr, void *buf, size_t buflen)
for (i = 0; i < buflen; i += 16) {
r = cat24c256_write16(memaddr + i, buf + i,
((buflen - i) < 16) ? (buflen - i) : 16);
((buflen - i) < 16) ? (buflen - i) : 16, flags);
if (r != OK) {
return r;
}

View file

@ -1298,6 +1298,7 @@
/* Bits in 'BDEV_FLAGS' field of block device transfer requests. */
# define BDEV_NOFLAGS 0x00 /* no flags are set */
# define BDEV_FORCEWRITE 0x01 /* force write to disk immediately */
# define BDEV_NOPAGE 0x02 /* eeprom: don't send page address */
/* Field names for GETRUSAGE related calls */
#define RU_ENDPT m1_i1 /* indicates a process for sys_getrusage */

View file

@ -98,8 +98,8 @@ typedef struct i2c_ioctl_exec {
void *iie_buf; /* pointer to data buffer */
size_t iie_buflen; /* length of data buffer */
} i2c_ioctl_exec_t;
#define I2C_EXEC_MAX_CMDLEN 32
#define I2C_EXEC_MAX_BUFLEN 32
#define I2C_EXEC_MAX_CMDLEN 128
#define I2C_EXEC_MAX_BUFLEN 128
#define I2C_IOCTL_EXEC _IOW('I', 0, i2c_ioctl_exec_t)