ms-tools/mshal/hal_rom.go
Bertold Van den Bergh 680e4f77ab Initial commit of code
2021-07-25 23:09:00 +02:00

213 lines
4.3 KiB
Go

package mshal
import (
"bytes"
"encoding/hex"
"time"
)
type cbApplyParamType func(h *HAL, out []byte) error
type cbPostExchangeType func(h *HAL, addr int, buf []byte) error
type romCommand struct {
id byte
is16bit bool
isWrite bool
maxPayload int
cbApplyParam cbApplyParamType
cbPostExchange cbPostExchangeType
}
func romCommandMake(id byte, is16bit bool, isWrite bool) romCommand {
return romCommand{
id: id,
is16bit: is16bit,
isWrite: isWrite,
}
}
func romCommandMakeReadWrite(id byte, is16bit bool) (romCommand, romCommand) {
return romCommandMake(id, is16bit, false), romCommandMake(id+1, is16bit, true)
}
func (h *HAL) romExchangeReport(out [9]byte, checkLen int) ([9]byte, error) {
var in [9]byte
if h.config.LogFunc != nil {
h.config.LogFunc(3, "ROMOut: %s", hex.EncodeToString(out[:]))
}
if _, err := h.dev.SendFeatureReport(out[:]); err != nil {
return in, err
}
_, err := h.dev.GetFeatureReport(in[:])
if err != nil {
return in, err
}
if h.config.LogFunc != nil {
h.config.LogFunc(3, "ROMIn: %s", hex.EncodeToString(in[:]))
}
if !bytes.Equal(out[:checkLen], in[:checkLen]) {
return in, ErrorInvalidResponse
}
return in, nil
}
func (h *HAL) romProtocolMakeHeader(cmd byte, is16bit bool, addr int) ([9]byte, int) {
var out [9]byte
out[0] = 0
out[1] = byte(cmd)
index := 2
if is16bit {
out[index] = byte(addr >> 8)
index++
}
out[index] = byte(addr)
index++
return out, index
}
func (h *HAL) romProtocolReadReply(buf []byte, in []byte, index int, maxReply int) int {
if len(buf) > maxReply {
buf = buf[:maxReply]
}
return copy(buf, in[index:])
}
func (h *HAL) romProtocolWritePayload(buf []byte, out []byte, index int, maxLen int) int {
if len(buf) > maxLen {
buf = buf[:maxLen]
}
return copy(out[index:], buf)
}
func (h *HAL) romProtocolExec(cmd romCommand, addr int, buf []byte) (int, error) {
if len(buf) == 0 {
return 0, nil
}
maxPayload := cmd.maxPayload
if maxPayload <= 0 {
maxPayload = 1
}
out, index := h.romProtocolMakeHeader(cmd.id, cmd.is16bit, addr)
txrLen := 0
if cmd.isWrite {
txrLen = h.romProtocolWritePayload(buf, out[:], index, maxPayload)
}
if cmd.cbApplyParam != nil {
if err := cmd.cbApplyParam(h, out[:]); err != nil {
return 0, err
}
}
in, err := h.romExchangeReport(out, index)
if err != nil {
return 0, err
}
if !cmd.isWrite {
txrLen = h.romProtocolReadReply(buf, in[:], index, maxPayload)
}
if cmd.cbPostExchange != nil {
if err := cmd.cbPostExchange(h, addr, buf); err != nil {
return 0, err
}
}
return txrLen, nil
}
type halROMMemoryRegion struct {
hal *HAL
readCommand *romCommand
writeCommand *romCommand
baseAddr int
length int
name MemoryRegionNameType
}
func (h halROMMemoryRegion) GetName() MemoryRegionNameType {
return h.name
}
func (h halROMMemoryRegion) GetLength() int {
return h.length
}
func (h halROMMemoryRegion) GetParent() (MemoryRegion, int) {
return nil, 0
}
func (h halROMMemoryRegion) Access(write bool, addr int, buf []byte) (int, error) {
if addr > h.length {
return 0, nil
}
if addr+len(buf) > h.length {
buf = buf[:h.length-addr]
}
if write {
if h.writeCommand == nil {
return 0, ErrorWriteNotAllowed
}
return h.hal.romProtocolExec(*h.writeCommand, h.baseAddr+addr, buf)
}
if h.writeCommand == nil {
return 0, ErrorWriteNotAllowed
}
return h.hal.romProtocolExec(*h.readCommand, h.baseAddr+addr, buf)
}
func (h *HAL) romMemoryRegionMake(name MemoryRegionNameType, baseAddr int, length int, read *romCommand, write *romCommand) MemoryRegion {
return regionWrapCompleteIO(halROMMemoryRegion{
hal: h,
baseAddr: baseAddr,
length: length,
readCommand: read,
writeCommand: write,
name: name,
})
}
func romEepromV2HandleTwoByteAddress(h *HAL, out []byte) error {
if h.eepromSize > 2048 {
out[8] = 1
}
return nil
}
func romEepromVerify(region MemoryRegion) cbPostExchangeType {
return func(h *HAL, addr int, buf []byte) error {
if buf[0] == 0 {
/* The chip returns 0 if there is no I2C response, so we just have to wait */
time.Sleep(15 * time.Millisecond)
return nil
}
var tmp [1]byte
for i := 0; i < 25; i++ {
if _, err := region.Access(false, addr, tmp[:]); err != nil {
return err
}
if tmp[0] == buf[0] {
return nil
}
}
return ErrorTimeout
}
}