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

📄 comport.c

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

Copyright (c) 1999  Microsoft Corporation

Module Name:

    comport.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 CreateSymbolicLink(POSPDOEXT *pdoExt)
{
	NTSTATUS status;
	PWCHAR comPortName;
	static WCHAR comNamePrefix[] = L"\\DosDevices\\COM";
	WCHAR buf[sizeof(comNamePrefix)/sizeof(WCHAR) + 4];
	LONG numLen = MyLog(10, pdoExt->comPortNumber)+1;

	ASSERT((numLen > 0) && (numLen <= 4));

	RtlCopyMemory(buf, comNamePrefix, sizeof(comNamePrefix));

	NumToDecString(	buf+sizeof(comNamePrefix)/sizeof(WCHAR)-1, 
					(USHORT)pdoExt->comPortNumber, 
					(USHORT)numLen);
	buf[sizeof(comNamePrefix)/sizeof(WCHAR) - 1 + numLen] = UNICODE_NULL;

	comPortName = MemDup(buf, sizeof(buf));
	if (comPortName){
		RtlInitUnicodeString(&pdoExt->symbolicLinkName, comPortName);

		status = IoCreateSymbolicLink(&pdoExt->symbolicLinkName, &pdoExt->pdoName);
		if (NT_SUCCESS(status)){
			UNICODE_STRING comPortSuffix;

			/*
			 *  Create the '\Device\POS_x = COMx' entry under HKLM\DEVICEMAP\SERIALCOMM
			 */
			RtlInitUnicodeString(&comPortSuffix, pdoExt->symbolicLinkName.Buffer+(sizeof(L"\\DosDevices\\")-sizeof(WCHAR))/sizeof(WCHAR));
			status = RtlWriteRegistryValue(	RTL_REGISTRY_DEVICEMAP, 
                                            L"SERIALCOMM",
                                            pdoExt->pdoName.Buffer, 
                                            REG_SZ,
                                            comPortSuffix.Buffer,
                                            comPortSuffix.Length + sizeof(WCHAR));
            if (NT_SUCCESS(status)){
                if (isWin9x){
                    NTSTATUS tmpStatus;

                    /*
                     *  Delete the temporary 'COMx=COMx' holder value we created earlier.
                     */
                    tmpStatus = RtlDeleteRegistryValue( RTL_REGISTRY_DEVICEMAP, 
                                                        L"SERIALCOMM",
                                                        comPortSuffix.Buffer);
                }
            }
            else {
                DBGERR(("CreateSymbolicLink: RtlWriteRegistryValue failed with status %xh.", status));
            }

		}
        else {
            DBGERR(("IoCreateSymbolicLink failed with status %xh.", status));
        }
	}
	else {
        ASSERT(comPortName);
		status = STATUS_INSUFFICIENT_RESOURCES;
	}

	return status;
}


NTSTATUS DestroySymbolicLink(POSPDOEXT *pdoExt)
{
	NTSTATUS status;

    /*
     *  Delete the symbolic link.
     *  pdoExt->pdoName.Buffer, which was allocated at pdo creation time,
     *  will get deleted when we delete the pdo.
     */
	ASSERT(pdoExt->symbolicLinkName.Buffer);
	IoDeleteSymbolicLink(&pdoExt->symbolicLinkName);

	status = RtlDeleteRegistryValue(RTL_REGISTRY_DEVICEMAP, 
					L"SERIALCOMM",
					pdoExt->pdoName.Buffer);

	FREEPOOL(pdoExt->symbolicLinkName.Buffer);

	return status;
}


