www.pudn.com > Microsoft Windows驱动程序模型设计 源代码.zip > ReadWrite.cpp


// Read/Write request processors for feature driver 
// Copyright (C) 1999 by Walter Oney 
// All rights reserved 
 
#include "stddcls.h" 
#include "driver.h" 
 
#ifdef DBG 
	#define MSGUSBSTRING(d,s,i) { \ 
		UNICODE_STRING sd; \ 
		if (i && NT_SUCCESS(GetStringDescriptor(d,i,&sd))) { \ 
			DbgPrint(s, sd.Buffer); \ 
			RtlFreeUnicodeString(&sd); \ 
		}} 
#else 
	#define MSGUSBSTRING(d,i,s) 
#endif 
 
/////////////////////////////////////////////////////////////////////////////// 
 
#pragma PAGEDCODE 
 
VOID AbortPipe(PDEVICE_OBJECT fdo, USBD_PIPE_HANDLE hpipe) 
	{							// AbortPipe 
	PAGED_CODE(); 
	PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION) fdo->DeviceExtension; 
	URB urb; 
 
	urb.UrbHeader.Length = (USHORT) sizeof(_URB_PIPE_REQUEST); 
	urb.UrbHeader.Function = URB_FUNCTION_ABORT_PIPE; 
	urb.UrbPipeRequest.PipeHandle = hpipe; 
 
	NTSTATUS status = SendAwaitUrb(fdo, &urb); 
	if (!NT_SUCCESS(status)) 
		KdPrint((DRIVERNAME " - Error %X in AbortPipe\n", status)); 
	}							// AbortPipe 
 
/////////////////////////////////////////////////////////////////////////////// 
 
#pragma PAGEDCODE 
 
NTSTATUS DispatchCreate(PDEVICE_OBJECT fdo, PIRP Irp) 
	{							// DispatchCreate 
	PAGED_CODE(); 
	KdPrint((DRIVERNAME " - IRP_MJ_CREATE\n")); 
	PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION) fdo->DeviceExtension; 
 
	PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(Irp); 
 
	// Claim the remove lock in Win2K so that removal waits until the 
	// handle closes. Don't do this in Win98, however, because this 
	// device might be removed by surprise with handles open, whereupon 
	// we'll deadlock in HandleRemoveDevice waiting for a close that 
	// can never happen because we can't run the user-mode code that 
	// would do the close. 
 
	NTSTATUS status; 
	if (win98) 
		status = STATUS_SUCCESS; 
	else  
		status = IoAcquireRemoveLock(&pdx->RemoveLock, stack->FileObject); 
 
	if (NT_SUCCESS(status)) 
		InterlockedIncrement(&pdx->handles); 
	return CompleteRequest(Irp, status, 0); 
	}							// DispatchCreate 
 
/////////////////////////////////////////////////////////////////////////////// 
 
#pragma PAGEDCODE 
 
NTSTATUS DispatchClose(PDEVICE_OBJECT fdo, PIRP Irp) 
	{							// DispatchClose 
	PAGED_CODE(); 
	KdPrint((DRIVERNAME " - IRP_MJ_CLOSE\n")); 
	PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION) fdo->DeviceExtension; 
	PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(Irp); 
	InterlockedDecrement(&pdx->handles); 
	 
	// Release the remove lock to match the acquisition done in DispatchCreate 
 
	if (!win98) 
		IoReleaseRemoveLock(&pdx->RemoveLock, stack->FileObject); 
 
	return CompleteRequest(Irp, STATUS_SUCCESS, 0); 
	}							// DispatchClose 
 
/////////////////////////////////////////////////////////////////////////////// 
 
#pragma PAGEDCODE 
 
NTSTATUS GetStringDescriptor(PDEVICE_OBJECT fdo, UCHAR istring, PUNICODE_STRING s) 
	{							// GetStringDescriptor 
	NTSTATUS status; 
	PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION) fdo->DeviceExtension; 
	URB urb; 
 
	UCHAR data[256];			// maximum-length buffer 
 
	// If this is the first time here, read string descriptor zero and arbitrarily select 
	// the first language identifer as the one to use in subsequent get-descriptor calls. 
 
	if (!pdx->langid) 
		{						// determine default language id 
		UsbBuildGetDescriptorRequest(&urb, sizeof(_URB_CONTROL_DESCRIPTOR_REQUEST), USB_STRING_DESCRIPTOR_TYPE, 
			0, 0, data, NULL, sizeof(data), NULL); 
		status = SendAwaitUrb(fdo, &urb); 
		if (!NT_SUCCESS(status)) 
			return status; 
		pdx->langid = *(LANGID*)(data + 2); 
		}						// determine default language id 
 
	// Fetch the designated string descriptor. 
 
	UsbBuildGetDescriptorRequest(&urb, sizeof(_URB_CONTROL_DESCRIPTOR_REQUEST), USB_STRING_DESCRIPTOR_TYPE, 
		istring, pdx->langid, data, NULL, sizeof(data), NULL); 
	status = SendAwaitUrb(fdo, &urb); 
	if (!NT_SUCCESS(status)) 
		return status; 
 
	ULONG nchars = (data[0] - 2) / 2; 
	PWSTR p = (PWSTR) ExAllocatePool(PagedPool, data[0]); 
	if (!p) 
		return STATUS_INSUFFICIENT_RESOURCES; 
 
	memcpy(p, data + 2, nchars*2); 
	p[nchars] = 0; 
 
	s->Length = (USHORT) (2 * nchars); 
	s->MaximumLength = (USHORT) ((2 * nchars) + 2); 
	s->Buffer = p; 
 
	return STATUS_SUCCESS; 
	}							// GetStringDescriptor 
 
/////////////////////////////////////////////////////////////////////////////// 
 
#pragma PAGEDCODE 
 
VOID ResetDevice(PDEVICE_OBJECT fdo) 
	{							// ResetDevice 
	PAGED_CODE(); 
	PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION) fdo->DeviceExtension; 
 
	KEVENT event; 
	KeInitializeEvent(&event, NotificationEvent, FALSE); 
	IO_STATUS_BLOCK iostatus; 
 
	PIRP Irp = IoBuildDeviceIoControlRequest(IOCTL_INTERNAL_USB_RESET_PORT, 
		pdx->LowerDeviceObject, NULL, 0, NULL, 0, TRUE, &event, &iostatus); 
	if (!Irp) 
		return; 
 
	NTSTATUS status = IoCallDriver(pdx->LowerDeviceObject, Irp); 
	if (status == STATUS_PENDING) 
		{ 
		KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL); 
		status = iostatus.Status; 
		} 
 
	if (!NT_SUCCESS(status)) 
		KdPrint((DRIVERNAME " - Error %X trying to reset device\n", status)); 
	}							// ResetDevice 
 
/////////////////////////////////////////////////////////////////////////////// 
 
#pragma PAGEDCODE 
 
NTSTATUS ResetPipe(PDEVICE_OBJECT fdo, USBD_PIPE_HANDLE hpipe) 
	{							// ResetPipe 
	PAGED_CODE(); 
	PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION) fdo->DeviceExtension; 
	URB urb; 
 
	urb.UrbHeader.Length = (USHORT) sizeof(_URB_PIPE_REQUEST); 
	urb.UrbHeader.Function = URB_FUNCTION_RESET_PIPE; 
	urb.UrbPipeRequest.PipeHandle = hpipe; 
 
	NTSTATUS status = SendAwaitUrb(fdo, &urb); 
	if (!NT_SUCCESS(status)) 
		KdPrint((DRIVERNAME " - Error %X trying to reset a pipe\n", status)); 
	return status; 
	}							// ResetPipe 
 
/////////////////////////////////////////////////////////////////////////////// 
 
#pragma PAGEDCODE 
 
