aboutsummaryrefslogtreecommitdiff
path: root/qga/commands-win32.c
diff options
context:
space:
mode:
Diffstat (limited to 'qga/commands-win32.c')
-rw-r--r--qga/commands-win32.c97
1 files changed, 96 insertions, 1 deletions
diff --git a/qga/commands-win32.c b/qga/commands-win32.c
index 2bcc4a5daf..a7822d5ff7 100644
--- a/qga/commands-win32.c
+++ b/qga/commands-win32.c
@@ -23,6 +23,8 @@
#ifdef CONFIG_QGA_NTDDSCSI
#include <winioctl.h>
#include <ntddscsi.h>
+#include <setupapi.h>
+#include <initguid.h>
#endif
#include "qga/guest-agent-core.h"
#include "qga/vss-win32.h"
@@ -424,9 +426,102 @@ static GuestDiskBusType find_bus_type(STORAGE_BUS_TYPE bus)
return win2qemu[(int)bus];
}
+DEFINE_GUID(GUID_DEVINTERFACE_VOLUME,
+ 0x53f5630dL, 0xb6bf, 0x11d0, 0x94, 0xf2,
+ 0x00, 0xa0, 0xc9, 0x1e, 0xfb, 0x8b);
+
static GuestPCIAddress *get_pci_info(char *guid, Error **errp)
{
- return NULL;
+ HDEVINFO dev_info;
+ SP_DEVINFO_DATA dev_info_data;
+ DWORD size = 0;
+ int i;
+ char dev_name[MAX_PATH];
+ char *buffer = NULL;
+ GuestPCIAddress *pci = NULL;
+ char *name = g_strdup(&guid[4]);
+
+ if (!QueryDosDevice(name, dev_name, ARRAY_SIZE(dev_name))) {
+ error_setg_win32(errp, GetLastError(), "failed to get dos device name");
+ goto out;
+ }
+
+ dev_info = SetupDiGetClassDevs(&GUID_DEVINTERFACE_VOLUME, 0, 0,
+ DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
+ if (dev_info == INVALID_HANDLE_VALUE) {
+ error_setg_win32(errp, GetLastError(), "failed to get devices tree");
+ goto out;
+ }
+
+ dev_info_data.cbSize = sizeof(SP_DEVINFO_DATA);
+ for (i = 0; SetupDiEnumDeviceInfo(dev_info, i, &dev_info_data); i++) {
+ DWORD addr, bus, slot, func, dev, data, size2;
+ while (!SetupDiGetDeviceRegistryProperty(dev_info, &dev_info_data,
+ SPDRP_PHYSICAL_DEVICE_OBJECT_NAME,
+ &data, (PBYTE)buffer, size,
+ &size2)) {
+ size = MAX(size, size2);
+ if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
+ g_free(buffer);
+ /* Double the size to avoid problems on
+ * W2k MBCS systems per KB 888609.
+ * https://support.microsoft.com/en-us/kb/259695 */
+ buffer = g_malloc(size * 2);
+ } else {
+ error_setg_win32(errp, GetLastError(),
+ "failed to get device name");
+ goto out;
+ }
+ }
+
+ if (g_strcmp0(buffer, dev_name)) {
+ continue;
+ }
+
+ /* There is no need to allocate buffer in the next functions. The size
+ * is known and ULONG according to
+ * https://support.microsoft.com/en-us/kb/253232
+ * https://msdn.microsoft.com/en-us/library/windows/hardware/ff543095(v=vs.85).aspx
+ */
+ if (!SetupDiGetDeviceRegistryProperty(dev_info, &dev_info_data,
+ SPDRP_BUSNUMBER, &data, (PBYTE)&bus, size, NULL)) {
+ break;
+ }
+
+ /* The function retrieves the device's address. This value will be
+ * transformed into device function and number */
+ if (!SetupDiGetDeviceRegistryProperty(dev_info, &dev_info_data,
+ SPDRP_ADDRESS, &data, (PBYTE)&addr, size, NULL)) {
+ break;
+ }
+
+ /* This call returns UINumber of DEVICE_CAPABILITIES structure.
+ * This number is typically a user-perceived slot number. */
+ if (!SetupDiGetDeviceRegistryProperty(dev_info, &dev_info_data,
+ SPDRP_UI_NUMBER, &data, (PBYTE)&slot, size, NULL)) {
+ break;
+ }
+
+ /* SetupApi gives us the same information as driver with
+ * IoGetDeviceProperty. According to Microsoft
+ * https://support.microsoft.com/en-us/kb/253232
+ * FunctionNumber = (USHORT)((propertyAddress) & 0x0000FFFF);
+ * DeviceNumber = (USHORT)(((propertyAddress) >> 16) & 0x0000FFFF);
+ * SPDRP_ADDRESS is propertyAddress, so we do the same.*/
+
+ func = addr & 0x0000FFFF;
+ dev = (addr >> 16) & 0x0000FFFF;
+ pci = g_malloc0(sizeof(*pci));
+ pci->domain = dev;
+ pci->slot = slot;
+ pci->function = func;
+ pci->bus = bus;
+ break;
+ }
+out:
+ g_free(buffer);
+ g_free(name);
+ return pci;
}
static int get_disk_bus_type(HANDLE vol_h, Error **errp)