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:
parent
11be35a165
commit
437177b028
|
@ -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");
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
Loading…
Reference in a new issue