NTSTATUS SendAwaitUrb(PDEVICE_OBJECT fdo, PURB urb) 
	{							// SendAwaitUrb 
	PAGED_CODE(); 
	ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL); 
	PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION) fdo->DeviceExtension; 
 
	KEVENT event; 
	KeInitializeEvent(&event, NotificationEvent, FALSE); 
 
	IO_STATUS_BLOCK iostatus; 
	PIRP Irp = IoBuildDeviceIoControlRequest(IOCTL_INTERNAL_USB_SUBMIT_URB, 
		pdx->LowerDeviceObject, NULL, 0, NULL, 0, TRUE, &event, &iostatus); 
 
	if (!Irp) 
		{ 
		KdPrint((DRIVERNAME " - Unable to allocate IRP for sending URB\n")); 
		return STATUS_INSUFFICIENT_RESOURCES; 
		} 
 
	PIO_STACK_LOCATION stack = IoGetNextIrpStackLocation(Irp); 
	stack->Parameters.Others.Argument1 = (PVOID) urb; 
	NTSTATUS status = IoCallDriver(pdx->LowerDeviceObject, Irp); 
	if (status == STATUS_PENDING) 
		{ 
		KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL); 
		status = iostatus.Status; 
		} 
	return status; 
	}							// SendAwaitUrb 
 
/////////////////////////////////////////////////////////////////////////////// 
 
#pragma PAGEDCODE 
 
