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

📄 readwrite.cpp

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


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



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

// ResetDevice is called during an attempt to recover after an error in order to

// reset the pipe that had the error



#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 != 2)

				{

				KdPrint((DRIVERNAME " - %d is the wrong number of endpoints\n", pid->bNumEndpoints));

				return STATUS_DEVICE_CONFIGURATION_ERROR;

				}



			PUSB_ENDPOINT_DESCRIPTOR ped = (PUSB_ENDPOINT_DESCRIPTOR) pid;

			ped = (PUSB_ENDPOINT_DESCRIPTOR) USBD_ParseDescriptors(pcd, tcd.wTotalLength, ped, USB_ENDPOINT_DESCRIPTOR_TYPE);

			if (!ped || ped->bEndpointAddress != 0x82 || ped->bmAttributes != USB_ENDPOINT_TYPE_BULK || ped->wMaxPacketSize != 64)

				{

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

				return STATUS_DEVICE_CONFIGURATION_ERROR;

				}

			++ped;

			if (!ped || ped->bEndpointAddress != 0x2 || ped->bmAttributes != USB_ENDPOINT_TYPE_BULK || ped->wMaxPacketSize != 64)

				{

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

				return STATUS_DEVICE_CONFIGURATION_ERROR;

				}

			++ped;



			PUSBD_INTERFACE_INFORMATION pii = interfaces[0].Interface;

			ASSERT(pii->NumberOfPipes == pid->bNumEndpoints);



			// Initialize the maximum transfer size for each of the endpoints. The

			// default would be PAGE_SIZE. The firmware itself only has a 4096-byte

			// ring buffer, though. We need to restrict the test applet to that many

			// bytes. In order to exercise the multi-segment aspect of the transfer code,

			// therefore, reduce the maximum transfer size to 1024 bytes.



			pii->Pipes[0].MaximumTransferSize = 1024;

			pii->Pipes[1].MaximumTransferSize = 1024;

			pdx->maxtransfer = 1024;	// save for use in handling reads & writes



			// 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 = pii->Pipes[0].PipeHandle;

			pdx->houtpipe = pii->Pipes[1].PipeHandle;



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



