📄 enum.cpp
字号:
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//
// Use of this source code is subject to the terms of the Microsoft end-user
// license agreement (EULA) under which you licensed this SOFTWARE PRODUCT.
// If you did not accept the terms of the EULA, you are not authorized to use
// this source code. For a copy of the EULA, please see the LICENSE.RTF on your
// install media.
//
#include "ufnmdd.h"
#define GET_DESCRIPTOR_TYPE(x) HIBYTE(x)
#define GET_DESCRIPTOR_INDEX(x) LOBYTE(x)
#define USB_REQUEST_RECIPIENT_MASK 0x1F
#define GET_REQUESET_RECIPIENT(x) ((x) & USB_REQUEST_RECIPIENT_MASK)
enum CONTROL_RESPONSE {
CR_SUCCESS = 0,
CR_SUCCESS_SEND_CONTROL_HANDSHAKE, // Use if no data stage
CR_STALL_DEFAULT_PIPE,
CR_UNHANDLED_REQUEST,
};
#ifdef DEBUG
static const LPCTSTR g_rgpszDeviceStates[] = {
_T("detached"),
_T("attached"),
_T("powered"),
_T("default"),
_T("addressed"),
_T("configured"),
_T("suspended"),
};
// Get a textual name of a device state.
LPCTSTR
GetDeviceStateName(
DEVICE_STATE ds
)
{
DEBUGCHK(ds < dim(g_rgpszDeviceStates));
LPCTSTR psz = g_rgpszDeviceStates[ds];
return psz;
}
#endif
// Return the configuration tree structure for the given speed.
static
PUFN_CONFIGURATION
GetConfig(
PUFN_MDD_CONTEXT pContext,
UFN_BUS_SPEED Speed
)
{
DEBUGCHK(pContext);
DEBUGCHK( (Speed == BS_FULL_SPEED) || (Speed == BS_HIGH_SPEED) );
PUFN_CONFIGURATION pConfig;
if (Speed == BS_HIGH_SPEED) {
pConfig = &pContext->HighSpeedConfig;
}
else {
pConfig = &pContext->FullSpeedConfig;
}
return pConfig;
}
DWORD
static
WINAPI
EnumTransferComplete(
PVOID pvNotifyParameter
)
{
SETFNAME();
FUNCTION_ENTER_MSG();
PUFN_MDD_CONTEXT pContext = (PUFN_MDD_CONTEXT) pvNotifyParameter;
UFN_TRANSFER hTransfer = pContext->hEnumTransfer;
pContext->hEnumTransfer = NULL;
DWORD dwUsbError;
DWORD cbTransferred;
PREFAST_DEBUGCHK(hTransfer);
DWORD dwErr = UfnMdd_GetTransferStatus(pContext, hTransfer, &cbTransferred,
&dwUsbError);
DEBUGCHK(dwErr == ERROR_SUCCESS);
dwErr = UfnMdd_CloseTransfer(pContext, hTransfer);
DEBUGCHK(dwErr == ERROR_SUCCESS);
DEBUGMSG(ZONE_USB_EVENTS, (_T("%s %u bytes written\r\n"), pszFname,
cbTransferred));
if (dwUsbError == UFN_NO_ERROR) {
PCPipe pPipe = &pContext->pPipes[0];
pPipe->SendControlStatusHandshake();
}
FUNCTION_LEAVE_MSG();
return ERROR_SUCCESS;
}
// Setup for a transfer.
static
VOID
SetupTx(
PUFN_MDD_CONTEXT pContext,
PVOID pvBuffer,
DWORD cbBuffer,
DWORD cbRequested
)
{
SETFNAME();
FUNCTION_ENTER_MSG();
ValidateContext(pContext);
DEBUGCHK(pvBuffer);
DWORD cbToSend = min(cbRequested, cbBuffer);
DEBUGMSG(ZONE_SEND, (_T("%s Asked to send %u of %u bytes. Sending %u bytes.\r\n"),
pszFname, cbRequested, cbBuffer, cbToSend));
PCPipe pPipeEndpoint0 = &pContext->pPipes[0];
DEBUGCHK(pContext->hEnumTransfer == NULL);
DWORD dwErr = UfnMdd_IssueTransfer(pContext, pPipeEndpoint0,
&EnumTransferComplete, pContext, USB_IN_TRANSFER, cbToSend,
pvBuffer, 0, NULL, &pContext->hEnumTransfer);
FUNCTION_LEAVE_MSG();
}
// Handle a Get Descriptor request.
static
CONTROL_RESPONSE
ProcessGetDescriptor(
PUFN_MDD_CONTEXT pContext,
USB_DEVICE_REQUEST udr,
DWORD dwMsg
)
{
SETFNAME();
FUNCTION_ENTER_MSG();
ValidateContext(pContext);
DEBUGCHK( (pContext->Speed == BS_HIGH_SPEED) ||
(pContext->Speed == BS_FULL_SPEED) );
CONTROL_RESPONSE response = CR_SUCCESS;
if (dwMsg == UFN_MSG_PREPROCESSED_SETUP_PACKET) {
// Nothing to do.
goto EXIT;
}
DWORD dwType = GET_DESCRIPTOR_TYPE(udr.wValue);
DWORD dwIndex = GET_DESCRIPTOR_INDEX(udr.wValue);
PVOID pvBuffer = NULL;
DWORD cbBuffer;
if ( (dwType != USB_STRING_DESCRIPTOR_TYPE) && (udr.wIndex != 0) ) {
DEBUGMSG(ZONE_ERROR, (_T("%s Invalid wIndex value %u\r\n"),
pszFname, udr.wIndex));
response = CR_STALL_DEFAULT_PIPE;
}
else if ( (dwType == USB_DEVICE_DESCRIPTOR_TYPE) && (dwIndex == 0) ) {
DEBUGMSG(ZONE_USB_EVENTS, (_T("%s Get device descriptor request.\r\n"),
pszFname));
if (pContext->Speed == BS_HIGH_SPEED) {
pvBuffer = &pContext->HighSpeedDeviceDesc;
}
else {
pvBuffer = &pContext->FullSpeedDeviceDesc;
}
cbBuffer = sizeof(USB_DEVICE_DESCRIPTOR);
}
else if ( (dwType == USB_DEVICE_QUALIFIER_DESCRIPTOR_TYPE) && (dwIndex == 0) ) {
DEBUGMSG(ZONE_USB_EVENTS, (_T("%s Get device qualifier descriptor request.\r\n"),
pszFname));
PUSB_DEVICE_DESCRIPTOR pDeviceDesc = NULL;
if (pContext->Speed == BS_HIGH_SPEED) {
pDeviceDesc = &pContext->FullSpeedDeviceDesc;
}
else {
if (PddSupportsHighSpeed(pContext)) {
pDeviceDesc = &pContext->HighSpeedDeviceDesc;
}
}
if (pDeviceDesc) {
cbBuffer = sizeof(USB_DEVICE_QUALIFIER_DESCRIPTOR);
memcpy(&pContext->DeviceQualifierDescToSend, pDeviceDesc, cbBuffer);
// Copy over the values that do match
pContext->DeviceQualifierDescToSend.bLength =
sizeof(USB_DEVICE_QUALIFIER_DESCRIPTOR);
pContext->DeviceQualifierDescToSend.bDescriptorType = (BYTE) dwType;
pContext->DeviceQualifierDescToSend.bNumConfigurations =
pDeviceDesc->bNumConfigurations;
pContext->DeviceQualifierDescToSend.bReserved = 0;
pvBuffer = &pContext->DeviceQualifierDescToSend;
}
else {
// We are connected at full speed and there is no support
// for high speed.
response = CR_STALL_DEFAULT_PIPE;
}
}
else if ( (dwType == USB_CONFIGURATION_DESCRIPTOR_TYPE) ||
(dwType == USB_OTHER_SPEED_CONFIGURATION_DESCRIPTOR_TYPE) ||
(dwType == USB_OTG_CONFIGURATION_DESCRIPTOR_TYPE)) {
if (dwIndex == 0) {
DEBUGMSG(ZONE_USB_EVENTS, (_T("%s Get dwType=%d configuration descriptor request.\r\n"),
pszFname, dwType ) );
PUSB_CONFIGURATION_DESCRIPTOR pConfigDesc;
if (dwType == USB_CONFIGURATION_DESCRIPTOR_TYPE) {
if (pContext->Speed == BS_HIGH_SPEED) {
pConfigDesc = pContext->pHighSpeedConfigDesc;
}
else {
pConfigDesc = pContext->pFullSpeedConfigDesc;
}
}
else if ( (dwType == USB_OTG_CONFIGURATION_DESCRIPTOR_TYPE)) {
// Copy over the values that do match
pContext->USBOTGDescToSend.bLength = sizeof (USB_OTG_DESCRIPTOR);
pContext->USBOTGDescToSend.bDescriptorType = USB_OTG_CONFIGURATION_DESCRIPTOR_TYPE;
pContext->USBOTGDescToSend.bmAttributes = ((pContext->uOTGCapabilityBits & USBOTG_DEVICE_ENABLE)!=0?3:0);
pvBuffer = &pContext->USBOTGDescToSend;
}
else {
DEBUGCHK(dwType == USB_OTHER_SPEED_CONFIGURATION_DESCRIPTOR_TYPE);
DEBUGCHK(PddSupportsHighSpeed(pContext));
if (pContext->Speed == BS_HIGH_SPEED) {
pConfigDesc = pContext->pFullSpeedConfigDesc;
}
else {
pConfigDesc = pContext->pHighSpeedConfigDesc;
}
}
pConfigDesc->bDescriptorType = (BYTE) dwType;
pvBuffer = pConfigDesc;
cbBuffer = pConfigDesc->wTotalLength;
}
else {
DEBUGMSG(ZONE_ERROR, (_T("%s Invalid configuration number %u\r\n"),
pszFname, dwIndex));
response = CR_STALL_DEFAULT_PIPE;
}
}
else if (dwType == USB_STRING_DESCRIPTOR_TYPE) {
WORD wLang = udr.wIndex;
DEBUGMSG(ZONE_USB_EVENTS, (_T("%s Get string descriptor request. Lang 0x%04x Idx %u\r\n"),
pszFname, wLang, dwIndex));
if (pContext->cStringSets) {
PUSB_STRING_DESCRIPTOR pStringDesc = (PUSB_STRING_DESCRIPTOR)
pContext->rgbStringDesc;
pStringDesc->bDescriptorType = USB_STRING_DESCRIPTOR_TYPE;
DWORD cbData;
if (dwIndex == 0) {
DEBUGCHK(pContext->cStringSets <= MAX_STRING_DESC_WCHARS);
DWORD dwLangId;
for (dwLangId = 0; dwLangId < pContext->cStringSets; ++dwLangId) {
pStringDesc->bString[dwLangId] =
pContext->pStringSets[dwLangId].wLangId;
}
cbData = pContext->cStringSets * sizeof(WCHAR);
}
else {
DWORD dwLangId;
PUFN_STRING_SET pStringSet;
for (dwLangId = 0; dwLangId < pContext->cStringSets; ++dwLangId) {
pStringSet = &pContext->pStringSets[dwLangId];
if (pStringSet->wLangId == wLang) {
break;
}
}
if (dwLangId == pContext->cStringSets) {
// Perhaps the client wishes to process string requests.
DEBUGMSG(ZONE_WARNING, (_T("%s Invalid language id 0x%04x\r\n"),
pszFname, wLang));
response = CR_UNHANDLED_REQUEST;
}
else {
--dwIndex;
if (dwIndex < pStringSet->cStrings) {
LPCWSTR pszString = pStringSet->ppszStrings[dwIndex];
DWORD cchString = wcslen(pszString);
DEBUGCHK(cchString <= MAX_STRING_DESC_WCHARS);
// Do not copy NULL terminator.
wcsncpy(pStringDesc->bString, pszString, cchString);
cbData = cchString * sizeof(WCHAR);
}
else {
// Perhaps the client wishes to process string requests.
DEBUGMSG(ZONE_WARNING, (_T("%s Invalid string index %u\r\n"),
pszFname, dwIndex));
response = CR_UNHANDLED_REQUEST;
}
}
}
if (response == CR_SUCCESS) {
pStringDesc->bLength = (UCHAR) (sizeof(USB_STRING_DESCRIPTOR) -
sizeof(pStringDesc->bString) + cbData);
pvBuffer = pStringDesc;
cbBuffer = pStringDesc->bLength;
}
}
else {
// Perhaps the client wishes to process string requests.
DEBUGMSG(ZONE_WARNING, (_T("%s Request for strings, but MDD has none. Index %u\r\n"),
pszFname, dwIndex));
response = CR_UNHANDLED_REQUEST;
}
}
else {
DEBUGMSG(ZONE_ERROR, (_T("%s Invalid GetDescriptor request\r\n"),
pszFname));
response = CR_STALL_DEFAULT_PIPE;
}
if (pvBuffer) {
DEBUGCHK(response == CR_SUCCESS);
SetupTx(pContext, (PBYTE) pvBuffer, cbBuffer, udr.wLength);
}
EXIT:
FUNCTION_LEAVE_MSG();
return response;
}
// Handle a Get Configuration request.
static
CONTROL_RESPONSE
ProcessGetConfiguration(
PUFN_MDD_CONTEXT pContext,
USB_DEVICE_REQUEST udr,
DWORD dwMsg
)
{
SETFNAME();
FUNCTION_ENTER_MSG();
ValidateContext(pContext);
if (dwMsg == UFN_MSG_PREPROCESSED_SETUP_PACKET) {
// Nothing to do.
goto EXIT;
}
const DWORD dwLength = 1;
DEBUGCHK(dim(pContext->rgbBuffer) >= dwLength);
DEBUGMSG(ZONE_USB_EVENTS, (_T("%s Get configuration.\r\n"), pszFname));
PUFN_CONFIGURATION pConfig = GetConfig(pContext, pContext->Speed);
BYTE bConfigurationValue = pConfig->Descriptor.bConfigurationValue;
DEBUGCHK(
( (pContext->deviceState == DS_ADDRESSED) && (pContext->dwConfiguration == 0) ) ||
( (pContext->deviceState == DS_CONFIGURED) && (pContext->dwConfiguration == bConfigurationValue) )
);
pContext->rgbBuffer[0] = (BYTE) pContext->dwConfiguration;
SetupTx(pContext, pContext->rgbBuffer, dwLength, udr.wLength);
FUNCTION_LEAVE_MSG();
EXIT:
return CR_SUCCESS;
}
// Handle a Get Interface request.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -