⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 readwrite.cpp

📁 用ddk和vc实现的一系列关于usb驱动设计的程序,对学习usb驱动的人能有所帮助
💻 CPP
📖 第 1 页 / 共 3 页
字号:
// Read/Write request processors for usbiso 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

typedef struct _RWCONTEXT {
	LIST_ENTRY list;			// list for queuing context structures
	PDEVICE_EXTENSION pdx;		// our device extension address
	PIRP mainirp;				// the main r/w IRP
	NTSTATUS status;			// ending status for main IRP
	ULONG numxfer;				// total number of bytes transferred
	ULONG numirps;				// total number of sub-irps
	LONG numpending;			// number of sub-irps not yet finished
	LONG refcnt;				// reference count (initially 2)
	struct {
		PIRP irp;				// subsidiary IRP
		PURB urb;				// URB packaged with sub-IRP
		PMDL mdl;				// partial MDL for the URB
		} sub[1];
	} RWCONTEXT, *PRWCONTEXT;

BOOLEAN DestroyContextStructure(PRWCONTEXT ctx);
VOID OnCancelReadWrite(PDEVICE_OBJECT fdo, PIRP Irp);
NTSTATUS OnReadWriteComplete(PDEVICE_OBJECT fdo, PIRP Irp, PRWCONTEXT context);
NTSTATUS OnStageComplete(PDEVICE_OBJECT fdo, PIRP Irp, PRWCONTEXT context);

NTSTATUS SelectAlternateInterface(PDEVICE_OBJECT fdo);
NTSTATUS SelectDefaultInterface(PDEVICE_OBJECT fdo);

///////////////////////////////////////////////////////////////////////////////

#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 LOCKEDCODE

BOOLEAN DestroyContextStructure(PRWCONTEXT ctx)
	{							// DestroyContextStructure

	// Decrement the reference count. If it goes to zero, delete
	// all the subsidiary IRPs and the context structure itself.

	if (InterlockedDecrement(&ctx->refcnt) > 0)
		return FALSE;					// still potentially in use
	for (ULONG i = 0; i < ctx->numirps; ++i)
		if (ctx->sub[i].irp)
			IoFreeIrp(ctx->sub[i].irp);
	ExFreePool(ctx);
	return TRUE;
	}							// DestroyContextStructure

///////////////////////////////////////////////////////////////////////////////