VOID StartIo(PDEVICE_OBJECT fdo, PIRP Irp)

	{							// StartIo

	PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION) fdo->DeviceExtension;



	// Use the remove lock to guard against lower drivers disappearing while 

	// this IRP is active. Whoever sent us this IRP is protecting us from removal

	// at least until our completion routine returns STATUS_SUCCESS, which is why

	// we don't need to use IoSetCompletionRoutineEx in this driver.



	NTSTATUS status = IoAcquireRemoveLock(&pdx->RemoveLock, Irp);

	if (!NT_SUCCESS(status))

		{

		CompleteRequest(Irp, status, 0);

		return;

		}

		

	PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(Irp);

	BOOLEAN read = stack->MajorFunction == IRP_MJ_READ;



	USBD_PIPE_HANDLE hpipe = read ? pdx->hinpipe : pdx->houtpipe;



	// Our strategy will be to do the transfer in stages up to MAXTRANSFER bytes

	// long using a single URB that we resubmit during the completion routine.

	// Note that chained URBs via UrbLink are not supported in either Win98 or Win2K.



	PRWCONTEXT ctx = (PRWCONTEXT) ExAllocatePool(NonPagedPool, sizeof(RWCONTEXT));

	if (!ctx)

		{

		KdPrint((DRIVERNAME " - Can't allocate memory for context structure\n"));

		StartNextPacket(&pdx->dqReadWrite, fdo);

		CompleteRequest(Irp, STATUS_INSUFFICIENT_RESOURCES, 0);

		IoReleaseRemoveLock(&pdx->RemoveLock, Irp);

		return;

		}

	RtlZeroMemory(ctx, sizeof(RWCONTEXT));



	ULONG length = Irp->MdlAddress ?  MmGetMdlByteCount(Irp->MdlAddress) : 0;

	if (!length)

		{						// zero-length read

		StartNextPacket(&pdx->dqReadWrite, fdo);

		CompleteRequest(Irp, STATUS_SUCCESS, 0);

		IoReleaseRemoveLock(&pdx->RemoveLock, Irp);

		return;

		}						// zero-length read

	ULONG_PTR va = (ULONG_PTR) MmGetMdlVirtualAddress(Irp->MdlAddress);



	ULONG urbflags =  USBD_SHORT_TRANSFER_OK | (read ? USBD_TRANSFER_DIRECTION_IN : USBD_TRANSFER_DIRECTION_OUT);



	// Calculate the length of the segment we'll transfer in the first stage. In the original

	// (pre-SP-5) version of this driver, I was transferring just enough data in the first

	// stage to get to a page boundary. John Hyde pointed out that this is incorrect unless the

	// buffer happens to be aligned on a 64-byte boundary because (according to section 5.8.3 of

	// the USB spec) all transfers except the last must be of maximum length. Therefore, I revised

	// this seample to just transfer the pipe maximum each time.



	ULONG seglen = length;

	if (seglen > pdx->maxtransfer)

		{

		seglen = pdx->maxtransfer;

		KdPrint((DRIVERNAME " - Read/write of %d bytes will be done in segments of %d\n",

			length, seglen));

		}



	// Allocate an MDL for each segment of the transfer. The parameters are chosen so

	// that the MDL will have room for a maximum-sized buffer in the worst case where

	// it starts just before a page boundary. (Note that the virtual address argument to

	// IoAllocateMdl is not actually used as an address.)



	PMDL mdl = IoAllocateMdl((PVOID) (PAGE_SIZE - 1), seglen, FALSE, FALSE, NULL);

	if (!mdl)

		{					// can't allocate MDL

		KdPrint((DRIVERNAME " - Can't allocate memory for MDL\n"));

		ExFreePool(ctx);

		StartNextPacket(&pdx->dqReadWrite, fdo);

		CompleteRequest(Irp, STATUS_INSUFFICIENT_RESOURCES, 0);

		IoReleaseRemoveLock(&pdx->RemoveLock, Irp);

		}					// can't allocate MDL



	// Initialize the (partial) MDL to describe the first segment's subset of the user

	// buffer.



	IoBuildPartialMdl(Irp->MdlAddress, mdl, (PVOID) va, seglen);



	// Reader Peter Diaconesco ran across an apparent bug in the Win2K version of UHCD.SYS. Under

	// heavy load conditions, UHCD was bug-checking because its internal call to MmGetSystemAddressForMdl

	// was apparently returning NULL (even though it's not supposed to). We can prevent that problem

	// by mapping the pages in the following "safe" manner:



	if (!GenericGetSystemAddressForMdl(mdl))

		{						// can't map transfer segment

		KdPrint((DRIVERNAME " - Can't map memory for read or write\n"));

		ExFreePool(ctx);

		StartNextPacket(&pdx->dqReadWrite, fdo);

		CompleteRequest(Irp, STATUS_INSUFFICIENT_RESOURCES, 0);

		IoReleaseRemoveLock(&pdx->RemoveLock, Irp);

		return;

		}						// can't map transfer segment



	UsbBuildInterruptOrBulkTransferRequest(ctx, sizeof(_URB_BULK_OR_INTERRUPT_TRANSFER),

		hpipe, NULL, mdl, seglen, urbflags, NULL);



	// Set context structure parameters to pick up where we just left off



	ctx->va = va + seglen;

	ctx->length = length - seglen;

	ctx->mdl = mdl;

	ctx->numxfer = 0;



	// Use the original Read or Write IRP as a container for the URB



	stack = IoGetNextIrpStackLocation(Irp);

	stack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;

	stack->Parameters.Others.Argument1 = (PVOID) (PURB) ctx;

	stack->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_URB;



	IoSetCompletionRoutine(Irp, (PIO_COMPLETION_ROUTINE) OnReadWriteComplete,

		(PVOID) ctx, TRUE, TRUE, TRUE);



	IoCallDriver(pdx->LowerDeviceObject, Irp);

	}							// StartIo



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



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