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

📄 readwrite.cpp

📁 VC++编写的WINDOWS WDM USB驱动程序
💻 CPP
📖 第 1 页 / 共 3 页
字号:

	// If the IRP/URB construction loop finished early, there must have been a memory allocation
	// error.

	if (i < numirps)
		status = STATUS_INSUFFICIENT_RESOURCES;

	// See if the main IRP has already been cancelled.

	else
		{						// check for cancellation
		IoSetCancelRoutine(Irp, OnCancelReadWrite);
		if (Irp->Cancel)
			{
			status = STATUS_CANCELLED;

			// The main IRP has been cancelled. If the cancellation just happened and our
			// cancel routine was called, the following call to IoSetCancelRoutine will
			// return NULL. In this case, both our cleanup code (see below) and the cancel
			// routine will be calling DestroyContextStructure. One or the other of those
			// calls will finish the cleanup of the structure. Otherwise, it will no longer
			// be possible for our cancel routine to get called and we should get rid of
			// its now-unnecessary claim on the structure.

			if (IoSetCancelRoutine(Irp, NULL))
				--ctx->refcnt;
			}
		else
			status = STATUS_SUCCESS;
		}						// check for cancellation

	// Install a completion routine for the main IRP. It will normally be called when
	// the last stage IRP finishes. It might get called pretty soon, though, if we
	// fail the IRP before submitting the stage IRPs.

	IoSetCompletionRoutine(Irp, (PIO_COMPLETION_ROUTINE) OnReadWriteComplete,
		(PVOID) ctx, TRUE, TRUE, TRUE);
	IoMarkIrpPending(Irp);
	IoSetNextIrpStackLocation(Irp);	// so our completion routine will get called

	// If we need to fail the main IRP, cleanup and fail it now.

	if (!NT_SUCCESS(status))
		{						// abort now
		for (i = 0; i < numirps; ++i)
			{					// release memory we were able to allocate
			if (ctx->sub[i].urb)
				ExFreePool(ctx->sub[i].urb);
			if (ctx->sub[i].mdl)
				IoFreeMdl(ctx->sub[i].mdl);
			}					// release memory we were able to allocate
		CompleteRequest(Irp, status, 0); // will trigger completion routine
		return STATUS_PENDING;
		}						// abort now

	ASSERT(length == 0);		// IRP construction loop didn't work right if not true

	// Install a completion routine for the main IRP. Once this is in place, submit the
	// subsidiary IRPs. Note that we can't touch the main IRP pointer after we submit the
	// subsidiary IRPs because the sub-IRP completion routine (OnStageComplete) may complete it.

	for (i = 0; i < numirps; ++i)
		IoCallDriver(pdx->LowerDeviceObject, ctx->sub[i].irp);

	return STATUS_PENDING;
	}							// DispatchRead

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

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

VOID OnCancelReadWrite(PDEVICE_OBJECT fdo, PIRP Irp)
	{							// OnCancelReadWrite
	
	IoReleaseCancelSpinLock(Irp->CancelIrql);

	// Attempt to cancel all the subsidiary IRPs for this IRP. The main IRP cannot
	// have progressed in the cancellation process past our own completion routine,
	// so it's safe to use DriverContext as a pointer to the context structure.

	PRWCONTEXT ctx = (PRWCONTEXT) Irp->Tail.Overlay.DriverContext[0];
	for (ULONG i = 0; i < ctx->numirps; ++i)
		IoCancelIrp(ctx->sub[i].irp);

	// Release our claim on the context structure and subsidiary IRP pointers. If
	// the completion routine has already run, it's up to us to finish the
	// completion process for this IRP.

	PDEVICE_EXTENSION pdx = ctx->pdx;

	if (DestroyContextStructure(ctx))
		{						// we're last
		CompleteRequest(Irp, STATUS_CANCELLED, 0);
		IoReleaseRemoveLock(&pdx->RemoveLock, Irp);
		}						// we're last
	}							// OnCancelReadWrite

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

#pragma LOCKEDCODE

