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

📄 read.c

📁 微软的point of sale的源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/*++

Copyright (c) 1999  Microsoft Corporation

Module Name:

    read.c

Abstract: ESC/POS (serial) interface for USB Point-of-Sale devices

Author:

    ervinp

Environment:

    Kernel mode

Revision History:


--*/

#include <WDM.H>

#include <usbdi.h>
#include "usbdlib.h"
#include <usbioctl.h>

#include "escpos.h"
#include "debug.h"




NTSTATUS ReadComPort(POSPDOEXT *pdoExt, PIRP irp)
{
	NTSTATUS status;
	PIO_STACK_LOCATION currentIrpSp;

    /* 
     *  In order to support ODD ENDPOINTs, we check
     *  whether this COM port has a read endpoint or not.
     */
    if(!pdoExt->inputEndpointInfo.pipeHandle) {
        DBGVERBOSE(("This PORT does not have an IN endpoint - Read request Rejected."));
        return STATUS_NOT_SUPPORTED;
    }

	DBGVERBOSE(("ReadComPort"));

	currentIrpSp = IoGetCurrentIrpStackLocation(irp);

	ASSERT(currentIrpSp->Parameters.Read.Length);
	ASSERT(!irp->MdlAddress);

	/*
	 *  Because this device object uses buffering method METHOD_NEITHER,
	 *  the read buffer is irp->UserBuffer, which is potentially an application
	 *  read buffer.  If the read completes on a different thread than this calling
	 *  thread, then the completion routine will not have the read buffer addressed
	 *  correctly.
	 *  Therefore, we have to map the UserBuffer using an MDL.
	 */
	irp->MdlAddress = MmCreateMdl(NULL, irp->UserBuffer, currentIrpSp->Parameters.Read.Length);

	if (irp->MdlAddress){
		status = STATUS_SUCCESS;
		
		__try {
			/*
			 *  We're writing the read data to the buffer, so probe for WriteAccess.
			 */
			MmProbeAndLockPages(irp->MdlAddress, UserMode, IoWriteAccess);
		}
		__except(EXCEPTION_EXECUTE_HANDLER) {
			status = GetExceptionCode();
			DBGERR(("MmProbeAndLockPages triggered exception status %xh.", status));
		}

		if (NT_SUCCESS(status)){

            status = EnqueueReadIrp(pdoExt, irp, FALSE, FALSE);

			if (status == STATUS_PENDING){
            	BOOLEAN doReadNow;
            	KIRQL oldIrql;

                /*
                 *  Atomically test-and-set the endpointIsBusy flag.
                 *  If the endpoint was not busy, issue a read after dropping the lock.
                 */
            	KeAcquireSpinLock(&pdoExt->devExtSpinLock, &oldIrql);
				if (pdoExt->inputEndpointInfo.endpointIsBusy){
                    doReadNow = FALSE;
                }
                else {
					pdoExt->inputEndpointInfo.endpointIsBusy = TRUE;
					doReadNow = TRUE;
				}
    			KeReleaseSpinLock(&pdoExt->devExtSpinLock, oldIrql);

			    if (doReadNow){
				    IssueReadForClient(pdoExt);
			    }
			}


		}
	}
	else {
		DBGERR(("MmCreateMdl failed"));
		status = STATUS_DATA_ERROR;
	}

	return status;
}


