github.com/platinasystems/nvram@v1.0.1-0.20190709235807-51a23abd5aec/cmos.go (about)

     1  // Copyright © 2019 Platina Systems, Inc. All rights reserved.
     2  // Use of this source code is governed by the GPL-2 license described in the
     3  // LICENSE file.
     4  
     5  package nvram
     6  
     7  import (
     8  	"fmt"
     9  	"github.com/platinasystems/nvram/debug"
    10  )
    11  
    12  const (
    13  	cmosSize        uint = 256
    14  	cmosRTCAreaSize uint = 14
    15  )
    16  
    17  func verifyCMOSByteIndex(index uint) bool {
    18  	return (index >= cmosRTCAreaSize) && (index < cmosSize)
    19  }
    20  
    21  type CMOSer interface {
    22  	Close() error
    23  	ReadByte(off uint) (byte, error)
    24  	WriteByte(off uint, b byte) error
    25  }
    26  
    27  type CMOS struct {
    28  	accessor CMOSer
    29  	checksum CMOSChecksum
    30  }
    31  
    32  func (c *CMOS) Open() (err error) {
    33  	// Close in case it is already opened.
    34  	c.Close()
    35  
    36  	// Open CMOS hardware accessor.
    37  	accessor := new(CMOSHW)
    38  	err = accessor.Open()
    39  	if err != nil {
    40  		return
    41  	}
    42  
    43  	c.accessor = accessor
    44  	return
    45  }
    46  
    47  func (c *CMOS) OpenMem(filename string) (err error) {
    48  	// Close in case it is already opened
    49  	c.Close()
    50  
    51  	// Open CMOS memory file accessor.
    52  	accessor := new(CMOSMem)
    53  	err = accessor.Open(filename)
    54  	if err != nil {
    55  		return
    56  	}
    57  
    58  	c.accessor = accessor
    59  	return
    60  }
    61  
    62  func (c *CMOS) Close() (err error) {
    63  	// Close any accessor if opened
    64  	if c.accessor != nil {
    65  		err = c.accessor.Close()
    66  		c.accessor = nil
    67  	}
    68  	return
    69  }
    70  
    71  func (c *CMOS) WriteEntry(e *CMOSEntry, v []byte) (err error) {
    72  	// Verify CMOS operation
    73  	err = verifyCMOSOp(e)
    74  	if err != nil {
    75  		return
    76  	}
    77  
    78  	// Calculate source size, bit offset and remaining bits for entry field.
    79  	src_size := uint(8)
    80  	src_bit := uint(0)
    81  	src_bit_remaining := e.length
    82  	if src_bit_remaining > uint(len(v)*8) {
    83  		src_bit_remaining = uint(len(v) * 8)
    84  	}
    85  
    86  	// Start at destination bit
    87  	dst_bit := e.bit
    88  	for src_bit_remaining > 0 {
    89  		// Get write value from source
    90  		wvalue := v[src_bit>>3]
    91  
    92  		debug.Trace(debug.LevelMSG3, "src_bit = %d dst_bit = %d src_size = %d  wvalue = %X\n",
    93  			src_bit, dst_bit, src_size, wvalue)
    94  
    95  		// Update destination with partial byte data
    96  		if src_size > src_bit_remaining {
    97  			// Find Write value with partial data
    98  			src_size = src_bit_remaining
    99  			wvalue = (wvalue >> (src_bit & 0x7)) & (byte(1<<src_size) - 1)
   100  
   101  			// Read current value from destination
   102  			n := byte(0)
   103  			n, err = c.ReadByte(dst_bit >> 3)
   104  			if err != nil {
   105  				return
   106  			}
   107  
   108  			// Update destination with remaining bits to write
   109  			mask := (byte(1<<src_size) - 1) << (dst_bit & 0x07)
   110  			n = (n & ^mask) | ((wvalue << (dst_bit & 0x07)) & mask)
   111  			err = c.WriteByte(dst_bit>>3, n)
   112  			return
   113  		} else {
   114  			// Overwrite whole byte values
   115  			err = c.WriteByte(dst_bit>>3, wvalue)
   116  			if err != nil {
   117  				return
   118  			}
   119  		}
   120  
   121  		// Move to next byte
   122  		src_bit += src_size
   123  		src_bit_remaining -= src_size
   124  		dst_bit += src_size
   125  	}
   126  
   127  	return
   128  }
   129  
   130  func (c *CMOS) ReadEntry(e *CMOSEntry) (v []byte, err error) {
   131  	// Verify CMOS operation
   132  	err = verifyCMOSOp(e)
   133  	if err != nil {
   134  		return
   135  	}
   136  
   137  	// Calculate source size, bit offset and remaining bits for entry field.
   138  	src_size := uint(8)
   139  	src_bit := e.bit
   140  	src_bit_remaining := e.length
   141  
   142  	// Start at destination bit
   143  	dst_bit := uint(0)
   144  
   145  	// Create return value buffer.
   146  	if e.config == CMOSEntryString {
   147  		v = make([]byte, (e.length+7)/8)
   148  	} else {
   149  		v = make([]byte, 8)
   150  	}
   151  
   152  	for src_bit_remaining > 0 {
   153  		// Read source byte
   154  		n := byte(0)
   155  		n, err = c.ReadByte(src_bit >> 3)
   156  		if err != nil {
   157  			return
   158  		}
   159  
   160  		debug.Trace(debug.LevelMSG3, "src_bit = %d dst_bit = %d, src_size = %d  n = %X\n",
   161  			src_bit, dst_bit, src_size, n)
   162  
   163  		// For last partial byte mask off extra bits
   164  		if src_size > src_bit_remaining {
   165  			src_size = src_bit_remaining
   166  			n = (n >> (src_bit & 0x7)) & (byte(1<<src_size) - 1)
   167  		}
   168  
   169  		// Copy byte read
   170  		v[dst_bit>>3] = n
   171  
   172  		// Move to next byte
   173  		src_bit += src_size
   174  		src_bit_remaining -= src_size
   175  		dst_bit += src_size
   176  	}
   177  
   178  	return
   179  }
   180  
   181  func (c *CMOS) ReadChecksum() (sum uint16, err error) {
   182  	var b0, b1 byte
   183  
   184  	// Read checksum b0 and b1
   185  	b0, err = c.ReadByte(c.checksum.index)
   186  	if err != nil {
   187  		return
   188  	}
   189  	b1, err = c.ReadByte(c.checksum.index + 1)
   190  	if err != nil {
   191  		return
   192  	}
   193  	// return in big endian format
   194  	sum = (uint16(b0) << 8) + uint16(b1)
   195  	return
   196  }
   197  
   198  func (c *CMOS) WriteChecksum(sum uint16) (err error) {
   199  	// Write checksum byte 0
   200  	err = c.WriteByte(c.checksum.index, byte(sum>>8))
   201  	if err != nil {
   202  		return
   203  	}
   204  	// Write checksum byte 1
   205  	err = c.WriteByte(c.checksum.index+1, byte(sum&0xFF))
   206  	if err != nil {
   207  		return
   208  	}
   209  	return
   210  }
   211  
   212  func (c *CMOS) ComputeChecksum() (sum uint16, err error) {
   213  	// Calculate checksum over chemsum area
   214  	for i := c.checksum.start; i <= c.checksum.end; i++ {
   215  		var b byte
   216  		b, err = c.ReadByte(i)
   217  		if err != nil {
   218  			return
   219  		}
   220  		sum += uint16(b)
   221  	}
   222  	return
   223  }
   224  
   225  func (c *CMOS) ReadAllMemory() (d []byte, err error) {
   226  	// Retrun buffer with all CMOS data bytes
   227  	// Ignore the RTC area.
   228  	d = make([]byte, cmosSize)
   229  	for i := cmosRTCAreaSize; i < cmosSize; i++ {
   230  		d[i], err = c.ReadByte(i)
   231  		if err != nil {
   232  			return
   233  		}
   234  	}
   235  	return
   236  }
   237  
   238  func (c *CMOS) WriteAllMemory(d []byte) (err error) {
   239  	if len(d) < int(cmosSize) {
   240  		return fmt.Errorf("nvram: Not enough data.")
   241  	}
   242  	// Write buffer to entire CMOS area.
   243  	// Ignore RTC area.
   244  	for i := cmosRTCAreaSize; i < cmosSize; i++ {
   245  		err = c.WriteByte(i, d[i])
   246  		if err != nil {
   247  			return
   248  		}
   249  	}
   250  	return
   251  }
   252  
   253  func (c *CMOS) ReadByte(off uint) (byte, error) {
   254  	// Read byte using current accessor
   255  	if c.accessor == nil {
   256  		return 0, ErrCMOSNotOpen
   257  	}
   258  	return c.accessor.ReadByte(off)
   259  }
   260  
   261  func (c *CMOS) WriteByte(off uint, b byte) error {
   262  	// Write byte using current accessor
   263  	if c.accessor == nil {
   264  		return ErrCMOSNotOpen
   265  	}
   266  	return c.accessor.WriteByte(off, b)
   267  }