#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))
		{						// not deleted
		if (InterlockedIncrement(&pdx->handles) == 1)
			{					// no handles previously open
			status = SelectAlternateInterface(fdo);
			if (!NT_SUCCESS(status))
				{				// error selecting alternate interface
				InterlockedDecrement(&pdx->handles);
				IoReleaseRemoveLock(&pdx->RemoveLock, stack->FileObject);
				}				// error selecting alternate interface
			}					// no handles previously open
		}						// not deleted
	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);
	if (InterlockedDecrement(&pdx->handles) == 0)
		SelectDefaultInterface(fdo);
	
	// 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 DispatchRead(PDEVICE_OBJECT fdo, PIRP Irp)
	{							// DispatchRead
	PAGED_CODE();
	PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION) fdo->DeviceExtension;

	ASSERT(pdx->hinpipe);

	NTSTATUS status = IoAcquireRemoveLock(&pdx->RemoveLock, Irp);
	if (!NT_SUCCESS(status))
		return CompleteRequest(Irp, status, 0);

	// Reset pipe if previous request had an error

	LONG haderr;
	haderr = InterlockedExchange(&pdx->inerror, 0);
	if (haderr && !NT_SUCCESS(ResetPipe(fdo, pdx->hinpipe)))
		ResetDevice(fdo);

	ULONG length = Irp->MdlAddress ?  MmGetMdlByteCount(Irp->MdlAddress) : 0;
	if (!length)
		{						// zero-length read
		IoReleaseRemoveLock(&pdx->RemoveLock, Irp);
		return CompleteRequest(Irp, STATUS_SUCCESS, 0);
		}						// zero-length read

	// Calculate the number of IRPs that we need to submit in order to fulfill the
	// request. One of the ingredients of the calculation is the "packet size" the
	// endpoint uses during each frame. We have to know this number a priori, because
	// it doesn't have a fixed relationship to the endpoint's transfer size. Another
	// ingredient of the calculation is the fact that one URB can accomodate only 255
	// packets. The last ingredient is the maximum transfer size we declared when we
	// first configured the pipe. This driver left the default value in place. Given
	// the value of 16 used here for the packet size, we'll end up with a "segsize" of
	// 4080 bytes in fact.

	ULONG packsize = 16;		// known because we write the firmware
	ULONG segsize = USBD_DEFAULT_MAXIMUM_TRANSFER_SIZE; // default we left in place
	if (segsize / packsize > 255)
		segsize = 255 * packsize;	// maximum based on # packets allowed
	ULONG numirps = (length + segsize - 1) / segsize;

	// Allocate a context structure for use in the main IRP's completion and cancel routines.
	// Build as many IRPs (and URBs) as are required to fulfill the request.

	ULONG ctxsize = sizeof(RWCONTEXT) + (numirps - 1) * sizeof(((PRWCONTEXT) 0)->sub);
	PRWCONTEXT ctx = (PRWCONTEXT) ExAllocatePool(NonPagedPool, ctxsize);
	if (!ctx)
		{
		KdPrint((DRIVERNAME	" - unable to allocate %d bytes for record keeping\n", ctxsize));
		IoReleaseRemoveLock(&pdx->RemoveLock, Irp);
		return CompleteRequest(Irp, STATUS_INSUFFICIENT_RESOURCES, 0);
		}
	RtlZeroMemory(ctx, ctxsize);

	ctx->numirps = ctx->numpending = numirps;
	ctx->pdx = pdx;
	ctx->mainirp = Irp;
	ctx->refcnt = 2;			// one for OnReadWriteComplete, one forOnCancelReadWrite
	Irp->Tail.Overlay.DriverContext[0] = (PVOID) ctx; // for cancel routine

	ULONG i;
	CCHAR stacksize = pdx->LowerDeviceObject->StackSize + 1; // 1 extra for OnStageComplete
	PUCHAR va = (PUCHAR) MmGetMdlVirtualAddress(Irp->MdlAddress);

	for (i = 0; i < numirps; ++i)
		{						// for each IRP

		// Create a subsidiary IRP

		PIRP subirp = IoAllocateIrp(stacksize, FALSE);
		if (!subirp)
			break;				// can't create subsidiary IRP
		ctx->sub[i].irp = subirp;

		// Determine how many packets are required and allocate an URB big enough for all of them

		if (segsize > length)
			segsize = length;	// last transfer is short

		ULONG npackets = (segsize + packsize - 1) / packsize; // # packets needed in this stage
		ASSERT(npackets <= 255);	// else we didn't calculate segsize correctly
		ULONG size = GET_ISO_URB_SIZE(npackets); // size of URB needed for that many packets
		PURB urb = (PURB) ExAllocatePool(NonPagedPool, size);
		if (!urb)
			break;

		ctx->sub[i].urb = urb;

		// Create a partial MDL to map this segment. This is necessary because the offset fields in
		// the packet descriptors we'll build must begin at zero for each URB. (It would have been better
		// if they were just relative to whatever MDL in in the URB.)

		PMDL mdl = IoAllocateMdl((PVOID) va, segsize, FALSE, FALSE, NULL);
		if (!mdl)
			break;				// can't allocate memory for MDL
		IoBuildPartialMdl(Irp->MdlAddress, mdl, (PVOID) va, segsize);
		ctx->sub[i].mdl = mdl;
		va += segsize;			// for next iteration

		// Initialize the URB

		RtlZeroMemory(urb, size);
		urb->UrbIsochronousTransfer.Hdr.Length = (USHORT) size;
		urb->UrbIsochronousTransfer.Hdr.Function = URB_FUNCTION_ISOCH_TRANSFER;
		urb->UrbIsochronousTransfer.PipeHandle = pdx->hinpipe;
		urb->UrbIsochronousTransfer.TransferFlags = USBD_TRANSFER_DIRECTION_IN | USBD_SHORT_TRANSFER_OK | USBD_START_ISO_TRANSFER_ASAP;
		urb->UrbIsochronousTransfer.TransferBufferLength = segsize;
		urb->UrbIsochronousTransfer.TransferBufferMDL = mdl;
		urb->UrbIsochronousTransfer.NumberOfPackets = npackets;

		// Initialize the buffer offset in each packet. The host controller will fill in the packet
		// length in one of two ways. For an input operation, it gets set to whatever the device
		// supplies. For an output operation, the host controller driver sets it based on the buffer
		// offsets.

		ULONG offset = 0;			// packet offset within subsidiary MDL

		for (ULONG j = 0; j < npackets; ++j)
			{						// for each packet
			urb->UrbIsochronousTransfer.IsoPacket[j].Offset = offset;
			ULONG packlen = length > packsize ? packsize : length;
			urb->UrbIsochronousTransfer.IsoPacket[j].Length = 0;

			length -= packlen;
			offset += packlen;
			}						// for each packet

		// Initialize the subsidiary IRP. The first stack location is for use by OnStageComplete,
		// which needs several pieces of information it's inconvenient to pass in a single
		// context pointer. The second stack location will describe an internal IOCTL for USBD.

		IoSetNextIrpStackLocation(subirp);
		PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(subirp);
		stack->DeviceObject = fdo;
		stack->Parameters.Others.Argument1 = (PVOID) urb;
		stack->Parameters.Others.Argument2 = (PVOID) mdl;

		stack = IoGetNextIrpStackLocation(subirp);
		stack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
		stack->Parameters.Others.Argument1 = (PVOID) urb;
		stack->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_URB;
		
		IoSetCompletionRoutine(subirp, (PIO_COMPLETION_ROUTINE) OnStageComplete,
			(PVOID) ctx, TRUE, TRUE, TRUE);
		}						// for each IRP

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -