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
headseems to be a magic number, but the firmware expects this to be0x0b. i2c_address, is0x00when we talk to the smi2020cbe chip, and0x4awhen addressing the saa7113 chip (both for read & write)bm_data_typeis a bit-map.bm_data_offsetis a bit-map.data_sizetells the device how many bytes ofdatait 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
I2CIs set for all access to the saa7113 chipI2C_WRITEIs cleared for all reads of the saa7113 chipNEXT_IS_READThis 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
SMIThis 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.OFFSETxThis 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.
- Set a smi2020cbe register
- Read a smi2020cbe register
- Set a saa7113 register
- Prepare to read a saa7113 register
- 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)