129 lines
4.0 KiB
Go
129 lines
4.0 KiB
Go
// Use and distribution licensed under the Apache license version 2.
|
|
//
|
|
// See the COPYING file in the root project directory for full text.
|
|
//
|
|
|
|
package ghw
|
|
|
|
import (
|
|
"strings"
|
|
|
|
"github.com/StackExchange/wmi"
|
|
"github.com/jaypipes/pcidb"
|
|
)
|
|
|
|
const wqlVideoController = "SELECT Caption, CreationClassName, Description, DeviceID, Name, PNPDeviceID, SystemCreationClassName, SystemName, VideoArchitecture, VideoMemoryType, VideoModeDescription, VideoProcessor FROM Win32_VideoController"
|
|
|
|
type win32VideoController struct {
|
|
Caption string
|
|
CreationClassName string
|
|
Description string
|
|
DeviceID string
|
|
Name string
|
|
PNPDeviceID string
|
|
SystemCreationClassName string
|
|
SystemName string
|
|
VideoArchitecture uint16
|
|
VideoMemoryType uint16
|
|
VideoModeDescription string
|
|
VideoProcessor string
|
|
}
|
|
|
|
const wqlPnPEntity = "SELECT Caption, CreationClassName, Description, DeviceID, Manufacturer, Name, PNPClass, PNPDeviceID FROM Win32_PnPEntity"
|
|
|
|
type win32PnPEntity struct {
|
|
Caption string
|
|
CreationClassName string
|
|
Description string
|
|
DeviceID string
|
|
Manufacturer string
|
|
Name string
|
|
PNPClass string
|
|
PNPDeviceID string
|
|
}
|
|
|
|
func (ctx *context) gpuFillInfo(info *GPUInfo) error {
|
|
// Getting data from WMI
|
|
var win32VideoControllerDescriptions []win32VideoController
|
|
if err := wmi.Query(wqlVideoController, &win32VideoControllerDescriptions); err != nil {
|
|
return err
|
|
}
|
|
|
|
// Building dynamic WHERE clause with addresses to create a single query collecting all desired data
|
|
queryAddresses := []string{}
|
|
for _, description := range win32VideoControllerDescriptions {
|
|
var queryAddres = strings.Replace(description.PNPDeviceID, "\\", `\\`, -1)
|
|
queryAddresses = append(queryAddresses, "PNPDeviceID='"+queryAddres+"'")
|
|
}
|
|
whereClause := strings.Join(queryAddresses[:], " OR ")
|
|
|
|
// Getting data from WMI
|
|
var win32PnPDescriptions []win32PnPEntity
|
|
var wqlPnPDevice = wqlPnPEntity + " WHERE " + whereClause
|
|
if err := wmi.Query(wqlPnPDevice, &win32PnPDescriptions); err != nil {
|
|
return err
|
|
}
|
|
|
|
// Converting into standard structures
|
|
cards := make([]*GraphicsCard, 0)
|
|
for _, description := range win32VideoControllerDescriptions {
|
|
card := &GraphicsCard{
|
|
Address: description.DeviceID, // https://stackoverflow.com/questions/32073667/how-do-i-discover-the-pcie-bus-topology-and-slot-numbers-on-the-board
|
|
Index: 0,
|
|
DeviceInfo: ctx.GetDevice(description.PNPDeviceID, win32PnPDescriptions),
|
|
}
|
|
cards = append(cards, card)
|
|
}
|
|
info.GraphicsCards = cards
|
|
return nil
|
|
}
|
|
|
|
func (ctx *context) GetDevice(id string, entities []win32PnPEntity) *PCIDevice {
|
|
// Backslashing PnP address ID as requested by JSON and VMI query: https://docs.microsoft.com/en-us/windows/win32/wmisdk/where-clause
|
|
var queryAddress = strings.Replace(id, "\\", `\\`, -1)
|
|
// Preparing default structure
|
|
var device = &PCIDevice{
|
|
Address: queryAddress,
|
|
Vendor: &pcidb.Vendor{
|
|
ID: UNKNOWN,
|
|
Name: UNKNOWN,
|
|
Products: []*pcidb.Product{},
|
|
},
|
|
Subsystem: &pcidb.Product{
|
|
ID: UNKNOWN,
|
|
Name: UNKNOWN,
|
|
Subsystems: []*pcidb.Product{},
|
|
},
|
|
Product: &pcidb.Product{
|
|
ID: UNKNOWN,
|
|
Name: UNKNOWN,
|
|
Subsystems: []*pcidb.Product{},
|
|
},
|
|
Class: &pcidb.Class{
|
|
ID: UNKNOWN,
|
|
Name: UNKNOWN,
|
|
Subclasses: []*pcidb.Subclass{},
|
|
},
|
|
Subclass: &pcidb.Subclass{
|
|
ID: UNKNOWN,
|
|
Name: UNKNOWN,
|
|
ProgrammingInterfaces: []*pcidb.ProgrammingInterface{},
|
|
},
|
|
ProgrammingInterface: &pcidb.ProgrammingInterface{
|
|
ID: UNKNOWN,
|
|
Name: UNKNOWN,
|
|
},
|
|
}
|
|
// If an entity is found we get its data inside the standard structure
|
|
for _, description := range entities {
|
|
if id == description.PNPDeviceID {
|
|
device.Vendor.ID = description.Manufacturer
|
|
device.Vendor.Name = description.Manufacturer
|
|
device.Product.ID = description.Name
|
|
device.Product.Name = description.Description
|
|
break
|
|
}
|
|
}
|
|
return device
|
|
}
|