windows-nt/Source/XPSP1/NT/drivers/wdm/usb/driver/usbdiag/chap9drv.c
2020-09-26 16:20:57 +08:00

3634 lines
142 KiB
C

/*++
Copyright (c) 1996 Microsoft Corporation
Module Name:
chap9drv.c
Abstract:
USB device driver for Intel/Microsoft diagnostic apps
Environment:
kernel mode only
Notes:
THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
PURPOSE.
Copyright (c) 1996 Microsoft Corporation. All Rights Reserved.
Revision History:
5-4-96 : created
--*/
#define DRIVER
#define USBDIAG_VERSION 0x0610
#include "wdm.h"
#include "stdarg.h"
#include "stdio.h"
// Enable 1-byte alignment in structs
#pragma pack (push,1)
#include "usb100.h"
#include "usbdi.h"
#include "usbdlib.h"
#include "usbioctl.h"
#pragma pack (pop) //disable 1-byte alignment
#include "opaque.h"
// Enable 1-byte alignment in structs
#pragma pack (push,1)
#include "hidpddi.h"
#include "ioctl.h"
#include "chap9drv.h"
#include "USBDIAG.h"
#include "chap11.h"
#include "_m_usb.h"
#include "typedefs.h"
#pragma pack (pop) //disable 1-byte alignment
#define DEADMAN_TIMEOUT 5000 //timeout in ms; we use a 5 second timeout
#define RAWPACKET_DIRECTION_IN(bmReq) (((bmReq) & bmReqD2H)>>7)
extern USBD_VERSION_INFORMATION gVersionInformation;
/* ------------------ local prototypes ---------------*/
typedef BYTE *PBYTE;
VOID
Ch9FillInReqStatus (
IN NTSTATUS ntStatusCode,
IN ULONG ulUrbStatus,
IN OUT struct _REQ_HEADER * pReqHeader
);
PBYTE
pAllocFromBuffer(
PBYTE pBuffer,
ULONG iSize,
PULONG piOffset,
PULONG piTotalUsed,
ULONG iAmountRequested
);
/* ------------------ end local prototypes ---------------*/
NTSTATUS
USBDIAG_Chap9Control(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
/*++
Routine Description:
Arguments:
DeviceObject - pointer to the device object for the USBDIAG driver's device
object, which is not the actual physical device. That ptr is not
used here since our PDO is in the REQ packet sent down from user app,
and that is in the IRP.
Return Value:
NT status code
--*/
{
PIO_STACK_LOCATION irpStack;
PVOID ioBuffer = NULL;
ULONG inputBufferLength = 0;
ULONG outputBufferLength= 0;
NTSTATUS ntStatus = STATUS_SUCCESS;
PURB urb = NULL;
ULONG ulUrbStatus = USBD_STATUS_SUCCESS;
ULONG siz = 0;
ULONG sizeToCopy;
BOOLEAN bCompleteIrp = TRUE;
PUSB_DEVICE_DESCRIPTOR deviceDesc ;
struct _REQ_HEADER * REQHeader;
PDEVICE_LIST_ENTRY devListEntry;
PDEVICE_OBJECT actualdeviceObject = NULL;
PDEVICE_EXTENSION deviceExtension = NULL;
// Get a pointer to the current location in the Irp. This is where
// the function codes and parameters are located.
irpStack = IoGetCurrentIrpStackLocation (Irp);
// Get the pointer to the input/output buffer and it's length
ioBuffer = Irp->AssociatedIrp.SystemBuffer;
inputBufferLength = irpStack->Parameters.DeviceIoControl.InputBufferLength;
outputBufferLength = irpStack->Parameters.DeviceIoControl.OutputBufferLength;
// The REQHeader, which is the struct that the app fills in describing this REQuest is
// referenced in the SystemBuffer since it is sent down in the InputBuffer field of the
// DeviceIoControl call in User Mode.
REQHeader = (struct _REQ_HEADER *)ioBuffer;
// The DeviceHandle is a ptr to the list entry that USBDIAG manages for devices it is
// testing. This used to be a "USBD Device handle" in the old Chap9 method. Now it's a
// ptr to the list entry object that USBDIAG maintains for each device under test. That
// list entry contains the PDO and other junk about the device object
devListEntry = (PDEVICE_LIST_ENTRY)(REQHeader->UsbdDeviceHandle);
//USBDIAG_KdPrint(("USBDIAG.SYS: DevListEntry: %X\n",devListEntry));
// Device object given is not the real DevObj that was created by PnPAddDevice, so
// extract that DevObj with a handy macro before calling the lower level drivers (USB stk)
// NOTE: This extracted DevObj contains the deviceExtension that in turn contains
// the "StackDeviceObject" that is needed by the IoCallDriver function to pass
// Urbs down the stack.
if(devListEntry)
{
actualdeviceObject = FDO_FROM_DEVICE_HANDLE(devListEntry);
deviceExtension = actualdeviceObject->DeviceExtension;
//USBDIAG_KdPrint(("USBDIAG.SYS: PDO for DUT: %X\n",actualdeviceObject));
}
// Find out which of the Chap9 functions is being sent down from app
switch (REQHeader->Function)
{
case REQ_FUNCTION_RESET_PARENT_PORT:
{
ntStatus = USBDIAG_ResetParentPort(actualdeviceObject);
Irp->IoStatus.Status = ntStatus;
Irp->IoStatus.Information = sizeof(struct _REQ_HEADER);
}
break;
case REQ_FUNCTION_GET_CHAP9VERSION:
{
struct _REQ_GETCHAP9_VERSION * pGetVersion;
pGetVersion = (struct _REQ_GETCHAP9_VERSION *)(ioBuffer);
pGetVersion->Version = USBDIAG_VERSION;
ntStatus = Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = sizeof (struct _REQ_GETCHAP9_VERSION);
}
break;
case REQ_FUNCTION_GET_DESCRIPTOR:
{
/* Create an URB for the USBD call to get device descriptor. */
struct _REQ_GETSET_DESCRIPTOR *pGetSetDesc = (struct _REQ_GETSET_DESCRIPTOR *)(ioBuffer) ;
//USBDIAG_KdPrint(("***USBDIAG.SYS: In Get Descriptor 0x%x\n", pGetSetDesc->DescriptorType)) ;
switch (pGetSetDesc->DescriptorType)
{
case USB_DEVICE_DESCRIPTOR_TYPE:
USBDIAG_KdPrint (("USBDIAG.SYS: DEVICE DESCRIPTOR requested\n"));
break;
case USB_CONFIGURATION_DESCRIPTOR_TYPE:
USBDIAG_KdPrint (("USBDIAG.SYS: CONFIG DESCRIPTOR requested\n"));
break;
case USB_STRING_DESCRIPTOR_TYPE:
USBDIAG_KdPrint (("USBDIAG.SYS: STRING DESCRIPTOR requested\n"));
break;
default:
USBDIAG_KdPrint (("USBDIAG.SYS: Error--Unknown Descriptor Type Requested!!\n"));
TRAP();
break;
}//switch
siz = sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST) ;
urb = USBDIAG_ExAllocatePool(NonPagedPool, siz ) ;
if (urb)
{
// Get the memory in Ke mode for this txfer, based on client's request
siz = (pGetSetDesc->TransferBufferLength);
deviceDesc = USBDIAG_ExAllocatePool(NonPagedPool, siz);
if (deviceDesc)
{
// NOTE: We create the URB down in Ke mode.
UsbBuildGetDescriptorRequest(
urb,
(USHORT) sizeof (struct _URB_CONTROL_DESCRIPTOR_REQUEST),
(UCHAR)(pGetSetDesc->DescriptorType),
(UCHAR)(pGetSetDesc->Index), // Descriptor Index
pGetSetDesc->LanguageId, //language ID
deviceDesc, //transfer buffer
NULL, // " " MDL
siz, //transfer buffer length
NULL); //link - not used
ntStatus = USBDIAG_Ch9CallUSBD(actualdeviceObject, urb, TRUE, NULL, NULL, TRUE);
ulUrbStatus = urb->UrbHeader.Status; //capture the urb status for later
if (!NT_SUCCESS(ntStatus))
{
USBDIAG_KdPrint (("USBDIAG.SYS: Error in Get device descriptor\n")) ;
}
if ( pGetSetDesc->DescriptorType == USB_DEVICE_DESCRIPTOR_TYPE )
{
//USBDIAG_KdPrint(("USBDIAG.SYS: A device descriptor was requested. Got back \n"));
/*USBDIAG_KdPrint(("USBDIAG.SYS: \tDevDesc Length = %x, type %x MaxpacketSize %x\n",
deviceDesc->bLength,
deviceDesc->bDescriptorType,
deviceDesc->bMaxPacketSize0));
*/
}
// copy the data directly into the User Mode buffer. We can do this becauase
// we're still in the thread context of the calling User Mode app
if (( ioBuffer ) && (pGetSetDesc->TransferBuffer))
{
/*
USBDIAG_KdPrint(("USBDIAG.SYS: Device sent back %d bytes of descriptor data\n",
urb->UrbControlDescriptorRequest.TransferBufferLength));
//USBDIAG_KdPrint(("USBDIAG.SYS: Copying %d bytes to UserMode's buffer (at %X)\n",
(pGetSetDesc->TransferBufferLength < urb->UrbControlDescriptorRequest.TransferBufferLength ) ? pGetSetDesc->TransferBufferLength : urb->UrbControlDescriptorRequest.TransferBufferLength,
pGetSetDesc->TransferBuffer));
*/
sizeToCopy = pGetSetDesc->TransferBufferLength < urb->UrbControlDescriptorRequest.TransferBufferLength
? pGetSetDesc->TransferBufferLength
: urb->UrbControlDescriptorRequest.TransferBufferLength;
__try
{
ProbeForWrite(pGetSetDesc->TransferBuffer,
sizeToCopy,
TYPE_ALIGNMENT(HIDP_DEVICE_DESC));
RtlCopyMemory( pGetSetDesc->TransferBuffer,
deviceDesc,
sizeToCopy);
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
ntStatus = STATUS_INVALID_PARAMETER;
sizeToCopy = 0;
// USBDIAG_KdPrint(("USBDIAG.SYS: BAD POINTER RECEIVED! Bailing...\n"));
}
}
USBDIAG_ExFreePool(deviceDesc);
// The Information field tells IOM how much to copy back into the
// usermode buffer in the BUFFERED method
// In this case all we want the IOM to copy back is the REQ itself
// so things like the status field get updated
//
Irp->IoStatus.Information = sizeof(struct _REQ_HEADER);
Irp->IoStatus.Status = ntStatus;
//
// Fill in the length in the REQ block with the number
// of bytes copied back into the TransferBuffer.
//
pGetSetDesc->TransferBufferLength = sizeToCopy;
}
else
{
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
}
USBDIAG_ExFreePool(urb);
} // if urb
} // REQ_FUNCTION_GET_DESCRIPTOR
break ;
case REQ_FUNCTION_SET_DESCRIPTOR:
{
struct _REQ_GETSET_DESCRIPTOR *pGetSetDesc = (struct _REQ_GETSET_DESCRIPTOR *)(ioBuffer) ;
//USBDIAG_KdPrint(("USBDIAG.SYS: In Set Descriptor buf = 0x%x\n", *pGetSetDesc)) ;
siz = sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST) ;
urb = USBDIAG_ExAllocatePool(NonPagedPool, siz ) ;
if (urb)
{
// Get nonpaged mem for this transfer and use len given by app
siz = pGetSetDesc->TransferBufferLength ;
deviceDesc = USBDIAG_ExAllocatePool(NonPagedPool, siz);
if (deviceDesc)
{
memcpy( deviceDesc, pGetSetDesc->TransferBuffer, siz);
//
// Unfortunately, there is no macro to build a
// SetDescriptorRequest in the USBDI.H. Therefore,
// we will use our own.
//
// NOTE: Should it every appear, the below statement
// can be changed.
//
_m_UsbBuildSetDescriptorRequest(urb,
(USHORT) sizeof (struct _URB_CONTROL_DESCRIPTOR_REQUEST), //len
(UCHAR)(pGetSetDesc->DescriptorType), //desc type
(UCHAR)(pGetSetDesc->Index), //index
pGetSetDesc->LanguageId, //language ID
deviceDesc, //buffer
NULL, //MDL
siz, //buff len
NULL); //link
ntStatus = USBDIAG_Ch9CallUSBD(actualdeviceObject, urb, TRUE, NULL, NULL, TRUE);
ulUrbStatus = urb->UrbHeader.Status; //capture the urb status for later
if ( ! NT_SUCCESS(ntStatus) )
{
//USBDIAG_KdPrint(("USBDIAG.SYS: Error in Set device descriptor\n")) ;
}
/*USBDIAG_KdPrint(("USBDIAG.SYS: Set Descriptor at %x, type %x len %x bytes\n",
deviceDesc,
pGetSetDesc->DescriptorType,
urb->UrbControlDescriptorRequest.TransferBufferLength));
*/
USBDIAG_ExFreePool(deviceDesc);
}
else
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
// The Information field tells IOM how much to copy back into the
// usermode buffer in the BUFFERED method
// In this case all we want the IOM to copy back is the REQ itself
// so things like the status field get updated
Irp->IoStatus.Information = sizeof(*pGetSetDesc);
Irp->IoStatus.Status = ntStatus;
USBDIAG_ExFreePool(urb);
} // if urb
//USBDIAG_KdPrint(("USBDIAG.SYS: Exiting Set Descriptor\n")) ;
} // End of REQ_FUNCTION_SET_DESCRIPTOR
break ;
case REQ_FUNCTION_SET_FEATURE:
case REQ_FUNCTION_CLEAR_FEATURE:
{
struct _REQ_FEATURE *pSetClrFeature;
pSetClrFeature = (struct _REQ_FEATURE *) ioBuffer;
// We check again here since the set_feat case drops thru here
if (REQHeader->Function == REQ_FUNCTION_CLEAR_FEATURE)
{
//USBDIAG_KdPrint(("USBDIAG.SYS: In Clear Feature\n")) ;
}
else
{
//USBDIAG_KdPrint(("USBDIAG.SYS: In Set Feature\n")) ;
}
if ( pSetClrFeature == NULL )
{
//USBDIAG_KdPrint(("USBDIAG.SYS: NULL parameter passsed\n")) ;
Irp->IoStatus.Information = sizeof(struct _REQ_HEADER);
Irp->IoStatus.Status = ntStatus = STATUS_INVALID_PARAMETER;
break ;
}
siz = sizeof(struct _URB_CONTROL_FEATURE_REQUEST) ;
urb = USBDIAG_ExAllocatePool(NonPagedPool, siz ) ;
if (urb)
{
/*
// Set the function code for USBD to use. NOte that the function code
// differs depending on the recipient and so we do this for each of the
// Set and Clear feature requests.
*/
ntStatus = STATUS_SUCCESS;
if ( REQHeader->Function == REQ_FUNCTION_CLEAR_FEATURE )
{
//Oh, look it's a CLEAR_FEATURE
switch (pSetClrFeature->Recipient)
{
case (RECIPIENT_DEVICE):
urb->UrbHeader.Function = URB_FUNCTION_CLEAR_FEATURE_TO_DEVICE;
break;
case (RECIPIENT_ENDPOINT):
urb->UrbHeader.Function = URB_FUNCTION_CLEAR_FEATURE_TO_ENDPOINT;
break;
case (RECIPIENT_INTERFACE):
urb->UrbHeader.Function = URB_FUNCTION_CLEAR_FEATURE_TO_INTERFACE;
break;
default:
ntStatus = STATUS_INVALID_PARAMETER;
break;
}//switch
}/*if it's a CLEAR_FEATURE */
else
{
// OK, it's a SET_FEATURE
switch (pSetClrFeature->Recipient)
{
case (RECIPIENT_DEVICE):
urb->UrbHeader.Function = URB_FUNCTION_SET_FEATURE_TO_DEVICE;
break;
case (RECIPIENT_ENDPOINT):
urb->UrbHeader.Function = URB_FUNCTION_SET_FEATURE_TO_ENDPOINT;
break;
case (RECIPIENT_INTERFACE):
urb->UrbHeader.Function = URB_FUNCTION_SET_FEATURE_TO_INTERFACE;
break;
default:
ntStatus = STATUS_INVALID_PARAMETER;
break;
}//switch
}/* else it's a SET_FEATURE */
if (NT_SUCCESS(ntStatus))
{
urb->UrbHeader.Length = (USHORT) sizeof (struct _URB_CONTROL_FEATURE_REQUEST);
urb->UrbControlFeatureRequest.UrbLink = NULL;
urb->UrbControlFeatureRequest.FeatureSelector = pSetClrFeature->FeatureSelector;
urb->UrbControlFeatureRequest.Index = pSetClrFeature->Index;
//USBDIAG_KdPrint(("USBDIAG.SYS: Device Object = %x\n", REQHeader->UsbdDeviceHandle )) ;
ntStatus = USBDIAG_Ch9CallUSBD(actualdeviceObject,
urb,
TRUE,
NULL,
NULL,
TRUE);
//
// Capture the urb status
//
ulUrbStatus = urb->UrbHeader.Status;
}
if (!NT_SUCCESS(ntStatus))
{
//USBDIAG_KdPrint(("USBDIAG.SYS: Error in Set/Clear feature\n")) ;
}
else
{
//USBDIAG_KdPrint(("USBDIAG.SYS: Successfully did Set/Clear feature\n")) ;
}
// The Information field tells IOM how much to copy back into the
// usermode buffer in the BUFFERED method
// In this case all we want the IOM to copy back is the REQ itself
// so things like the status field get updated
Irp->IoStatus.Information = sizeof(struct _REQ_FEATURE);
Irp->IoStatus.Status = ntStatus;
USBDIAG_ExFreePool(urb);
} // if urb
//USBDIAG_KdPrint(("USBDIAG.SYS: Exiting Set/Clear feature\n")) ;
} // End of REQ_FUNCTION_CLEAR_FEATURE
break ;
case REQ_FUNCTION_GET_STATUS:
{
struct _REQ_GET_STATUS * pGetStatus = (struct _REQ_GET_STATUS *)(ioBuffer) ;
//USBDIAG_KdPrint(("USBDIAG.SYS: In GetStatus\n")) ;
if (pGetStatus == NULL)
{
//USBDIAG_KdPrint(("USBDIAG.SYS: NULL parameter passsed\n")) ;
TRAP();
break ;
}
siz = sizeof(struct _URB_CONTROL_GET_STATUS_REQUEST) ;
//Create an URB for the USBD call to get status
urb = USBDIAG_ExAllocatePool(NonPagedPool, siz ) ;
if (urb)
{
USHORT function;
USHORT * pStatus;
switch (pGetStatus->Recipient)
{
case RECIPIENT_DEVICE :
//USBDIAG_KdPrint(("USBDIAG.SYS: Getting Status from DEVICE\n"))
function = URB_FUNCTION_GET_STATUS_FROM_DEVICE;
break;
case RECIPIENT_INTERFACE:
//USBDIAG_KdPrint(("USBDIAG.SYS: Getting Status from INTERFACE\n"))
function = URB_FUNCTION_GET_STATUS_FROM_INTERFACE;
break;
case RECIPIENT_ENDPOINT:
//USBDIAG_KdPrint(("USBDIAG.SYS: Getting Status from ENDPOINT\n"))
function = URB_FUNCTION_GET_STATUS_FROM_ENDPOINT;
break;
default:
//USBDIAG_KdPrint(("USBDIAG.SYS: Getting Status from OTHER (??)\n"))
function = URB_FUNCTION_GET_STATUS_FROM_OTHER; // ?
} //switch
// Fill in the URB
urb->UrbHeader.Function = function;
urb->UrbHeader.Length = (USHORT) sizeof (struct _URB_CONTROL_GET_STATUS_REQUEST);
urb->UrbControlGetStatusRequest.UrbLink = NULL;
//
// Get a buffer for the status data to be put in
// Don't know why we have to get so much more data than we need?
// Don't use siz again but I'm not about to investigate the
// effects of a change.
//
siz = GET_STATUS_DATA_LEN + 128;
pStatus = USBDIAG_ExAllocatePool(NonPagedPool, siz);
if (pStatus == NULL)
{
//USBDIAG_KdPrint(("USBDIAG.SYS: Failed getting mem in GetStatus!\n"));
TRAP();
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
goto GetStatus_FreeMem;
}//if
urb->UrbControlGetStatusRequest.TransferBufferLength = GET_STATUS_DATA_LEN;
urb->UrbControlGetStatusRequest.TransferBuffer = pStatus;
urb->UrbControlGetStatusRequest.TransferBufferMDL = NULL;
urb->UrbControlGetStatusRequest.Index = pGetStatus->Index;
ntStatus = USBDIAG_Ch9CallUSBD (actualdeviceObject, urb, TRUE, NULL, NULL, TRUE);
ulUrbStatus = urb->UrbHeader.Status; //capture the urb status for later
if (NT_SUCCESS(ntStatus))
{
//USBDIAG_KdPrint(("USBDIAG.SYS: Successfully did Get Status\n")) ;
//USBDIAG_KdPrint(("USBDIAG.SYS: Status value = %02x\n", *pStatus )) ;
pGetStatus->Status = *pStatus ;
}
else
{
//USBDIAG_KdPrint(("USBDIAG.SYS: Failed Get Status\n")) ;
}
USBDIAG_ExFreePool(pStatus) ;
GetStatus_FreeMem:
// The Information field tells IOM how much to copy back into the
// usermode buffer in the BUFFERED method
// In this case all we want the IOM to copy back is the REQ itself
// so things like the status field get updated
Irp->IoStatus.Information = sizeof(struct _REQ_GET_STATUS);
Irp->IoStatus.Status = ntStatus;
USBDIAG_ExFreePool(urb);
}// if urb
//USBDIAG_KdPrint(("USBDIAG.SYS: Exiting Get Status\n")) ;
} // End of REQ_FUNCTION_GET_STATUS
break ;
case REQ_FUNCTION_SET_ADDRESS:
{
char SetUpPacket[8] ;
struct _REQ_SET_ADDRESS * pSetAddr = (struct _REQ_SET_ADDRESS *)(ioBuffer) ;
//USBDIAG_KdPrint(("USBDIAG.SYS: In Set Address\n")) ;
// Set up the setup packet for SET_ADDRESS
SetUpPacket[0] = 0x0 ;
SetUpPacket[1] = USB_REQUEST_SET_ADDRESS ;
SetUpPacket[2] = LOBYTE(pSetAddr->DevAddr) ;
SetUpPacket[3] = HIBYTE(pSetAddr->DevAddr) ;
SetUpPacket[4] = 0x0 ;
SetUpPacket[5] = 0x0 ;
SetUpPacket[6] = 0x0 ;
SetUpPacket[7] = 0x0 ;
//USBDIAG_KdPrint(("USBDIAG.SYS: Set Address to %02x %02x\n", SetUpPacket[2], SetUpPacket[3] )) ;
siz = 0;
ntStatus = USBDIAG_SendPacket(actualdeviceObject,SetUpPacket, NULL, &siz, &ulUrbStatus) ;
if (NT_SUCCESS(ntStatus))
{
//USBDIAG_KdPrint(("USBDIAG.SYS: Successfully did Set Address\n")) ;
}
else
{
//USBDIAG_KdPrint(("USBDIAG.SYS: Failed Set Address\n")) ;
}
//USBDIAG_KdPrint(("USBDIAG.SYS: Exiting Set Address\n")) ;
// The Information field tells IOM how much to copy back into the
// usermode buffer in the BUFFERED method
// In this case all we want the IOM to copy back is the REQ itself
// so things like the status field get updated
Irp->IoStatus.Information = sizeof(struct _REQ_SET_ADDRESS);
Irp->IoStatus.Status = ntStatus;
// return the status
pSetAddr->Hdr.Status = ntStatus;
} /* end case REQ_FUNCTION_SET_ADDRESS */
break ;
case REQ_FUNCTION_GET_CONFIGURATION:
{
struct _REQ_GETSET_CONFIGURATION * pGetConf = (struct _REQ_GETSET_CONFIGURATION *)(ioBuffer) ;
UCHAR SetUpPacket[8] ;
char *ConfigValue = NULL ;
//USBDIAG_KdPrint(("USBDIAG.SYS: In Get Configuration\n")) ;
siz = 1;
ConfigValue = USBDIAG_ExAllocatePool(NonPagedPool, siz + 16) ;
// Set up the setup packet for GET_CONFIG
SetUpPacket[0] = (bmReqD2H | bmReqSTANDARD | bmReqDEVICE) ;
SetUpPacket[1] = USB_REQUEST_GET_CONFIGURATION ;
SetUpPacket[2] = 0x0;
SetUpPacket[3] = 0x0;
SetUpPacket[4] = 0x0 ;
SetUpPacket[5] = 0x0 ;
SetUpPacket[6] = 0x01 ; //Configuration value is 1 byte
SetUpPacket[7] = 0x0;
ntStatus = USBDIAG_SendPacket( actualdeviceObject, (PCHAR)SetUpPacket, ConfigValue, &siz, &ulUrbStatus) ;
if (NT_SUCCESS(ntStatus))
{
//USBDIAG_KdPrint(("USBDIAG.SYS: Successfully did Get Configuration (%d bytes txferred)\n", siz)) ;
//USBDIAG_KdPrint(("USBDIAG.SYS: Configuration value = %02x\n", *ConfigValue )) ;
pGetConf->ConfigValue = (USHORT)*ConfigValue ;
}
else
{
//USBDIAG_KdPrint(("USBDIAG.SYS: Failed Get Configuration\n")) ;
}
// The Information field tells IOM how much to copy back into the
// usermode buffer in the BUFFERED method
// In this case all we want the IOM to copy back is the REQ itself
// so things like the status field get updated
Irp->IoStatus.Information = sizeof(struct _REQ_GETSET_CONFIGURATION);
Irp->IoStatus.Status = ntStatus;
// return the status
pGetConf->Hdr.Status = ntStatus;
USBDIAG_ExFreePool(ConfigValue) ;
//USBDIAG_KdPrint(("USBDIAG.SYS: Exiting Get Configuration\n")) ;
} // End of case REQ_FUNCTION_GET_CONFIGURATION
break ;
case REQ_FUNCTION_SET_CONFIGURATION:
{
struct _REQ_GETSET_CONFIGURATION * pGetConf = (struct _REQ_GETSET_CONFIGURATION *)(ioBuffer) ;
char SetUpPacket[8] ;
//USBDIAG_KdPrint(("USBDIAG.SYS: In Set Configuration\n")) ;
siz=0;
// Set up the setup packet for SET_CONFIG
SetUpPacket[0] = (bmReqH2D | bmReqSTANDARD | bmReqDEVICE) ;
SetUpPacket[1] = USB_REQUEST_SET_CONFIGURATION ;
SetUpPacket[2] = LOBYTE(pGetConf->ConfigValue) ;
SetUpPacket[3] = HIBYTE(pGetConf->ConfigValue) ;
SetUpPacket[4] = 0x00 ;
SetUpPacket[5] = 0x00 ;
SetUpPacket[6] = 0x00 ;
SetUpPacket[7] = 0x00 ;
ntStatus = USBDIAG_SendPacket(actualdeviceObject,SetUpPacket, NULL, &siz, &ulUrbStatus) ;
if (NT_SUCCESS(ntStatus))
{
//USBDIAG_KdPrint(("USBDIAG.SYS: Successfully did Set Configuration to %02x\n", pGetConf->ConfigValue)) ;
}
else
{
//USBDIAG_KdPrint(("USBDIAG.SYS: Failed Set Configuration\n")) ;
}
// The Information field tells IOM how much to copy back into the
// usermode buffer in the BUFFERED method
// In this case all we want the IOM to copy back is the REQ itself
// so things like the status field get updated
Irp->IoStatus.Information = sizeof(struct _REQ_GETSET_CONFIGURATION);
Irp->IoStatus.Status = ntStatus;
// return the status
pGetConf->Hdr.Status = ntStatus;
//USBDIAG_KdPrint(("USBDIAG.SYS: Exiting Set Configuration\n")) ;
} // End of REQ_FUNCTION_SET_CONFIGURATION
break ;
case REQ_FUNCTION_GET_INTERFACE:
{
struct _REQ_GETSET_INTERFACE * pGetInt = (struct _REQ_GETSET_INTERFACE *)(ioBuffer) ;
UCHAR SetUpPacket[8] ;
ULONG cbBytesToGet;
char *IntValue = NULL ;
//USBDIAG_KdPrint(("USBDIAG.SYS: In Get Interfaces\n")) ;
cbBytesToGet = siz = 1 ;
IntValue = USBDIAG_ExAllocatePool(NonPagedPool, siz) ;
// Set up the setup packet for GET_INTERFACE
SetUpPacket[0] = (bmReqD2H | bmReqSTANDARD | bmReqINTERFACE) ;
SetUpPacket[1] = USB_REQUEST_GET_INTERFACE ;
SetUpPacket[2] = 0 ;
SetUpPacket[3] = 0 ;
SetUpPacket[4] = LOBYTE(pGetInt->Index) ;
SetUpPacket[5] = HIBYTE(pGetInt->Index) ;
SetUpPacket[6] = LOBYTE(cbBytesToGet) ;
SetUpPacket[7] = HIBYTE(cbBytesToGet) ;
ntStatus = USBDIAG_SendPacket(actualdeviceObject, (PCHAR)SetUpPacket, IntValue, &siz, &ulUrbStatus) ;
if (NT_SUCCESS(ntStatus))
{
//USBDIAG_KdPrint(("USBDIAG.SYS: Successfully did Get Interface (%d bytes txferred)\n", siz)) ;
//USBDIAG_KdPrint(("USBDIAG.SYS: Interface value = %02x\n", *IntValue )) ;
pGetInt->AltSetting = (USHORT)*IntValue ;
}
else
{
//USBDIAG_KdPrint(("USBDIAG.SYS: Failed Get Interface\n")) ;
}
// The Information field tells IOM how much to copy back into the
// usermode buffer in the BUFFERED method
// In this case all we want the IOM to copy back is the REQ itself
// so things like the status field get updated
Irp->IoStatus.Information = sizeof(struct _REQ_GETSET_INTERFACE);
Irp->IoStatus.Status = ntStatus;
// return the status
pGetInt->Hdr.Status = ntStatus;
USBDIAG_ExFreePool(IntValue) ;
//USBDIAG_KdPrint(("USBDIAG.SYS: Exiting Get Interfaces\n")) ;
} // End of REQ_FUNCTION_GET_INTERFACE
break ;
case REQ_FUNCTION_SET_INTERFACE:
{
struct _REQ_GETSET_INTERFACE * pGetInt = (struct _REQ_GETSET_INTERFACE *)(ioBuffer) ;
char SetUpPacket[8] ;
//USBDIAG_KdPrint(("USBDIAG.SYS: In Set Interfaces\n")) ;
siz = 0;
// Set up the setup packet for SET_INTERF
SetUpPacket[0] = (bmReqH2D | bmReqSTANDARD | bmReqINTERFACE) ;
SetUpPacket[1] = USB_REQUEST_SET_INTERFACE ;
SetUpPacket[2] = LOBYTE(pGetInt->AltSetting) ;
SetUpPacket[3] = HIBYTE(pGetInt->AltSetting) ;
SetUpPacket[4] = LOBYTE(pGetInt->Index) ;
SetUpPacket[5] = HIBYTE(pGetInt->Index) ;
SetUpPacket[6] = 0x00 ;
SetUpPacket[7] = 0x00 ;
//USBDIAG_KdPrint(("USBDIAG.SYS: SetupPacket: %X\n",SetUpPacket)) ;
ntStatus = USBDIAG_SendPacket(actualdeviceObject, SetUpPacket, NULL, &siz, &ulUrbStatus) ;
if (NT_SUCCESS(ntStatus))
{
//USBDIAG_KdPrint(("USBDIAG.SYS: Successfully did Set Interface\n")) ;
}
else
{
//USBDIAG_KdPrint(("USBDIAG.SYS: Failed Set Interface\n")) ;
}
// The Information field tells IOM how much to copy back into the
// usermode buffer in the BUFFERED method
// In this case all we want the IOM to copy back is the REQ itself
// so things like the status field get updated
Irp->IoStatus.Information = sizeof(struct _REQ_GETSET_INTERFACE);
Irp->IoStatus.Status = ntStatus;
// return the status
pGetInt->Hdr.Status = ntStatus;
//USBDIAG_KdPrint(("USBDIAG.SYS: Exiting Set Interfaces\n")) ;
} // End of REQ_FUNCTION_SET_INTERFACE
break ;
case REQ_FUNCTION_ORAW_PACKET:
{
struct _REQ_HEADER *REQHeader = (struct _REQ_HEADER *)ioBuffer;
struct _REQ_SEND_ORAWPACKET * pRawPkt = (struct _REQ_SEND_ORAWPACKET *)(Irp->UserBuffer) ;
char SetUpPacket[8] ;
char *buffer = NULL ;
UCHAR bmRT=0;
//USBDIAG_KdPrint(("USBDIAG.SYS: Entering Send Raw Packet\n")) ;
//USBDIAG_KdPrint(("USBDIAG.SYS: SystemBuffer: %X\t|UserBuffer: %X\n", ioBuffer, Irp->UserBuffer)) ;
if ( pRawPkt == NULL )
{
ntStatus = STATUS_INSUFFICIENT_RESOURCES ;
//USBDIAG_KdPrint(("USBDIAG.SYS: Called with NULL Raw Packet\n")) ;
break ;
}
bmRT = pRawPkt->bmRequestType; //save the bmReqType in case it gets stomped on (gets used later)
siz = pRawPkt->wLength ;
//USBDIAG_KdPrint(("USBDIAG.SYS: Raw Packet siz = %d\n",siz));
if ( siz )
{
buffer = USBDIAG_ExAllocatePool(NonPagedPool, siz) ;
if ( buffer == NULL )
{
ntStatus = STATUS_INSUFFICIENT_RESOURCES ;
break ;
}//if couldn't get buffer
}
//USBDIAG_KdPrint(("USBDIAG.SYS: Raw Packet bmRequestType = %x bRequest = %x\n",pRawPkt->bmRequestType, pRawPkt->bRequest )) ;
//USBDIAG_KdPrint(("USBDIAG.SYS: wValue = %x wIndex = %x Length = %x\n", pRawPkt->wValue, pRawPkt->wIndex, pRawPkt->wLength )) ;
//USBDIAG_KdPrint(("USBDIAG.SYS: SetupPacket base: %x\n",SetUpPacket));
SetUpPacket[0] = pRawPkt->bmRequestType ;
SetUpPacket[1] = pRawPkt->bRequest ;
SetUpPacket[2] = LOBYTE(pRawPkt->wValue) ;
SetUpPacket[3] = HIBYTE(pRawPkt->wValue) ;
SetUpPacket[4] = LOBYTE(pRawPkt->wIndex) ;
SetUpPacket[5] = HIBYTE(pRawPkt->wIndex) ;
SetUpPacket[6] = LOBYTE(pRawPkt->wLength) ;
SetUpPacket[7] = HIBYTE(pRawPkt->wLength) ;
ntStatus = USBDIAG_SendPacket(actualdeviceObject, SetUpPacket, buffer, &siz, &ulUrbStatus) ;
if (NT_SUCCESS(ntStatus))
{
//USBDIAG_KdPrint(("USBDIAG.SYS: Successful Procssed RAWPKT; copying %d bytes to %X\n",
// siz, pRawPkt->pvBuffer)) ;
// Only copy the data back to user's buffer if user's wLength indicates
// it and there are valid buffers from which to copy and the direction was
// Device to Host
if ( (siz>0) && //some bytes to copy
(buffer != NULL) && //source buffer valid
(pRawPkt->pvBuffer != NULL) && //dest buffer valid
(RAWPACKET_DIRECTION_IN(bmRT))) //dir was Dev2Host
{
// copy data to user mode buffer
memcpy(pRawPkt->pvBuffer, buffer,siz) ;
//Fill in the length in the REQ block so user-mode knows how much data is in buffer
pRawPkt->wLength = LOWORD(siz);
}//if ok to copy to user's buffer
}
else
{
//USBDIAG_KdPrint(("USBDIAG.SYS: Failed Processing RAW PKT : Status = %x\n", ntStatus)) ;
}
// The Information field tells IOM how much to copy back into the
// usermode buffer in the BUFFERED method
// In this case all we want the IOM to copy back is the REQ itself
// so things like the status field get updated
Irp->IoStatus.Information = sizeof(struct _REQ_HEADER);
Irp->IoStatus.Status = ntStatus;
// return the status
REQHeader->Status = ntStatus;
if (buffer != NULL)
{
USBDIAG_ExFreePool(buffer) ;
}// if buffer should be freed
//USBDIAG_KdPrint(("USBDIAG.SYS: Exiting Send Raw Packet\n")) ;
} // End switch REQ_FUNCTION_ORAW_PACKET
break;
case REQ_FUNCTION_READ_FROM_PIPE:
{
struct _REQ_READ_WRITE_PIPE * pREQ_RWPipe;
USBD_INTERFACE_INFORMATION * pInterfaceInfo;
USBD_PIPE_INFORMATION * pPipeInfo;
ULONG ulPipeNum;
PVOID pvBuffer;
//USBDIAG_KdPrint(("USBDIAG.SYS: enter READ\n"));
pREQ_RWPipe = (struct _REQ_READ_WRITE_PIPE *) (ioBuffer);
ulPipeNum = pREQ_RWPipe->Contxt.PipeNum;
ASSERT (deviceExtension != NULL);
pInterfaceInfo = deviceExtension->Interface[0];
ASSERT (pInterfaceInfo != NULL);
ASSERT (pREQ_RWPipe != NULL);
ASSERT (ulPipeNum <= (pInterfaceInfo->NumberOfPipes));
pPipeInfo = &(deviceExtension->Interface[0]->Pipes[ulPipeNum]);
ASSERT (pPipeInfo != NULL);
ASSERT ((pPipeInfo->PipeHandle) != NULL);
siz = sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER);
// allocate urb
urb = USBDIAG_ExAllocatePool(NonPagedPool, siz);
// allocate data buffer
pvBuffer = USBDIAG_ExAllocatePool (NonPagedPool, pREQ_RWPipe->ulLength);
// set up urb
UsbBuildInterruptOrBulkTransferRequest(urb, //ptr to urb
(USHORT) siz, //siz of urb
pPipeInfo->PipeHandle, //usbd pipe handle
pvBuffer, //transferbuffer
NULL, //mdl
pREQ_RWPipe->ulLength, //bufferlength
USBD_SHORT_TRANSFER_OK, //flags
NULL); //link
// NOTE: We don't request a TIMEOUT in this call to Ch9CallUSBD
ntStatus = USBDIAG_Ch9CallUSBD(actualdeviceObject, urb, TRUE, NULL, NULL, FALSE);
// The Information field tells IOM how much to copy back into the
// usermode buffer in the BUFFERED method
// In this case all we want the IOM to copy back is the REQ itself
// so things like the status field get updated
Irp->IoStatus.Information = sizeof(struct _REQ_READ_WRITE_PIPE);
Irp->IoStatus.Status = ntStatus;
pREQ_RWPipe->Hdr.Status = ntStatus;
if (!NT_SUCCESS(ntStatus))
{
USBDIAG_KdPrint(("'Read pipe failed!\n ntStatus = 0x%x\n urbStatus = 0x%x\n",
ntStatus,
urb->UrbHeader.Status));
}
// The REQ coming from user mode gets its length field trampled on w/ the actual
// length of this transfer, so user mode app should look there and not in
// the nBytes field of the DeviceIoControl call.
pREQ_RWPipe->ulLength = urb->UrbBulkOrInterruptTransfer.TransferBufferLength;
ulUrbStatus = urb->UrbHeader.Status; //capture the Urb status for later
// Copy the data back to user mode buffer if successful transfer
if (ulUrbStatus == USBD_STATUS_SUCCESS)
{
//USBDIAG_KdPrint(("USBDIAG.SYS: Successful Read; Copying %d bytes to UserMode Buf (%X)",
//pREQ_RWPipe->ulLength,
//pREQ_RWPipe->pvBuffer));
if (pREQ_RWPipe->pvBuffer)
{
memcpy ( (pREQ_RWPipe->pvBuffer) , pvBuffer, (pREQ_RWPipe->ulLength) );
} // if pvBuffer is non NULL
}//if status is SUCCESS
// free allocated urb
USBDIAG_ExFreePool(urb);
// free our non paged pool data buffer
USBDIAG_ExFreePool (pvBuffer);
//USBDIAG_KdPrint(("USBDIAG.SYS: exit READ\n"));
break;
}//REQ_FUNCTION_READ_FROM_PIPE
break; //REQ_FUNCTION_READ_FROM_PIPE
case REQ_FUNCTION_WRITE_TO_PIPE:
{
struct _REQ_READ_WRITE_PIPE * pREQ_RWPipe;
USBD_INTERFACE_INFORMATION * pInterfaceInfo;
USBD_PIPE_INFORMATION * pPipeInfo;
ULONG ulPipeNum;
PVOID pvBuffer;
//USBDIAG_KdPrint(("USBDIAG.SYS: enter WRITE \n"));
pREQ_RWPipe = (struct _REQ_READ_WRITE_PIPE *) (ioBuffer);
ulPipeNum = pREQ_RWPipe->Contxt.PipeNum;
ASSERT (deviceExtension != NULL);
pInterfaceInfo = deviceExtension->Interface[0];
ASSERT (pInterfaceInfo != NULL);
ASSERT (pREQ_RWPipe != NULL);
ASSERT (ulPipeNum <= (pInterfaceInfo->NumberOfPipes));
pPipeInfo = &(deviceExtension->Interface[0]->Pipes[ulPipeNum]);
ASSERT (pPipeInfo != NULL);
ASSERT ((pPipeInfo->PipeHandle) != NULL);
siz = sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER);
// allocate urb
urb = USBDIAG_ExAllocatePool(NonPagedPool, siz);
// allocate data buffer
pvBuffer = USBDIAG_ExAllocatePool (NonPagedPool, pREQ_RWPipe->ulLength);
// COPY the data to write out into the nonpaged pool buffer
RtlCopyMemory(pvBuffer, pREQ_RWPipe->pvBuffer, pREQ_RWPipe->ulLength);
// set up urb
UsbBuildInterruptOrBulkTransferRequest(urb, //ptr to urb
(USHORT) siz, //siz of urb
pPipeInfo->PipeHandle, //usbd pipe handle
pvBuffer, //transferbuffer
NULL, //mdl
pREQ_RWPipe->ulLength, //bufferlength
USBD_SHORT_TRANSFER_OK, //flags
NULL); //link
// NOTE: We don't request a TIMEOUT in this call to Ch9CallUSBD
ntStatus = USBDIAG_Ch9CallUSBD(actualdeviceObject, urb, TRUE, NULL, NULL, FALSE);
// The Information field tells IOM how much to copy back into the
// usermode buffer in the BUFFERED method
// In this case all we want the IOM to copy back is the REQ itself
// so things like the status field get updated
Irp->IoStatus.Information = sizeof(struct _REQ_HEADER);
Irp->IoStatus.Status = ntStatus;
// The REQ coming from user mode gets its length field trampled on w/ the actual
// length of this transfer, so user mode app should look there and not in
// the nBytes field of the DeviceIoControl call.
pREQ_RWPipe->ulLength = urb->UrbBulkOrInterruptTransfer.TransferBufferLength;
ulUrbStatus = urb->UrbHeader.Status; //capture the Urb status for later
// Copy the data back to user mode buffer if successful transfer
if (ulUrbStatus == USBD_STATUS_SUCCESS)
{
//USBDIAG_KdPrint(("USBDIAG.SYS: Successful Write; %d bytes Transferred",
//pREQ_RWPipe->ulLength));
}//if status is SUCCESS
// free allocated urb
USBDIAG_ExFreePool(urb);
// free our non paged pool data buffer
USBDIAG_ExFreePool (pvBuffer);
//USBDIAG_KdPrint(("USBDIAG.SYS: exit WRITE \n"));
// The Information field tells IOM how much to copy back into the
// usermode buffer in the BUFFERED method
// In this case all we want the IOM to copy back is the REQ itself
// so things like the status field get updated
Irp->IoStatus.Information = sizeof(struct _REQ_READ_WRITE_PIPE);
Irp->IoStatus.Status = ntStatus;
}
break; //REQ_FUNCTION_WRITE_TO_PIPE
case REQ_FUNCTION_CANCEL_TRANSFERS:
{
// Input: a device on which any outstanding Irps should be cancelled
// We get the Irp ptr from the device extension. For now, we
// only support one outstanding Irp on an entire device, even
// if that Irp is on one of the device's pipes. This is a limitation
// that can be lifted if we keep a track of more Irps on the device.
NTSTATUS ntStatus = USBDIAG_CancelAllIrps(deviceExtension);
BOOLEAN status = (BOOLEAN)NT_SUCCESS(ntStatus);
ASSERT (deviceExtension != NULL);
if (deviceExtension != NULL)
{
Ch9FillInReqStatus (status, status, REQHeader);
Irp->IoStatus.Information = sizeof(struct _REQ_HEADER);
Irp->IoStatus.Status = ntStatus;
}// if valid physdevice extension
}//REQ_FUNCTION_CANCEL_TRANSFERS
break;
case REQ_FUNCTION_SET_DEVICE_POWER_STATE:
{
/*******
Suspends/resumes device under test
Input: Device Handle
Output: Nothing yet
********/
PDEVICE_OBJECT stackDeviceObject;
POWER_STATE powerState;
struct _REQ_GET_SET_DEVICE_POWER_STATE * pSetDevicePowerState = (struct _REQ_GET_SET_DEVICE_POWER_STATE *)ioBuffer;
stackDeviceObject = deviceExtension->StackDeviceObject;
// Set device to suspend
powerState.DeviceState = pSetDevicePowerState->DevicePowerState;
// cancel the pending irp if applicable
if (powerState.DeviceState != PowerDeviceD0)
{
//USBDIAG_KdPrint(("Powering down - InterruptIrp = 0x%x\n", deviceExtension->InterruptIrp));
if (deviceExtension->InterruptIrp)
{
if (IoCancelIrp(deviceExtension->InterruptIrp))
{
USBDIAG_KdPrint(("'Powering down, so all pending interrupt irp cancelled\n"));
}
else
{
USBDIAG_KdPrint(("'Powering down, pending interrupt irp cancelled FAILED\n"));
}
deviceExtension->InterruptIrp = NULL;
}
}
ntStatus = USBDIAG_SetDevicePowerState(actualdeviceObject,
powerState.DeviceState);
if (NT_SUCCESS(ntStatus))
{
//USBDIAG_KdPrint(("'USBDIAG.SYS: Set device power state 0x%x passed\n", powerState.DeviceState));
}
else
{
USBDIAG_KdPrint(("'USBDIAG.SYS: Set device power state 0x%x FAILED (0x%x)\n", powerState.DeviceState, ntStatus));
}
} //REQ_FUNCTION_CHAP11_SUSPEND_HUT
break;
case REQ_FUNCTION_GET_DEVICE_STATE:
{
struct _REQ_GET_SET_DEVICE_POWER_STATE * pREQ_GetDevPowerState = (struct _REQ_GET_SET_DEVICE_POWER_STATE *)(ioBuffer);
USBDIAG_KdPrint(("'USBDIAG.SYS: REQ_GET_DEV_POWER_STATE\n"));
pREQ_GetDevPowerState->DevicePowerState = (ULONG)deviceExtension->CurrentDeviceState.DeviceState;
ntStatus = STATUS_SUCCESS;
Irp->IoStatus.Information = sizeof(struct _REQ_GET_SET_DEVICE_POWER_STATE);
Irp->IoStatus.Status = ntStatus;
}
break;
case REQ_FUNCTION_ISSUE_WAIT_WAKE:
USBDIAG_KdPrint(("'USBDIAG.SYS: REQ_FUNCTION_ISSUE_WAIT_WAKE\n"));
if (deviceExtension->WaitWakeIrp)
{
return STATUS_DEVICE_BUSY;
}
else
{
USBDIAG_KdPrint(("'Generating IRP_MN_WAIT_WAKE Power Irp\n"));
// Generate and save the power irp
ntStatus = USBDIAG_IssueWaitWake(actualdeviceObject);
if (ntStatus == STATUS_PENDING)
{
Irp->IoStatus.Status = ntStatus = STATUS_SUCCESS;
Irp->IoStatus.Information = 0;
}
}
break;
case REQ_FUNCTION_WAIT_FOR_WAKEUP:
{
NTSTATUS ntStatus = USBDIAG_WaitForWakeup(deviceExtension);
Irp->IoStatus.Status = ntStatus;
Irp->IoStatus.Information = 0;
}
break;
case REQ_FUNCTION_CANCEL_WAIT_WAKE:
{
ntStatus = STATUS_UNSUCCESSFUL;
if (deviceExtension->WaitWakeIrp)
{
BOOLEAN bCancelSuccess = IoCancelIrp(deviceExtension->WaitWakeIrp);
if (bCancelSuccess)
{
ntStatus = STATUS_SUCCESS;
}
}
Irp->IoStatus.Status = ntStatus;
Irp->IoStatus.Information = 0;
}
break;
case REQ_FUNCTION_CHAP11_CREATE_USBD_DEVICE:
/*******
Creates handle to device attatched to hub
Input:
Output: Device handle, and device descriptor
********/
{
ntStatus = USBDIAG_CreateInitDownstreamDevice((PREQ_ENUMERATE_DOWNSTREAM_DEVICE)ioBuffer,
deviceExtension);
ASSERT(NT_SUCCESS(ntStatus));
Irp->IoStatus.Status = ntStatus;
Irp->IoStatus.Information = sizeof(struct _REQ_ENUMERATE_DOWNSTREAM_DEVICE);;
}
break;
case REQ_FUNCTION_CHAP11_INIT_USBD_DEVICE:
/*******
Initialize device attached to hub.
Input: Device Handle
Output: Nothing yet
********/
if (gVersionInformation.USBDI_Version >= USBD_WIN98_SE_VERSION) // Win98 SE / Win2K & beyond
{
ntStatus = USBDIAG_SetCfgEnableRWu(deviceExtension, (PREQ_ENUMERATE_DOWNSTREAM_DEVICE)ioBuffer);
Irp->IoStatus.Status = ntStatus;
Irp->IoStatus.Information = sizeof(struct _REQ_ENUMERATE_DOWNSTREAM_DEVICE);
}
else
ntStatus = STATUS_NOT_IMPLEMENTED;
break;
case REQ_FUNCTION_CHAP11_DESTROY_USBD_DEVICE:
/*******
Destroys device handle to device attached to hub.
Input: Device Handle
Output: Nothing yet
********/
if (gVersionInformation.USBDI_Version >= USBD_WIN98_SE_VERSION) // Win98 SE / Win2K & beyond
{
PREQ_ENUMERATE_DOWNSTREAM_DEVICE pEnumerate = (PREQ_ENUMERATE_DOWNSTREAM_DEVICE)ioBuffer;
UCHAR ucPortNumber = pEnumerate->ucPortNumber;
UCHAR flags = 0;
USBDIAG_KdPrint(("*************************************************\n"));
USBDIAG_KdPrint(("USBDIAG.SYS: REQ_FUNCTION_DESTROY_USBD_DEVICE\n"));
USBDIAG_KdPrint(("Port: %d\n", ucPortNumber));
if (deviceExtension->DeviceData[ucPortNumber] != NULL)
{
ntStatus = USBD_RemoveDevice(deviceExtension->DeviceData[ucPortNumber],
deviceExtension->RootHubPdo,
flags);
}
else
{
ntStatus = STATUS_SUCCESS;
}
if (NT_SUCCESS(ntStatus))
{
deviceExtension->DeviceData[ucPortNumber] = NULL;
Irp->IoStatus.Status = ntStatus;
Irp->IoStatus.Information = sizeof(struct _REQ_ENUMERATE_DOWNSTREAM_DEVICE);;
}
}
else
ntStatus = STATUS_NOT_IMPLEMENTED;
break;
case REQ_FUNCTION_CHAP11_SEND_PACKET_DOWNSTREAM:
{
PREQ_SEND_PACKET_DOWNSTREAM pReqSendPacket = (PREQ_SEND_PACKET_DOWNSTREAM)ioBuffer;
UCHAR ucPortNumber = (UCHAR)pReqSendPacket->usPortNumber;
PUSBD_DEVICE_DATA DeviceData = deviceExtension->DeviceData[ucPortNumber];
//PDEVICE_OBJECT StackDeviceObject =deviceExtension->StackDeviceObject;
USBDIAG_KdPrint(("*************************************************\n"));
USBDIAG_KdPrint(("USBDIAG.SYS: REQ_FUNCTION_CHAP11_SEND_PACKET_DOWNSTREAM\n"));
//USBDIAG_KdPrint(("DeviceData: 0x%x\n", DeviceData));
//USBDIAG_KdPrint(("DeviceObject: 0x%x\n", StackDeviceObject));
USBDIAG_KdPrint(("PortNumber: %d\n", ucPortNumber));
//USBDIAG_KdPrint(("DeviceData: 0x%x\n", deviceExtension->DeviceData[ucPortNumber]));
//USBDIAG_KdPrint(("bLowSpeed: 0x%x\n", pReqSendPacket->bLowSpeed));
//USBDIAG_KdPrint(("pucBuffer: 0x%x\n", pReqSendPacket->pucBuffer));
USBDIAG_KdPrint(("SetupPacket:\n"));
USBDIAG_KdPrint((" wRequest: 0x%04x\n", pReqSendPacket->SetupPacket.wRequest));
USBDIAG_KdPrint((" wValue: 0x%04x\n", pReqSendPacket->SetupPacket.wValue));
USBDIAG_KdPrint((" wIndex: 0x%04x\n", pReqSendPacket->SetupPacket.wIndex));
USBDIAG_KdPrint((" wLength: 0x%04x\n", pReqSendPacket->SetupPacket.wLength));
if (deviceExtension->DeviceData[ucPortNumber] != NULL)
{
ntStatus = USBDIAG_Chap11SendPacketDownstream(DeviceData,
deviceExtension->RootHubPdo,
pReqSendPacket);
if (NT_SUCCESS(ntStatus))
{
Irp->IoStatus.Status = ntStatus;
Irp->IoStatus.Information = sizeof(struct _REQ_SEND_PACKET_DOWNSTREAM);
}
}
else
{
ntStatus = STATUS_INVALID_PARAMETER;
}
ASSERT(NT_SUCCESS(ntStatus));
break;
}
case REQ_FUNCTION_CHAP11_GET_DOWNSTREAM_DESCRIPTOR:
{
PREQ_GET_DOWNSTREAM_DESCRIPTOR pGetDownstreamDescriptor = (PREQ_GET_DOWNSTREAM_DESCRIPTOR)ioBuffer;
USHORT usPortNumber = pGetDownstreamDescriptor->usPortNumber;
PUSBD_DEVICE_DATA DeviceData = deviceExtension->DeviceData[usPortNumber];
USHORT usDescType = pGetDownstreamDescriptor->DescriptorType;
Irp->IoStatus.Information = sizeof(struct _REQ_GET_DOWNSTREAM_DESCRIPTOR);
USBDIAG_KdPrint(("'REQ_FUNCTION_CHAP11_GET_DOWNSTREAM_DESCRIPTOR:\n"));
USBDIAG_KdPrint(("'PortNumber %d\n", usPortNumber));
USBDIAG_KdPrint(("'DeviceData 0x%x\n", DeviceData));
USBDIAG_KdPrint(("'usDescType %d\n", usDescType));
USBDIAG_KdPrint(("'pGetDownstreamDescriptor->TransferBufferLength %d\n", pGetDownstreamDescriptor->TransferBufferLength));
USBDIAG_KdPrint(("'sizeof(USB_DEVICE_DESCRIPTOR) %d\n", sizeof(USB_DEVICE_DESCRIPTOR)));
if (!DeviceData) goto BAD_REQ_CHAP11_GET_DOWNSTREAM_DESCRIPTOR;
switch (usDescType)
{
case USB_DEVICE_DESCRIPTOR_TYPE:
if (pGetDownstreamDescriptor->TransferBufferLength < sizeof(USB_DEVICE_DESCRIPTOR))
goto BAD_REQ_CHAP11_GET_DOWNSTREAM_DESCRIPTOR;
RtlCopyMemory(pGetDownstreamDescriptor->TransferBuffer,
&DeviceData->DeviceDescriptor,
sizeof(USB_DEVICE_DESCRIPTOR));
ntStatus = STATUS_SUCCESS;
break;
case USB_CONFIGURATION_DESCRIPTOR_TYPE:
if (pGetDownstreamDescriptor->TransferBufferLength < sizeof(USB_CONFIGURATION_DESCRIPTOR) ||
deviceExtension->DownstreamConfigDescriptor[usPortNumber] == NULL)
goto BAD_REQ_CHAP11_GET_DOWNSTREAM_DESCRIPTOR;
RtlCopyMemory(pGetDownstreamDescriptor->TransferBuffer,
deviceExtension->DownstreamConfigDescriptor[usPortNumber],
sizeof(USB_CONFIGURATION_DESCRIPTOR));
ntStatus = STATUS_SUCCESS;
break;
default: // currently all others are unsupported
goto BAD_REQ_CHAP11_GET_DOWNSTREAM_DESCRIPTOR;
}
break;
BAD_REQ_CHAP11_GET_DOWNSTREAM_DESCRIPTOR:
ntStatus = STATUS_INVALID_PARAMETER;
break;
}
break;
case REQ_FUNCTION_DISABLE_ENABLING_REMOTE_WAKEUP:
case REQ_FUNCTION_ENABLE_ENABLING_REMOTE_WAKEUP:
{
BOOLEAN bDisable = (BOOLEAN)(REQHeader->Function == REQ_FUNCTION_DISABLE_ENABLING_REMOTE_WAKEUP ? TRUE : FALSE);
ntStatus = USBDIAG_DisableRemoteWakeupEnable(actualdeviceObject, bDisable);
}
break;
default:
Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
}
Ch9FillInReqStatus (ntStatus, ulUrbStatus, REQHeader);
if (bCompleteIrp)
{
IoCompleteRequest(Irp, IO_NO_INCREMENT);
}
//USBDIAG_KdPrint(("USBDIAG.SYS: Chap9Ctrl returning w/ ntStatus: %#X REQStatus: %#X\n",
//ntStatus,
//REQHeader->Status));
return ntStatus;
} //USBDIAG_Chap9Control
NTSTATUS
USBDIAG_Ch9CallUSBD(
IN PDEVICE_OBJECT DeviceObject,
IN PURB Urb,
IN BOOLEAN fBlock, // currently ignored
PIO_COMPLETION_ROUTINE CompletionRoutine, // just passed to generic completion routine
PVOID pvContext, // just passed to generic completion routine
BOOLEAN fWantTimeOut // currently ignored
)
/**************************************************************************
Routine Description:
Passes a URB to the USBD class driver
NOTE: Creates an IRP to do this. Doesn't use the IRP that is passed down from user
mode app (it's not passed to this routine at all).
Arguments:
DeviceObject - pointer to the device object for this instance of a UTB
Urb - pointer to Urb request block
fBlock - bool indicating if this fn should wait for IRP to return from USBD
CompletionRoutine - fn to set as the completionroutine for this transfer ONLY IF
the fBlock is set to FALSE, indicating that the caller wants
to handle completion on their own and this fn should not
block
pvContext - Context to be set in setting up the completion routine for the
Irp created in this function. This is passed in by caller and is
just a pass-thru to the IoSetCompletionRoutine call.
fWantTimeOut - If caller wants this function to use a deadman timeout and cancel
the Irp after the timeout expires. TRUE means this function will
use the timeout mechanism, and FALSE means this function will block
indefinitely and wait for the Irp/Urb to return from the USB stack.
Return Value:
STATUS_SUCCESS if successful,
STATUS_UNSUCCESSFUL otherwise
**************************************************************************/
{
NTSTATUS ntStatus;
PDEVICE_EXTENSION deviceExtension;
PIRP irp;
IO_STATUS_BLOCK ioStatus;
PIO_STACK_LOCATION nextStack;
PCOMPLETION_CONTEXT pGenericContext;
USBDIAG_KdPrint(("USBDIAG.SYS: enter USBDIAG_Ch9CallUSBD\n"));
{
KIRQL irql;
irql = KeGetCurrentIrql();
ASSERT(irql <= PASSIVE_LEVEL);
}
pGenericContext = ExAllocatePool(NonPagedPool, sizeof(COMPLETION_CONTEXT));
if (!pGenericContext)
return STATUS_INSUFFICIENT_RESOURCES;
deviceExtension = DeviceObject->DeviceExtension;
ASSERT (deviceExtension != NULL);
ASSERT ((deviceExtension->StackDeviceObject) != NULL);
if ((deviceExtension) && (deviceExtension->StackDeviceObject))
{
// issue a synchronous request to read the USB Device Ctrl pipe
KeInitializeEvent(&pGenericContext->DoneEvent, NotificationEvent, FALSE);
// Create the IRP that we'll use to submit this URB to the USB stack
irp = IoBuildDeviceIoControlRequest(
IOCTL_INTERNAL_USB_SUBMIT_URB,
deviceExtension->StackDeviceObject,
NULL,
0,
NULL,
0,
TRUE, /* INTERNAL */
//&event,
&pGenericContext->DoneEvent,
&ioStatus); //the status codes in NT IRPs go here
pGenericContext->DeviceObject = DeviceObject;
pGenericContext->Irp = irp;
pGenericContext->CompletionRoutine = CompletionRoutine;
pGenericContext->Context = pvContext;
//NOTE: The status returned by USBD in the URB is more USB transfer-specific (e.g.,
// it indicates things like USB stall conditions, etc.). The USBD status
// is contained in the URB's status field. However, USBD maps those URB error
// codes to more generic NT_STATUS_XXX error codes when the IRP returns. To
// get a more detailed and USB-specific reading of the error code, look at
// the URB's status field.
// Call the class driver to perform the operation. If the returned status
// is PENDING, wait for the request to complete.
nextStack = IoGetNextIrpStackLocation(irp);
ASSERT(nextStack != NULL);
// save a pointer to the Irp for our cancel routine
ntStatus = USBDIAG_SaveIrp(deviceExtension, irp);
USBDIAG_KdPrint (("USBDIAG.SYS: Urb header function 0x%x (0x%x)\n",
Urb->UrbHeader.Function,
URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER));
if (Urb->UrbHeader.Function == URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER)
{
USBDIAG_KdPrint(("Saving interrupt irp\n"));
ASSERT(deviceExtension->InterruptIrp == NULL);
deviceExtension->InterruptIrp = irp;
}
if (!NT_SUCCESS(ntStatus))
{
ExFreePool(pGenericContext);
return ntStatus;
}
// pass the URB to the USBD 'class driver'
nextStack->Parameters.Others.Argument1 = Urb;
// set the generic routine
IoSetCompletionRoutine(irp,
USBDIAG_IoGenericCompletionRoutine,
pGenericContext,
TRUE, //InvokeOnSuccess
TRUE, //InvokeOnError,
TRUE); //InvokeOnCancel
USBDIAG_KdPrint (("USBDIAG.SYS: calling USBD\n"));
ntStatus = IoCallDriver(deviceExtension->StackDeviceObject, irp);
USBDIAG_KdPrint (("USBDIAG.SYS: return from IoCallDriver USBD in USBDIAG_Ch9CallUSBD %x\n", ntStatus));
if (ntStatus == STATUS_PENDING)
{
USBDIAG_KdPrint(("USBDIAG.SYS: Waiting for done signal\n"));
KeWaitForSingleObject(&pGenericContext->DoneEvent,
Suspended,
KernelMode,
FALSE,
NULL);
ntStatus = Urb->UrbHeader.Status;
}
USBDIAG_KdPrint (("USBDIAG.SYS: Urb status = %x Irp status %x\n",
Urb->UrbHeader.Status,
irp->IoStatus.Status));
ioStatus.Status = ntStatus;
//ioStatus.Information = 0;
//USBD maps the error code for us
USBDIAG_KdPrint(("USBDIAG.SYS: URB TransferBufferLength OUT is: %d\n",Urb->UrbControlDescriptorRequest.TransferBufferLength));
}//if valid deviceExtension and StackDevObjects
else
{
// Invalid extension or stackdevobj received
ntStatus = STATUS_INVALID_PARAMETER;
USBDIAG_KdPrint(("USBDIAG.SYS: Invalid deviceExtension or StackDeviceObject\n"));
} //else invalid devExt or stackdevobj
USBDIAG_KdPrint(("USBDIAG.SYS: exiting USBDIAG_Ch9CallUSBD w/ URB/ntStatus: %x\n", ntStatus));
ExFreePool(pGenericContext);
return ntStatus;
}//USBDIAG_Ch9CallUSBD
NTSTATUS
USBDIAG_SendPacket(
IN PDEVICE_OBJECT DeviceObject,
IN CHAR SetUpPacket[],
PVOID TxBuffer,
ULONG * TxBufferLen, //see comments below!
ULONG * pulUrbStatus
)
/*++
Routine Description:
Arguments:
DeviceObject - pointer to the device object for this instance of the TESTDRV
devcice.
SetupPacket - formatted by caller to contain exactly the 8 bytes setup pkt
TxBuffer - if a data stage occurs, this is where data originates or ends up
TxBufferLen - incoming it's a ptr to the len of the TxBuffer
- outgoing we shove the actual len of the data in the buffer for INPUT bus transfers
pulUrbStatus - Urb status is put here for more visibility into what happened on USB
Return Value:
NT status code
--*/
{
PDEVICE_EXTENSION deviceExtension;
NTSTATUS ntStatus;
PURB urb;
// PUSB_CONFIGURATION_DESCRIPTOR configurationDescriptor = NULL;
int i = 0 ;
//USBDIAG_KdPrint(("USBDIAG.SYS: enter USBDIAG_SendPacket\n"));
deviceExtension = DeviceObject->DeviceExtension;
urb = USBDIAG_ExAllocatePool(NonPagedPool,
sizeof(struct _URB_CONTROL_TRANSFER));
// need to zero out this buffer, kludge to fix a language ID problem
RtlZeroMemory(urb, sizeof(struct _URB_CONTROL_TRANSFER));
if (urb)
{
(urb)->UrbHeader.Function = URB_FUNCTION_CONTROL_TRANSFER;
(urb)->UrbHeader.Length = sizeof(struct _URB_CONTROL_TRANSFER);
(urb)->UrbControlTransfer.PipeHandle = 0; // this will cause us to use the default pipe
//USBDIAG_KdPrint(("USBDIAG.SYS: TxBufferLen=%d | TxBuffer = %x\n",*TxBufferLen, TxBuffer));
(urb)->UrbControlTransfer.TransferBufferLength = *TxBufferLen ;
(urb)->UrbControlTransfer.TransferBufferMDL = NULL ;
(urb)->UrbControlTransfer.TransferBuffer = TxBuffer ;
(urb)->UrbControlTransfer.UrbLink = NULL;
(urb)->UrbControlTransfer.TransferFlags = ( (SetUpPacket[0] & bmReqD2H) ? (USBD_TRANSFER_DIRECTION_IN | USBD_SHORT_TRANSFER_OK) : 0 ) ;
//USBDIAG_KdPrint(("USBDIAG.SYS: Tx direction %x\n", (urb)->UrbControlTransfer.TransferFlags)) ;
(urb)->UrbControlTransfer.UrbLink = NULL;
for ( i = 0 ; i < SETUP_PACKET_LEN ; i ++ )
{
(urb)->UrbControlTransfer.SetupPacket[i] = SetUpPacket[i] ; // 0x01;
}
//don't need to do this. stack will yank it out of the PDO and use
//the right usbdhandle for this txfer
// urb->UrbHeader.UsbdDeviceHandle = UsbdHandle ;
ntStatus = USBDIAG_Ch9CallUSBD(DeviceObject, urb, TRUE, NULL, NULL, TRUE);
// Set the caller's urb status
if (pulUrbStatus)
*pulUrbStatus = urb->UrbHeader.Status;
//USBDIAG_KdPrint(("USBDIAG.SYS: SendPacket: UrbStatus = 0x%x\n",urb->UrbHeader.Status));
if (NT_SUCCESS(ntStatus) && (TxBufferLen != NULL))
{
// Tell caller how much data was transferred (mostly valid on INs)
// Don't know how interesting this is on OUTs but it's set anyway
//
*TxBufferLen = urb->UrbControlDescriptorRequest.TransferBufferLength;
//USBDIAG_KdPrint(("USBDIAG.SYS: USBDIAG_SendPacket-TransferBufferLength: %d\n",
//*TxBufferLen));
}//if
USBDIAG_ExFreePool(urb);
//USBDIAG_KdPrint(("USBDIAG.SYS: Inside the if before the else STATUS_INSUFFICIENT_RESOURCES\n"));
}
else
{
//USBDIAG_KdPrint(("USBDIAG.SYS: Inside the else STATUS_INSUFFICIENT_RESOURCES"));
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
}
//USBDIAG_KdPrint(("USBDIAG.SYS: exit USBDIAG_SendPacket (%x)\n",ntStatus));
return ntStatus;
} /* End of USBDIAG_SendPacket() */
PBYTE
pAllocFromBuffer(
PBYTE pBuffer,
ULONG iSize,
PULONG piOffset,
PULONG piTotalUsed,
ULONG iRequested
)
/*
This function is used to sub-allocate memory from the buffer managed
by the ioctl call. This allows complex structures to be build in a
single contigious buffer, which can be returned to ring 3. (The
routine is necessary because DeviceIoControl only provides for the
movement of one buffer from ring 3 to ring 0 and back
*/
{
PVOID pReturn;
//
// CROBINS: This was buggy...Changed *piOffset+iRequested to
// *piTtoalUsed+iRequested
if (*piTotalUsed + iRequested > iSize)
{
pReturn=NULL;
}
else
{
pReturn = pBuffer + *piTotalUsed;
*piOffset = *piTotalUsed;
(*piTotalUsed)+=iRequested;
}
return pReturn;
}
NTSTATUS
USBDIAG_HIDP_GetCollection(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
/*++
History:
This routine was added for support of the HID Test application's parsing
capabilities.
Kosar Jaff 8-14-96 (Intel Corp.)
Routine Description:
Calls the Hid Parser driver with a raw report descriptor
(see HidP_GetCollectionDescription in hidpddi.h for behavior)
This function assumes that the caller will use an IOCTL with the
METHOD_BUFFERED specified. The function will place the result of
the parse in the SystemBuffer and expect IOS to copy the result to the
user's OutputBuffer specified in the DeviceIoControl call made in UserMode.
The incoming buffer will be used as it appears in the SystemBuffer (locked by
IOS on the way down) even though since this function is in the calling thread's
context, we could have used UserBuffer directly.
Note: This function will put the
Arguments:
DeviceObject - ptr to this driver's "Device" object
Irp - incoming IRP from user mode ioctl
Return Value:
NT status code
--*/
{
PIO_STACK_LOCATION irpStack;
HIDP_DEVICE_DESC rCollectionsAndIDs;
PVOID ioBuffer;
ULONG inputBufferLength;
ULONG outputBufferLength;
NTSTATUS ntStatus;
PHIDP_COLLECTION_DESC pHidPCollDesc = NULL;
//PHIDP_COLLECTION_DESC pTempCollDesc = NULL;
PCHAR pCollBlock;
ULONG ulBytInBuff;
ULONG nCollectionDescElem = 0;
ULONG i;
//ULONG ulTotBytesCopied =0;
BOOL bFailed = FALSE;
ULONG iOffset=0;
ULONG iTotalUsed=0;
PBYTE pSubBuffer;
PHIDP_DEVICE_DESC pDeviceDesc;
PHIDP_COLLECTION_DESC pCollectionDesc;
// Get a pointer to the current location in the Irp. This is where
// the function codes and parameters are located.
irpStack = IoGetCurrentIrpStackLocation (Irp);
//USBDIAG_KdPrint(("USBDIAG.SYS: irpStk->Prm.DvIoC.InptLn: %x | OutptLen: %x | UsrBuff: %x\n",
//irpStack->Parameters.DeviceIoControl.InputBufferLength,
//irpStack->Parameters.DeviceIoControl.OutputBufferLength,
//Irp->UserBuffer));
// Get the pointer to the input/output buffer and it's length
// the SystemBuffer contains the raw descriptor that is to be parsed
ioBuffer = Irp->AssociatedIrp.SystemBuffer;
inputBufferLength = irpStack->Parameters.DeviceIoControl.InputBufferLength;
outputBufferLength = irpStack->Parameters.DeviceIoControl.OutputBufferLength;
//USBDIAG_KdPrint(("USBDIAG.SYS: RepDesc (ioBuffer): %X | RepDesc Len: %d\n",
//ioBuffer,
//inputBufferLength));
//call the parser function in HIDPARSE library
/* ntStatus =
HidP_GetCollectionDescription (ioBuffer,
inputBufferLength,
NonPagedPool,
&pHidPCollDesc,
&nCollectionDescElem);
This is being changed to match a change to hidparse. JobyL
*/
rCollectionsAndIDs.CollectionDesc=NULL;
rCollectionsAndIDs.CollectionDescLength=0;
//USBDIAG_KdPrint(("USBDIAG.SYS: Before the call to HidP_GetCollectionDescription\n"));
ntStatus=HidP_GetCollectionDescription (ioBuffer,
inputBufferLength,
NonPagedPool,
&rCollectionsAndIDs);
//USBDIAG_KdPrint(("USBDIAG.SYS: After the call to HidP_GetCollectionDescription\n"));
pHidPCollDesc=rCollectionsAndIDs.CollectionDesc;
nCollectionDescElem=rCollectionsAndIDs.CollectionDescLength;
//USBDIAG_KdPrint(("USBDIAG.SYS: HidCollDesc: %X | NbrCollElem: %d\n",
//pHidPCollDesc,
//nCollectionDescElem));
if ( (nCollectionDescElem) && NT_SUCCESS(ntStatus) ) {
/*
// We put the collection descriptor into the "systembuffer" so that
// IOS can copy from there to the user buffer when we complete the IRP.
// Note the collection descriptors go in the buffer first, and then if
// there is room left, the PreParsedData is appended to the end.
//
// Since the pointers in the structures passed back from HIDPARSE are all
// Ke-Mode pointers, they won't be valid in User Mode, so we convert all
// those to relative pointers (offsets) and then let User Mode code re-convert
// them back to pointers w.r.t. the User Mode base pointers.
//
// VERY IMPORTANT: Note that the pointer to the Pre Parsed Data structure that
// gets patched by this routine is an OFFSET based on the base
// of the collection descriptor blocks. So, this means that the
// pre parsed data blocks are referenced based on the first
// collection description element, which also happens to be the
// base of the entire output buffer.
//
// User mode code that is trying to reconstruct this buffer must
// be aware of this organization.
//
*/
ASSERT (pHidPCollDesc != NULL);
ulBytInBuff = outputBufferLength;
// Early out--if not enough room for the fixed size blocks, don't continue
if (ulBytInBuff < (nCollectionDescElem * sizeof(HIDP_COLLECTION_DESC))) {
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
//USBDIAG_KdPrint(("USBDIAG.SYS: ERROR: Not enuf mem in outbuff to put collection descriptions!\n"));
TRAP();
goto DoneWithParse;
}
//set the base ptr of collection descriptions and PPD blocks
pCollBlock = (PCHAR)ioBuffer;
//USBDIAG_KdPrint(("USBDIAG.SYS: pCollBlock (base): %X NbrCollDescElem: %d\n",
//pCollBlock, nCollectionDescElem));
pSubBuffer = pAllocFromBuffer((PBYTE) pCollBlock,
outputBufferLength,
&iOffset,
&iTotalUsed,
sizeof(HIDP_DEVICE_DESC));
if (NULL == pSubBuffer)
{
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
TRAP();
goto DoneWithParse;
}
memcpy(pSubBuffer, &rCollectionsAndIDs, sizeof(HIDP_DEVICE_DESC));
pDeviceDesc = (PHIDP_DEVICE_DESC) pSubBuffer;
pSubBuffer = pAllocFromBuffer((PBYTE) pCollBlock,
outputBufferLength,
&iOffset,
&iTotalUsed,
sizeof(HIDP_REPORT_IDS)*(pDeviceDesc->ReportIDsLength));
if (NULL == pSubBuffer)
{
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
TRAP();
goto DoneWithParse;
}
memcpy(pSubBuffer,
pDeviceDesc->ReportIDs,
sizeof(HIDP_REPORT_IDS)*(pDeviceDesc->ReportIDsLength));
//
// patch pointer to make it relative
//
pDeviceDesc->ReportIDs = (PHIDP_REPORT_IDS) UlongToPtr(iOffset);
pSubBuffer = pAllocFromBuffer((PBYTE) pCollBlock,
outputBufferLength,
&iOffset,
&iTotalUsed,
sizeof(HIDP_COLLECTION_DESC)*(pDeviceDesc->CollectionDescLength));
if (NULL == pSubBuffer)
{
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
TRAP();
goto DoneWithParse;
}
memcpy(pSubBuffer,
pDeviceDesc->CollectionDesc,
sizeof(HIDP_COLLECTION_DESC)*(pDeviceDesc->CollectionDescLength));
//
// patch pointer to make it relative
//
pDeviceDesc->CollectionDesc = (PHIDP_COLLECTION_DESC) ULongToPtr(iOffset);
pCollectionDesc = (PHIDP_COLLECTION_DESC) pSubBuffer;
for (i=0; i < pDeviceDesc->CollectionDescLength; i++)
{
pSubBuffer = pAllocFromBuffer((PBYTE) pCollBlock,
outputBufferLength,
&iOffset,
&iTotalUsed,
pCollectionDesc->PreparsedDataLength);
if (NULL == pSubBuffer)
{
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
TRAP();
goto DoneWithParse;
}
memcpy(pSubBuffer,
pCollectionDesc->PreparsedData,
pCollectionDesc->PreparsedDataLength);
//
// patch pointer to make it relative
//
pCollectionDesc->PreparsedData = (PHIDP_PREPARSED_DATA) ULongToPtr(iOffset);
pCollectionDesc++;
}
DoneWithParse:
/*
// Setting the Irp->IoStatus.Information field tells the IOS how many bytes to copy
// back into the user buffer and hopefully will set the value in
// DeviceIoControl's "lpBytesReturned" field.
*/
//
// free up collection stuff that parser returned
//
HidP_FreeCollectionDescription(&rCollectionsAndIDs);
Irp->IoStatus.Information = iTotalUsed;
//USBDIAG_KdPrint(("USBDIAG.SYS: TotalBytesCopied into systembuffer%d\n", iTotalUsed));
} else {
// call to parser failed
// //USBDIAG_KdPrint(("USBDIAG.SYS: HidP_GetCollectionDescription failed w/ ntStatus: %X\n", ntStatus));
memcpy(ioBuffer,&rCollectionsAndIDs,sizeof(HIDP_DEVICE_DESC));
// Irp->IoStatus.Information = sizeof(HIDP_DEVICE_DESC); //Copy just the DeviceDesc struct so that ring3 gets the debug struct
Irp->IoStatus.Information=sizeof(HIDP_DEVICE_DESC);
bFailed=TRUE;
}//if
// We always complete w/ success since the real status is in the REQ Header status field
Irp->IoStatus.Status = ntStatus = STATUS_SUCCESS;
// Complete the IRP here so we can free the buffer created by HIDPARSE when we called it
// after the IOS copies stuff back to user space, etc.
return ntStatus;
}//USBDIAG_HIDP_GetCollection
VOID
USBDIAG_SyncTimeoutDPC(
IN PKDPC Dpc,
IN PVOID DeferredContext,
IN PVOID SystemArgument1,
IN PVOID SystemArgument2
)
/*++
Routine Description:
This routine runs at DISPATCH_LEVEL IRQL.
Arguments:
Dpc - Pointer to the DPC object.
DeferredContext - passed in to IOS by caller as context (we use it as pIrp)
SystemArgument1 - not used.
SystemArgument2 - not used.
Return Value:
None.
--*/
{
BOOLEAN status;
PIRP irp = DeferredContext;
// TRAP();
// The cancel Irp call below will return immediately, but that doesn't mean things are all
// cleaned up in the USB stack. The only way to be assured of that is when the
// WaitForSingleObject that blocked in the first place returns (due to the USB stack
// completing the Irp, either due to normal completion or due to this cancel Irp call.
status = IoCancelIrp(irp);
//BUGBUG (kosar) We don't do anything if the cancel fails, and we probably should.
// (like maybe reschedule or something)
return;
}
NTSTATUS
USBDIAG_Configure_Device (
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp)
{
PDEVICE_EXTENSION deviceExtension;
NTSTATUS ntStatus;
PURB urb = NULL;
ULONG siz;
PUSB_CONFIGURATION_DESCRIPTOR configurationDescriptor = NULL;
struct _REQ_HEADER * REQHeader = NULL;
struct _REQ_SET_DEVICE_CONFIG * REQSetDeviceConfig = NULL;
PIO_STACK_LOCATION irpStack = NULL;
PVOID ioBuffer;
ULONG inputBufferLength;
ULONG outputBufferLength;
PDEVICE_LIST_ENTRY devListEntry;
PDEVICE_OBJECT actualdeviceObject;
ULONG ulUrbStatus;
//USBDIAG_KdPrint(("USBDIAG.SYS: enter USBDIAG_ConfigureDevice\n"));
// Get a pointer to the current location in the Irp. This is where
// the function codes and parameters are located.
irpStack = IoGetCurrentIrpStackLocation (Irp);
// Get the pointer to the input/output buffer and it's length
ioBuffer = Irp->AssociatedIrp.SystemBuffer;
inputBufferLength = irpStack->Parameters.DeviceIoControl.InputBufferLength;
outputBufferLength = irpStack->Parameters.DeviceIoControl.OutputBufferLength;
// The REQHeader, which is the struct that the app fills in describing this REQuest is
// referenced in the SystemBuffer since it is sent down in the InputBuffer field of the
// DeviceIoControl call in User Mode.
// The ReqSetDeviceConfig is where the results of this call will go (using a separate
// var here just for convenience.
REQHeader = (struct _REQ_HEADER *)ioBuffer;
REQSetDeviceConfig = (struct _REQ_SET_DEVICE_CONFIG *) ioBuffer;
// The DeviceHandle is a ptr to the list entry that USBDIAG manages for devices it is
// testing. This used to be a "USBD Device handle" in the old Chap9 method. Now it's a
// ptr to the list entry object that USBDIAG maintains for each device under test. That
// list entry contains the PDO and other junk about the device object
devListEntry = (PDEVICE_LIST_ENTRY)(REQHeader->UsbdDeviceHandle);
//USBDIAG_KdPrint(("USBDIAG.SYS: DevListEntry: %X\n",devListEntry));
ASSERT (devListEntry != NULL);
if (devListEntry == NULL)
{
ntStatus = STATUS_INVALID_PARAMETER;
REQHeader->Status = CH9_STATUS_INVALID_PARAMETER;
Irp->IoStatus.Information=sizeof (struct _REQ_HEADER); //return the status junk
Irp->IoStatus.Information=ntStatus;
goto Exit_USBDIAGConfigureDevice; //Bail if things look bad
} //if
// Device object given is not the real PDO that is needed by the USB stack, so
// extract that PDO with a handy macro before calling the lower level drivers (USB stk)
actualdeviceObject = FDO_FROM_DEVICE_HANDLE(devListEntry);
//USBDIAG_KdPrint(("USBDIAG.SYS: PDO for DUT: %X\n",actualdeviceObject));
ASSERT (actualdeviceObject != NULL);
if (actualdeviceObject == NULL)
{
ntStatus = STATUS_INVALID_PARAMETER;
REQHeader->Status = CH9_STATUS_INVALID_PARAMETER;
Irp->IoStatus.Information=sizeof (struct _REQ_HEADER); //return the status junk
Irp->IoStatus.Information=ntStatus;
goto Exit_USBDIAGConfigureDevice; //Bail if things look bad
}//if
urb = USBDIAG_ExAllocatePool(NonPagedPool, sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST));
if (urb)
{
/*
// Set size of the data buffer. Note we add padding to cover hardware faults
// that may cause the device to go past the end of the data buffer
*/
siz = sizeof(USB_CONFIGURATION_DESCRIPTOR) + 256;
// Get the nonpaged pool memory for the data buffer
configurationDescriptor = USBDIAG_ExAllocatePool(NonPagedPool, siz);
//USBDIAG_KdPrint(("USBDIAG.SYS: Config Index Requested: %#X\n",
//REQSetDeviceConfig->iConfigurationDescIndex));
if (configurationDescriptor)
{
UsbBuildGetDescriptorRequest(urb,
(USHORT) sizeof (struct _URB_CONTROL_DESCRIPTOR_REQUEST),
USB_CONFIGURATION_DESCRIPTOR_TYPE,
(UCHAR)(REQSetDeviceConfig->iConfigurationDescIndex),
0, //LANGUAGE ID
configurationDescriptor,
NULL,
siz, // sizeof (USB_CONFIGURATION_DESCRIPTOR),/* Get only the configuration descriptor */
NULL);
ntStatus = USBDIAG_Ch9CallUSBD(actualdeviceObject, urb, TRUE, NULL, NULL, TRUE);
ulUrbStatus = urb->UrbHeader.Status;
if (NT_SUCCESS(ntStatus))
{
//USBDIAG_KdPrint(("USBDIAG.SYS: Configuration Descriptor is at %x, bytes txferred: %d\n\
//Configuration Descriptor Actual Length: %d\n",
//configurationDescriptor,
//urb->UrbControlDescriptorRequest.TransferBufferLength,
//configurationDescriptor->wTotalLength));
}//if
else
{
//Urb had a failure
//USBDIAG_KdPrint(("USBDIAG.SYS: Failed getting partial Config Descr: UrbStatus: %#X\n",ulUrbStatus));
Ch9FillInReqStatus (ntStatus, ulUrbStatus, REQHeader);
Irp->IoStatus.Information = sizeof (struct _REQ_SET_DEVICE_CONFIG);
Irp->IoStatus.Status = ntStatus;
goto Exit_USBDIAGConfigureDevice;
}//else failed Urb
}
else
{
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
goto Exit_USBDIAGConfigureDevice;
}//if-else
// Determine how much data is in the entire configuration descriptor
// and add extra room to protect against accidental overrun
siz = configurationDescriptor->wTotalLength + 16;
// Free up the data buffer memory just used
USBDIAG_ExFreePool(configurationDescriptor);
configurationDescriptor = NULL;
// Get nonpaged pool memory for the data buffer
configurationDescriptor = USBDIAG_ExAllocatePool(NonPagedPool,
siz);
// Now get the entire Configuration Descriptor
if (configurationDescriptor)
{
UsbBuildGetDescriptorRequest(urb,
(USHORT) sizeof (struct _URB_CONTROL_DESCRIPTOR_REQUEST),
USB_CONFIGURATION_DESCRIPTOR_TYPE,
(UCHAR)(REQSetDeviceConfig->iConfigurationDescIndex),
0, //LANGUAGE ID
configurationDescriptor,
NULL,
siz, // Get all the descriptor data
NULL);
//USBDIAG_KdPrint(("USBDIAG.SYS: Trying to get entire Config Descriptor (%d bytes)...\n",
//siz-16));
ntStatus = USBDIAG_Ch9CallUSBD(actualdeviceObject, urb, TRUE, NULL, NULL, TRUE);
ulUrbStatus = urb->UrbHeader.Status;
if (NT_SUCCESS(ntStatus))
{
//USBDIAG_KdPrint(("USBDIAG.SYS: Entire Configuration Descriptor is at %x, bytes txferred: %d\n",
//configurationDescriptor,
//urb->UrbControlDescriptorRequest.TransferBufferLength));
}
else
{
//Error in getting configuration descriptor
//USBDIAG_KdPrint(("USBDIAG.SYS: Failed getting entire Config Descr: UrbStatus: %#X\n",ulUrbStatus));
Ch9FillInReqStatus (ntStatus, ulUrbStatus, REQHeader);
Irp->IoStatus.Information = sizeof (struct _REQ_HEADER);
Irp->IoStatus.Status = ntStatus;
goto Exit_USBDIAGConfigureDevice;
}//else failed getconfig descriptor
}
else
{
// Failed getting data buffer (configurationDescriptor) memory
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
REQHeader->Status = CH9_STATUS_NO_MEMORY;
Irp->IoStatus.Information = sizeof (struct _REQ_HEADER);
Irp->IoStatus.Status = ntStatus;
goto Exit_USBDIAGConfigureDevice;
}//if-else
}
else
{
// failed getting urb memory
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
REQHeader->Status = CH9_STATUS_NO_MEMORY;
Irp->IoStatus.Information = sizeof (struct _REQ_HEADER);
Irp->IoStatus.Status = ntStatus;
goto Exit_USBDIAGConfigureDevice;
}//if-else
/*
// We have the configuration descriptor for the configuration
// we want.
//
// Now we issue the SelectConfiguration command to get
// the pipes associated with this configuration.
*/
if (configurationDescriptor)
{
// Get our pipes
// NOTE: USBDIAG_SelectInterfaces will set the status field in the Chap9 REQHeader
// struct so we don't need to do it here, just set the length of the Irp based
// on the ntStatus code that SelectInterfaces returns.
ntStatus = USBDIAG_SelectInterfaces(actualdeviceObject,
configurationDescriptor,
NULL, // Device not yet configured
REQSetDeviceConfig //Send the user's config context down
);
if (NT_SUCCESS(ntStatus))
{
//If success, then copy back all the data to user's buffer
//USBDIAG_KdPrint(("USBDIAG.SYS: Successful SelectInterfaces \n"));
Irp->IoStatus.Information= REQHeader->Length; //return everything if success
Irp->IoStatus.Status = ntStatus; //fill in Irp code
} //if success
else
{
//if didn't succeed, only copy the header portion which has the status code
//USBDIAG_KdPrint(("USBDIAG.SYS: Failed SelectInterfaces \n"));
Irp->IoStatus.Information= sizeof (REQHeader); //return only header portion
Irp->IoStatus.Status = ntStatus; //fill in Irp code
}//else failure
} //if
Exit_USBDIAGConfigureDevice:
// Clean up and exit this routine
if (urb)
{
USBDIAG_ExFreePool(urb); // Free urb memory
}//if
if (configurationDescriptor)
{
USBDIAG_ExFreePool(configurationDescriptor);// Free data buffer
}//if
//USBDIAG_KdPrint(("USBDIAG.SYS: exit USBDIAG_ConfigureDevice (ntStat: %x)\n", ntStatus));
return ntStatus;
}//USBDIAG_Configure_Device
NTSTATUS
USBDIAG_SelectInterfaces(
IN PDEVICE_OBJECT DeviceObject,
IN PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor,
IN PUSBD_INTERFACE_INFORMATION Interface,
IN OUT struct _REQ_SET_DEVICE_CONFIG * REQSetDeviceConfig
)
/*++
Arguments:
DeviceObject - pointer to the device object for this instance of the USB Device
ConfigurationDescriptor - pointer to the USB configuration descriptor containing the interface and endpoint
descriptors.
Interface - pointer to a USBD Interface Information Object
- If this is NULL, then this driver must choose its interface based on driver-specific
criteria, and the driver must also CONFIGURE the device.
- If it is NOT NULL, then the driver has already been given an interface and
the device has already been configured by the parent of this device driver.
REQSetDeviceConfig - Where the results will go for this config request
Return Value:
NT status code
--*/
{
PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
NTSTATUS ntStatus = STATUS_SUCCESS;
PURB urb;
ULONG siz, numberOfInterfaces, j, numberOfPipes;
PUSB_INTERFACE_DESCRIPTOR interfaceDescriptor;
PUSBD_INTERFACE_INFORMATION interfaceObject;
//USBDIAG_KdPrint(("USBDIAG.SYS: enter USBDIAG_SelectInterfaces\n"));
if (Interface == NULL)
{
// This driver only supports one interface.
numberOfInterfaces = ConfigurationDescriptor->bNumInterfaces;
//USBDIAG_KdPrint(("USBDIAG.SYS: Device has %d Interfaces\n",numberOfInterfaces));
numberOfInterfaces =1; // Fixed for this sample driver in this revision
numberOfPipes = 0; // Initialize to zero
// Call a USBD helper function that returns a ptr to a USB Interface Descriptor given
// a USB Configuration Descriptor, an Inteface Number, and an Alternate Setting for that Interface
interfaceDescriptor =
USBD_ParseConfigurationDescriptorEx(ConfigurationDescriptor,
ConfigurationDescriptor,
-1, // InterfaceNumber
-1, // AlternateSetting
-1, // InterfaceClass
-1, // InterfaceSubClass
-1); // InterfaceProtocol
ASSERT(interfaceDescriptor != NULL);
if (interfaceDescriptor != NULL)
{
//USBDIAG_KdPrint(("USBDIAG.SYS: Device has %d Interface(s) | Interface is at: (%#X)\n",
//numberOfInterfaces, interfaceDescriptor));
// Check if caller gave us enough pipe contexts to put all the info in
if ((REQSetDeviceConfig->nNumContexts) < (interfaceDescriptor->bNumEndpoints))
{
//USBDIAG_KdPrint(("USBDIAG.SYS: Not enough mem to configure device \n"));
//USBDIAG_KdPrint(("USBDIAG.SYS: Number of Contexts: %d | Number of Endpoints: %d",
//REQSetDeviceConfig->nNumContexts,interfaceDescriptor->bNumEndpoints));
return (STATUS_INSUFFICIENT_RESOURCES);
}/* if size is ok */
// Check if the number of pipes in this interface exceeds the maximum we can
// support in the device extension area
if ((interfaceDescriptor->bNumEndpoints) > USBDIAG_MAX_PIPES)
{
//USBDIAG_KdPrint(("USBDIAG.SYS: Number of Endpoints (%d) exceeds MAX_PIPES (%d)",
//interfaceDescriptor->bNumEndpoints, USBDIAG_MAX_PIPES));
return (STATUS_INSUFFICIENT_RESOURCES);
}/* if dev ext has enough room */
/* Add to the tally of pipes in this configuration */
numberOfPipes += interfaceDescriptor->bNumEndpoints;
//USBDIAG_KdPrint(("USBDIAG.SYS: Interface has %d endpoints\n",
//interfaceDescriptor->bNumEndpoints));
/*
// Now that we have looked at the interface, we configure the device so that the remainder
// of the USBD objects will come into existence (ie., pipes, etc.) as a result of the configuration,
// thus completing the configuration process for the USB device.
//
// Allocate a URB big enough for this Select Configuration request
// This driver supports only 1 interface
//
// NOTE: The new service USBD_CreateConfigurationRequest will replace some of the
// code below. Future releases of this driver will demonstrate how to use
// that service.
//
*/
siz = GET_SELECT_CONFIGURATION_REQUEST_SIZE(numberOfInterfaces, numberOfPipes);
//USBDIAG_KdPrint(("USBDIAG.SYS: size of config request Urb = %d\n", siz));
urb = USBDIAG_ExAllocatePool(NonPagedPool,
siz);
if (urb) {
interfaceObject = (PUSBD_INTERFACE_INFORMATION) (&(urb->UrbSelectConfiguration.Interface));
//USBDIAG_KdPrint(("USBDIAG.SYS: urb.Interface=%#X\n", &(urb->UrbSelectConfiguration.Interface)));
// set up the input parameters in our interface request structure.
interfaceObject->Length = (USHORT)GET_USBD_INTERFACE_SIZE(interfaceDescriptor->bNumEndpoints);
//USBDIAG_KdPrint(("USBDIAG.SYS: size of interface request = %d\n", interfaceObject->Length));
interfaceObject->InterfaceNumber = interfaceDescriptor->bInterfaceNumber;
interfaceObject->AlternateSetting = interfaceDescriptor->bAlternateSetting;
interfaceObject->NumberOfPipes = interfaceDescriptor->bNumEndpoints;
/*
// We set up a default max transfer size for the endpoints. Your driver will
// need to change this to reflect the capabilities of your device's endpoints.
*/
for (j=0; j<interfaceDescriptor->bNumEndpoints; j++) {
interfaceObject->Pipes[j].MaximumTransferSize =
USBD_DEFAULT_MAXIMUM_TRANSFER_SIZE; //Defaults to PAGE_SIZE (4k)
interfaceObject->Pipes[j].PipeFlags = 0;
} /* for */
//USBDIAG_KdPrint(("USBDIAG.SYS: InterfaceObj Inteface Nbr: %d | InterfaceObj AltSett: %d |NbrPip: %d\n",
//interfaceObject->InterfaceNumber,
//interfaceObject->AlternateSetting,
//interfaceObject->NumberOfPipes));
UsbBuildSelectConfigurationRequest(urb,
(USHORT) siz,
ConfigurationDescriptor);
ntStatus = USBDIAG_Ch9CallUSBD(DeviceObject, urb, TRUE, NULL, NULL, TRUE);
if (NT_SUCCESS(ntStatus) && USBD_SUCCESS(urb->UrbSelectConfiguration.Hdr.Status)) {
// Save the configuration handle for this device
deviceExtension->ConfigurationHandle =
urb->UrbSelectConfiguration.ConfigurationHandle;
deviceExtension->Interface[0] = USBDIAG_ExAllocatePool(NonPagedPool,
interfaceObject->Length);
if (deviceExtension->Interface[0]) {
// Save a copy of the interfaceObject information returned
RtlCopyMemory(deviceExtension->Interface[0], interfaceObject, interfaceObject->Length);
// Dump the interfaceObject to the debugger
//USBDIAG_KdPrint(("USBDIAG.SYS: ---------\n"));
//USBDIAG_KdPrint(("USBDIAG.SYS: NumberOfPipes 0x%x\n", deviceExtension->Interface[0]->NumberOfPipes));
//USBDIAG_KdPrint(("USBDIAG.SYS: Length 0x%x\n", deviceExtension->Interface[0]->Length));
//USBDIAG_KdPrint(("USBDIAG.SYS: Alt Setting 0x%x\n", deviceExtension->Interface[0]->AlternateSetting));
//USBDIAG_KdPrint(("USBDIAG.SYS: Interface Number 0x%x\n", deviceExtension->Interface[0]->InterfaceNumber));
// Dump the pipe info
for (j=0; j<interfaceObject->NumberOfPipes; j++) {
PUSBD_PIPE_INFORMATION pipeInformation;
pipeInformation = &(deviceExtension->Interface[0]->Pipes[j]);
//USBDIAG_KdPrint(("USBDIAG.SYS: ---------\n"));
//USBDIAG_KdPrint(("USBDIAG.SYS: PipeType 0x%x\n", pipeInformation->PipeType));
//USBDIAG_KdPrint(("USBDIAG.SYS: EndpointAddress 0x%x\n", pipeInformation->EndpointAddress));
//USBDIAG_KdPrint(("USBDIAG.SYS: MaxPacketSize 0x%x\n", pipeInformation->MaximumPacketSize));
//USBDIAG_KdPrint(("USBDIAG.SYS: Interval 0x%x\n", pipeInformation->Interval));
//USBDIAG_KdPrint(("USBDIAG.SYS: Handle 0x%x\n", pipeInformation->PipeHandle));
//USBDIAG_KdPrint(("USBDIAG.SYS: MaximumTransferSize 0x%x\n", pipeInformation->MaximumTransferSize));
// Set the user's pipe context information structure
//USBDIAG_KdPrint(("USBDIAG.SYS: Setting PipeNum: %d\n",j));
//USBDIAG_KdPrint(("USBDIAG.SYS: Setting PipeType: %d\n",pipeInformation->PipeType));
//USBDIAG_KdPrint(("USBDIAG.SYS: &PipeNum: %#X\n", &(REQSetDeviceConfig->Contxt[j].PipeNum) ));
//USBDIAG_KdPrint(("USBDIAG.SYS: &PipeType: %#X\n",&(REQSetDeviceConfig->Contxt[j].PipeType) ));
REQSetDeviceConfig->Contxt[j].PipeNum = j;
REQSetDeviceConfig->Contxt[j].PipeType = pipeInformation->PipeType;
}/* for all the pipes in this interface */
//USBDIAG_KdPrint(("USBDIAG.SYS: ---------\n"));
} /*If ExAllocate passed */
}/* if selectconfiguration request was successful */
//Fill in the user mode app's status field
Ch9FillInReqStatus (ntStatus, urb->UrbSelectConfiguration.Hdr.Status,
((struct _REQ_HEADER * ) REQSetDeviceConfig) );
} /* if urb create successful */
else
{
//USBDIAG_KdPrint(("USBDIAG.SYS: Sample_SelectInterfaces FAILED creating Urb for selecting interface\n"));
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
}/* Failed creating mem for urb */
} /* if there was a valid interfacedesc */
else
{
ntStatus = STATUS_INVALID_PARAMETER;
}//else error in interfacedesc
}//if Interface given to this func was NULL (ie., we are the configuring driver)
//USBDIAG_KdPrint(("USBDIAG.SYS: exit Sample_SelectInterfaces (ntSt: %x)\n", ntStatus));
return ntStatus;
}/* Sample_SelectInterfaces */
VOID
Ch9FillInReqStatus (
IN NTSTATUS ntStatusCode,
IN ULONG ulUrbStatus,
IN OUT struct _REQ_HEADER * REQHeader //This should be the SystemBuffer (ioBuffer)
)
{
// Put the status code in the Chapter 9 structure so that the app can
// finger out what happened
switch (ntStatusCode)
{
case (STATUS_SUCCESS):
//Success
//USBDIAG_KdPrint(("USBDIAG.SYS: Status Success received\n"));
REQHeader->Status = CH9_STATUS_SUCCESS;
break;
case (STATUS_CANCELLED):
//Irp was cancelled, and we assume it was due to a nonresponsive device
//USBDIAG_KdPrint(("USBDIAG.SYS: Status Cancelled received\n"));
REQHeader->Status = CH9_STATUS_DEVICE_NOT_RESPONDING;
break; //Status_Cancelled
default:
// if you got here the irp was not successful, so look at the Urb status
// that was saved and see if that can be mapped to something the app
// understands
switch (ulUrbStatus | 0xC0000000) {
case USBD_STATUS_CRC:
//USBDIAG_KdPrint(("USBDIAG.SYS: UrbStatus CRC Failure\n"));
REQHeader->Status = CH9_STATUS_CRC_ERROR;
break;
case USBD_STATUS_STALL_PID:
case USBD_STATUS_ENDPOINT_HALTED:
//USBDIAG_KdPrint(("USBDIAG.SYS: UrbStatus EP Stalled\n"));
REQHeader->Status = CH9_STATUS_ENDPOINT_STALLED;
break;
case USBD_STATUS_BTSTUFF:
//USBDIAG_KdPrint(("USBDIAG.SYS: UrbStatus USBD_STATUS_BTSTUFF\n"));
REQHeader->Status = CH9_STATUS_BITSTUFF_ERROR;
break;
case USBD_STATUS_DATA_TOGGLE_MISMATCH:
//USBDIAG_KdPrint(("USBDIAG.SYS: UrbStatus USBD_STATUS_DATA_TOGGLE_MISMATCH\n"));
REQHeader->Status = CH9_STATUS_DATA_TOGGLE_ERROR;
break;
case USBD_STATUS_DEV_NOT_RESPONDING:
//USBDIAG_KdPrint(("USBDIAG.SYS: UrbStatus USBD_STATUS_DEV_NOT_RESPONDING\n"));
REQHeader->Status = CH9_STATUS_DEVICE_NOT_RESPONDING;
break;
default:
REQHeader->Status = CH9_STATUS_DEVICE_ERROR; //put a generic one in here for now
//USBDIAG_KdPrint(("USBDIAG.SYS: UrbStatus Other Device Failure\n"));
break;
}//switch ulUrbStatus
}//switch ntStatus
return;
}//FillInReqStatus
//#if 0
VOID
USBDIAG_IoCancelRoutine (
PDEVICE_OBJECT DeviceObject,
PIRP Irp
)
/* ++
-- */
{
//USBDIAG_KdPrint(("USBDIAG.SYS: In USBDIAG_IoCancelRoutine %x %x\n",DeviceObject,Irp));
TRAP();
return;
}//USBDIAG_IoCancelRoutine
//#endif
NTSTATUS
USBDIAG_IoGenericCompletionRoutine (
PDEVICE_OBJECT DeviceObject,
PIRP Irp,
PVOID context
)
{
PCOMPLETION_CONTEXT Context = (PCOMPLETION_CONTEXT)context;
PDEVICE_OBJECT actualDeviceObject = Context->DeviceObject;
PDEVICE_EXTENSION deviceExtension = actualDeviceObject->DeviceExtension;
PIRP irp = Context->Irp;
//USBDIAG_KdPrint(("USBDIAG.SYS: In USBDIAG_IoGenericCompletionRoutine %x %x\n",DeviceObject,Irp));
//TRAP();
// remove the irp from the irp list
USBDIAG_ClearSavedIrp(deviceExtension, irp);
if (irp->Cancel) // cancel all irps is the only one to set this bit
{
//USBDIAG_KdPrint(("CompletionRoutine: irp->Cancel bit set\n"));
KeSetEvent(&deviceExtension->CancelEvent,
1,
FALSE);
}
//USBDIAG_KdPrint(("USBDIAG.SYS: Setting DoneEvent\n"));
// KeSetEvent(&Context->DoneEvent,
// 1,
// FALSE); // ditto with the priority
return STATUS_SUCCESS;
// return STATUS_MORE_PROCESSING_REQUIRED;
}
NTSTATUS
USBDIAG_WaitWakeCompletionRoutine(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID Context
)
{
PCOMPLETION_CONTEXT CompletionContext = (PCOMPLETION_CONTEXT)Context;
PDEVICE_OBJECT deviceObject = CompletionContext->DeviceObject;
PDEVICE_EXTENSION deviceExtension = deviceObject->DeviceExtension;
POWER_STATE powerState;
POWER_STATE_TYPE Type = DevicePowerState;
POWER_STATE State;
NTSTATUS ntStatus = STATUS_SUCCESS;
USBDIAG_KdPrint(("'Entering USBDIAG_WaitWakeCompletionRoutine\n"));
if (Irp->Cancel)
{
USBDIAG_KdPrint(("'Cancel Bit Set. Calling USBDIAG_WaitWakeCancelRoutine\n"));
USBDIAG_WaitWakeCancelRoutine(deviceObject, Irp);
return STATUS_CANCELLED;
}
else
{
deviceExtension->WaitWakeIrp = NULL;
State.DeviceState = PowerDeviceD0;
powerState = PoSetPowerState(deviceObject, Type, State);
IoSetCancelRoutine(Irp, NULL);
IoCompleteRequest(Irp, IO_NO_INCREMENT);
ntStatus = Irp->IoStatus.Status;
KeSetEvent(&CompletionContext->DoneEvent, 1, FALSE);
}
return ntStatus;
}
VOID
USBDIAG_WaitWakeCancelRoutine
(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
{
PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
USBDIAG_KdPrint(("'Entering USBDIAG_WaitWakeCancelRoutine\n"));
IoSetCancelRoutine(Irp, NULL);
IoReleaseCancelSpinLock(Irp->CancelIrql);
// reset any relevant flags here
deviceExtension->WaitWakeIrp = NULL;
Irp->IoStatus.Status = STATUS_CANCELLED;
}
NTSTATUS
USBDIAG_PoRequestCompletion(
IN PDEVICE_OBJECT DeviceObject,
IN UCHAR MinorFunction,
IN POWER_STATE PowerState,
IN PVOID Context,
IN PIO_STATUS_BLOCK IoStatus
)
/*++
Routine Description:
This routine is called when the port driver completes an IRP.
Arguments:
DeviceObject - Pointer to the device object for the class device.
Context - Driver defined context.
Return Value:
The function value is the final status from the operation.
--*/
{
PDEVICE_OBJECT deviceObject = (PDEVICE_OBJECT)Context;
PDEVICE_EXTENSION deviceExtension = deviceObject->DeviceExtension;
PIRP irp = deviceExtension->PowerIrp;
NTSTATUS ntStatus;
ntStatus = IoStatus->Status;
//USBDIAG_KdPrint(("***USBDIAG.SYS: USBDIAG_PoRequestCompletion\n"));
IoCopyCurrentIrpStackLocationToNext(irp);
PoStartNextPowerIrp(irp);
PoCallDriver(deviceExtension->PhysicalDeviceObject, irp);
return ntStatus;
}
NTSTATUS
USBDIAG_SaveIrp(
IN PDEVICE_EXTENSION deviceExtension,
IN PIRP Irp
)
{
PIRPNODE pNode = USBDIAG_ExAllocatePool(NonPagedPool, sizeof(IRPNODE));
KIRQL Irql = KeGetCurrentIrql();
NTSTATUS ntStatus = STATUS_SUCCESS;
//USBDIAG_KdPrint(("USBDIAG_SaveIrp: Irql = 0x%x\n", Irql));
if (!pNode)
return STATUS_INSUFFICIENT_RESOURCES;
KeAcquireSpinLock(&deviceExtension->SpinLock, &Irql);
pNode->Irp = Irp;
InsertHeadList(&deviceExtension->ListHead, (PLIST_ENTRY)pNode);
KeReleaseSpinLock(&deviceExtension->SpinLock, Irql);
return ntStatus;
}
NTSTATUS
USBDIAG_ClearSavedIrp(
IN PDEVICE_EXTENSION deviceExtension,
IN PIRP Irp
)
{
NTSTATUS ntStatus = STATUS_UNSUCCESSFUL; // assume initially it won't be found
PIRPNODE pNode = NULL;
KIRQL Irql = KeGetCurrentIrql();
BOOLEAN fContinue = TRUE;
PIRPNODE pFirstNodeSeen = NULL;
USBDIAG_KdPrint(("'USBDIAG_ClearSavedIrp: Searching for Irp 0x%x at Irql 0x%x...\n",
Irp,
Irql));
KeAcquireSpinLock(&deviceExtension->SpinLock, &Irql);
if (IsListEmpty(&deviceExtension->ListHead))
{
ntStatus = STATUS_INVALID_PARAMETER;
}
else
{
while (fContinue)
{
pNode = (PIRPNODE)RemoveHeadList(&deviceExtension->ListHead);
if (pNode == pFirstNodeSeen) // back at original head of list -> stop
{
fContinue = FALSE;
InsertHeadList(&deviceExtension->ListHead, (PLIST_ENTRY)pNode);
}
else if (pNode->Irp == Irp)
{
if (Irp == deviceExtension->InterruptIrp)
{
USBDIAG_KdPrint(("'Interrupt complete (0x%x) - clearing from list\n", Irp));
deviceExtension->InterruptIrp = NULL;
}
fContinue = FALSE;
ntStatus = STATUS_SUCCESS;
USBDIAG_ExFreePool(pNode);
}
else // not head, put at end of list
{
if (!pFirstNodeSeen)
pFirstNodeSeen = pNode;
InsertTailList(&deviceExtension->ListHead, (PLIST_ENTRY)pNode);
}
}
}
KeReleaseSpinLock(&deviceExtension->SpinLock, Irql);
return ntStatus;
}
NTSTATUS
USBDIAG_CancelAllIrps(
PDEVICE_EXTENSION deviceExtension
)
{
NTSTATUS ntStatus = STATUS_SUCCESS;
BOOLEAN bCancelled = FALSE;
KIRQL Irql = KeGetCurrentIrql();
//KIRQL RaisedIrql = DISPATCH_LEVEL;
PIRPNODE pNode = NULL;
ASSERT (deviceExtension);
USBDIAG_KdPrint(("'USBDIAG_CancelAllIrps: Entering\n"));
KeAcquireSpinLock(&deviceExtension->SpinLock, &Irql);
while (!IsListEmpty(&deviceExtension->ListHead))
{
// get the head, cancel it, and put it back
pNode = (PIRPNODE)RemoveHeadList(&deviceExtension->ListHead);
bCancelled = IoCancelIrp(pNode->Irp);
InsertHeadList(&deviceExtension->ListHead, (PLIST_ENTRY)pNode);
KeReleaseSpinLock(&deviceExtension->SpinLock, Irql);
if (!bCancelled)
{
USBDIAG_KdPrint(("USBDIAG.SYS: CancelIrp FAILED (Irp=%X | returned value=%X)\n",
pNode->Irp,
bCancelled));
// return this if not all irps were successfully cancelled
ntStatus = STATUS_UNSUCCESSFUL;
}
else
{
//USBDIAG_KdPrint(("USBDIAG.SYS: Successfully Cancelled Irp (%X)\n", pNode->Irp));
// Sleep to let the irps clean themselves up
USBDIAG_KdPrint(("'Going to sleep in cancel routine\n"));
KeWaitForSingleObject(&deviceExtension->CancelEvent,
Suspended,
KernelMode,
FALSE,
NULL);
USBDIAG_KdPrint(("'Waking up in cancel routine\n"));
}
KeAcquireSpinLock(&deviceExtension->SpinLock, &Irql);
}
KeReleaseSpinLock(&deviceExtension->SpinLock, Irql);
USBDIAG_KdPrint(("'USBDIAG_CancelAllIrps: Exiting\n"));
return ntStatus;
}
NTSTATUS
USBDIAG_IssueWaitWake(
IN PDEVICE_OBJECT DeviceObject
)
{
PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
NTSTATUS ntStatus;
POWER_STATE powerState;
USBDIAG_KdPrint(("'*********************************\n"));
USBDIAG_KdPrint(("'USBDIAG_IssueWaitWake: Entering\n"));
USBDIAG_KdPrint(("'Issue Wait/Wake for Device Object 0x%x, extension 0x%x\n",
DeviceObject,
deviceExtension));
if (deviceExtension->WaitWakeIrp != NULL)
{
USBDIAG_KdPrint(("'Wait wake all ready active!\n"));
return STATUS_INVALID_DEVICE_STATE;
}
powerState.SystemState = deviceExtension->DeviceCapabilities.DeviceWake;
ntStatus = PoRequestPowerIrp(deviceExtension->PhysicalDeviceObject,
IRP_MN_WAIT_WAKE,
powerState,
USBDIAG_RequestWaitWakeCompletion,
DeviceObject,
&deviceExtension->WaitWakeIrp);
if (!deviceExtension->WaitWakeIrp)
{
USBDIAG_KdPrint(("'Wait wake is NULL!\n"));
return STATUS_UNSUCCESSFUL;
}
USBDIAG_KdPrint(("'USBDIAG_IssueWaitWake: exiting with ntStatus 0x%x (wait wake is 0x%x)\n",
ntStatus,
deviceExtension->WaitWakeIrp));
return ntStatus;
}
// **************************************************************************
// Completion routine for irp generated by PoRequestPowerIrp in USBDIAG_IssueWaitWake
NTSTATUS
USBDIAG_RequestWaitWakeCompletion(
IN PDEVICE_OBJECT DeviceObject,
IN UCHAR MinorFunction,
IN POWER_STATE PowerState,
IN PVOID Context,
IN PIO_STATUS_BLOCK IoStatus
)
{
PDEVICE_OBJECT deviceObject = Context;
PDEVICE_EXTENSION deviceExtension = deviceObject->DeviceExtension;
POWER_STATE powerState;
//POWER_STATE_TYPE Type = DevicePowerState;
POWER_STATE State;
NTSTATUS ntStatus = STATUS_SUCCESS;
USBDIAG_KdPrint(("'#########################################\n"));
USBDIAG_KdPrint(("'### USBDIAG_RequestWaitWakeCompletion ###\n"));
USBDIAG_KdPrint(("'#########################################\n"));
USBDIAG_KdPrint(("'Received Wait/Wake completion for Device Object 0x%x (0x%x) extension 0x%x\n",
deviceObject,
DeviceObject,
deviceExtension));
State.DeviceState = PowerDeviceD0;
ntStatus = IoStatus->Status;
deviceExtension->WaitWakeIrp = NULL;
USBDIAG_KdPrint(("'USBDIAG_RequestWaitWakeCompletion: Wake irp completed status 0x%x\n", ntStatus));
//DbgPrint("Wait/Wake completed with status 0x%x\n", ntStatus);
switch (ntStatus)
{
case STATUS_SUCCESS:
USBDIAG_KdPrint(("'USBDIAG_RequestWaitWakeCompletion: Wake irp completed succefully.\n"));
// There are 3 cases in which we will cancel the wait wake IRP
// 1) We are going to an S state where we can't wake the machine. We will
// resend the irp when we transition back to S0
// 2) We get a stop. We will resend the irp if we get another start
// 3) We get a remove. We will not (obviously) send another wait wake
ntStatus = USBDIAG_SetDevicePowerState(deviceObject, PowerDeviceD0);
break;
case STATUS_CANCELLED:
USBDIAG_KdPrint(("'USBDIAG_RequestWaitWakeCompletion: Wake irp cancelled\n"));
// case STATUS_ACPI_POWER_REQUEST_FAILED:
// case STATUS_POWER_STATE_INVALID:
break;
default:
break;
}
USBDIAG_KdPrint(("'Setting WaitWakeEvent\n"));
KeSetEvent(&deviceExtension->WaitWakeEvent, IO_NO_INCREMENT, FALSE);
return ntStatus;
}
NTSTATUS
USBDIAG_PoSelfRequestCompletion(
IN PDEVICE_OBJECT DeviceObject,
IN UCHAR MinorFunction,
IN POWER_STATE PowerState,
IN PVOID Context,
IN PIO_STATUS_BLOCK IoStatus
)
{
PDEVICE_OBJECT deviceObject = Context;
PDEVICE_EXTENSION deviceExtension = deviceObject->DeviceExtension;
NTSTATUS ntStatus = IoStatus->Status;
// We only need to set the event if we're powering up;
// No caller waits on power down complete
if (deviceExtension->CurrentDeviceState.DeviceState > PowerState.DeviceState)
{
// Trigger Self-requested power irp completed event;
// The caller is waiting for completion
KeSetEvent(deviceExtension->SelfRequestedPowerIrpEvent, 1, FALSE);
}
USBDIAG_KdPrint(("'USBDIAG_PoSelfRequestCompletion:\n"));// Setting deviceExtension->PowerState.DeviceState\n"));
//deviceExtension->PowerState.DeviceState = PowerState.DeviceState;
USBDIAG_KdPrint(("'Exiting USBDIAG_PoSelfRequestCompletion\n"));
return ntStatus;
}
NTSTATUS
USBDIAG_PowerIrpCompletionRoutine(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID Context
)
{
PKEVENT event = Context;
// Set the input event
KeSetEvent(event,
1, // Priority increment for waiting thread.
FALSE); // Flag this call is not immediately followed by wait.
// This routine must return STATUS_MORE_PROCESSING_REQUIRED because we have not yet called
// IoFreeIrp() on this IRP.
return STATUS_MORE_PROCESSING_REQUIRED;
}
#define DRIVER
#pragma warning(disable:4214) // bitfield nonstd
#include "wdm.h"
#pragma warning(default:4214)
#include "stdarg.h"
#include "stdio.h"
#pragma warning(disable:4200) //non std struct used
#include "usbdi.h"
#pragma warning(default:4200)
#include "usbdlib.h"
#include "ioctl.h"
#include "USBDIAG.h"
UCHAR *SystemPowerStateString[] = {
"PowerSystemUnspecified",
"PowerSystemWorking",
"PowerSystemSleeping1",
"PowerSystemSleeping2",
"PowerSystemSleeping3",
"PowerSystemHibernate",
"PowerSystemShutdown",
"PowerSystemMaximum"
};
UCHAR *DevicePowerStateString[] = {
"PowerDeviceUnspecified",
"PowerDeviceD0",
"PowerDeviceD1",
"PowerDeviceD2",
"PowerDeviceD3",
"PowerDeviceMaximum"
};
NTSTATUS
USBDIAG_Power(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
{
PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
NTSTATUS ntStatus = STATUS_SUCCESS;
BOOLEAN fGoingToD0 = FALSE;
POWER_STATE sysPowerState, desiredDevicePowerState;
KEVENT event;
USBDIAG_KdPrint(("'=======================================================================\n"));
USBDIAG_KdPrint(("'USBDIAG_Power() IRP_MJ_POWER\n"));
switch (irpStack->MinorFunction)
{
case IRP_MN_WAIT_WAKE:
USBDIAG_KdPrint(("'==========================================\n"));
USBDIAG_KdPrint(("'USBDIAG_Power() Enter IRP_MN_WAIT_WAKE --\n"));
// The only way this comes through us is if we send it via PoRequestPowerIrp
IoSkipCurrentIrpStackLocation(Irp); // not attaching a completion routine
PoStartNextPowerIrp(Irp);
ntStatus = PoCallDriver(deviceExtension->StackDeviceObject, Irp);
break;
case IRP_MN_SET_POWER:
// The system power policy manager sends this IRP to set the system power state.
// A device power policy manager sends this IRP to set the device power state for a device.
USBDIAG_KdPrint(("'==========================================\n"));
USBDIAG_KdPrint(("'USBDIAG_Power() Enter IRP_MN_SET_POWER\n"));
// Set Irp->IoStatus.Status to STATUS_SUCCESS to indicate that the device
// has entered the requested state. Drivers cannot fail this IRP.
switch (irpStack->Parameters.Power.Type)
{
case SystemPowerState:
// Get input system power state
sysPowerState.SystemState = irpStack->Parameters.Power.State.SystemState;
USBDIAG_KdPrint(("'USBDIAG_Power() Set Power, type SystemPowerState = %s\n",
SystemPowerStateString[sysPowerState.SystemState] ));
// If system is in working state always set our device to D0
// regardless of the wait state or system-to-device state power map
if ( sysPowerState.SystemState == PowerSystemWorking)
{
desiredDevicePowerState.DeviceState = PowerDeviceD0;
USBDIAG_KdPrint(("'USBDIAG_Power() PowerSystemWorking, will set D0, not use state map\n"));
}
else
{
// set to corresponding system state if IRP_MN_WAIT_WAKE pending
if ( deviceExtension->WaitWakeIrp ) // got a WAIT_WAKE IRP pending?
{
// Find the device power state equivalent to the given system state.
// We get this info from the DEVICE_CAPABILITIES struct in our device
// extension (initialized in USBDIAG_PnPAddDevice() )
desiredDevicePowerState.DeviceState =
deviceExtension->DeviceCapabilities.DeviceState[ sysPowerState.SystemState ];
USBDIAG_KdPrint(("'USBDIAG_Power() IRP_MN_WAIT_WAKE pending, will use state map\n"));
}
else
{
// if no wait pending and the system's not in working state, just turn off
desiredDevicePowerState.DeviceState = PowerDeviceD3;
USBDIAG_KdPrint(("'USBDIAG_Power() Not EnabledForWakeup and the system's not in working state,\n settting PowerDeviceD3 (off )\n"));
}
}
//
// We've determined the desired device state; are we already in this state?
//
USBDIAG_KdPrint(("'USBDIAG_Power() Set Power, desiredDevicePowerState = %s\n",
DevicePowerStateString[desiredDevicePowerState.DeviceState]));
if (desiredDevicePowerState.DeviceState != deviceExtension->CurrentDeviceState.DeviceState)
{
// No, request that we be put into this state
// by requesting a new Power Irp from the Pnp manager
deviceExtension->PowerIrp = Irp;
ntStatus = PoRequestPowerIrp(deviceExtension->PhysicalDeviceObject,
IRP_MN_SET_POWER,
desiredDevicePowerState,
// completion routine will pass the Irp down to the PDO
USBDIAG_PoRequestCompletion,
DeviceObject,
NULL);
}
else
{
// Yes, just pass it on to PDO (Physical Device Object)
IoCopyCurrentIrpStackLocationToNext(Irp);
PoStartNextPowerIrp(Irp);
ntStatus = PoCallDriver(deviceExtension->StackDeviceObject, Irp);
USBDIAG_KdPrint(("'USBDIAG_Power() Exit IRP_MN_SET_POWER\n"));
}
break;
case DevicePowerState:
USBDIAG_KdPrint(("'USBDIAG_Power() Set Power, type DevicePowerState = %s\n",
DevicePowerStateString[irpStack->Parameters.Power.State.DeviceState]));
// For requests to D1, D2, or D3 ( sleep or off states ),
// sets deviceExtension->CurrentDeviceState to DeviceState immediately.
// This enables any code checking state to consider us as sleeping or off
// already, as this will imminently become our state.
// For requests to DeviceState D0 ( fully on ), sets fGoingToD0 flag TRUE
// to flag that we must set a completion routine and update
// deviceExtension->CurrentDeviceState there.
// In the case of powering up to fully on, we really want to make sure
// the process is completed before updating our CurrentDeviceState,
// so no IO will be attempted or accepted before we're really ready.
fGoingToD0 = (BOOLEAN)(irpStack->Parameters.Power.State.DeviceState == PowerDeviceD0);
IoCopyCurrentIrpStackLocationToNext(Irp);
if (fGoingToD0) {
USBDIAG_KdPrint(("'USBDIAG_Power() Set PowerIrp Completion Routine, fGoingToD0 =%d\n", fGoingToD0));
IoSetCompletionRoutine(Irp,
USBDIAG_PowerIrp_Complete,
// Always pass FDO to completion routine as its Context;
// This is because the DriverObject passed by the system to the routine
// is the Physical Device Object ( PDO ) not the Functional Device Object ( FDO )
DeviceObject,
TRUE, // invoke on success
TRUE, // invoke on error
TRUE); // invoke on cancellation of the Irp
}
PoStartNextPowerIrp(Irp);
ntStatus = PoCallDriver(deviceExtension->StackDeviceObject,
Irp);
USBDIAG_KdPrint(("'USBDIAG_Power() Exit IRP_MN_SET_POWER\n"));
break;
} /* case irpStack->Parameters.Power.Type */
break; /* IRP_MN_SET_POWER */
case IRP_MN_QUERY_POWER:
//
// A power policy manager sends this IRP to determine whether it can change
// the system or device power state, typically to go to sleep.
//
USBDIAG_KdPrint(("'==========================================\n"));
USBDIAG_KdPrint(("'USBDIAG_Power() IRP_MN_QUERY_POWER\n"));
// We do nothing special here, just let the PDO handle it
IoCopyCurrentIrpStackLocationToNext(Irp);
PoStartNextPowerIrp(Irp);
ntStatus = PoCallDriver(deviceExtension->StackDeviceObject,
Irp);
break; /* IRP_MN_QUERY_POWER */
default:
USBDIAG_KdPrint(("'==========================================\n"));
USBDIAG_KdPrint(("'USBDIAG_Power() UNKNOWN POWER MESSAGE (%x)\n", irpStack->MinorFunction));
//
// All unhandled power messages are passed on to the PDO
//
IoCopyCurrentIrpStackLocationToNext(Irp);
PoStartNextPowerIrp(Irp);
ntStatus = PoCallDriver(deviceExtension->StackDeviceObject, Irp);
}
USBDIAG_KdPrint(("'Exit USBDIAG_Power() ntStatus = 0x%x\n", ntStatus ) );
return ntStatus;
}
NTSTATUS
USBDIAG_SetDevicePowerState(
IN PDEVICE_OBJECT DeviceObject,
IN ULONG ulPowerState
)
{
PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
NTSTATUS ntStatus = STATUS_SUCCESS;
POWER_STATE PowerState;
PowerState.DeviceState = (DEVICE_POWER_STATE)ulPowerState;
deviceExtension->SelfRequestedPowerIrpEvent = ExAllocatePool(NonPagedPool, sizeof(KEVENT));
if (!deviceExtension->SelfRequestedPowerIrpEvent)
return STATUS_INSUFFICIENT_RESOURCES;
KeInitializeEvent(deviceExtension->SelfRequestedPowerIrpEvent, NotificationEvent, FALSE);
ntStatus = PoRequestPowerIrp(deviceExtension->PhysicalDeviceObject,
IRP_MN_SET_POWER,
PowerState,
USBDIAG_PoSelfRequestCompletion,
DeviceObject,
NULL);
if ( ntStatus == STATUS_PENDING )
{
// We only need to wait for completion if we're powering up
if ( deviceExtension->CurrentDeviceState.DeviceState > PowerState.DeviceState )
{
NTSTATUS waitStatus;
waitStatus = KeWaitForSingleObject(
deviceExtension->SelfRequestedPowerIrpEvent,
Suspended,
KernelMode,
FALSE,
NULL);
ExFreePool(deviceExtension->SelfRequestedPowerIrpEvent);
deviceExtension->SelfRequestedPowerIrpEvent = NULL;
}
}
deviceExtension->CurrentDeviceState.DeviceState = PowerState.DeviceState;
USBDIAG_KdPrint(("'CurrentDeviceState set to 0x%x\n",deviceExtension->CurrentDeviceState.DeviceState));
ntStatus = STATUS_SUCCESS;
return ntStatus;
}
NTSTATUS
USBDIAG_PowerIrp_Complete(
IN PDEVICE_OBJECT NullDeviceObject,
IN PIRP Irp,
IN PVOID Context
)
/*++
Routine Description:
This routine is called when An IRP_MN_SET_POWER of type 'DevicePowerState'
has been received by USBDIAG_ProcessPowerIrp(), and that routine has determined
1) the request is for full powerup ( to PowerDeviceD0 ), and
2) We are not already in that state
A call is then made to PoRequestPowerIrp() with this routine set as the completion routine.
Arguments:
DeviceObject - Pointer to the device object for the class device.
Irp - Irp completed.
Context - Driver defined context.
Return Value:
The function value is the final status from the operation.
--*/
{
PDEVICE_OBJECT deviceObject = (PDEVICE_OBJECT) Context;
PDEVICE_EXTENSION deviceExtension = deviceObject->DeviceExtension;
NTSTATUS ntStatus = STATUS_SUCCESS;
PIO_STACK_LOCATION irpStack;
USBDIAG_KdPrint(("'enter USBDIAG_PowerIrp_Complete\n"));
// If the lower driver returned PENDING, mark our stack location as pending also.
if (Irp->PendingReturned)
{
IoMarkIrpPending(Irp);
}
irpStack = IoGetCurrentIrpStackLocation (Irp);
// We can assert that we're a device powerup-to D0 request,
// because that was the only type of request we set a completion routine
// for in the first place
ASSERT(irpStack->MajorFunction == IRP_MJ_POWER);
ASSERT(irpStack->MinorFunction == IRP_MN_SET_POWER);
ASSERT(irpStack->Parameters.Power.Type==DevicePowerState);
ASSERT(irpStack->Parameters.Power.State.DeviceState==PowerDeviceD0);
// Now that we know we've let the lower drivers do what was needed to power up,
// we can set our device extension flags accordingly
deviceExtension->CurrentDeviceState.DeviceState = PowerDeviceD0;
Irp->IoStatus.Status = ntStatus;
USBDIAG_KdPrint(("'exit USBDIAG_PowerIrp_Complete Exit IRP_MN_SET_POWER D0 complete\n"));
return ntStatus;
}
#if 0
NTSTATUS
ISOPERF_ResetPipe(
IN PDEVICE_OBJECT DeviceObject,
IN PUSBD_PIPE_INFORMATION Pipe,
IN BOOLEAN IsoClearStall
)
/*++
Routine Description:
Reset a given USB pipe.
NOTES:
This will reset the host to Data0 and should also reset the device
to Data0 for Bulk and Interrupt pipes.
For Iso pipes this will set the virgin state of pipe so that ASAP
transfers begin with the current bus frame instead of the next frame
after the last transfer occurred.
Arguments:
Return Value:
--*/
{
NTSTATUS ntStatus;
PURB urb;
ISOPERF_KdPrint ( DBGLVL_MEDIUM, (" Reset Pipe %x\n", Pipe));
urb = ExAllocatePool(NonPagedPool,
sizeof(struct _URB_PIPE_REQUEST));
if (urb) {
urb->UrbHeader.Length = (USHORT) sizeof (struct _URB_PIPE_REQUEST);
urb->UrbHeader.Function = URB_FUNCTION_RESET_PIPE;
urb->UrbPipeRequest.PipeHandle =
Pipe->PipeHandle;
ntStatus = ISOPERF_CallUSBD(DeviceObject, urb);
ExFreePool(urb);
} else {
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
}
//
// Memphis RESET_PIPE will send a Clear-Feature Endpoint Stall to
// reset the data toggle of non-Iso pipes as part of a RESET_PIPE
// request. It does not do this for Iso pipes as Iso pipes do not use
// the data toggle (all Iso packets are Data0). However, we also use
// the Clear-Feature Endpoint Stall request in our device firmware to
// reset data buffer points inside the device so we explicitly send
// this request to the device for Iso pipes if desired.
//
if (NT_SUCCESS(ntStatus) && IsoClearStall &&
(Pipe->PipeType == UsbdPipeTypeIsochronous)) {
urb = ExAllocatePool(NonPagedPool,
sizeof(struct _URB_CONTROL_FEATURE_REQUEST));
if (urb)
{
UsbBuildFeatureRequest(urb,
URB_FUNCTION_CLEAR_FEATURE_TO_ENDPOINT,
USB_FEATURE_ENDPOINT_STALL,
Pipe->EndpointAddress,
NULL);
ntStatus = ISOPERF_CallUSBD(DeviceObject, urb);
ExFreePool(urb);
}
else
{
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
}
}
return ntStatus;
}
#endif
NTSTATUS
USBDIAG_DisableRemoteWakeupEnable(
IN PDEVICE_OBJECT DeviceObject,
IN BOOLEAN bDisable
)
{
PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
NTSTATUS ntStatus;
WCHAR KeyName[] = L"DisableRemoteWakeup";
ULONG KeyNameLength = sizeof(KeyName);
PVOID Data = ExAllocatePool(NonPagedPool, sizeof(ULONG));
ULONG DataLength = sizeof(ULONG);
ULONG KeyType = REG_DWORD;
if (Data)
{
*((PULONG)Data) = bDisable ? 0x01 : 0x00;
USBDIAG_KdPrint(("'calling USBD_SetPdoRegistryParameter with Data = 0x%x\n", *((PULONG)Data)));
ntStatus = USBD_SetPdoRegistryParameter(deviceExtension->PhysicalDeviceObject,
KeyName,
KeyNameLength,
Data,
DataLength,
KeyType,
PLUGPLAY_REGKEY_DRIVER);
USBDIAG_KdPrint(("'USBD_SetPdoRegistryParameter returned ntStatus 0x%x\n", ntStatus));
ExFreePool(Data);
Data = NULL;
}
else
{
ntStatus = STATUS_NO_MEMORY;
}
return ntStatus;
}