github.com/jaypipes/ghw@v0.21.1/pkg/gpu/gpu_windows.go (about)

     1  // Use and distribution licensed under the Apache license version 2.
     2  //
     3  // See the COPYING file in the root project directory for full text.
     4  //
     5  
     6  package gpu
     7  
     8  import (
     9  	"strings"
    10  
    11  	"github.com/jaypipes/pcidb"
    12  	"github.com/yusufpapurcu/wmi"
    13  
    14  	"github.com/jaypipes/ghw/pkg/pci"
    15  	"github.com/jaypipes/ghw/pkg/util"
    16  )
    17  
    18  const wqlVideoController = "SELECT Caption, CreationClassName, Description, DeviceID, DriverVersion, Name, PNPDeviceID, SystemCreationClassName, SystemName, VideoArchitecture, VideoMemoryType, VideoModeDescription, VideoProcessor FROM Win32_VideoController"
    19  
    20  type win32VideoController struct {
    21  	Caption                 string
    22  	CreationClassName       string
    23  	Description             string
    24  	DeviceID                string
    25  	DriverVersion           string
    26  	Name                    string
    27  	PNPDeviceID             string
    28  	SystemCreationClassName string
    29  	SystemName              string
    30  	VideoArchitecture       uint16
    31  	VideoMemoryType         uint16
    32  	VideoModeDescription    string
    33  	VideoProcessor          string
    34  }
    35  
    36  const wqlPnPEntity = "SELECT Caption, CreationClassName, Description, DeviceID, Manufacturer, Name, PNPClass, PNPDeviceID FROM Win32_PnPEntity"
    37  
    38  type win32PnPEntity struct {
    39  	Caption           string
    40  	CreationClassName string
    41  	Description       string
    42  	DeviceID          string
    43  	Manufacturer      string
    44  	Name              string
    45  	PNPClass          string
    46  	PNPDeviceID       string
    47  }
    48  
    49  func (i *Info) load() error {
    50  	// Getting data from WMI
    51  	var win32VideoControllerDescriptions []win32VideoController
    52  	if err := wmi.Query(wqlVideoController, &win32VideoControllerDescriptions); err != nil {
    53  		return err
    54  	}
    55  
    56  	// Building dynamic WHERE clause with addresses to create a single query collecting all desired data
    57  	queryAddresses := []string{}
    58  	for _, description := range win32VideoControllerDescriptions {
    59  		var queryAddres = strings.ReplaceAll(description.PNPDeviceID, "\\", `\\`)
    60  		queryAddresses = append(queryAddresses, "PNPDeviceID='"+queryAddres+"'")
    61  	}
    62  	whereClause := strings.Join(queryAddresses[:], " OR ")
    63  
    64  	// Getting data from WMI
    65  	var win32PnPDescriptions []win32PnPEntity
    66  	var wqlPnPDevice = wqlPnPEntity + " WHERE " + whereClause
    67  	if err := wmi.Query(wqlPnPDevice, &win32PnPDescriptions); err != nil {
    68  		return err
    69  	}
    70  
    71  	// Converting into standard structures
    72  	cards := make([]*GraphicsCard, 0)
    73  	for _, description := range win32VideoControllerDescriptions {
    74  		card := &GraphicsCard{
    75  			Address:    description.DeviceID, // https://stackoverflow.com/questions/32073667/how-do-i-discover-the-pcie-bus-topology-and-slot-numbers-on-the-board
    76  			Index:      0,
    77  			DeviceInfo: GetDevice(description.PNPDeviceID, win32PnPDescriptions),
    78  		}
    79  		card.DeviceInfo.Driver = description.DriverVersion
    80  		cards = append(cards, card)
    81  	}
    82  	i.GraphicsCards = cards
    83  	return nil
    84  }
    85  
    86  func GetDevice(id string, entities []win32PnPEntity) *pci.Device {
    87  	// Backslashing PnP address ID as requested by JSON and VMI query: https://docs.microsoft.com/en-us/windows/win32/wmisdk/where-clause
    88  	var queryAddress = strings.ReplaceAll(id, "\\", `\\`)
    89  	// Preparing default structure
    90  	var device = &pci.Device{
    91  		Address: queryAddress,
    92  		Vendor: &pcidb.Vendor{
    93  			ID:       util.UNKNOWN,
    94  			Name:     util.UNKNOWN,
    95  			Products: []*pcidb.Product{},
    96  		},
    97  		Subsystem: &pcidb.Product{
    98  			ID:         util.UNKNOWN,
    99  			Name:       util.UNKNOWN,
   100  			Subsystems: []*pcidb.Product{},
   101  		},
   102  		Product: &pcidb.Product{
   103  			ID:         util.UNKNOWN,
   104  			Name:       util.UNKNOWN,
   105  			Subsystems: []*pcidb.Product{},
   106  		},
   107  		Class: &pcidb.Class{
   108  			ID:         util.UNKNOWN,
   109  			Name:       util.UNKNOWN,
   110  			Subclasses: []*pcidb.Subclass{},
   111  		},
   112  		Subclass: &pcidb.Subclass{
   113  			ID:                    util.UNKNOWN,
   114  			Name:                  util.UNKNOWN,
   115  			ProgrammingInterfaces: []*pcidb.ProgrammingInterface{},
   116  		},
   117  		ProgrammingInterface: &pcidb.ProgrammingInterface{
   118  			ID:   util.UNKNOWN,
   119  			Name: util.UNKNOWN,
   120  		},
   121  	}
   122  	// If an entity is found we get its data inside the standard structure
   123  	for _, description := range entities {
   124  		if id == description.PNPDeviceID {
   125  			device.Vendor.ID = description.Manufacturer
   126  			device.Vendor.Name = description.Manufacturer
   127  			device.Product.ID = description.Name
   128  			device.Product.Name = description.Description
   129  			break
   130  		}
   131  	}
   132  	return device
   133  }