📄 comport.c
字号:
/*++
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 + -