NTSTATUS OpenComPort(POSPDOEXT *pdoExt, PIRP irp)
{
	NTSTATUS status;
	PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(irp);

	// BUGBUG FINISH - security, permissions, etc.

	DBGVERBOSE(("OpenComPort: shareAccess=%xh, desiredAccess=%xh, options=%xh.", 
							(ULONG)irpSp->Parameters.Create.ShareAccess, 
							(ULONG)irpSp->Parameters.Create.SecurityContext->DesiredAccess, 
							(ULONG)irpSp->Parameters.Create.Options));

	if (irpSp->Parameters.Create.Options & FILE_DIRECTORY_FILE){
        /*
         *  Attempt to open this device as a directory
         */
		DBGWARN(("OpenComPort: STATUS_NOT_A_DIRECTORY"));
	        status = STATUS_NOT_A_DIRECTORY;
	}
	else {
		FILEEXT *fileExt = ALLOCPOOL(NonPagedPool, sizeof(FILEEXT));
		if (fileExt){
			KIRQL oldIrql;

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

			if (IsListEmpty(&pdoExt->fileExtensionList)){

				ASSERT(irpSp->FileObject->FsContext == NULL);
				irpSp->FileObject->FsContext = fileExt;	// BUGBUG ?

				fileExt->signature = ESCPOS_TAG;
				fileExt->fileObject = irpSp->FileObject;
				InsertTailList(&pdoExt->fileExtensionList, &fileExt->listEntry);
				status = STATUS_SUCCESS;
			}
			else {
				/*
				 *  Only allow one open for now
				 */
				DBGWARN(("OpenComPort: failing repeat open"));
				FREEPOOL(fileExt);
				status = STATUS_SHARING_VIOLATION;
			}

			KeReleaseSpinLock(&pdoExt->devExtSpinLock, oldIrql);
		}
		else {
			status = STATUS_INSUFFICIENT_RESOURCES;
		}
	}

	irp->IoStatus.Information = 0;

	return status;
}


NTSTATUS CloseComPort(POSPDOEXT *pdoExt, PIRP irp)
{
	NTSTATUS status;
	KIRQL oldIrql;
	FILEEXT *callerFileExt, *myFileExt;
	PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(irp);

	ASSERT(irpSp->FileObject);
	ASSERT(irpSp->FileObject->FsContext);
	callerFileExt = (FILEEXT *)irpSp->FileObject->FsContext;
	ASSERT(callerFileExt->signature == ESCPOS_TAG);

	KeAcquireSpinLock(&pdoExt->devExtSpinLock, &oldIrql);
	
	if (IsListEmpty(&pdoExt->fileExtensionList)){
		status = STATUS_DEVICE_DATA_ERROR;
	}
	else {
		PLIST_ENTRY listEntry;
			
		// BUGBUG - assume only one open for now
		listEntry = RemoveHeadList(&pdoExt->fileExtensionList);
		myFileExt = CONTAINING_RECORD(listEntry, FILEEXT, listEntry);
		ASSERT(myFileExt->signature == ESCPOS_TAG);
		if (myFileExt == callerFileExt){
			status = STATUS_SUCCESS;
		}
		else {
			/*
			 *  We only allow one open, so this should have been the one
			 */
			ASSERT(myFileExt == callerFileExt);
			InsertHeadList(&pdoExt->fileExtensionList, &myFileExt->listEntry);
			status = STATUS_DEVICE_DATA_ERROR;
		}
	}

	KeReleaseSpinLock(&pdoExt->devExtSpinLock, oldIrql);

	/*
	 *  Wait until we've dropped the spinlock to call outside the driver to free memory.
	 */
	if (NT_SUCCESS(status)){
		irpSp->FileObject->FsContext = NULL;
		FREEPOOL(myFileExt);
	}
	else {
		DBGERR(("CloseComPort: failing with status %xh.", status));
	}

	irp->IoStatus.Information = 0;

	return status;
}



PWCHAR CreateChildPdoName(PARENTFDOEXT *parentFdoExt, ULONG portNumber)
{
	static WCHAR pdoNamePrefix[] = L"\\Device\\POS_";
	WCHAR buf[sizeof(pdoNamePrefix)/sizeof(WCHAR)+4] = { 0 };
	PWCHAR result;
	ULONG numLen = MyLog(10, portNumber)+1;

	ASSERT((numLen > 0) && (numLen <= 4));

	RtlCopyMemory(buf, pdoNamePrefix, sizeof(pdoNamePrefix));
	NumToDecString(buf+sizeof(pdoNamePrefix)/sizeof(WCHAR)-1, (USHORT)portNumber, (USHORT)numLen);

	result = MemDup(buf, sizeof(buf));

	return result;
}


