github.com/u-root/u-root@v7.0.1-0.20200915234505-ad7babab0a8e+incompatible/pkg/pci/pci.go (about)

     1  // Copyright 2012-2017 the u-root Authors. All rights reserved
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package pci
     6  
     7  import (
     8  	"encoding/binary"
     9  	"encoding/hex"
    10  	"fmt"
    11  	"io/ioutil"
    12  	"os"
    13  	"path/filepath"
    14  	"strings"
    15  )
    16  
    17  // PCI is a PCI device. We will fill this in as we add options.
    18  // For now it just holds two uint16 per the PCI spec.
    19  type PCI struct {
    20  	Addr       string
    21  	Vendor     string `pci:"vendor"`
    22  	Device     string `pci:"device"`
    23  	VendorName string
    24  	DeviceName string
    25  	FullPath   string
    26  	ExtraInfo  []string
    27  }
    28  
    29  // String concatenates PCI address, Vendor, and Device and other information
    30  // to make a useful display for the user.
    31  func (p *PCI) String() string {
    32  	return strings.Join(append([]string{fmt.Sprintf("%s: %v %v", p.Addr, p.VendorName, p.DeviceName)}, p.ExtraInfo...), "\n")
    33  }
    34  
    35  // SetVendorDeviceName changes VendorName and DeviceName from a name to a number,
    36  // if possible.
    37  func (p *PCI) SetVendorDeviceName() {
    38  	ids = newIDs()
    39  	p.VendorName, p.DeviceName = Lookup(ids, p.Vendor, p.Device)
    40  }
    41  
    42  // ReadConfig reads the config space and adds it to ExtraInfo as a hexdump.
    43  func (p *PCI) ReadConfig() error {
    44  	c, err := ioutil.ReadFile(filepath.Join(p.FullPath, "config"))
    45  	if err != nil {
    46  		return err
    47  	}
    48  	p.ExtraInfo = append(p.ExtraInfo, hex.Dump(c))
    49  	return nil
    50  }
    51  
    52  type barreg struct {
    53  	offset int64
    54  	*os.File
    55  }
    56  
    57  func (r *barreg) Read(b []byte) (int, error) {
    58  	return r.ReadAt(b, r.offset)
    59  }
    60  
    61  func (r *barreg) Write(b []byte) (int, error) {
    62  	return r.WriteAt(b, r.offset)
    63  }
    64  
    65  // ReadConfigRegister reads a configuration register of size 8, 16, 32, or 64.
    66  // It will only work on little-endian machines.
    67  func (p *PCI) ReadConfigRegister(offset, size int64) (uint64, error) {
    68  	f, err := os.Open(filepath.Join(p.FullPath, "config"))
    69  	if err != nil {
    70  		return 0, err
    71  	}
    72  	defer f.Close()
    73  	var reg uint64
    74  	r := &barreg{offset: offset, File: f}
    75  	switch size {
    76  	default:
    77  		return 0, fmt.Errorf("%d is not valid: only options are 8, 16, 32, 64", size)
    78  	case 64:
    79  		err = binary.Read(r, binary.LittleEndian, &reg)
    80  	case 32:
    81  		var val uint32
    82  		err = binary.Read(r, binary.LittleEndian, &val)
    83  		reg = uint64(val)
    84  	case 16:
    85  		var val uint16
    86  		err = binary.Read(r, binary.LittleEndian, &val)
    87  		reg = uint64(val)
    88  	case 8:
    89  		var val uint8
    90  		err = binary.Read(r, binary.LittleEndian, &val)
    91  		reg = uint64(val)
    92  	}
    93  	return reg, err
    94  }
    95  
    96  // WriteConfigRegister writes a configuration register of size 8, 16, 32, or 64.
    97  // It will only work on little-endian machines.
    98  func (p *PCI) WriteConfigRegister(offset, size int64, val uint64) error {
    99  	f, err := os.OpenFile(filepath.Join(p.FullPath, "config"), os.O_WRONLY, 0)
   100  	if err != nil {
   101  		return err
   102  	}
   103  	defer f.Close()
   104  	w := &barreg{offset: offset, File: f}
   105  	switch size {
   106  	default:
   107  		return fmt.Errorf("%d is not valid: only options are 8, 16, 32, 64", size)
   108  	case 64:
   109  		err = binary.Write(w, binary.LittleEndian, &val)
   110  	case 32:
   111  		var v = uint32(val)
   112  		err = binary.Write(w, binary.LittleEndian, &v)
   113  	case 16:
   114  		var v = uint16(val)
   115  		err = binary.Write(w, binary.LittleEndian, &v)
   116  	case 8:
   117  		var v = uint8(val)
   118  		err = binary.Write(w, binary.LittleEndian, &v)
   119  	}
   120  	return err
   121  }
   122  
   123  // Read implements the BusReader interface for type bus. Iterating over each
   124  // PCI bus device, and applying optional Filters to it.
   125  func (bus *bus) Read(filters ...Filter) (Devices, error) {
   126  	devices := make(Devices, 0, len(bus.Devices))
   127  iter:
   128  	for _, d := range bus.Devices {
   129  		p, err := onePCI(d)
   130  		if err != nil {
   131  			return nil, err
   132  		}
   133  		p.Addr = filepath.Base(d)
   134  		p.FullPath = d
   135  		for _, f := range filters {
   136  			if !f(p) {
   137  				continue iter
   138  			}
   139  		}
   140  		devices = append(devices, p)
   141  	}
   142  	return devices, nil
   143  }