NTSTATUS StartDevice(PDEVICE_OBJECT fdo, PCM_PARTIAL_RESOURCE_LIST raw, PCM_PARTIAL_RESOURCE_LIST translated) 
	{							// StartDevice 
	PAGED_CODE(); 
	NTSTATUS status; 
	PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION) fdo->DeviceExtension; 
 
	URB urb;					// URB for use in this subroutine 
 
	// Read our device descriptor. The only real purpose to this would be to find out how many 
	// configurations there are so we can read their descriptors. In this simplest of examples, 
	// there's only one configuration. 
 
	UsbBuildGetDescriptorRequest(&urb, sizeof(_URB_CONTROL_DESCRIPTOR_REQUEST), USB_DEVICE_DESCRIPTOR_TYPE, 
		0, 0, &pdx->dd, NULL, sizeof(pdx->dd), NULL); 
	status = SendAwaitUrb(fdo, &urb); 
	if (!NT_SUCCESS(status)) 
		{ 
		KdPrint((DRIVERNAME " - Error %X trying to read device descriptor\n", status)); 
		return status; 
		} 
 
	MSGUSBSTRING(fdo, DRIVERNAME " - Configuring device from %ws\n", pdx->dd.iManufacturer); 
	MSGUSBSTRING(fdo, DRIVERNAME " - Product is %ws\n", pdx->dd.iProduct); 
	MSGUSBSTRING(fdo, DRIVERNAME " - Serial number is %ws\n", pdx->dd.iSerialNumber); 
 
	// Read the descriptor of the first configuration. This requires two steps. The first step 
	// reads the fixed-size configuration descriptor alone. The second step reads the 
	// configuration descriptor plus all imbedded interface and endpoint descriptors. 
 
	USB_CONFIGURATION_DESCRIPTOR tcd; 
	UsbBuildGetDescriptorRequest(&urb, sizeof(_URB_CONTROL_DESCRIPTOR_REQUEST), USB_CONFIGURATION_DESCRIPTOR_TYPE, 
		0, 0, &tcd, NULL, sizeof(tcd), NULL); 
	status = SendAwaitUrb(fdo, &urb); 
	if (!NT_SUCCESS(status)) 
		{ 
		KdPrint((DRIVERNAME " - Error %X trying to read configuration descriptor 1\n", status)); 
		return status; 
		} 
 
	ULONG size = tcd.wTotalLength; 
	PUSB_CONFIGURATION_DESCRIPTOR pcd = (PUSB_CONFIGURATION_DESCRIPTOR) ExAllocatePool(NonPagedPool, size); 
	if (!pcd) 
		{ 
		KdPrint((DRIVERNAME " - Unable to allocate %X bytes for configuration descriptor\n", size)); 
		return STATUS_INSUFFICIENT_RESOURCES; 
		} 
 
	__try 
		{ 
		UsbBuildGetDescriptorRequest(&urb, sizeof(_URB_CONTROL_DESCRIPTOR_REQUEST), USB_CONFIGURATION_DESCRIPTOR_TYPE, 
			0, 0, pcd, NULL, size, NULL); 
		status = SendAwaitUrb(fdo, &urb); 
		if (!NT_SUCCESS(status)) 
			{ 
			KdPrint((DRIVERNAME " - Error %X trying to read configuration descriptor 1\n", status)); 
			return status; 
			} 
                                    
		MSGUSBSTRING(fdo, DRIVERNAME " - Selecting configuration named %ws\n", pcd->iConfiguration); 
 
		// Locate the descriptor for the one and only interface we expect to find 
 
		PUSB_INTERFACE_DESCRIPTOR pid = USBD_ParseConfigurationDescriptorEx(pcd, pcd, 
			-1, -1, -1, -1, -1); 
		ASSERT(pid); 
                                    
		MSGUSBSTRING(fdo, DRIVERNAME " - Selecting interface named %ws\n", pid->iInterface); 
 
		// Create a URB to use in selecting a configuration. 
 
		USBD_INTERFACE_LIST_ENTRY interfaces[2] = { 
			{pid, NULL}, 
			{NULL, NULL},		// fence to terminate the array 
			}; 
 
		PURB selurb = USBD_CreateConfigurationRequestEx(pcd, interfaces); 
		if (!selurb) 
			{ 
			KdPrint((DRIVERNAME " - Unable to create configuration request\n")); 
			return STATUS_INSUFFICIENT_RESOURCES; 
			} 
 
		__try 
			{ 
 
			// Verify that the interface describes exactly the endpoints we expect 
 
			if (pid->bNumEndpoints != 0) 
				{ 
				KdPrint((DRIVERNAME " - %d is the wrong number of endpoints\n", pid->bNumEndpoints)); 
				return STATUS_DEVICE_CONFIGURATION_ERROR; 
				} 
 
			PUSBD_INTERFACE_INFORMATION pii = interfaces[0].Interface; 
			ASSERT(pii->NumberOfPipes == pid->bNumEndpoints); 
 
			// Submit the set-configuration request 
 
			status = SendAwaitUrb(fdo, selurb); 
			if (!NT_SUCCESS(status)) 
				{ 
				KdPrint((DRIVERNAME " - Error %X trying to select configuration\n", status)); 
				return status; 
				} 
 
			// Save the configuration and pipe handles 
 
			pdx->hconfig = selurb->UrbSelectConfiguration.ConfigurationHandle; 
 
			// Transfer ownership of the configuration descriptor to the device extension 
			 
			pdx->pcd = pcd; 
			pcd = NULL; 
			} 
		__finally 
			{ 
			ExFreePool(selurb); 
			} 
 
		} 
	__finally 
		{ 
		if (pcd) 
			ExFreePool(pcd); 
		} 
 
	return STATUS_SUCCESS; 
	}							// StartDevice 
 
/////////////////////////////////////////////////////////////////////////////// 
 
#pragma PAGEDCODE 
 
VOID StopDevice(IN PDEVICE_OBJECT fdo, BOOLEAN oktouch /* = FALSE */) 
	{							// StopDevice 
	PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION) fdo->DeviceExtension; 
 
	// If it's okay to touch our hardware (i.e., we're processing an IRP_MN_STOP_DEVICE), 
	// deconfigure the device. 
	 
	if (oktouch) 
		{						// deconfigure device 
		URB urb; 
		UsbBuildSelectConfigurationRequest(&urb, sizeof(_URB_SELECT_CONFIGURATION), NULL); 
		NTSTATUS status = SendAwaitUrb(fdo, &urb); 
		if (!NT_SUCCESS(status)) 
			KdPrint((DRIVERNAME " - Error %X trying to deconfigure device\n", status)); 
		}						// deconfigure device 
 
	if (pdx->pcd) 
		ExFreePool(pdx->pcd); 
	pdx->pcd = NULL; 
	}							// StopDevice