📄 vcom_device.c
字号:
pIrp->IoStatus.Information = sizeof(ULONG );
KeAcquireSpinLock(&pDeviceExtension->controlSpinLock, &oldIrql);
*(PULONG)pIrp->AssociatedIrp.SystemBuffer = pDeviceExtension->serModemControlRegister;
KeReleaseSpinLock(&pDeviceExtension->controlSpinLock, oldIrql);
break;
}
case IOCTL_SERIAL_SET_MODEM_CONTROL:
{
ULONG mcr;
KdPrint(("vCOMDeviceControl: IOCTL_SERIAL_SET_MODEM_CONTROL\n"));
if (pIrpStackLocation->Parameters.DeviceIoControl.InputBufferLength < sizeof(ULONG))
{
status = STATUS_BUFFER_TOO_SMALL;
break;
}
mcr = *(PULONG)pIrp->AssociatedIrp.SystemBuffer;
KeAcquireSpinLock(&pDeviceExtension->controlSpinLock, &oldIrql);
pDeviceExtension->serModemControlRegister = mcr;
KeReleaseSpinLock(&pDeviceExtension->controlSpinLock, oldIrql);
if ((mcr & SERIAL_MCR_DTR) == SERIAL_MCR_DTR)
{
pDeviceExtension->serDTR = TRUE;
if (!pTwinDeviceExtension->serDSR)
{
pTwinDeviceExtension->serDSR = TRUE;
vCOMCheckComEvents(pTwinDeviceExtension, SERIAL_EV_DSR);
}
}
else
{
pDeviceExtension->serDTR = FALSE;
if (pTwinDeviceExtension->serDSR)
{
pTwinDeviceExtension->serDSR = FALSE;
vCOMCheckComEvents(pTwinDeviceExtension, SERIAL_EV_DSR);
}
}
if ((mcr & SERIAL_MCR_RTS) == SERIAL_MCR_RTS)
{
pDeviceExtension->serRTS = TRUE;
if (!pTwinDeviceExtension->serCTS)
{
pTwinDeviceExtension->serCTS= TRUE;
vCOMCheckComEvents(pTwinDeviceExtension, SERIAL_EV_CTS);
}
}
else
{
pDeviceExtension->serRTS = FALSE;
if (pTwinDeviceExtension->serCTS)
{
pTwinDeviceExtension->serCTS= FALSE;
vCOMCheckComEvents(pTwinDeviceExtension, SERIAL_EV_CTS);
}
}
break;
}
case IOCTL_SERIAL_XOFF_COUNTER:
case IOCTL_SERIAL_SET_XON:
case IOCTL_SERIAL_SET_XOFF:
case IOCTL_SERIAL_SET_FIFO_CONTROL:
case IOCTL_SERIAL_SET_BREAK_ON:
case IOCTL_SERIAL_SET_BREAK_OFF:
case IOCTL_SERIAL_RESET_DEVICE:
KdPrint(("vCOMDeviceControl: Other IOControl\n"));
break;
default:
status = STATUS_INVALID_PARAMETER;
break;
}
if (status != STATUS_PENDING)
{
vCOMCompleteRequest(pIrp, status, pIrp->IoStatus.Information);
}
return status;
}
NTSTATUS vCOMCleanupDevice(PDEVICE_OBJECT DeviceObject, PIRP pIrp)
{
PvCOM_DEVICE_EXTENSION pDeviceExtension;
LIST_ENTRY tempQueue;
PLIST_ENTRY thisEntry;
KIRQL OldIrql;
PIRP pendingIrp;
PIO_STACK_LOCATION pendingIrpStack;
PIO_STACK_LOCATION irpStack;
pDeviceExtension = DeviceObject->DeviceExtension;
irpStack = IoGetCurrentIrpStackLocation(pIrp);
while (pendingIrp = IoCsqRemoveNextIrp (&pDeviceExtension->cancelSafeReadQueue, irpStack->FileObject))
{
// Cancel the IRP
vCOMCompleteRequest(pendingIrp, STATUS_CANCELLED, 0);
}
while (pendingIrp = IoCsqRemoveNextIrp (&pDeviceExtension->cancelSafeWriteQueue, irpStack->FileObject))
{
// Cancel the IRP
vCOMCompleteRequest(pendingIrp, STATUS_CANCELLED, 0);
}
// Finally complete the cleanup IRP
vCOMCompleteRequest(pIrp, STATUS_SUCCESS, 0);
return STATUS_SUCCESS;
}
NTSTATUS vCOMGetRegistryKeyValue(HANDLE hRegistry, PCWSTR keyName, PVOID data, ULONG dataLength)
{
NTSTATUS status;
UNICODE_STRING keyNameString;
ULONG length;
PKEY_VALUE_PARTIAL_INFORMATION pInfo;
status = STATUS_INSUFFICIENT_RESOURCES;
RtlInitUnicodeString(&keyNameString, keyName);
length = sizeof(KEY_VALUE_PARTIAL_INFORMATION) + dataLength;
pInfo = ExAllocatePool(PagedPool, length);
if (pInfo != NULL)
{
status = ZwQueryValueKey(hRegistry, &keyNameString, KeyValuePartialInformation,
pInfo, length, &length);
if (NT_SUCCESS(status))
{
if (dataLength >= pInfo->DataLength)
RtlCopyMemory(data, &pInfo->Data, pInfo->DataLength);
else
status = STATUS_BUFFER_TOO_SMALL;
}
ExFreePool(pInfo);
}
return status;
}
VOID vCOMCancelWaitIrp(PDEVICE_OBJECT DeviceObject, PIRP pIrp)
{
PvCOM_DEVICE_EXTENSION pDeviceExtension;
KIRQL oldIrql;
pDeviceExtension = DeviceObject->DeviceExtension;
IoReleaseCancelSpinLock(pIrp->CancelIrql);
KeAcquireSpinLock(&pDeviceExtension->controlSpinLock, &oldIrql);
pDeviceExtension-> pWaitIrp = NULL;
KeReleaseSpinLock(&pDeviceExtension->controlSpinLock, oldIrql);
vCOMCompleteRequest(pIrp, STATUS_CANCELLED, 0);
}
VOID vCOMCancelCurrentReadIrp(PDEVICE_OBJECT DeviceObject, PIRP pIrp)
{
PvCOM_DEVICE_EXTENSION pDeviceExtension;
KIRQL oldIrql;
pDeviceExtension = DeviceObject->DeviceExtension;
IoReleaseCancelSpinLock(pIrp->CancelIrql);
KeAcquireSpinLock(&pDeviceExtension->readSpinLock, &oldIrql);
pDeviceExtension-> pReadIrpCurrent = NULL;
KeReleaseSpinLock(&pDeviceExtension->readSpinLock, oldIrql);
vCOMCompleteRequest(pIrp, STATUS_CANCELLED, 0);
KeSetEvent(&pDeviceExtension->currentReadIrpWasCancelledEvent, 0, FALSE);
}
VOID vCOMCancelCurrentWriteIrp(PDEVICE_OBJECT DeviceObject, PIRP pIrp)
{
PvCOM_DEVICE_EXTENSION pDeviceExtension;
KIRQL oldIrql;
pDeviceExtension = DeviceObject->DeviceExtension;
IoReleaseCancelSpinLock(pIrp->CancelIrql);
KeAcquireSpinLock(&pDeviceExtension->writeSpinLock, &oldIrql);
pDeviceExtension-> pWriteIrpCurrent= NULL;
KeReleaseSpinLock(&pDeviceExtension->writeSpinLock, oldIrql);
vCOMCompleteRequest(pIrp, STATUS_CANCELLED, 0);
KeSetEvent(&pDeviceExtension->currentWriteIrpWasCancelledEvent, 0, FALSE);
}
ULONG vCOMCalculateReadTimeoutValues(PDEVICE_OBJECT pDeviceObject, PIRP pIrp)
{
PvCOM_DEVICE_EXTENSION pDeviceExtension;
PIO_STACK_LOCATION pIrpStackLocation;
ULONG dataLength;
ULONG readIntervalTimeout;
ULONG readTotalTimeoutMultiplier;
ULONG readTotalTimeoutConstant;
ULONG readCombinedTimeout;
pDeviceExtension = pDeviceObject->DeviceExtension;
pIrpStackLocation = IoGetCurrentIrpStackLocation(pIrp);
dataLength = pIrpStackLocation->Parameters.Read.Length;
readIntervalTimeout = pDeviceExtension->serTimeouts.ReadIntervalTimeout;
readTotalTimeoutMultiplier = pDeviceExtension->serTimeouts.ReadTotalTimeoutMultiplier;
readTotalTimeoutConstant = pDeviceExtension->serTimeouts.ReadTotalTimeoutConstant;
KdPrint(("readIntervalTimeout is %lu\n", readIntervalTimeout));
KdPrint(("readTotalTimeoutMultiplier is %lu\n", readTotalTimeoutMultiplier));
KdPrint(("readTotalTimeoutConstant is %lu\n", readTotalTimeoutConstant));
KdPrint(("MAXULONG is %lu\n", MAXULONG));
/* NOTE:
The timeout values for serTimeouts are in milliseconds.
The kernel timers want the timeouts to be specified in multiples of 100 nS intervals.
100 nS = 0.000000100 * 10000 = 0.001 or 1 mS
So we need to multiply the values in mS by 10000 to get the proper time timeout values.
10,000 1nS intervals is 1 mS.
*/
if (readIntervalTimeout == MAXULONG && readTotalTimeoutMultiplier == 0 && readTotalTimeoutConstant == 0)
{
KdPrint(("return immediately with whatever bytes there are or none...\n"));
//return immediately with whatever bytes there are
pDeviceExtension->readTotalTimeoutValue.QuadPart = 0;
pDeviceExtension->readIntervalTimeoutValue.QuadPart = 0;
return TIMEOUTS_IMMEDIATE_RETURN_WITH_BYTES;
}
else if (readIntervalTimeout == 0 && readTotalTimeoutMultiplier == 0 && readTotalTimeoutConstant == 0)
{
KdPrint(("wait forever...\n"));
//total timeout is not used
pDeviceExtension->readTotalTimeoutValue.QuadPart = 0;
pDeviceExtension->readIntervalTimeoutValue.QuadPart = 0;
return TIMEOUTS_WAIT_FOREVER;
}
else if (readIntervalTimeout > 0 && readTotalTimeoutMultiplier == 0 && readTotalTimeoutConstant == 0)
{
KdPrint(("interval timeout...\n"));
pDeviceExtension->readTotalTimeoutValue.QuadPart = 0;
pDeviceExtension->readIntervalTimeoutValue.QuadPart = ((LONGLONG)readIntervalTimeout) * -10000;
return TIMEOUTS_INTERVAL_TIMEOUT;
}
else if (readIntervalTimeout == MAXULONG && readTotalTimeoutMultiplier == MAXULONG && readTotalTimeoutConstant > 0 && readTotalTimeoutConstant != MAXULONG)
{
KdPrint(("if any bytes available return immediately with them, if none wait or total timeout...\n"));
//if any bytes avaliable return immediately with them
//if no bytes available wait and then return with any
//otherwise timeout when readTotalTimeoutConstant time expires
pDeviceExtension->readTotalTimeoutValue.QuadPart = ((LONGLONG)readTotalTimeoutConstant) * -10000;
pDeviceExtension->readIntervalTimeoutValue.QuadPart = 0;
return TIMEOUTS_RETURNBYTES_OR_WAIT;
}
else if (readIntervalTimeout == 0 && readTotalTimeoutMultiplier != 0 && readTotalTimeoutConstant != 0)
{
KdPrint(("Total timeout only...\n"));
//use total timeouts
readCombinedTimeout = readTotalTimeoutConstant + readTotalTimeoutMultiplier * dataLength;
pDeviceExtension->readTotalTimeoutValue.QuadPart = ((LONGLONG)readCombinedTimeout) * -10000;
pDeviceExtension->readIntervalTimeoutValue.QuadPart = 0;
return TIMEOUTS_TOTAL_TIMEOUT;
}
else if (readIntervalTimeout != 0 && readTotalTimeoutMultiplier != 0 && readTotalTimeoutConstant != 0)
{
KdPrint(("use combined timeouts...\n"));
//use total timeouts and interval
readCombinedTimeout = readTotalTimeoutConstant + readTotalTimeoutMultiplier * dataLength;
pDeviceExtension->readTotalTimeoutValue.QuadPart = ((LONGLONG)readCombinedTimeout) * -10000;
pDeviceExtension->readIntervalTimeoutValue.QuadPart = ((LONGLONG)readIntervalTimeout) * -10000;
return TIMEOUTS_COMBINED_TIMEOUT;
}
else
{
KdPrint(("default: use total timeout only...\n"));
//use total timeouts
readCombinedTimeout = readTotalTimeoutConstant + readTotalTimeoutMultiplier * dataLength;
pDeviceExtension->readTotalTimeoutValue.QuadPart = ((LONGLONG)readCombinedTimeout) * -10000;
pDeviceExtension->readIntervalTimeoutValue.QuadPart = 0;
return TIMEOUTS_TOTAL_TIMEOUT;
}
}
ULONG vCOMCalculateWriteTimeoutValues(PDEVICE_OBJECT pDeviceObject, PIRP pIrp)
{
PvCOM_DEVICE_EXTENSION pDeviceExtension;
PIO_STACK_LOCATION pIrpStackLocation;
ULONG dataLength;
ULONG writeTotalTimeoutMultiplier;
ULONG writeTotalTimeoutConstant;
ULONG writeCombinedTimeout;
pDeviceExtension = pDeviceObject->DeviceExtension;
pIrpStackLocation = IoGetCurrentIrpStackLocation(pIrp);
dataLength = pIrpStackLocation->Parameters.Read.Length;
writeTotalTimeoutMultiplier = pDeviceExtension->serTimeouts.WriteTotalTimeoutMultiplier;
writeTotalTimeoutConstant = pDeviceExtension->serTimeouts.WriteTotalTimeoutConstant;
/* NOTE:
The timeout values for serTimeouts are in milliseconds.
The kernel timers want the timeouts to be specified in multiples of 100 nS intervals.
100 nS = 0.000000100 * 10000 = 0.001 or 1 mS
So we need to multiply the values in mS by 10000 to get the proper time timeout values.
10,000 1nS intervals is 1 mS.
*/
KdPrint(("writeTotalTimeoutMultiplier is %lu\n", writeTotalTimeoutMultiplier));
KdPrint(("writeTotalTimeoutConstant is %lu\n", writeTotalTimeoutConstant));
KdPrint(("MAXULONG is %lu\n", MAXULONG));
if (writeTotalTimeoutMultiplier != 0 || writeTotalTimeoutConstant != 0)
{
KdPrint(("use write timeout...\n"));
//use total timeouts and interval
writeCombinedTimeout = writeTotalTimeoutConstant + writeTotalTimeoutMultiplier * dataLength;
pDeviceExtension->writeTotalTimeoutValue.QuadPart = ((LONGLONG)writeCombinedTimeout) * -10000;
pDeviceExtension->writeDelayLoopTimerValue.QuadPart = (LONGLONG)(-10000 * 10); //10mS
return TIMEOUTS_TOTAL_TIMEOUT;
}
else
{
KdPrint(("default: no write timeout...\n"));
//use total timeouts
pDeviceExtension->writeTotalTimeoutValue.QuadPart = 0;
pDeviceExtension->writeDelayLoopTimerValue.QuadPart = (LONGLONG)(-10000 * 100); //100mS
return TIMEOUTS_WAIT_FOREVER;
}
}
VOID vCOMCheckComEvents(PvCOM_DEVICE_EXTENSION pDeviceExtension, ULONG events)
{
PIRP pOldWaitIrp = NULL;
PDRIVER_CANCEL pOldCancelRoutine;
KIRQL oldIrql;
KeAcquireSpinLock(&pDeviceExtension->controlSpinLock, &oldIrql);
pDeviceExtension->eventHistory |= events;
events &= pDeviceExtension->eventMask;
if ((pDeviceExtension->pWaitIrp != NULL) && (events != 0))
{
pOldWaitIrp = pDeviceExtension->pWaitIrp;
pOldCancelRoutine = IoSetCancelRoutine(pOldWaitIrp, NULL);
if (pOldCancelRoutine != NULL)
{
pOldWaitIrp->IoStatus.Information = sizeof(ULONG);
*(PULONG)pOldWaitIrp->AssociatedIrp.SystemBuffer = events;
pOldWaitIrp->IoStatus.Status = STATUS_SUCCESS;
pDeviceExtension->pWaitIrp = NULL;
pDeviceExtension->eventHistory= 0;
}
else
{
pOldWaitIrp = NULL;
}
}
KeReleaseSpinLock(&pDeviceExtension->controlSpinLock, oldIrql);
if (pOldWaitIrp != NULL)
{
IoCompleteReques
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -