github.com/u-root/u-root@v7.0.1-0.20200915234505-ad7babab0a8e+incompatible/cmds/exp/ectool/lpc.go (about) 1 package main 2 3 import ( 4 "errors" 5 "fmt" 6 "os" 7 "time" 8 ) 9 10 const ( 11 initialUdelay time.Duration = time.Microsecond 12 maximumUdelay time.Duration = 20 * time.Microsecond 13 ) 14 15 type lpc struct { 16 ioport 17 statusAddr ioaddr 18 status ioaddr 19 cmd ioaddr 20 initial, max time.Duration 21 debugf 22 } 23 24 func init() { 25 chips["lpc"] = newLPC 26 } 27 28 func newLPC(p ioport, sa ioaddr, i, m time.Duration, d debugf) ec { 29 return &lpc{ioport: p, statusAddr: sa, initial: i, max: m, debugf: d} 30 } 31 32 func (l *lpc) Wait(timeout time.Duration) error { 33 delay := l.initial 34 35 for i := time.Duration(0); i < timeout; i += l.initial { 36 // TODO: kill this static timeout and use chans. 37 // But for now we clone what the C code did. 38 if delay > l.max { 39 delay = l.max 40 } 41 /* 42 * Delay first, in case we just sent out a command but the EC 43 * hasn't raised the busy flag. However, I think this doesn't 44 * happen since the LPC commands are executed in order and the 45 * busy flag is set by hardware. Minor issue in any case, 46 * since the initial delay is very short. 47 */ 48 time.Sleep(delay) 49 v, err := l.Inb(l.statusAddr) 50 if err != nil { 51 return err 52 } 53 if v == 0 { 54 return nil 55 } 56 if i > 20 && delay < l.max { 57 delay *= 2 58 } 59 } 60 return fmt.Errorf("LPC timed out") 61 } 62 63 func (l *lpc) Cleanup(timeout time.Duration) error { return nil } 64 func (l *lpc) Probe(timeout time.Duration) error { return nil } 65 66 func (l *lpc) Command(c command, v version, idata []byte, outsize int, timeout time.Duration) ([]byte, error) { 67 flags := uint8(ecHostArgsFlagFromHost) 68 csum := flags + uint8(c) + uint8(v) + uint8(len(idata)) 69 70 for i, d := range idata { 71 err := l.Outb(l.statusAddr+ioaddr(i), d) 72 if err != nil { 73 return nil, err 74 } 75 csum += d 76 } 77 78 cmd := []uint8{ecHostArgsFlagFromHost, uint8(v), uint8(len(idata)), uint8(csum)} 79 _, err := l.Outs(l.statusAddr, cmd) 80 if err != nil { 81 fmt.Fprintf(os.Stderr, "%v", err) 82 return nil, err 83 } 84 85 l.Outb(l.cmd, uint8(c)) 86 l.Outb(l.status, 0xa5) 87 88 if err := l.Wait(10 * time.Second); err != nil { 89 return nil, errors.New("Timeout waiting for EC response") 90 } 91 92 /* Check result */ 93 i, err := l.Inb(ecLpcAddrHostData) 94 if err != nil { 95 return nil, err 96 } 97 98 if i != 0 { 99 return nil, fmt.Errorf("Bad EC value %d", i) 100 } 101 102 /* Read back args */ 103 dres, err := l.Ins(ecLpcAddrHostArgs, 4) 104 if err != nil { 105 return nil, err 106 } 107 108 /* 109 * If EC didn't modify args flags, then somehow we sent a new-style 110 * command to an old EC, which means it would have read its params 111 * from the wrong place. 112 */ 113 if flags&ecHostArgsFlagToHost == ecHostArgsFlagToHost { 114 return nil, errors.New("EC appears to have reset (may be expected)") 115 } 116 117 if dres[2] > uint8(outsize) { 118 return nil, errors.New("EC returned too much data") 119 } 120 121 /* Start calculating response checksum */ 122 csum = uint8(c) + dres[0] + uint8(v) + dres[2] 123 124 /* Read response and update checksum */ 125 dout, err := l.Ins(ecLpcAddrHostParam, int(dres[2])) 126 if err != nil { 127 return nil, err 128 } 129 130 for _, i := range dout { 131 csum += i 132 } 133 /* Verify checksum */ 134 if dout[3] != csum { 135 return nil, errors.New("EC response has invalid checksum") 136 } 137 138 return dout, nil 139 }