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  }