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

📄 readwrite.cpp

📁 Programming the Microsoft Windows driver model.2nd 随书光盘。内有很多作者送的实用工具和随书源码。WDM编程
💻 CPP
📖 第 1 页 / 共 2 页
字号:
	// 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;



	// 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))

		{

		InterlockedExchangeAdd((PLONG) &ctx->numxfer, (LONG) 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



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,

		0, 1, -1, -1, -1);



	if (!pid)

		{

		KdPrint((DRIVERNAME " - No alternatate interface defined\n"));

		return STATUS_DEVICE_CONFIGURATION_ERROR;

		}



	// Verify the characteristics of the interface



	PUSB_CONFIGURATION_DESCRIPTOR pcd = pdx->pcd;

	PUSB_ENDPOINT_DESCRIPTOR ped = (PUSB_ENDPOINT_DESCRIPTOR) pid;

	ped = (PUSB_ENDPOINT_DESCRIPTOR) USBD_ParseDescriptors(pcd, pcd->wTotalLength, ped, USB_ENDPOINT_DESCRIPTOR_TYPE);



	if (!ped || ped->bmAttributes != USB_ENDPOINT_TYPE_ISOCHRONOUS || ped->wMaxPacketSize < 16)

		{

		KdPrint((DRIVERNAME " - Alternate interface has wrong attributes\n"));

		return STATUS_DEVICE_CONFIGURATION_ERROR;

		}

	

	// Allocate an URB big enough to describe the alternate interface. First determine

	// how many pipes will be opened



	ULONG size = GET_SELECT_INTERFACE_REQUEST_SIZE(pid->bNumEndpoints);

	PURB urb = (PURB) ExAllocatePool(NonPagedPool, size);

	if (!urb)

		{

		KdPrint((DRIVERNAME " - can't allocate %d bytes for Select Interface URB\n", size));

		return STATUS_INSUFFICIENT_RESOURCES;

		}

	RtlZeroMemory(urb, size);



	// Build and submit the URB



	UsbBuildSelectInterfaceRequest(urb, (USHORT) size, pdx->hconfig, 0, 1);

	urb->UrbSelectInterface.Interface.Length = GET_USBD_INTERFACE_SIZE(pid->bNumEndpoints);

	urb->UrbSelectInterface.Interface.Pipes[0].MaximumTransferSize = PAGE_SIZE;



	status = SendAwaitUrb(fdo, urb);

	if (NT_SUCCESS(status))

		{

		pdx->hinpipe = urb->UrbSelectInterface.Interface.Pipes[0].PipeHandle;

		MSGUSBSTRING(fdo, DRIVERNAME " - Selecting interface named %ws\n", pid->iInterface);

		status = STATUS_SUCCESS;

		}

	else

		KdPrint((DRIVERNAME " - Error %X trying to select alternate interface\n", status));





	ExFreePool(urb);

	return status;

	}							// SelectAlternateInterface



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



#pragma PAGEDCODE



NTSTATUS SelectDefaultInterface(PDEVICE_OBJECT fdo)

	{							// SelectDefaultInterface

	NTSTATUS status;

	PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION) fdo->DeviceExtension;

	

	// Allocate an URB big enough to describe the default interface. First determine

	// how many pipes will be opened



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

		0, 0, -1, -1, -1);

	ASSERT(pid);

	ULONG size = GET_SELECT_INTERFACE_REQUEST_SIZE(pid->bNumEndpoints);

	PURB urb = (PURB) ExAllocatePool(NonPagedPool, size);

	if (!urb)

		{

		KdPrint((DRIVERNAME " - can't allocate %d bytes for Select Interface URB\n", size));

		return STATUS_INSUFFICIENT_RESOURCES;

		}

	RtlZeroMemory(urb, size);



	// Build and submit the URB



	UsbBuildSelectInterfaceRequest(urb, (USHORT) size, pdx->hconfig, 0, 0);

	urb->UrbSelectInterface.Interface.Length = GET_USBD_INTERFACE_SIZE(pid->bNumEndpoints);

	status = SendAwaitUrb(fdo, urb);

	if (NT_SUCCESS(status))

		{

		pdx->hinpipe = NULL;

		MSGUSBSTRING(fdo, DRIVERNAME " - Selecting interface named %ws\n", pid->iInterface);

		status = STATUS_SUCCESS;

		}

	else

		KdPrint((DRIVERNAME " - Error %X trying to select default interface\n", status));





	ExFreePool(urb);

	return status;

	}							// SelectDefaultInterface



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



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

			pdx->hinpipe = NULL;



			// 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

⌨️ 快捷键说明

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