NTSTATUS CreateCOMPdo(	PARENTFDOEXT *parentFdoExt,
                        ULONG comInterfaceIndex,
                        ENDPOINTINFO *inputEndpointInfo, 
                        ENDPOINTINFO *outputEndpointInfo,
                        ENDPOINTINFO *statusEndpointInfo)
{
    NTSTATUS status;
    LONG comPortNumber;

    comPortNumber = GetComPort(parentFdoExt, comInterfaceIndex);
    if (comPortNumber == -1){
        status = STATUS_DEVICE_DATA_ERROR;
    }
    else {
        PWCHAR deviceName = CreateChildPdoName(parentFdoExt, comPortNumber);
        if (deviceName){
            PDEVICE_OBJECT pdo;
            UNICODE_STRING uPdoName;

            RtlInitUnicodeString(&uPdoName, deviceName);

            status = IoCreateDevice(parentFdoExt->driverObj, 
                                    sizeof(DEVEXT),
                                    &uPdoName,  // name for this device
                                    FILE_DEVICE_SERIAL_PORT, 
                                    0,			// device characteristics
                                    FALSE,		// exclusive - BUGBUG ?
                                    &pdo);		// our device object

            if (NT_SUCCESS(status)){
                DEVEXT *devExt = (DEVEXT *)pdo->DeviceExtension;
                POSPDOEXT *pdoExt;
                KIRQL oldIrql;

                RtlZeroMemory(devExt, sizeof(DEVEXT));

                devExt->signature = DEVICE_EXTENSION_SIGNATURE;
                devExt->isPdo = TRUE;

                pdoExt = &devExt->pdoExt;

                pdoExt->state = STATE_INITIALIZED;
                pdoExt->pdo = pdo;
                pdoExt->parentFdoExt = parentFdoExt;
                pdoExt->comPortNumber = comPortNumber;

                /*
                 *  Initializing variables and endpointinfo for Serial Emulation
                 */
                if (parentFdoExt->posFlag & SERIAL_EMULATION) {
                    InitializeSerEmulVariables(pdoExt);
                    pdoExt->statusEndpointInfo = *statusEndpointInfo;
                    DBGVERBOSE(("CreateCOMPdo: EndpointInfo & Variables for Serial Emulation initialized"));
                }

                RtlInitUnicodeString(&pdoExt->pdoName, deviceName);

                InitializeListHead(&pdoExt->fileExtensionList);
                InitializeListHead(&pdoExt->pendingReadIrpsList);
                InitializeListHead(&pdoExt->pendingWriteIrpsList);
                InitializeListHead(&pdoExt->completedReadPacketsList);

                KeInitializeSpinLock(&pdoExt->devExtSpinLock);

                ExInitializeWorkItem(&pdoExt->writeWorkItem, WorkItemCallback_Write, pdoExt);
                ExInitializeWorkItem(&pdoExt->readWorkItem, WorkItemCallback_Read, pdoExt);

                pdoExt->totalQueuedReadDataLength = 0;

                /*
                 *  Copy contents of endpointInfo structures. To incorporate 
                 *  the ODD_ENDPOINT feature we have to make the checks below.
                 */
                if (inputEndpointInfo){
                    pdoExt->inputEndpointInfo = *inputEndpointInfo;
                }

                if (outputEndpointInfo){
                    pdoExt->outputEndpointInfo = *outputEndpointInfo;
                }

                pdo->StackSize = parentFdoExt->functionDevObj->StackSize+1;

                /*
                 *  Insert child PDO in parent's device relations array.
                 */
                KeAcquireSpinLock(&parentFdoExt->devExtSpinLock, &oldIrql);
                parentFdoExt->deviceRelations->Objects[parentFdoExt->deviceRelations->Count++] = pdo;
                KeReleaseSpinLock(&parentFdoExt->devExtSpinLock, oldIrql);

                ASSERT(!(pdo->Flags & DO_POWER_PAGABLE)); 
                pdo->Flags |= DO_POWER_PAGABLE;

                DBGVERBOSE(("CreateCOMPdo: created pdo %ph, pdoExt = %ph.", pdo, pdoExt));
            }
            else {
                DBGERR(("CreateCOMPdo: IoCreateDevice failed with status %xh.", status));
            }
        }
        else {
            status = STATUS_INSUFFICIENT_RESOURCES;
        }

        if (!NT_SUCCESS(status)){
	        ReleaseCOMPort(comPortNumber);
        }
    }

    ASSERT(NT_SUCCESS(status));
    return status;
}


NTSTATUS CleanupIO(POSPDOEXT *pdoExt, PIRP irp)
{
	// BUGBUG FINISH
	irp->IoStatus.Information = 0;
	return STATUS_SUCCESS;

⌨️ 快捷键说明

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