ChangeDeviceRegisters - Manouchehri/smi2021 GitHub Wiki

Summary

How to write/read registers

Introduction

This is what we know about writing/reading the data registers as a result of trying to reverse-engineer the firmware.

All reading/writing of the registers is handled by usb control transfers.

Instead of putting the register address and value in the wValue and wIndex like most other devices does, the somagic device requires the register address and value to be sent as part of a data structure in the data part of the control transfer.

This makes reading require two usb control transfers, since we first have to send the struct with the request about what to read, and then send an empty struct for the response. I2C Reads require 3 control transfer, we first have to prepare the I2C subsystem, before we can setup the read.

I've had some luck in reverse-engineering this struct.

struct somagic_register {
        u8 head;
        u8 i2c_address;
        u8 bm_data_type;
        u8 bm_data_offset;
        u8 data_size;
        u8 data[8];                /* This is data, and we never
                                      use more than the three first bytes */
};
  • The head seems to be a magic number, but the firmware expects this to be 0x0b.
  • i2c_address, is 0x00 when we talk to the smi2020cbe chip, and 0x4a when addressing the saa7113 chip (both for read & write)
  • bm_data_type is a bit-map.
  • bm_data_offset is a bit-map.
  • data_size tells the device how many bytes of data it should read

Bit-maps

BIT7 BIT6 BIT5 BIT4 BIT3 BIT2 BIT1 BIT0
bm_data_type I2C I2C_WRITE NEXT_IS_READ ????
bm_data_offset SMI ???? ???? OFFSET3 OFFSET2 OFFSET1 OFFSET0

bm_data_type

  • I2C Is set for all access to the saa7113 chip
  • I2C_WRITE Is cleared for all reads of the saa7113 chip
  • NEXT_IS_READ This is not clear to me, but the firmware needs this to be set if the next usb control transfer is going to be a read.
  • ???? I have no idea what the purpose of this is, I can not see that the firmware checks for the status of this bit. I suspect that this value is transfered to the usb subsystem on the device, and that this bit is checked for there?

bm_data_offset

  • SMI This is set for all access to the smi2020cbe chip.
  • ???? These bits are checked for in the firmware, but I don't know what they are good for.
  • OFFSETx This is a 4-bit number that tells the firmware the offset of the register-value in the data part of the struct. The saa7113 chip expects 1 byte i2c sub-addresses, so the value is after the i2c-sub-address i.e. the offset is 1. The smi2020cbe chip needs the register sub-address to be 2 bytes, so here the offset is 2.

Usage in the driver

There are five different versions of this struct that is used for reading/writing the registers in the device.

  1. Set a smi2020cbe register
  2. Read a smi2020cbe register
  3. Set a saa7113 register
  4. Prepare to read a saa7113 register
  5. Read a saa7113 register

1. Set a smi2020cbe register

struct somagic_register {
        .head = 0x0b,
        .i2c_address = 0x00,
        .bm_data_type = 0x00,
        .bm_data_offset = 0x82, /* SMI | OFFSET1 */
        .data_size = 0x01,
        .data = { REG_HI_ADDR, REG_LO_ADDR, REG_VALUE },
};

2. Read a smi2020cbe register

struct somagic_register {
        .head = 0x0b,
        .i2c_address = 0x00,
        .bm_data_type = 0x20,          /* NEXT_IS_READ */
        .bm_data_offset = 0x82,        /* SMI | OFFSET1 */
        .data_size = 0x01,
        .data = { REG_HI_ADDR, REG_LO_ADDR },

(We can now send a usb receive request for 13 byte to ep. 0x80)

3. Set a saa7113 register

struct somagic_register {
        .head = 0x0b,
        .i2c_address = 0x4a,
        .bm_data_type = 0xc0,          /* I2C | I2C_WRITE */
        .bm_data_offset = 0x01,        /* OFFSET0 */
        .data_size = 0x01,
        .data = { REG_ADDR, REG_VALUE },
};

4. Prepare to read a saa7113 register

struct somagic_register {
        .head = 0x0b,
        .i2c_address = 0x4a,
        .bm_data_type = 0x84,          /* I2C | ???? */
        .bm_data_offset = 0x00,
        .data_size = 0x01,
        .data = { REG_ADDR },
};

5. Read a saa7113 register

struct somagic_register {
        .head = 0x0b,
        .i2c_address = 0x4a,
        .bm_data_type = 0xa0,          /* I2C | NEXT_IS_READ */
        .bm_data_offset = 0x00,
        .data_size = 0x01,
        .data = { REG_ADDR },
};

(We can now send a usb receive request for 13 byte to ep. 0x80)