#include <stdarg.h>
+#define INITGUID
+
#include "windef.h"
#include "winbase.h"
#include "winnt.h"
#include "winioctl.h"
#include "rpc.h"
#include "rpcdce.h"
+#define WINE_MOUNTMGR_EXTENSIONS
+#include "ntddstor.h"
+#define WINE_USBHUB_EXTENSIONS
+#include "ddk/usbioctl.h"
#include "setupapi_private.h"
struct DeviceInfo
{
struct DeviceInfoSet *set;
+ struct DeviceInfo *parent;
HKEY key;
BOOL phantom;
DWORD devId;
if (devInfo)
{
devInfo->set = set;
+ devInfo->parent = NULL;
devInfo->devId = (DWORD)devInst;
devInfo->instanceId = HeapAlloc(GetProcessHeap(), 0,
{
struct InterfaceInstances *iface, *next;
+ if (devInfo->parent)
+ SETUPDI_FreeDeviceInfo(devInfo->parent);
if (devInfo->key != INVALID_HANDLE_VALUE)
RegCloseKey(devInfo->key);
if (devInfo->phantom)
GlobalUnlock((HANDLE)dnDevInst);
return CR_SUCCESS;
}
+
+static const WCHAR usbpdoW[] = {'\\','D','e','v','i','c','e','\\',
+ 'U','S','B','P','D','O','-','%','u',0};
+
+static BOOL SETUPDI_GetUsbstorParent( struct DeviceInfo *devInfo, LPWSTR Buffer )
+{
+ static const WCHAR usbstorW[] = {'u','s','b','s','t','o','r','\\',0};
+ struct InterfaceInstances *iface;
+ struct InterfaceInfo *ifaceInfo;
+ struct usb_device_address usbda;
+ struct usb_device_info usbDevInfo;
+ OBJECT_ATTRIBUTES attr;
+ UNICODE_STRING name;
+ IO_STATUS_BLOCK io;
+ HANDLE dev;
+ WCHAR *pdoName;
+ BOOL ret;
+
+ if (strncmpiW(devInfo->instanceId, usbstorW, strlenW(usbstorW)))
+ return FALSE;
+
+ if (!SETUPDI_FindInterface(devInfo, &GUID_DEVINTERFACE_DISK, &iface) ||
+ !iface->cInstances || !iface->instances[0].Reserved)
+ return FALSE;
+ ifaceInfo = (struct InterfaceInfo *)iface->instances[0].Reserved;
+ dev = CreateFileW(ifaceInfo->symbolicLink, GENERIC_READ|GENERIC_WRITE,
+ FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0);
+ if (dev == INVALID_HANDLE_VALUE) return FALSE;
+ ret = DeviceIoControl(dev, IOCTL_STORAGE_USB_DEVICE_ADDRESS,
+ &usbda, sizeof(usbda), &usbda, sizeof(usbda), NULL, NULL);
+ CloseHandle(dev);
+ if (!ret) return FALSE;
+
+ pdoName = HeapAlloc(GetProcessHeap(), 0, 30 * sizeof(WCHAR));
+ if (!pdoName) return FALSE;
+ snprintfW(pdoName, 30, usbpdoW, usbda.bus - 1);
+ RtlInitUnicodeString(&name, pdoName);
+ attr.Length = sizeof(attr);
+ attr.RootDirectory = 0;
+ attr.Attributes = OBJ_CASE_INSENSITIVE;
+ attr.ObjectName = &name;
+ attr.SecurityDescriptor = NULL;
+ attr.SecurityQualityOfService = NULL;
+ if (NtOpenFile(&dev, GENERIC_READ|GENERIC_WRITE, &attr, &io,
+ FILE_SHARE_READ|FILE_SHARE_WRITE, 0))
+ {
+ HeapFree(GetProcessHeap(), 0, pdoName);
+ return FALSE;
+ }
+ ret = FALSE;
+ usbDevInfo.connection_index = 1;
+ while (!ret && !NtDeviceIoControlFile(dev, NULL, NULL, NULL, &io,
+ IOCTL_USB_GET_DEVICE_INFO, &usbDevInfo, sizeof(usbDevInfo),
+ &usbDevInfo, sizeof(usbDevInfo)))
+ {
+ if (usbDevInfo.device_address == usbda.addr)
+ {
+ memcpy(Buffer, usbDevInfo.device_id, MAX_DEVICE_ID_LEN * sizeof(WCHAR));
+ ret = TRUE;
+ }
+ ++usbDevInfo.connection_index;
+ }
+ NtClose(dev);
+ HeapFree(GetProcessHeap(), 0, pdoName);
+ return ret;
+}
+
+static BOOL SETUPDI_GetUsbParent( struct DeviceInfo *devInfo, LPWSTR Buffer )
+{
+ static const WCHAR usbW[] = {'u','s','b','\\',0};
+ struct usb_device_info usbDevInfo;
+ WCHAR *pdoName;
+ UNICODE_STRING name;
+ OBJECT_ATTRIBUTES attr;
+ IO_STATUS_BLOCK io;
+ HANDLE dev;
+ BOOL ret = FALSE;
+ ULONG k = 0;
+
+ if (strncmpiW(devInfo->instanceId, usbW, strlenW(usbW)))
+ return FALSE;
+
+ attr.Length = sizeof(attr);
+ attr.RootDirectory = 0;
+ attr.Attributes = OBJ_CASE_INSENSITIVE;
+ attr.ObjectName = &name;
+ attr.SecurityDescriptor = NULL;
+ attr.SecurityQualityOfService = NULL;
+ pdoName = HeapAlloc(GetProcessHeap(), 0, 30 * sizeof(WCHAR));
+ if (!pdoName) return FALSE;
+ while (!ret)
+ {
+ snprintfW(pdoName, 30, usbpdoW, k++);
+ RtlInitUnicodeString(&name, pdoName);
+ if (NtOpenFile(&dev, GENERIC_READ|GENERIC_WRITE, &attr, &io,
+ FILE_SHARE_READ|FILE_SHARE_WRITE, 0))
+ {
+ HeapFree(GetProcessHeap(), 0, pdoName);
+ return FALSE;
+ }
+ usbDevInfo.connection_index = 1;
+ while (!ret && !NtDeviceIoControlFile(dev, NULL, NULL, NULL, &io,
+ IOCTL_USB_GET_DEVICE_INFO, &usbDevInfo, sizeof(usbDevInfo),
+ &usbDevInfo, sizeof(usbDevInfo)))
+ {
+ if (!strcmpiW(devInfo->instanceId, usbDevInfo.device_id))
+ {
+ memcpy(Buffer, usbDevInfo.root_hub_id,
+ MAX_DEVICE_ID_LEN * sizeof(WCHAR));
+ ret = TRUE;
+ }
+ ++usbDevInfo.connection_index;
+ }
+ NtClose(dev);
+ }
+ HeapFree(GetProcessHeap(), 0, pdoName);
+ return TRUE;
+}
+
+/***********************************************************************
+ * CM_Get_Parent_Ex (SETUPAPI.@)
+ */
+CONFIGRET WINAPI CM_Get_Parent_Ex( PDEVINST pdnDevInst, DEVINST dnDevInst,
+ ULONG ulFlags, HMACHINE hMachine )
+{
+ struct DeviceInfo *devInfo = GlobalLock((HANDLE)dnDevInst);
+ WCHAR instanceId[MAX_DEVICE_ID_LEN];
+
+ TRACE("%p %08x %08x %p\n", pdnDevInst, dnDevInst, ulFlags, hMachine);
+
+ if (!devInfo)
+ return CR_INVALID_DEVNODE;
+ if (!SETUPDI_GetUsbstorParent(devInfo, instanceId) &&
+ !SETUPDI_GetUsbParent(devInfo, instanceId))
+ {
+ GlobalUnlock((HANDLE)dnDevInst);
+ return CR_NO_SUCH_DEVNODE;
+ }
+ if (!devInfo->parent && !(devInfo->parent =
+ SETUPDI_AllocateDeviceInfo(NULL, 0, instanceId, FALSE)))
+ {
+ GlobalUnlock((HANDLE)dnDevInst);
+ return CR_FAILURE;
+ }
+ *pdnDevInst = devInfo->parent->devId;
+ GlobalUnlock((HANDLE)dnDevInst);
+ return CR_SUCCESS;
+}
+
+/***********************************************************************
+ * CM_Get_Parent (SETUPAPI.@)
+ */
+DWORD WINAPI CM_Get_Parent( PDEVINST pdnDevInst, DEVINST dnDevInst,
+ ULONG ulFlags )
+{
+ return CM_Get_Parent_Ex(pdnDevInst, dnDevInst, ulFlags, NULL);
+}