From efe0c282ba5de0aaf70a779f499a003864d7105c Mon Sep 17 00:00:00 2001 From: Jan Hoffmann Date: Fri, 27 Mar 2026 18:33:43 +0100 Subject: [PATCH] Fix I2C access code While the current implementation works for what it is actually used, it is broken when trying to do larger transfers. The length field in the control register has a size of 4 bits. In every transfer, length+1 bytes are read. Thus, each transfer is limited to a maximum of 16 bytes. Add a check for the length, and write the correct value to the register. Also update the loop in "sfp_send_data" to properly increment the output register. Remove the unused special case for a length of 128 bytes. --- httpd/page_impl.c | 17 +++++++++-------- rtlplayground.c | 4 ++-- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/httpd/page_impl.c b/httpd/page_impl.c index 78c773e..f6a471e 100644 --- a/httpd/page_impl.c +++ b/httpd/page_impl.c @@ -175,11 +175,15 @@ void send_sfp_info(uint8_t sfp) void sfp_send_data(uint8_t slot, uint8_t reg, uint8_t len) { + // maximum supported transfer size is 16 bytes + if (len > 16) + return; + if (reg & 0x80) { // Configure SFP readings address (0x51) as I2C device address reg &= 0x7f; - REG_WRITE(RTL837X_REG_I2C_CTRL, 0x00, 0x1 << (I2C_MEM_ADDR_WIDTH-16) | len & 0xf, 0x51 >> 5, (0x51 << 3) & 0xff); + REG_WRITE(RTL837X_REG_I2C_CTRL, 0x00, 0x1 << (I2C_MEM_ADDR_WIDTH-16) | (len - 1) & 0xf, 0x51 >> 5, (0x51 << 3) & 0xff); } else { - REG_WRITE(RTL837X_REG_I2C_CTRL, 0x00, 0x1 << (I2C_MEM_ADDR_WIDTH-16) | len & 0xf, 0x50 >> 5, (0x50 << 3) & 0xff); + REG_WRITE(RTL837X_REG_I2C_CTRL, 0x00, 0x1 << (I2C_MEM_ADDR_WIDTH-16) | (len - 1) & 0xf, 0x50 >> 5, (0x50 << 3) & 0xff); } reg_read_m(RTL837X_REG_I2C_CTRL); @@ -196,13 +200,10 @@ void sfp_send_data(uint8_t slot, uint8_t reg, uint8_t len) reg_read_m(RTL837X_REG_I2C_CTRL); } while (sfr_data[3] & 0x1); - for (uint8_t i = 0; i < len & 0xf; i++) { + for (uint8_t i = 0; i < len; i++) { if (!(i & 0x3)) - reg_read_m(RTL837X_REG_I2C_OUT + (i >> 2)); - if (len & 0x80) - char_to_html(sfr_data[3 - (i & 0x3)]); - else - byte_to_html(sfr_data[3 - (i & 0x3)]); + reg_read_m(RTL837X_REG_I2C_OUT + i); + byte_to_html(sfr_data[3 - (i & 0x3)]); } } diff --git a/rtlplayground.c b/rtlplayground.c index 358650d..7097d64 100644 --- a/rtlplayground.c +++ b/rtlplayground.c @@ -832,9 +832,9 @@ uint8_t sfp_read_reg(uint8_t slot, uint8_t reg) { if (reg & 0x80) { // Configure SFP readings address (0x51) as I2C device address reg &= 0x7f; - REG_WRITE(RTL837X_REG_I2C_CTRL, 0x00, 0x1 << (I2C_MEM_ADDR_WIDTH-16) | 1, 0x51 >> 5, (0x51 << 3) & 0xff); + REG_WRITE(RTL837X_REG_I2C_CTRL, 0x00, 0x1 << (I2C_MEM_ADDR_WIDTH-16) | 0, 0x51 >> 5, (0x51 << 3) & 0xff); } else { - REG_WRITE(RTL837X_REG_I2C_CTRL, 0x00, 0x1 << (I2C_MEM_ADDR_WIDTH-16) | 1, 0x50 >> 5, (0x50 << 3) & 0xff); + REG_WRITE(RTL837X_REG_I2C_CTRL, 0x00, 0x1 << (I2C_MEM_ADDR_WIDTH-16) | 0, 0x50 >> 5, (0x50 << 3) & 0xff); } reg_read_m(RTL837X_REG_I2C_CTRL);