gitee.com/mirrors_u-root/u-root@v7.0.0+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, ®) 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 }