usbcounterdevice.cpp
来自「WindowsXP WDM驱动程序开发实例」· C++ 代码 · 共 518 行
CPP
518 行
// USBCounterDevice.cpp
// Implementation of USBCounterDevice device class
//
// Generated by DriverWizard version DriverStudio 2.6.0 (Build 336)
// Requires Compuware's DriverWorks classes
//
#pragma warning(disable:4065) // Allow switch statement with no cases
#include <vdw.h>
#include <kusb.h>
#include "..\USBCounterDeviceinterface.h"
#include "USBCounter.h"
#include "USBCounterDevice.h"
#include "..\USBCounterioctl.h"
#pragma hdrstop("USBCounter.pch")
extern KTrace t; // Global driver trace object
GUID USBCounterDevice_Guid = USBCounterDevice_CLASS_GUID;
////////////////////////////////////////////////////////////////////////
// USBCounterDevice::USBCounterDevice
//
// Routine Description:
// This is the constructor for the Functional Device Object, or FDO.
// It is derived from KPnpDevice, which builds in automatic
// dispatching of subfunctions of IRP_MJ_POWER and IRP_MJ_PNP to
// virtual member functions.
//
// Parameters:
// Pdo - Physical Device Object - this is a pointer to a system
// device object that represents the physical device.
//
// Unit - Unit number. This is a number to append to the device's
// base device name to form the Logical Device Object's name
//
// Return Value:
// None
//
// Comments:
// The object being constructed contains a data member (m_Lower) of type
// KPnpLowerDevice. By initializing it, the driver binds the FDO to the
// PDO and creates an interface to the upper edge of the system class driver.
//
USBCounterDevice::USBCounterDevice(PDEVICE_OBJECT Pdo, ULONG Unit) :
KPnpDevice(Pdo, &USBCounterDevice_Guid)
{
t << "Entering USBCounterDevice (constructor)\n";
// Check constructor status
if ( ! NT_SUCCESS(m_ConstructorStatus) )
{
return;
}
// Remember our unit number
m_Unit = Unit;
// Initialize the lower device
m_Lower.Initialize(this, Pdo);
// Initialize the interface object. The wizard generates code
// to support a single interface. You may create and add additional
// interfaces. By default, the wizard uses InterfaceNumber 0 (the
// first interface descriptor), ConfigurationValue 1 (the first
// configuration descriptor), and initial interface alternate
// setting of 0. If your device has multiple interfaces or alternate
// settings for an interface, you can add additional KUsbInterface
// objects or adjust the parameters passed to this function.
m_Interface.Initialize(
m_Lower, //KUsbLowerDevice
0, //InterfaceNumber
1, //ConfigurationValue
0 //Initial Interface Alternate Setting
);
// Initialize each Pipe object
m_Endpoint1IN.Initialize(m_Lower, 0x81, 8);
// Inform the base class of the lower edge device object
SetLowerDevice(&m_Lower);
// Initialize the PnP Policy settings to the "standard" policy
SetPnpPolicy();
// TODO: Customize the PnP Policy for this device by setting
// flags in m_Policies.
m_pItem.Initialize(Pdo);
}
USBCounterDevice::~USBCounterDevice()
{
t << "Entering ~USBCounterDevice() (destructor)\n";
}
NTSTATUS USBCounterDevice::DefaultPnp(KIrp I)
{
I.ForceReuseOfCurrentStackLocationInCalldown();
return m_Lower.PnpCall(this, I);
}
NTSTATUS USBCounterDevice::DefaultPower(KIrp I)
{
I.IndicatePowerIrpProcessed();
I.CopyParametersDown();
return m_Lower.PnpPowerCall(this, I);
}
NTSTATUS USBCounterDevice::SystemControl(KIrp I)
{
I.ForceReuseOfCurrentStackLocationInCalldown();
return m_Lower.PnpCall(this, I);
}
NTSTATUS USBCounterDevice::OnStartDevice(KIrp I)
{
t << "Entering OnStartDevice\n";
NTSTATUS status = STATUS_UNSUCCESSFUL;
AC_STATUS acStatus = AC_SUCCESS;
I.Information() = 0;
// The default Pnp policy has already cleared the IRP with the lower device
//By default, the wizard passes a ConfigurationValue of 1 to
//ActivateConfiguration(). This corresponds to the first configuration
//that the device reports in its configuration descriptor. If the device
//supports multiple configurations, pass the appropriate
//ConfigurationValue of the configuration to activate here.
acStatus = m_Lower.ActivateConfiguration(
1 // ConfigurationValue 1 (the first configuration)
);
switch (acStatus)
{
case AC_SUCCESS:
status = STATUS_INSUFFICIENT_RESOURCES;
m_buffer = new (NonPagedPool) UCHAR[8];
if ( m_buffer == NULL)
{
m_Lower.ReleaseResources();
break;
}
m_kIrp = KIrp::Allocate( m_Lower.StackRequirement() );
if ( m_kIrp == NULL )
{
delete m_buffer;
m_Lower.ReleaseResources();
break;
}
// allocate and initialize an URB
m_pUrb = m_Endpoint1IN.BuildInterruptTransfer(
m_buffer, // transfer buffer
1, // transfer buffer size
TRUE, // Short Ok
NULL, // link urb
NULL // new urb
);
if ( m_pUrb == NULL )
{
KIrp::Deallocate(m_kIrp);
delete m_buffer;
m_Lower.ReleaseResources();
break;
}
t << "USB Configuration OK\n";
GetStringDescriptors();
status = STATUS_SUCCESS;
break;
case AC_COULD_NOT_LOCATE_INTERFACE:
t << "Could not locate interface\n";
break;
case AC_COULD_NOT_PRECONFIGURE_INTERFACE:
t << "Could not get configuration descriptor\n";
break;
case AC_CONFIGURATION_REQUEST_FAILED:
t << "Board did not accept configuration URB\n";
break;
case AC_FAILED_TO_INITIALIZE_INTERFACE_OBJECT:
t << "Failed to initialize interface object\n";
break;
case AC_FAILED_TO_GET_DESCRIPTOR:
t << "Failed to get device descriptor\n";
break;
case AC_FAILED_TO_OPEN_PIPE_OBJECT:
//NOTE: this may not be an error. It could mean that
//the device has an endpoint for which a KUsbPipe object has
//not been instanced. If the intention is to not use this endpoint,
//then it's likely not a problem.
status = STATUS_SUCCESS;
t << "Failed to open pipe object\n";
break;
default:
t << "Unexpected error activating USB configuration\n";
break;
}
return status; // base class completes the IRP
}
NTSTATUS USBCounterDevice::OnStopDevice(KIrp I)
{
t << "Entering OnStopDevice\n";
m_Lower.DeActivateConfiguration();
return STATUS_SUCCESS;
}
NTSTATUS USBCounterDevice::OnRemoveDevice(KIrp I)
{
t << "Entering OnRemoveDevice\n";
if ( m_pUrb != NULL ) delete m_pUrb;
if ( m_kIrp != NULL ) KIrp::Deallocate(m_kIrp);
if ( m_buffer != NULL ) delete m_buffer;
// Device removed, release the system resources used by the USB lower device.
m_Lower.ReleaseResources();
return STATUS_SUCCESS;
}
////////////////////////////////////////////////////////////////////////
// USBCounterDevice::OnQueryCapabilities
//
// Handler for IRP_MJ_PNP subfunction IRP_MN_QUERY_CAPABILITIES
//
// Input
// I Current IRP
//
// Notes
// This function is implemented to allow surprise removal of the
// counter
//
NTSTATUS USBCounterDevice::OnQueryCapabilities(KIrp I)
{
I.CopyParametersDown();
I.SetCompletionRoutine(LinkTo(OnQueryCapabilitiesComplete), this);
return m_Lower.PnpCall(this, I);
}
NTSTATUS USBCounterDevice::OnQueryCapabilitiesComplete(KIrp I)
{
if (I->PendingReturned)
I.MarkPending();
I.DeviceCapabilities()->SurpriseRemovalOK = TRUE;
return STATUS_SUCCESS;
}
NTSTATUS USBCounterDevice::Create(KIrp I)
{
NTSTATUS status;
status = I.PnpComplete(this, STATUS_SUCCESS, IO_NO_INCREMENT);
return status;
}
NTSTATUS USBCounterDevice::Close(KIrp I)
{
NTSTATUS status;
status = I.PnpComplete(this, STATUS_SUCCESS, IO_NO_INCREMENT);
return status;
}
NTSTATUS USBCounterDevice::DeviceControl(KIrp I)
{
NTSTATUS status;
t << "Entering Device Control, " << I << EOL;
switch (I.IoctlCode())
{
case READ_COUNTER:
status = ReadCounterAsynch(I);
break;
case RESET_COUNTER:
status = ResetCounter();
break;
default:
// Unrecognized IOCTL request
status = STATUS_INVALID_PARAMETER;
break;
}
// If the IRP's IOCTL handler deferred processing using some driver
// specific scheme, the status variable is set to STATUS_PENDING.
// In this case we simply return that status, and the IRP will be
// completed later. Otherwise, complete the IRP using the status
// returned by the IOCTL handler.
if (status == STATUS_PENDING)
{
return status;
}
else
{
return I.PnpComplete(this, status);
}
}
void USBCounterDevice::GetStringDescriptors(void)
{
NTSTATUS status = STATUS_SUCCESS;
PWCHAR String = (PWCHAR) new (NonPagedPool) WCHAR[MAXIMUM_USB_STRING_LENGTH];
if(NULL == String)
{
//error during allocation
t << "ERROR: Memory allocation error in GetStringDescriptors().\n";
return;
}
USB_DEVICE_DESCRIPTOR desc;
status = m_Lower.GetDeviceDescriptor( &desc );
if ( !NT_SUCCESS(status) )
{
t << "ERROR: Could not get Device Descriptor.\n";
delete String;
return;
}
t << "Index of Manufacturer string = " << desc.iManufacturer << "\n";
t << "Index of Product string = " << desc.iProduct << "\n";
t << "Index of Serial Number string = " << desc.iSerialNumber << "\n";
t << "Number of configurations = " << desc.bNumConfigurations << "\n";
t << "Index of configuration string = " << m_Lower.m_Config->iConfiguration << "\n";
t << "***** USB Counter String Descriptors *****\n";
for(UCHAR i = 0; i <= NUM_STRING_DESCRIPTORS; i++)
{
RtlZeroMemory(String, MAXIMUM_USB_STRING_LENGTH * sizeof(WCHAR));
if(NT_SUCCESS(status = m_Lower.GetStringDescriptor(
i,
String,
MAXIMUM_USB_STRING_LENGTH,
0x109)))
{
if (i==0)
{
PUSHORT languageid = (PUSHORT)String;
t << "String " << i << ": " << *languageid << "\n";
}
else
t << "String " << i << ": " << String << "\n";
}
else
{
t << "GetStringDescriptor returns status = " << ULONG(status) << "\n";
}
}
delete String;
}
NTSTATUS USBCounterDevice::ResetCounter()
{
PURB pUrb;
NTSTATUS status;
UCHAR buffer[8];
memset(buffer, 0, 8);
pUrb = m_Lower.BuildVendorRequest(
buffer, // transfer buffer
8, // transfer buffer size
0, // request reserved bits
0, // request
0, // Value
TRUE, // In (??)
TRUE, // Short Ok
NULL, // link urb
0, // index
URB_FUNCTION_VENDOR_ENDPOINT // function
);
if ( pUrb == NULL )
{
status = STATUS_INSUFFICIENT_RESOURCES;
}
else
{
// submit the URB to USBD
status = m_Lower.SubmitUrb(pUrb);
delete pUrb;
}
return status;
}
NTSTATUS USBCounterDevice::ReadCounterAsynch(KIrp I)
{
I.Information() = 0;
m_pUrb = m_Endpoint1IN.BuildInterruptTransfer(
m_buffer, // transfer buffer
1, // transfer buffer size
TRUE, // Short Ok
NULL, // link urb
m_pUrb // new urb
);
if ( m_pUrb == NULL )
{
return STATUS_INSUFFICIENT_RESOURCES;;
}
PVOID CI = InterlockedCompareExchangePointer( (PVOID*)&CurrentIrp(), PVOID( PIRP(I)), NULL);
// Allow only one request at a time
if ( CI != NULL ) return STATUS_DEVICE_BUSY;
CancelSpinLock::Acquire();
if ( I.WasCanceled() )
{
CurrentIrp() = NULL;
CancelSpinLock::Release();
return STATUS_CANCELLED;
}
I.SetCancelRoutine( LinkTo(Cancel) );
CancelSpinLock::Release();
I.MarkPending();
t << "Submit URB\n";
// submit the URB to USBD
IncrementOutstandingRequestCount();
m_Endpoint1IN.SubmitUrb(m_kIrp, m_pUrb, LinkTo(ReadCounterComplete),this);
return STATUS_PENDING;
}
NTSTATUS USBCounterDevice::ReadCounterComplete(KIrp I)
{
t << "Completion routine\n";
KIrp Current( CurrentIrp() );
if ( Current == NULL )
{
DecrementOutstandingRequestCount();
return STATUS_MORE_PROCESSING_REQUIRED;
}
CancelSpinLock::Acquire();
if ( Current.WasCanceled() )
{
CancelSpinLock::Release();
DecrementOutstandingRequestCount();
return STATUS_MORE_PROCESSING_REQUIRED;
}
else
{
Current.SetCancelRoutine(NULL);
CancelSpinLock::Release();
CurrentIrp() = NULL;
}
if ( I.Status() != STATUS_SUCCESS )
{
NTSTATUS status = I.Status();
Current.PnpComplete(this, status);
DecrementOutstandingRequestCount();
return STATUS_MORE_PROCESSING_REQUIRED;
}
// find the buffer pointer in the URB
PUCHAR buffer = (PUCHAR)m_pUrb->UrbBulkOrInterruptTransfer.TransferBuffer;
PUCHAR IrpBuffer;
// Dump the buffer
t << "Urb data[0]: " << buffer[0] << "\n";
// Data from the IRP read is stored in the ioctl buffer associated with this
// IRP:
IrpBuffer = PUCHAR(Current.IoctlBuffer());
IrpBuffer[0] = buffer[0];
Current.Information() = 1;
Current.PnpComplete(this, STATUS_SUCCESS);
DecrementOutstandingRequestCount();
return STATUS_MORE_PROCESSING_REQUIRED;
}
VOID USBCounterDevice::Cancel(KIrp I)
{
if ( (PIRP)I == CurrentIrp() )
{
CurrentIrp() = NULL;
CancelSpinLock::Release(I.CancelIrql());
I.Information() = 0;
I.PnpComplete(this, STATUS_CANCELLED);
IncrementOutstandingRequestCount();
m_pItem.Queue(LinkTo(Workitem), this);
}
else
CancelSpinLock::Release(I.CancelIrql());
}
VOID USBCounterDevice::Workitem()
{
m_Endpoint1IN.Abort();
DecrementOutstandingRequestCount();
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?