diff --git a/kernel/spec-i2c.c b/kernel/spec-i2c.c index 9a25aa938be0d9336eac5b7068254998c2d63f91..0303352df5fb179213007386eaea069f896ddaa1 100644 --- a/kernel/spec-i2c.c +++ b/kernel/spec-i2c.c @@ -141,32 +141,36 @@ int mi2c_scan(struct fmc_device *fmc) return found; } -/* FIXME: this is very inefficient: read several bytes in a row instead */ int spec_eeprom_read(struct fmc_device *fmc, uint32_t offset, void *buf, size_t size) { - int i; + int ret = size; uint8_t *buf8 = buf; unsigned char c; - for(i = 0; i < size; i++) { - mi2c_start(fmc); - if(mi2c_put_byte(fmc, fmc->eeprom_addr << 1) < 0) { - mi2c_stop(fmc); - return -EIO; - } + if (offset > SPEC_I2C_EEPROM_SIZE) + return -EINVAL; + if (offset + size > SPEC_I2C_EEPROM_SIZE) + return -EINVAL; - mi2c_put_byte(fmc, (offset >> 8) & 0xff); - mi2c_put_byte(fmc, offset & 0xff); - offset++; + /* Read it all in a single loop: hardware allows it */ + mi2c_start(fmc); + if(mi2c_put_byte(fmc, fmc->eeprom_addr << 1) < 0) { mi2c_stop(fmc); - mi2c_start(fmc); - mi2c_put_byte(fmc, (fmc->eeprom_addr << 1) | 1); - mi2c_get_byte(fmc, &c, 0); + return -EIO; + } + mi2c_put_byte(fmc, (offset >> 8) & 0xff); + mi2c_put_byte(fmc, offset & 0xff); + mi2c_stop(fmc); + mi2c_start(fmc); + mi2c_put_byte(fmc, (fmc->eeprom_addr << 1) | 1); + while (size--) { + mi2c_get_byte(fmc, &c, size != 0); *buf8++ = c; - mi2c_stop(fmc); + //printk("read 0x%08x, %4i to go\n", c, size); } - return size; + mi2c_stop(fmc); + return ret; } int spec_eeprom_write(struct fmc_device *fmc, uint32_t offset,