VOID SatisfyPendingReads(POSPDOEXT *pdoExt)
{
	LIST_ENTRY irpsToCompleteList, readPacketsToFree;
    PLIST_ENTRY listEntry;
	PIRP irp;
	READPACKET *readPacket;
    KIRQL oldIrql;

	DBGVERBOSE(("SatisfyPendingReads"));

	/*
	 *  Accumulate the complete-ready IRPs on a private queue before completing.
	 *  This is so we don't loop forever if they get re-queued on the same thread.
	 */
	InitializeListHead(&irpsToCompleteList);
	InitializeListHead(&readPacketsToFree);

    KeAcquireSpinLock(&pdoExt->devExtSpinLock, &oldIrql);

	while (irp = DequeueReadIrp(pdoExt, TRUE)){

		PIO_STACK_LOCATION currentIrpSp = IoGetCurrentIrpStackLocation(irp);
		BOOLEAN canSatisfyOneIrp;

		/*
		 *  Do we have enough bytes to satisfy this IRP ?
		 */
		#if PARTIAL_READ_BUFFERS_OK
			canSatisfyOneIrp = (pdoExt->totalQueuedReadDataLength > 0);
		#else
			canSatisfyOneIrp = (pdoExt->totalQueuedReadDataLength >= currentIrpSp->Parameters.Read.Length);
		#endif

		if (canSatisfyOneIrp){

			ULONG userBufferOffset = 0;
			BOOLEAN satisfiedThisIrp = FALSE;
			PUCHAR mappedUserBuffer;

			ASSERT(irp->MdlAddress);
			ASSERT(!IsListEmpty(&pdoExt->completedReadPacketsList));

			/*
			 *  We may be completing this IRP on a different thread than the calling thread.
			 *  So we cannot dereference UserBuffer directly.
			 *  Use the MDL we created at call time instead.
			 */
			mappedUserBuffer = PosMmGetSystemAddressForMdlSafe(irp->MdlAddress);

			if (mappedUserBuffer){

				while (!IsListEmpty(&pdoExt->completedReadPacketsList) &&
					   (userBufferOffset < currentIrpSp->Parameters.Read.Length)){

					ULONG bytesToCopy;
					BOOLEAN thisIrpFull;

					listEntry = RemoveHeadList(&pdoExt->completedReadPacketsList);
					ASSERT(listEntry);
					readPacket = CONTAINING_RECORD(listEntry, READPACKET, listEntry);
					ASSERT(readPacket->signature == READPACKET_SIG);

					bytesToCopy = MIN(currentIrpSp->Parameters.Read.Length-userBufferOffset,
									  readPacket->length-readPacket->offset);
					ASSERT(bytesToCopy <= pdoExt->totalQueuedReadDataLength);

					DBGVERBOSE(("SatisfyPendingReads: transferring %xh bytes to read irp", bytesToCopy));

					/*
					 *  Since we may be completing this IRP on a different thread than
					 *  the one we got it on, we cannot write into the UserBuffer.
					 *  We have to write into the MDL we allocated when we queued this IRP.
					 */
					RtlCopyMemory(mappedUserBuffer+userBufferOffset,
								  readPacket->data+readPacket->offset,
								  bytesToCopy);

					userBufferOffset += bytesToCopy;
					readPacket->offset += bytesToCopy;
					pdoExt->totalQueuedReadDataLength -= bytesToCopy;

					ASSERT(userBufferOffset <= currentIrpSp->Parameters.Read.Length);
					ASSERT(readPacket->offset <= readPacket->length);

					#if PARTIAL_READ_BUFFERS_OK
						thisIrpFull = (userBufferOffset > 0);
					#else
						thisIrpFull = (userBufferOffset >= currentIrpSp->Parameters.Read.Length);
					#endif

					if (thisIrpFull){
						/*
						 *  We've satisfied this IRP.
						 *  Break out of the inner loop so we get a new IRP.
						 *  Put the readPacket back in its queue in case there
						 *  are more bytes left in it.
						 */
						irp->IoStatus.Information = userBufferOffset;
						irp->IoStatus.Status = STATUS_SUCCESS;
						InsertTailList(&irpsToCompleteList, &irp->Tail.Overlay.ListEntry);
						InsertHeadList(&pdoExt->completedReadPacketsList, &readPacket->listEntry);
						satisfiedThisIrp = TRUE;
						break;
					}
					else if (readPacket->offset == readPacket->length){
						/*
						 *  We've depleted this readPacket buffer.
						 */
                        InsertTailList(&readPacketsToFree, &readPacket->listEntry);
						ASSERT(!IsListEmpty(&pdoExt->completedReadPacketsList));
					}
					else {
						DBGERR(("SatisfyPendingReads - data error"));
						break;
					}

				}

				ASSERT(satisfiedThisIrp);
			}
			else {
				DBGERR(("PosMmGetSystemAddressForMdlSafe failed"));
				irp->IoStatus.Information = 0;
				irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
				InsertTailList(&irpsToCompleteList, &irp->Tail.Overlay.ListEntry);
			}
		}
		else {
			/*
			 *  We can't satisfy this IRP, so put it back at the head of the list.
			 */
            NTSTATUS status;
			DBGVERBOSE(("SatisfyPendingReads: not enough bytes to satisfy irp (%xh/%xh)", pdoExt->totalQueuedReadDataLength, currentIrpSp->Parameters.Read.Length));
            status = EnqueueReadIrp(pdoExt, irp, TRUE, TRUE);
            if (status == STATUS_CANCELLED){
                /*
                 *  The IRP was cancelled and the cancel routine was not called,
                 *  so complete the IRP here.
                 */
				irp->IoStatus.Information = 0;
                irp->IoStatus.Status = status;
    			InsertTailList(&irpsToCompleteList, &irp->Tail.Overlay.ListEntry);
            }

			break;
		}

	}

    KeReleaseSpinLock(&pdoExt->devExtSpinLock, oldIrql);

⌨️ 快捷键说明

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