USBLib-win.cpp revision 59190ecd61435d19ba3515b876272aee7bd12298
/* $Id$ */
/** @file
* USBLIB - USB support library interface, Windows.
*/
/*
* Copyright (C) 2006-2007 Oracle Corporation
*
* Oracle Corporation confidential
* All rights reserved
*/
/*******************************************************************************
* Header Files *
*******************************************************************************/
#define LOG_GROUP LOG_GROUP_DRV_USBPROXY
#include <windows.h>
#include "../USBLibInternal.h"
#include <stdio.h>
#include <setupapi.h>
#include <usbdi.h>
#include <hidsdi.h>
/*******************************************************************************
* Global Variables *
*******************************************************************************/
/** Flags whether or not we started the service. */
static bool g_fStartedService = false;
typedef struct
{
char szName[512];
char szDriverRegName[512];
static uint32_t cMaxDevices = 0;
static uint32_t g_cUSBStateChange = 0;
/*******************************************************************************
* Defined Constants And Macros *
*******************************************************************************/
/** @def VBOX_WITH_ANNOYING_USB_ASSERTIONS
* Enable this to get assertions on various failures.
*/
//#define VBOX_WITH_ANNOYING_USB_ASSERTIONS
#ifdef DOXYGEN_RUNNING
# define VBOX_WITH_ANNOYING_USB_ASSERTIONS
#endif
/*******************************************************************************
* Internal Functions *
*******************************************************************************/
bool ValidateUSBDevice(char *pszName)
{
if (INVALID_HANDLE_VALUE == hOut) {
goto failure;
}
else
{
/*
* Check the version
*/
USBSUP_VERSION version = {0};
DWORD cbReturned = 0;
if (!DeviceIoControl(hOut, SUPUSB_IOCTL_GET_VERSION, NULL, 0,&version, sizeof(version), &cbReturned, NULL))
{
goto failure;
}
{
Log(("USB: Invalid version %d:%d vs %d:%d\n", version.u32Major, version.u32Minor, USBDRV_MAJOR_VERSION, USBDRV_MINOR_VERSION));
goto failure;
}
{
goto failure;
}
}
return true;
if (hOut != INVALID_HANDLE_VALUE)
return false;
}
{
ULONG predictedLength = 0;
ULONG requiredLength = 0;
//
// allocate a function class device data structure to receive the
// goods about this particular device.
//
NULL, // probing so no output buffer yet
0, // probing so output buffer length of zero
NULL); // not interested in the specific dev-node
if(NULL == functionClassDeviceData)
{
return false;
}
//
// Retrieve the information from Plug and Play.
//
&requiredLength, &devInfo))
{
goto failure;
}
/* Query the registry path of the associated driver */
requiredLength = 0;
SetupDiGetDeviceRegistryProperty(HardwareDeviceInfo, &devInfo, SPDRP_DRIVER, NULL, NULL, 0, &requiredLength);
{
if (!SetupDiGetDeviceRegistryProperty(HardwareDeviceInfo, &devInfo, SPDRP_DRIVER, NULL, (PBYTE)pUsbDev->szDriverRegName, predictedLength, &requiredLength))
goto failure;
}
return rc;
return false;
}
{
//
// Open a handle to the plug and play dev node.
// SetupDiGetClassDevs() returns a device information set that contains info on all
// installed devices of a specified class.
//
NULL, // Define no enumerator (global)
NULL, // Define no
(DIGCF_PRESENT | // Only Devices present
DIGCF_DEVICEINTERFACE)); // Function class devices.
int j = 0, i = 0;
while(true)
{
// SetupDiEnumDeviceInterfaces() returns information about device interfaces
// exposed by one or more devices. Each call returns information about one interface;
// the routine can be called repeatedly to get information about several interfaces
// exposed by one or more devices.
Log(("OpenUsbDevices: SetupDiEnumDeviceInterfaces\n"));
0, // We don't care about specific PDOs
i,
{
{
uint32_t z;
for (z=0;z<cMaxDevices;z++)
{
{
j++;
break;
}
}
}
}
else
{
if (ERROR_NO_MORE_ITEMS == GetLastError())
{
Log(("OpenUsbDevices: No more items\n"));
break;
}
}
i++;
}
*pcNumDevices = j;
// SetupDiDestroyDeviceInfoList() destroys a device information set
// and frees all associated memory.
return true;
}
/**
* Initialize the OS specific part of the library.
* On Win32 this involves:
* - registering the device driver
* - start device driver.
* - open driver.
*
* @returns VBox status code
*/
{
if (pUSBDev)
cMaxDevices = 0;
*pcNumDevices = 0;
if (cNumNewDevices == 0)
return 0; /* nothing to do */
if (!pUSBDev)
{
AssertFailed();
return VERR_NO_MEMORY;
}
{
AssertFailed();
return VERR_INTERNAL_ERROR;
}
AssertMsg(*pcNumDevices <= cNumNewDevices, ("cNumDevices = %d, cNumNewDevices = %d\n", *pcNumDevices, cNumNewDevices));
return VINF_SUCCESS;
}
/**
* Returns the nth USB device name
*
* @returns NULL on failure, otherwise the requested name
*/
{
int j=0;
for(uint32_t i=0;i<cMaxDevices;i++)
{
{
if (j == idxDev)
j++;
}
}
return NULL;
}
/**
* Returns the nth USB device registry path
*
* @returns NULL on failure, otherwise the requested name
*/
{
int j=0;
for(uint32_t i=0;i<cMaxDevices;i++)
{
{
if (j == idxDev)
return pUSBDev[i].szDriverRegName;
j++;
}
}
return NULL;
}
/**
* Converts a supdrv error code to an nt status code.
*
* @returns corresponding SUPDRV_ERR_*.
* @param rc Win32 error code.
*/
static int suplibConvertWin32Err(int rc)
{
/* Conversion program (link with ntdll.lib from ddk):
#define _WIN32_WINNT 0x0501
#include <windows.h>
#include <ntstatus.h>
#include <winternl.h>
#include <stdio.h>
int main()
{
#define CONVERT(a) printf(#a " %#x -> %d\n", a, RtlNtStatusToDosError((a)))
CONVERT(STATUS_SUCCESS);
CONVERT(STATUS_NOT_SUPPORTED);
CONVERT(STATUS_INVALID_PARAMETER);
CONVERT(STATUS_ACCESS_DENIED);
CONVERT(STATUS_INVALID_HANDLE);
CONVERT(STATUS_INVALID_ADDRESS);
CONVERT(STATUS_NOT_LOCKED);
CONVERT(STATUS_IMAGE_ALREADY_LOADED);
return 0;
}
*/
switch (rc)
{
//case 0: return STATUS_SUCCESS;
case 0: return 0;
//case SUPDRV_ERR_GENERAL_FAILURE: return STATUS_NOT_SUPPORTED;
case ERROR_NOT_SUPPORTED: return VERR_GENERAL_FAILURE;
//case SUPDRV_ERR_INVALID_PARAM: return STATUS_INVALID_PARAMETER;
case ERROR_INVALID_PARAMETER: return VERR_INVALID_PARAMETER;
//case SUPDRV_ERR_INVALID_MAGIC: return STATUS_ACCESS_DENIED;
case ERROR_ACCESS_DENIED: return VERR_INVALID_MAGIC;
//case SUPDRV_ERR_INVALID_HANDLE: return STATUS_INVALID_HANDLE;
case ERROR_INVALID_HANDLE: return VERR_INVALID_HANDLE;
//case SUPDRV_ERR_INVALID_POINTER: return STATUS_INVALID_ADDRESS;
case ERROR_UNEXP_NET_ERR: return VERR_INVALID_POINTER;
//case SUPDRV_ERR_LOCK_FAILED: return STATUS_NOT_LOCKED;
case ERROR_NOT_LOCKED: return VERR_LOCK_FAILED;
//case SUPDRV_ERR_ALREADY_LOADED: return STATUS_IMAGE_ALREADY_LOADED;
case ERROR_SERVICE_ALREADY_RUNNING: return VERR_ALREADY_LOADED;
}
return VERR_GENERAL_FAILURE;
}
//*****************************************************************************
// D E F I N E S
//*****************************************************************************
#define NUM_HCS_TO_CHECK 10
#include <cfgmgr32.h>
#include "usbdesc.h"
//
// Structure used to build a linked list of String Descriptors
// retrieved from a device.
//
typedef struct _STRING_DESCRIPTOR_NODE
{
struct _STRING_DESCRIPTOR_NODE *Next;
//
// Structures assocated with TreeView items through the lParam. When an item
// is selected, the lParam is retrieved and the structure it which it points
// is used to display information in the edit control.
//
typedef struct
{
//*****************************************************************************
// L O C A L F U N C T I O N P R O T O T Y P E S
//*****************************************************************************
);
const char *pszHubName
);
);
);
);
);
);
);
);
);
);
//*****************************************************************************
// G L O B A L S P R I V A T E T O T H I S F I L E
//*****************************************************************************
{
"NoDeviceConnected",
"DeviceConnected",
"DeviceFailedEnumeration",
"DeviceGeneralFailure",
"DeviceCausedOvercurrent",
"DeviceNotEnoughPower"
};
static ULONG TotalDevicesConnected;
static int TotalHubs;
VOID AddLeaf(PUSBDEVICEINFO info, PCHAR pszLeafName, PCHAR pszDriverKeyName, const char *pszHubName, ULONG iHubPort)
{
Log3(("usbproxy:AddLeaf: pszDriverKeyName=%s pszLeafName=%s pszHubName=%s iHubPort=%d\n", pszDriverKeyName, pszLeafName, pszHubName, iHubPort));
if (pDevice)
{
if (info->ConnectionInfo)
{
char **pString;
/** @todo check which devices are used for primary input (keyboard & mouse) */
if (!pszDriverKeyName || *pszDriverKeyName == 0)
else
pDevice->bNumConfigurations = 0;
pDevice->u64SerialHash = 0;
while (pStrDesc)
{
{
}
else
{
}
else
{
}
if (pString)
{
char *pStringUTF8 = NULL;
{
}
}
}
if (*ppDeviceList == NULL)
{
*ppDeviceList = pDevice;
}
else
{
*ppDeviceList = pDevice;
}
}
return;
}
AssertFailed();
}
//*****************************************************************************
//
// EnumerateHostController()
//
// hTreeParent - Handle of the TreeView item under which host controllers
// should be added.
//
//*****************************************************************************
)
{
if (driverKeyName)
{
if (deviceDesc)
{
}
}
if (rootHubName != NULL)
{
NULL, // ConnectionInfo
NULL, // ConfigDesc
NULL, // StringDescs
"RootHub" // DeviceDesc
);
}
}
//*****************************************************************************
//
// EnumerateHostControllers()
//
// hTreeParent - Handle of the TreeView item under which host controllers
// should be added.
//
//*****************************************************************************
{
char HCName[16];
int HCNum;
TotalHubs = 0;
// Iterate over some Host Controller names and try to open them.
//
{
// If the handle is valid, then we've successfully opened a Host
// Controller. Display some info about the Host Controller itself,
// then enumerate the Root Hub attached to the Host Controller.
//
if (hHCDev != INVALID_HANDLE_VALUE)
{
leafName);
}
}
ppDeviceList = NULL;
}
//*****************************************************************************
//
// EnumerateHub()
//
// hTreeParent - Handle of the TreeView item under which this hub should be
// added.
//
// HubName - Name of this hub. This pointer is kept so the caller can neither
// free nor reuse this memory.
//
// ConnectionInfo - NULL if this is a root hub, else this is the connection
// info for an external hub. This pointer is kept so the caller can neither
// free nor reuse this memory.
//
// ConfigDesc - NULL if this is a root hub, else this is the Configuration
// Descriptor for an external hub. This pointer is kept so the caller can
// neither free nor reuse this memory.
//
//*****************************************************************************
)
{
// Initialize locals to not allocated state so the error cleanup routine
// only tries to cleanup things that were successfully allocated.
//
// Allocate some space for a USBDEVICEINFO structure to hold the
// hub info, hub name, and connection info pointers. GPTR zero
// initializes the structure for us.
//
{
AssertFailed();
goto EnumerateHubError;
}
// Keep copies of the Hub Name, Connection Info, and Configuration
// Descriptor pointers
//
// Allocate some space for a USB_NODE_INFORMATION structure for this Hub,
//
{
AssertFailed();
goto EnumerateHubError;
}
// Allocate a temp buffer for the full hub device name.
//
if (deviceName == NULL)
{
AssertFailed();
goto EnumerateHubError;
}
// Create the full hub device name
//
// Try to hub the open device
//
// Done with temp buffer for full hub device name
//
if (hHubDevice == INVALID_HANDLE_VALUE)
{
AssertFailed();
goto EnumerateHubError;
}
//
// Now query USBHUB for the USB_NODE_INFORMATION structure for this hub.
// This will tell us the number of downstream ports to enumerate, among
// other things.
//
sizeof(USB_NODE_INFORMATION),
sizeof(USB_NODE_INFORMATION),
&nBytes,
NULL);
if (!success)
{
AssertFailed();
goto EnumerateHubError;
}
// Build the leaf name from the port number and the device description
//
if (ConnectionInfo)
{
}
else
{
leafName[0] = 0;
}
if (DeviceDesc)
{
}
else
{
}
// Now recursively enumerate the ports of this hub.
//
);
return;
//
// Clean up any stuff that got allocated
//
if (hHubDevice != INVALID_HANDLE_VALUE)
{
}
{
{
}
{
}
}
if (ConnectionInfo)
{
}
if (ConfigDesc)
{
}
if (StringDescs != NULL)
{
do {
StringDescs = Next;
} while (StringDescs != NULL);
}
}
//*****************************************************************************
//
// EnumerateHubPorts()
//
// hTreeParent - Handle of the TreeView item under which the hub port should
// be added.
//
// hHubDevice - Handle of the hub device to enumerate.
//
// NumPorts - Number of ports on the hub.
//
//*****************************************************************************
const char *pszHubName
)
{
// Loop over all ports of the hub.
//
// Port indices are 1 based, not 0 based.
//
{
// Allocate space to hold the connection info for this port.
// For now, allocate it big enough to hold info for 30 pipes.
//
// Endpoint numbers are 0-15. Endpoint number 0 is the standard
// control endpoint which is not explicitly listed in the Configuration
// Descriptor. There can be an IN endpoint and an OUT endpoint at
// endpoint numbers 1-15 so there can be a maximum of 30 endpoints
// per device configuration.
//
// Should probably size this dynamically at some point.
//
nBytes = sizeof(USB_NODE_CONNECTION_INFORMATION_EX) +
sizeof(USB_PIPE_INFO) * 30;
if (connectionInfo == NULL)
{
AssertFailed();
break;
}
//
// Now query USBHUB for the USB_NODE_CONNECTION_INFORMATION_EX structure
// for this port. This will tell us if a device is attached to this
// port, among other things.
//
&nBytes,
NULL);
if (!success)
{
continue;
}
// Update the count of connected devices
//
{
}
else
{
continue;
}
if (connectionInfo->DeviceIsHub)
{
TotalHubs++;
}
// If there is a device connected, get the Device Description
//
deviceDesc = NULL;
szDriverKeyName[0] = 0;
{
index);
if (pszDriverKeyName)
{
Log(("Attached driver %s [port=%d]%s\n", pszDriverKeyName, index, connectionInfo->DeviceIsHub ? " DeviceIsHub" : ""));
}
}
// If there is a device connected to the port, try to retrieve the
// Configuration Descriptor from the device.
//
if (gDoConfigDesc &&
{
0);
}
else
{
configDesc = NULL;
}
if (configDesc != NULL &&
{
}
else
{
stringDescs = NULL;
}
// If the device connected to the port is an external hub, get the
// name of the external hub and recursively enumerate it.
//
if (connectionInfo->DeviceIsHub)
{
index);
if (extHubName != NULL)
{
// On to the next port
//
continue;
}
}
// Allocate some space for a USBDEVICEINFO structure to hold the
// hub info, hub name, and connection info pointers. GPTR zero
// initializes the structure for us.
//
{
AssertFailed();
if (configDesc != NULL)
{
}
break;
}
if (deviceDesc)
{
}
}
}
//*****************************************************************************
//
// WideStrToMultiStr()
//
//*****************************************************************************
{
// Get the length of the converted string
//
0,
-1,
NULL,
0,
NULL,
NULL);
if (nBytes == 0)
{
return NULL;
}
// Allocate space to hold the converted string
//
{
return NULL;
}
// Convert the string
//
0,
-1,
NULL,
NULL);
if (nBytes == 0)
{
return NULL;
}
return MultiStr;
}
//*****************************************************************************
//
// GetRootHubName()
//
//*****************************************************************************
)
{
rootHubNameW = NULL;
rootHubNameA = NULL;
// Get the length of the name of the Root Hub attached to the
// Host Controller
//
0,
0,
sizeof(rootHubName),
&nBytes,
NULL);
if (!success)
{
AssertFailed();
goto GetRootHubNameError;
}
// Allocate space to hold the Root Hub name
//
if (rootHubNameW == NULL)
{
AssertFailed();
goto GetRootHubNameError;
}
// Get the name of the Root Hub attached to the Host Controller
//
NULL,
0,
&nBytes,
NULL);
if (!success)
{
AssertFailed();
goto GetRootHubNameError;
}
// Convert the Root Hub name
//
// All done, free the uncoverted Root Hub name and return the
// converted Root Hub name
//
return rootHubNameA;
// There was an error, free anything that was allocated
//
if (rootHubNameW != NULL)
{
rootHubNameW = NULL;
}
return NULL;
}
//*****************************************************************************
//
// GetExternalHubName()
//
//*****************************************************************************
)
{
extHubNameW = NULL;
extHubNameA = NULL;
// Get the length of the name of the external hub attached to the
// specified port.
//
sizeof(extHubName),
sizeof(extHubName),
&nBytes,
NULL);
if (!success)
{
AssertFailed();
goto GetExternalHubNameError;
}
// Allocate space to hold the external hub name
//
if (nBytes <= sizeof(extHubName))
{
AssertFailed();
goto GetExternalHubNameError;
}
if (extHubNameW == NULL)
{
AssertFailed();
goto GetExternalHubNameError;
}
// Get the name of the external hub attached to the specified port
//
&nBytes,
NULL);
if (!success)
{
AssertFailed();
goto GetExternalHubNameError;
}
// Convert the External Hub name
//
// All done, free the uncoverted external hub name and return the
// converted external hub name
//
return extHubNameA;
// There was an error, free anything that was allocated
//
if (extHubNameW != NULL)
{
extHubNameW = NULL;
}
return NULL;
}
//*****************************************************************************
//
// GetDriverKeyName()
//
//*****************************************************************************
)
{
// Get the length of the name of the driver key of the device attached to
// the specified port.
//
sizeof(driverKeyName),
sizeof(driverKeyName),
&nBytes,
NULL);
if (!success)
{
goto GetDriverKeyNameError;
}
// Allocate space to hold the driver key name
//
if (nBytes <= sizeof(driverKeyName))
{
AssertFailed();
goto GetDriverKeyNameError;
}
if (driverKeyNameW == NULL)
{
AssertFailed();
goto GetDriverKeyNameError;
}
// Get the name of the driver key of the device attached to
// the specified port.
//
&nBytes,
NULL);
if (!success)
{
AssertFailed();
goto GetDriverKeyNameError;
}
// Convert the driver key name
//
// All done, free the uncoverted driver key name and return the
// converted driver key name
//
return driverKeyNameA;
// There was an error, free anything that was allocated
//
if (driverKeyNameW != NULL)
{
}
return NULL;
}
//*****************************************************************************
//
// GetHCDDriverKeyName()
//
//*****************************************************************************
)
{
// Get the length of the name of the driver key of the HCD
//
sizeof(driverKeyName),
sizeof(driverKeyName),
&nBytes,
NULL);
if (!success)
{
AssertFailed();
goto GetHCDDriverKeyNameError;
}
// Allocate space to hold the driver key name
//
if (nBytes <= sizeof(driverKeyName))
{
AssertFailed();
goto GetHCDDriverKeyNameError;
}
if (driverKeyNameW == NULL)
{
AssertFailed();
goto GetHCDDriverKeyNameError;
}
// Get the name of the driver key of the device attached to
// the specified port.
//
&nBytes,
NULL);
if (!success)
{
AssertFailed();
goto GetHCDDriverKeyNameError;
}
// Convert the driver key name
//
// All done, free the uncoverted driver key name and return the
// converted driver key name
//
return driverKeyNameA;
// There was an error, free anything that was allocated
//
if (driverKeyNameW != NULL)
{
}
return NULL;
}
//*****************************************************************************
//
// GetConfigDescriptor()
//
// hHubDevice - Handle of the hub device containing the port from which the
// Configuration Descriptor will be requested.
//
// ConnectionIndex - Identifies the port on the hub to which a device is
// attached from which the Configuration Descriptor will be requested.
//
// DescriptorIndex - Configuration Descriptor index, zero based.
//
//*****************************************************************************
)
{
sizeof(USB_CONFIGURATION_DESCRIPTOR)];
// Request the Configuration Descriptor the first time using our
// local buffer, which is just big enough for the Cofiguration
// Descriptor itself.
//
nBytes = sizeof(configDescReqBuf);
// Zero fill the entire request structure
//
// Indicate the port from which the descriptor will be requested
//
//
// USBHUB uses URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE to process this
// IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION request.
//
// USBD will automatically initialize these fields:
// bmRequest = 0x80
// bRequest = 0x06
//
// We must inititialize these fields:
// wValue = Descriptor Type (high) and Descriptor Index (low byte)
// wIndex = Zero (or Language ID for String Descriptors)
// wLength = Length of descriptor buffer
//
// Now issue the get descriptor request.
//
NULL);
if (!success)
{
AssertMsgFailed(("DeviceIoControl IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION failed with %d\n", GetLastError()));
#else
LogRel(("DeviceIoControl IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION failed with %d\n", GetLastError()));
#endif
return NULL;
}
if (nBytes != nBytesReturned)
{
AssertFailed();
return NULL;
}
{
AssertFailed();
return NULL;
}
// Now request the entire Configuration Descriptor using a dynamically
// allocated buffer which is sized big enough to hold the entire descriptor
//
if (configDescReq == NULL)
{
AssertFailed();
return NULL;
}
// Indicate the port from which the descriptor will be requested
//
//
// USBHUB uses URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE to process this
// IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION request.
//
// USBD will automatically initialize these fields:
// bmRequest = 0x80
// bRequest = 0x06
//
// We must inititialize these fields:
// wValue = Descriptor Type (high) and Descriptor Index (low byte)
// wIndex = Zero (or Language ID for String Descriptors)
// wLength = Length of descriptor buffer
//
// Now issue the get descriptor request.
//
NULL);
if (!success)
{
AssertMsgFailed(("DeviceIoControl IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION failed with %d\n", GetLastError()));
#else
LogRel(("DeviceIoControl IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION failed with %d\n", GetLastError()));
#endif
return NULL;
}
if (nBytes != nBytesReturned)
{
AssertMsgFailed(("DeviceIoControl IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION %d != %d\n", nBytes, nBytesReturned));
#else
LogRel(("DeviceIoControl IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION %d != %d\n", nBytes, nBytesReturned));
#endif
return NULL;
}
{
AssertMsgFailed(("DeviceIoControl IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION %d != %d\n", configDesc->wTotalLength, (nBytes - sizeof(USB_DESCRIPTOR_REQUEST)));
#else
LogRel(("DeviceIoControl IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION %d != %d\n", configDesc->wTotalLength, (nBytes - sizeof(USB_DESCRIPTOR_REQUEST)) ));
#endif
return NULL;
}
return configDescReq;
}
//*****************************************************************************
//
// AreThereStringDescriptors()
//
// DeviceDesc - Device Descriptor for which String Descriptors should be
// checked.
//
// ConfigDesc - Configuration Descriptor (also containing Interface Descriptor)
// for which String Descriptors should be checked.
//
//*****************************************************************************
)
{
//
// Check Device Descriptor strings
//
if (DeviceDesc->iManufacturer ||
DeviceDesc->iProduct ||
)
{
return TRUE;
}
//
// Check the Configuration and Interface Descriptor strings
//
{
switch (commonDesc->bDescriptorType)
{
{
AssertFailed();
break;
}
{
return TRUE;
}
continue;
{
AssertFailed();
break;
}
{
return TRUE;
}
continue;
default:
continue;
}
break;
}
return FALSE;
}
//*****************************************************************************
//
// GetAllStringDescriptors()
//
// hHubDevice - Handle of the hub device containing the port from which the
// String Descriptors will be requested.
//
// ConnectionIndex - Identifies the port on the hub to which a device is
// attached from which the String Descriptors will be requested.
//
// DeviceDesc - Device Descriptor for which String Descriptors should be
// requested.
//
// ConfigDesc - Configuration Descriptor (also containing Interface Descriptor)
// for which String Descriptors should be requested.
//
//*****************************************************************************
)
{
//
// Get the array of supported Language IDs, which is returned
// in String Descriptor 0
//
0,
0);
if (supportedLanguagesString == NULL)
{
return NULL;
}
//
// Get the Device Descriptor strings
//
if (DeviceDesc->iManufacturer)
{
}
if (DeviceDesc->iProduct)
{
}
if (DeviceDesc->iSerialNumber)
{
}
//
// Get the Configuration and Interface Descriptor strings
//
{
switch (commonDesc->bDescriptorType)
{
{
AssertFailed();
break;
}
{
}
continue;
{
AssertFailed();
break;
}
{
}
continue;
default:
continue;
}
break;
}
return supportedLanguagesString;
}
//*****************************************************************************
//
// GetStringDescriptor()
//
// hHubDevice - Handle of the hub device containing the port from which the
// String Descriptor will be requested.
//
// ConnectionIndex - Identifies the port on the hub to which a device is
// attached from which the String Descriptor will be requested.
//
// DescriptorIndex - String Descriptor index.
//
// LanguageID - Language in which the string should be requested.
//
//*****************************************************************************
)
{
nBytes = sizeof(stringDescReqBuf);
// Zero fill the entire request structure
//
// Indicate the port from which the descriptor will be requested
//
//
// USBHUB uses URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE to process this
// IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION request.
//
// USBD will automatically initialize these fields:
// bmRequest = 0x80
// bRequest = 0x06
//
// We must inititialize these fields:
// wValue = Descriptor Type (high) and Descriptor Index (low byte)
// wIndex = Zero (or Language ID for String Descriptors)
// wLength = Length of descriptor buffer
//
// Now issue the get descriptor request.
//
NULL);
//
// Do some sanity checks on the return from the get descriptor request.
//
if (!success)
{
AssertMsgFailed(("DeviceIoControl IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION failed with %d\n", GetLastError()));
#else
LogRel(("DeviceIoControl IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION failed with %d\n", GetLastError()));
#endif
return NULL;
}
if (nBytesReturned < 2)
{
AssertFailed();
return NULL;
}
{
AssertFailed();
return NULL;
}
{
AssertFailed();
return NULL;
}
{
AssertFailed();
return NULL;
}
//
// Looks good, allocate some (zero filled) space for the string descriptor
// node and copy the string descriptor to it.
//
if (stringDescNode == NULL)
{
AssertFailed();
return NULL;
}
return stringDescNode;
}
//*****************************************************************************
//
// GetStringDescriptors()
//
// hHubDevice - Handle of the hub device containing the port from which the
// String Descriptor will be requested.
//
// ConnectionIndex - Identifies the port on the hub to which a device is
// attached from which the String Descriptor will be requested.
//
// DescriptorIndex - String Descriptor index.
//
// NumLanguageIDs - Number of languages in which the string should be
// requested.
//
// LanguageIDs - Languages in which the string should be requested.
//
//*****************************************************************************
)
{
ULONG i;
for (i=0; i<NumLanguageIDs; i++)
{
*LanguageIDs);
if (StringDescNodeTail->Next)
{
}
LanguageIDs++;
}
return StringDescNodeTail;
}
//*****************************************************************************
//
// DriverNameToDeviceDesc()
//
// Returns the Device Description of the DevNode with the matching DriverName.
// Returns NULL if the matching DevNode is not found.
//
// The caller should copy the returned string buffer instead of just saving
// the pointer value. XXXXX Dynamically allocate return buffer?
//
//*****************************************************************************
{
// Get Root DevNode
//
NULL,
0);
if (cr != CR_SUCCESS)
{
return NULL;
}
// Do a depth first search for the DevNode with a matching
// DriverName value
//
while (!walkDone)
{
// Get the DriverName value
//
NULL,
buf,
&len,
0);
// If the DriverName value matches, return the DeviceDescription
//
{
NULL,
buf,
&len,
0);
if (cr == CR_SUCCESS)
{
return buf;
}
else
{
return NULL;
}
}
// This DevNode didn't match, go down a level to the first child.
//
0);
if (cr == CR_SUCCESS)
{
continue;
}
// Can't go down any further, go across to the next sibling. If
// there are no more siblings, go back up until there is a sibling.
// If we can't go up any further, we're back at the root and we're
// done.
//
for (;;)
{
0);
if (cr == CR_SUCCESS)
{
break;
}
0);
if (cr == CR_SUCCESS)
{
}
else
{
walkDone = 1;
break;
}
}
}
return NULL;
}
/**
* Attempts to start the service, creating it if necessary.
*
* @returns 0 on success.
* @returns -1 on failure.
* @param fRetry Indicates retry call.
*/
int usbMonStartService(void)
{
/*
* Check if the driver service is there.
*/
{
AssertMsgFailed(("couldn't open service manager in SERVICE_QUERY_CONFIG | SERVICE_QUERY_STATUS mode!\n"));
return -1;
}
/*
* Try open our service to check it's status.
*/
if (!hService)
return -1;
/*
* Check if open and on demand create succeeded.
*/
int rc = -1;
if (hService)
{
/*
* Query service status to see if we need to start it or not.
*/
{
/*
* Start it.
*/
LogRel(("usbMonStartService -> start it\n"));
if (fRc)
g_fStartedService = true;
}
/*
* Wait for the service to finish starting.
* We'll wait for 10 seconds then we'll give up.
*/
{
int iWait;
{
Sleep(100);
}
("Failed to start. LastError=%Rwa iWait=%d status=%d\n",
}
rc = 0;
/*
* Close open handles.
*/
}
else
{
}
if (!CloseServiceHandle(hSMgr))
AssertFailed();
return rc;
}
/**
* Stops a possibly running service.
*
* @returns 0 on success.
* @returns -1 on failure.
*/
int usbMonStopService(void)
{
LogRel(("usbMonStopService\n"));
/*
* Assume it didn't exist, so we'll create the service.
*/
int rc = -1;
if (hSMgr)
{
if (hService)
{
/*
* Stop the service.
*/
rc = 0;
{
int iWait = 100;
{
Sleep(100);
}
rc = 0;
else
}
else
{
AssertMsgFailed(("ControlService failed with LastError=%Rwa. status=%d\n", LastError, Status.dwCurrentState));
}
}
else if (GetLastError() == ERROR_SERVICE_DOES_NOT_EXIST)
rc = 0;
else
{
}
}
return rc;
}
/**
* Initialize the USB library
*
* @returns VBox status code.
*/
USBLIB_DECL(int) USBLibInit(void)
{
int rc;
USBSUP_VERSION version = {0};
Log(("usbproxy: usbLibInit\n"));
g_hUSBMonitor = CreateFile(USBMON_DEVICE_NAME, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
if (g_hUSBMonitor == INVALID_HANDLE_VALUE)
{
g_hUSBMonitor = CreateFile(USBMON_DEVICE_NAME, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
if (g_hUSBMonitor == INVALID_HANDLE_VALUE)
{
/* AssertFailed(); */
goto failure;
}
}
/*
* Check the version
*/
cbReturned = 0;
if (!DeviceIoControl(g_hUSBMonitor, SUPUSBFLT_IOCTL_GET_VERSION, NULL, 0,&version, sizeof(version), &cbReturned, NULL))
{
goto failure;
}
{
LogRel(("usbproxy: Filter driver version mismatch!!\n"));
goto failure;
}
return VINF_SUCCESS;
if (g_hUSBMonitor != INVALID_HANDLE_VALUE)
{
}
return rc;
}
/**
* Terminate the USB library
*
* @returns VBox status code.
*/
USBLIB_DECL(int) USBLibTerm(void)
{
if (g_hUSBMonitor != INVALID_HANDLE_VALUE)
{
}
#if 0
/*
* If we started the service we might consider stopping it too.
*
* Since this won't work unless the process starting it is the
* last user we might wanna skip this...
*/
if (g_fStartedService)
{
g_fStartedService = false;
}
#endif
return VINF_SUCCESS;
}
/**
* Capture specified USB device
*
* @returns VBox status code
* @param usVendorId Vendor id
* @param usProductId Product id
* @param usRevision Revision
*/
USBLIB_DECL(int) USBLibCaptureDevice(uint16_t usVendorId, uint16_t usProductId, uint16_t usRevision)
{
DWORD cbReturned = 0;
if (g_hUSBMonitor == INVALID_HANDLE_VALUE)
return VERR_NOT_SUPPORTED;
if (!DeviceIoControl(g_hUSBMonitor, SUPUSBFLT_IOCTL_CAPTURE_DEVICE, &capture, sizeof(capture), NULL, 0, &cbReturned, NULL))
{
return RTErrConvertFromWin32(GetLastError());
}
return VINF_SUCCESS;
}
/**
* Release specified USB device to the host.
*
* @returns VBox status code
* @param usVendorId Vendor id
* @param usProductId Product id
* @param usRevision Revision
*/
USBLIB_DECL(int) USBLibReleaseDevice(uint16_t usVendorId, uint16_t usProductId, uint16_t usRevision)
{
DWORD cbReturned = 0;
if (g_hUSBMonitor == INVALID_HANDLE_VALUE)
return VERR_NOT_SUPPORTED;
if (!DeviceIoControl(g_hUSBMonitor, SUPUSBFLT_IOCTL_RELEASE_DEVICE, &release, sizeof(release), NULL, 0, &cbReturned, NULL))
{
return RTErrConvertFromWin32(GetLastError());
}
return VINF_SUCCESS;
}
{
DWORD cbReturned = 0;
if (g_hUSBMonitor == INVALID_HANDLE_VALUE)
return NULL;
Log(("usblibInsertFilter: Manufacturer=%s Product=%s Serial=%s\n",
USBFilterGetString(pFilter, USBFILTERIDX_MANUFACTURER_STR) ? USBFilterGetString(pFilter, USBFILTERIDX_MANUFACTURER_STR) : "<null>",
USBFilterGetString(pFilter, USBFILTERIDX_PRODUCT_STR) ? USBFilterGetString(pFilter, USBFILTERIDX_PRODUCT_STR) : "<null>",
USBFilterGetString(pFilter, USBFILTERIDX_SERIAL_NUMBER_STR) ? USBFilterGetString(pFilter, USBFILTERIDX_SERIAL_NUMBER_STR) : "<null>"));
if (!DeviceIoControl(g_hUSBMonitor, SUPUSBFLT_IOCTL_ADD_FILTER, (LPVOID)pFilter, sizeof(*pFilter), &add_out, sizeof(add_out), &cbReturned, NULL))
{
return NULL;
}
{
return NULL;
}
}
{
DWORD cbReturned = 0;
if (g_hUSBMonitor == INVALID_HANDLE_VALUE)
return;
if (!DeviceIoControl(g_hUSBMonitor, SUPUSBFLT_IOCTL_REMOVE_FILTER, &uId, sizeof(uId), NULL, 0,&cbReturned, NULL))
}
/**
* Return all attached USB devices.that are captured by the filter
*
* @returns VBox status code
* @param ppDevices Receives pointer to list of devices
* @param pcDevices Number of USB devices in the list
*/
{
char *pszDevname = NULL;
uint32_t cHostDevices = 0;
Log(("usbLibGetDevices: enter\n"));
if (g_hUSBMonitor == INVALID_HANDLE_VALUE)
return VERR_NOT_SUPPORTED;
/* 1: Enumerate all usb devices attached to the host */
#ifdef LOG_ENABLED
int iDevice = 0;
while(pDevice)
{
iDevice++;
if (pDevice->pszSerialNumber)
{
Log((" State USBDEVICESTATE_UNSUPPORTED\n"));
break;
Log((" State USBDEVICESTATE_USED_BY_HOST\n"));
break;
Log((" State USBDEVICESTATE_USED_BY_HOST_CAPTURABLE\n"));
break;
case USBDEVICESTATE_UNUSED:
Log((" State USBDEVICESTATE_UNUSED\n"));
break;
Log((" State USBDEVICESTATE_HELD_BY_PROXY\n"));
break;
Log((" State USBDEVICESTATE_USED_BY_GUEST\n"));
break;
}
}
#endif
*ppDevices = 0;
*pcDevices = 0;
/*
* Get the return data.
* Note that we might be called a bit too early here. Give windows time to register the new USB driver/device.
* It's no problem to block here as we're in the async usb detection thread (not EMT)
*/
for (int i=0;i<100;i++)
{
/*
* Get the number of USB devices.
*/
cbReturned = 0;
if (!DeviceIoControl(g_hUSBMonitor, SUPUSBFLT_IOCTL_GET_NUM_DEVICES, NULL, 0, &numdev, sizeof(numdev), &cbReturned, NULL))
{
return RTErrConvertFromWin32(GetLastError());
}
if ((int32_t)numdev.cUSBDevices <= 0) /** @todo why does this return -1. Happend here when detaching a captured device which hadn't yet been opened by a VM process. */
break;
break;
RTThreadSleep(100);
}
{
/* Only return the host devices */
return VINF_SUCCESS;
}
/* 2: Get all the USB devices that the filter has captured for us */
/* Get the required info for each captured device */
{
USBSUP_GETDEV dev = {0};
hDev = CreateFile(pszDevname, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_WRITE | FILE_SHARE_READ, NULL,
if (hDev != INVALID_HANDLE_VALUE)
{
cbReturned = 0;
if (!DeviceIoControl(hDev, SUPUSB_IOCTL_GET_DEVICE, &dev, sizeof(dev), &dev, sizeof(dev), &cbReturned, NULL))
{
int iErr = GetLastError();
/* ERROR_DEVICE_NOT_CONNECTED -> device was removed just now */
Log(("SUPUSB_IOCTL_GET_DEVICE: DeviceIoControl %d no longer connected\n", i));
}
else
{
goto failure;
/* The following is not 100% accurate but we only care about high-speed vs non-high-speed */
Log(("usbLibGetDevices: Detected device vid=%x did=%x rev=%x hispd=%d hash=%s hash=%RX64\n", dev.vid, dev.did, dev.rev, dev.fHiSpeed, dev.serial_hash, pDevice->u64SerialHash));
/* Insert into the list */
if (pCaptured)
}
}
else
}
if (!pCaptured)
{
/* Only return the host devices */
return VINF_SUCCESS;
}
/* 3: Add all host devices to array of captured devices; obviously making sure there are no duplicates */
{
uint32_t j;
for (j=0;j<cHostDevices;j++)
{
char *pszDeviceRegPath = usblibQueryDeviceRegPath(i);
if (pszDeviceRegPath)
{
{
break;
}
}
}
if (j == cHostDevices)
{
/* Probably in the process of being reattached */
Log(("usbLibGetDevices: Captured device %s not found in host device list\n", usblibQueryDeviceRegPath(i)));
/* do nothing */
}
else
{
}
}
/* Free captured devices list */
while (pDevice)
{
if (pDevice->pszAddress)
if (pDevice->pszAltAddress)
if (pDevice->pszHubName)
if (pDevice->pszManufacturer)
if (pDevice->pszProduct)
if (pDevice->pszSerialNumber)
}
#ifdef LOG_ENABLED
iDevice = 0;
while(pDevice)
{
iDevice++;
if (pDevice->pszSerialNumber)
{
Log((" State USBDEVICESTATE_UNSUPPORTED\n"));
break;
Log((" State USBDEVICESTATE_USED_BY_HOST\n"));
break;
Log((" State USBDEVICESTATE_USED_BY_HOST_CAPTURABLE\n"));
break;
case USBDEVICESTATE_UNUSED:
Log((" State USBDEVICESTATE_UNUSED\n"));
break;
Log((" State USBDEVICESTATE_HELD_BY_PROXY\n"));
break;
Log((" State USBDEVICESTATE_USED_BY_GUEST\n"));
break;
}
}
#endif
return VINF_SUCCESS;
pHostDevices = NULL;
while (pDevice)
{
if (pDevice->pszAddress)
if (pDevice->pszManufacturer)
if (pDevice->pszProduct)
if (pDevice->pszSerialNumber)
{
}
}
Log(("usbLibGetDevices: returns VERR_NO_MEMORY\n"));
return VERR_NO_MEMORY;
}
/**
* Return all USB devices attached to the host
*
* @returns VBox status code
* @param ppDevices Receives pointer to list of devices
* @param pcDevices Number of USB devices in the list
*/
{
return VINF_SUCCESS;
}
/**
* Check for USB device arrivals or removals
*
* @returns boolean
*/
USBLIB_DECL(bool) USBLibHasPendingDeviceChanges(void)
{
if (g_hUSBMonitor == INVALID_HANDLE_VALUE)
return false;
cbReturned = 0;
if ( DeviceIoControl(g_hUSBMonitor, SUPUSBFLT_IOCTL_USB_CHANGE, NULL, 0, &out, sizeof(out), &cbReturned, NULL)
{
Log(("usbLibHasPendingDeviceChanges: Detected USB state change!!\n"));
return true;
}
return false;
}