NTSTATUS OnReadWriteComplete(PDEVICE_OBJECT fdo, PIRP Irp, PRWCONTEXT ctx)
	{							// OnReadWriteComplete
	ASSERT(ctx->mainirp == Irp);
	PDEVICE_EXTENSION pdx = ctx->pdx;

	if (NT_SUCCESS(Irp->IoStatus.Status))
		Irp->IoStatus.Information = ctx->numxfer;
	else
		InterlockedIncrement(&pdx->inerror);

	// Release the context structure. If the cancel routine has run (or can't ever
	// run), we'll return a normal status. If the cancel routine is working now as
	// well, however, return STATUS_MORE_PROCESSING_REQUIRED to stop the completion
	// process for the time being.

	if (DestroyContextStructure(ctx))
		{						// we're last
		IoReleaseRemoveLock(&pdx->RemoveLock, Irp);
		return STATUS_SUCCESS;
		}						// we're last
	else
		return STATUS_MORE_PROCESSING_REQUIRED;
	}							// OnReadWriteComplete

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

#pragma LOCKEDCODE

NTSTATUS OnStageComplete(PDEVICE_OBJECT fdo, PIRP Irp, PRWCONTEXT ctx)
	{							// OnStageComplete
	PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(Irp);
	PIRP mainirp = ctx->mainirp;
	PURB urb = (PURB) stack->Parameters.Others.Argument1;

	NTSTATUS status = Irp->IoStatus.Status;
	if (NT_SUCCESS(status))
		ctx->numxfer += urb->UrbIsochronousTransfer.TransferBufferLength;
	else
		{
		KdPrint((DRIVERNAME " - read failed with status %X (USBD status %X)\n", status, URB_STATUS(urb)));
		ctx->status = status;
		}

#if DBG
	KdPrint((DRIVERNAME " - iso transfer started in frame %8.8lX, %d packets had errors\n",
		urb->UrbIsochronousTransfer.StartFrame, urb->UrbIsochronousTransfer.ErrorCount));
	for (ULONG i = 0; i < urb->UrbIsochronousTransfer.NumberOfPackets; ++i)
		{						// for each packet
		PUSBD_ISO_PACKET_DESCRIPTOR pipd = &urb->UrbIsochronousTransfer.IsoPacket[i];
		KdPrint((DRIVERNAME " - Packet %d, %d bytes, ending status %8.8lX\n", i, pipd->Length, pipd->Status));
		}						// for each packet
#endif

	ExFreePool(urb);
	IoFreeMdl((PMDL) stack->Parameters.Others.Argument2);

	if (InterlockedDecrement(&ctx->numpending) == 0)
		{						// complete main IRP

		// Clear the main IRP's cancel pointer in preparation for completing it. If
		// the cancel routine has already run (or is now running), it called/will call
		// DestroyContextStructure. If IoSetCancelRoutine returns a non-NULL value,
		// however, it means that the cancel routine can never be called. We should
		// therefore use up its reference to the context structure so the main
		// completion routine can delete it.

		if (IoSetCancelRoutine(mainirp, NULL))
			InterlockedDecrement(&ctx->refcnt);	// cancel routine can no longer run
		mainirp->IoStatus.Status = ctx->status;
		IoCompleteRequest(mainirp, IO_NO_INCREMENT);
		}						// complete main IRP

	// Return STATUS_MORE_PROCESSING_REQUIRED to prevent IoCompleteRequest from
	// queuing an APC to release the memory for this subsidiary IRP. A comment
	// in OnReadWriteComplete explains what's going on here

	return STATUS_MORE_PROCESSING_REQUIRED;
	}							// OnStageComplete

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

#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 SelectAlternateInterface(PDEVICE_OBJECT fdo)
	{							// SelectAlternateInterface
	NTSTATUS status;
	PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION) fdo->DeviceExtension;

	// Locate the descriptor for the alternate interface we want

	PUSB_INTERFACE_DESCRIPTOR pid = USBD_ParseConfigurationDescriptorEx(pdx->pcd, pdx->pcd,

⌨️ 快捷键说明

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