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 + -
显示快捷键?