📄 vcom_device.c
字号:
pTwinDeviceExtension->outBufferCount++;
if (pTwinDeviceExtension->outBufferCount >= pTwinDeviceExtension->outBufferSize)
break;
}
pDeviceExtension->inBufferCount = 0;
pDeviceExtension->inBufferWritePosition = 0;
pDeviceExtension->inBufferReadPosition = 0;
KeReleaseSpinLock(&pDeviceExtension->writeSpinLock, write_oldIrql);
if (eventCharRcvd)
vCOMCheckComEvents(pTwinDeviceExtension, SERIAL_EV_RXFLAG | SERIAL_EV_RXCHAR);
else
vCOMCheckComEvents(pTwinDeviceExtension, SERIAL_EV_RXCHAR);
// notify the read thread for the twin device that a transfer occurred
KeSetEvent(&pTwinDeviceExtension->transferOccurredEvent, 6, FALSE);
return STATUS_SUCCESS;
}
}
NTSTATUS vCOMDeviceControl(PDEVICE_OBJECT DeviceObject, PIRP pIrp)
{
NTSTATUS status;
PvCOM_DEVICE_EXTENSION pDeviceExtension;
PvCOM_DEVICE_EXTENSION pTwinDeviceExtension;
PIO_STACK_LOCATION pIrpStackLocation;
KIRQL oldIrql;
KIRQL write_oldIrql;
KIRQL read_oldIrql;
KIRQL cancelIrql;
PIRP pOldWaitIrp;
PDRIVER_CANCEL cancelRoutine;
PDRIVER_CANCEL pOldCancelRoutine;
status = STATUS_SUCCESS;
pDeviceExtension = DeviceObject->DeviceExtension;
pTwinDeviceExtension = pDeviceExtension->pTwin->DeviceExtension;
pIrpStackLocation = IoGetCurrentIrpStackLocation(pIrp);
pIrp->IoStatus.Information = 0;
if (status == STATUS_CANCELLED)
{
return vCOMCompleteRequest(pIrp, status, 0);
}
KdPrint(("vCOMDeviceControl: IOControlCode = %x\n", pIrpStackLocation->Parameters.DeviceIoControl.IoControlCode));
switch (pIrpStackLocation->Parameters.DeviceIoControl.IoControlCode)
{
case IOCTL_SERIAL_SET_TIMEOUTS:
{
PSERIAL_TIMEOUTS pNewTimeouts;
pNewTimeouts = (PSERIAL_TIMEOUTS)pIrp->AssociatedIrp.SystemBuffer;
KdPrint(("vCOMDeviceControl: IOCTL_SERIAL_SET_TIMEOUTS\n"));
if (pIrpStackLocation->Parameters.DeviceIoControl.InputBufferLength < sizeof(SERIAL_TIMEOUTS))
{
status = STATUS_BUFFER_TOO_SMALL;
break;
}
if ((pNewTimeouts->ReadIntervalTimeout == MAXULONG) &&
(pNewTimeouts->ReadTotalTimeoutMultiplier == MAXULONG) &&
(pNewTimeouts->ReadTotalTimeoutConstant == MAXULONG))
{
status = STATUS_INVALID_PARAMETER;
break;
}
//this is a fix to make the driver work with MSCOMM in return with any mode
//see http://support.microsoft.com/default.aspx?scid=kb;en-us;318784
//driver mode is TIMEOUTS_IMMEDIATE_RETURN_WITH_BYTES
if ((pNewTimeouts->ReadIntervalTimeout == MAXULONG) &&
(pNewTimeouts->ReadTotalTimeoutMultiplier == 0) &&
(pNewTimeouts->ReadTotalTimeoutConstant == 0))
{
pDeviceExtension->fastRead = TRUE;
}
else
pDeviceExtension->fastRead = FALSE;
KeAcquireSpinLock(&pDeviceExtension->readSpinLock, &oldIrql);
RtlMoveMemory(&pDeviceExtension->serTimeouts, pNewTimeouts, sizeof(SERIAL_TIMEOUTS));
KeReleaseSpinLock(&pDeviceExtension->readSpinLock, oldIrql);
KdPrint(("ReadIntervalTimeout: %lu\n", pNewTimeouts->ReadIntervalTimeout));
KdPrint(("ReadTotalTimeoutMultiplier: %lu\n", pNewTimeouts->ReadTotalTimeoutMultiplier));
KdPrint(("ReadTotalTimeoutConstant: %lu\n", pNewTimeouts->ReadTotalTimeoutConstant));
break;
}
case IOCTL_SERIAL_GET_TIMEOUTS:
KdPrint(("vCOMDeviceControl: IOCTL_SERIAL_GET_TIMEOUTS\n"));
if (pIrpStackLocation->Parameters.DeviceIoControl.OutputBufferLength < sizeof(SERIAL_TIMEOUTS))
{
status = STATUS_BUFFER_TOO_SMALL;
break;
}
pIrp->IoStatus.Information = sizeof(SERIAL_TIMEOUTS);
KeAcquireSpinLock(&pDeviceExtension->readSpinLock, &oldIrql);
RtlMoveMemory(pIrp->AssociatedIrp.SystemBuffer, &pDeviceExtension->serTimeouts, sizeof(SERIAL_TIMEOUTS));
KeReleaseSpinLock(&pDeviceExtension->readSpinLock, oldIrql);
break;
case IOCTL_SERIAL_GET_WAIT_MASK:
KdPrint(("vCOMDeviceControl: IOCTL_SERIAL_GET_WAIT_MASK\n"));
if (pIrpStackLocation->Parameters.DeviceIoControl.OutputBufferLength < sizeof(ULONG))
{
status = STATUS_BUFFER_TOO_SMALL;
break;
}
pIrp->IoStatus.Information = sizeof(ULONG);
*(PULONG)pIrp->AssociatedIrp.SystemBuffer = pDeviceExtension->eventMask;
break;
case IOCTL_SERIAL_SET_WAIT_MASK:
{
ULONG newMask;
KdPrint(("vCOMDeviceControl: IOCTL_SERIAL_SET_WAIT_MASK\n"));
if (pIrpStackLocation->Parameters.DeviceIoControl.InputBufferLength < sizeof(ULONG))
{
status = STATUS_BUFFER_TOO_SMALL;
break;
}
newMask = *(PULONG)pIrp->AssociatedIrp.SystemBuffer;
if ((newMask & ~(SERIAL_EV_RXCHAR | SERIAL_EV_RXFLAG | SERIAL_EV_TXEMPTY | SERIAL_EV_CTS |
SERIAL_EV_DSR | SERIAL_EV_RLSD | SERIAL_EV_BREAK | SERIAL_EV_ERR |
SERIAL_EV_RING | SERIAL_EV_PERR | SERIAL_EV_RX80FULL | SERIAL_EV_EVENT1 |
SERIAL_EV_EVENT2)) != 0)
{
status = STATUS_INVALID_PARAMETER;
break;
}
KeAcquireSpinLock(&pDeviceExtension->controlSpinLock, &oldIrql);
pOldWaitIrp = pDeviceExtension->pWaitIrp;
if (pOldWaitIrp != NULL)
{
pOldCancelRoutine = IoSetCancelRoutine(pOldWaitIrp, NULL);
if (pOldCancelRoutine != NULL)
{
pOldWaitIrp->IoStatus.Information = sizeof(ULONG);
*(PULONG)pOldWaitIrp->AssociatedIrp.SystemBuffer = 0;
pOldWaitIrp->IoStatus.Status = STATUS_SUCCESS;
pDeviceExtension->pWaitIrp = NULL;
}
else
{
pOldWaitIrp = NULL;
}
}
pDeviceExtension->eventMask = newMask;
KeReleaseSpinLock(&pDeviceExtension->controlSpinLock, oldIrql);
if (pOldWaitIrp != NULL)
IoCompleteRequest(pOldWaitIrp, IO_NO_INCREMENT);
break;
}
case IOCTL_SERIAL_WAIT_ON_MASK:
KdPrint(("vCOMDeviceControl: IOCTL_SERIAL_WAIT_ON_MASK\n"));
if (pIrpStackLocation->Parameters.DeviceIoControl.OutputBufferLength < sizeof(ULONG))
{
status = STATUS_BUFFER_TOO_SMALL;
break;
}
KeAcquireSpinLock(&pDeviceExtension->controlSpinLock, &oldIrql);
if ((pDeviceExtension->pWaitIrp != NULL) || (pDeviceExtension->eventMask == 0))
{
status = STATUS_INVALID_PARAMETER;
}
else if ((pDeviceExtension->eventMask & pDeviceExtension->eventHistory) != 0)
{
pIrp->IoStatus.Information = sizeof(ULONG);
*(PULONG)pIrp->AssociatedIrp.SystemBuffer = pDeviceExtension->eventMask & pDeviceExtension->eventHistory;
pDeviceExtension->eventHistory = 0;
KdPrint(("IOCTL_SERIAL_WAIT_ON_MASK set with STATUS_SUCCESS...\n"));
status = STATUS_SUCCESS;
}
else
{
pDeviceExtension->pWaitIrp = pIrp;
status = STATUS_PENDING;
IoSetCancelRoutine(pIrp, vCOMCancelWaitIrp);
if (pIrp->Cancel)
{
pOldCancelRoutine = IoSetCancelRoutine(pIrp, NULL);
if (pOldCancelRoutine != NULL)
{
KdPrint(("IOCTL_SERIAL_WAIT_ON_MASK set with STATUS_CANCELLED...\n"));
status = STATUS_CANCELLED;
pDeviceExtension->pWaitIrp = NULL;
}
else
{
KdPrint(("IOCTL_SERIAL_WAIT_ON_MASK set with STATUS_PENDING...\n"));
IoMarkIrpPending(pIrp);
}
}
else
{
KdPrint(("IOCTL_SERIAL_WAIT_ON_MASK set with STATUS_PENDING...\n"));
IoMarkIrpPending(pIrp);
}
}
KeReleaseSpinLock(&pDeviceExtension->controlSpinLock, oldIrql);
break;
case IOCTL_SERIAL_PURGE:
{
ULONG mask;
ULONG channels;
KdPrint(("vCOMDeviceControl: IOCTL_SERIAL_PURGE\n"));
if (pIrpStackLocation->Parameters.DeviceIoControl.InputBufferLength < sizeof(ULONG))
{
pIrp->IoStatus.Information = 0;
status = STATUS_BUFFER_TOO_SMALL;
break;
}
mask = *(PULONG)pIrp->AssociatedIrp.SystemBuffer;
KdPrint(("purge mask: %x\n", mask));
if ((mask == 0) || ((mask & ~(SERIAL_PURGE_TXABORT | SERIAL_PURGE_RXABORT |
SERIAL_PURGE_TXCLEAR | SERIAL_PURGE_RXCLEAR)) != 0))
{
pIrp->IoStatus.Information = 0;
status = STATUS_INVALID_PARAMETER;
break;
}
if (mask & SERIAL_PURGE_RXABORT)
{
KdPrint(("purge SERIAL_PURGE_RXABORT\n"));
if (pDeviceExtension->pReadIrpCurrent != NULL)
{
IoAcquireCancelSpinLock(&cancelIrql);
cancelRoutine = pDeviceExtension->pReadIrpCurrent->CancelRoutine;
pDeviceExtension->pReadIrpCurrent->Cancel = TRUE;
if (cancelRoutine)
{
pDeviceExtension->pReadIrpCurrent->CancelRoutine = NULL;
pDeviceExtension->pReadIrpCurrent->CancelIrql = cancelIrql;
cancelRoutine(DeviceObject, pDeviceExtension->pReadIrpCurrent);
}
else
{
IoReleaseCancelSpinLock(cancelIrql);
}
}
pIrp->IoStatus.Information = sizeof(ULONG);
}
if (mask & SERIAL_PURGE_TXABORT)
{
KdPrint(("purge SERIAL_PURGE_TXABORT\n"));
if (pDeviceExtension->pWriteIrpCurrent != NULL)
{
IoAcquireCancelSpinLock(&cancelIrql);
cancelRoutine = pDeviceExtension->pWriteIrpCurrent->CancelRoutine;
pDeviceExtension->pWriteIrpCurrent->Cancel = TRUE;
if (cancelRoutine)
{
pDeviceExtension->pWriteIrpCurrent->CancelRoutine = NULL;
pDeviceExtension->pWriteIrpCurrent->CancelIrql = cancelIrql;
cancelRoutine(DeviceObject, pDeviceExtension->pWriteIrpCurrent);
}
else
{
IoReleaseCancelSpinLock(cancelIrql);
}
}
pIrp->IoStatus.Information = sizeof(ULONG);
}
if (mask & SERIAL_PURGE_RXCLEAR)
{
KdPrint(("purge SERIAL_PURGE_RXCLEAR\n"));
KeAcquireSpinLock(&pDeviceExtension->readSpinLock, &read_oldIrql);
pDeviceExtension->outBufferReadPosition = 0;
pDeviceExtension->outBufferWritePosition = 0;
pDeviceExtension->outBufferCount = 0;
pDeviceExtension->readBufferCount = 0;
RtlZeroMemory(pDeviceExtension->outBuffer, BUFFERLENGTH);
pDeviceExtension->eventHistory = 0;
KeReleaseSpinLock(&pDeviceExtension->readSpinLock, read_oldIrql);
pIrp->IoStatus.Information = sizeof(ULONG);
}
if (mask & SERIAL_PURGE_TXCLEAR)
{
KdPrint(("purge SERIAL_PURGE_TXCLEAR\n"));
KeAcquireSpinLock(&pDeviceExtension->writeSpinLock, &write_oldIrql);
pDeviceExtension->inBufferReadPosition = 0;
pDeviceExtension->inBufferWritePosition = 0;
pDeviceExtension->inBufferCount = 0;
RtlZeroMemory(pDeviceExtension->inBuffer, BUFFERLENGTH);
pDeviceExtension->eventHistory = 0;
KeReleaseSpinLock(&pDeviceExtension->writeSpinLock, write_oldIrql);
pIrp->IoStatus.Information = sizeof(ULONG);
}
break;
}
case IOCTL_SERIAL_GET_BAUD_RATE:
KdPrint(("vCOMDeviceControl: IOCTL_SERIAL_GET_BAUD_RATE\n"));
if (pIrpStackLocation->Parameters.DeviceIoControl.OutputBufferLength < sizeof(SERIAL_BAUD_RATE))
{
status = STATUS_BUFFER_TOO_SMALL;
break;
}
pIrp->IoStatus.Information = sizeof(SERIAL_BAUD_RATE);
KeAcquireSpinLock(&pDeviceExtension->controlSpinLock, &oldIrql);
RtlMoveMemory(pIrp->AssociatedIrp.SystemBuffer, &pDeviceExtension->serBaudRate, sizeof(SERIAL_BAUD_RATE));
KeReleaseSpinLock(&pDeviceExtension->controlSpinLock, oldIrql);
break;
case IOCTL_SERIAL_SET_BAUD_RATE:
{
PSERIAL_BAUD_RATE pNewBaudRate = (PSERIAL_BAUD_RATE)pIrp->AssociatedIrp.SystemBuffer;
KdPrint(("vCOMDeviceControl: IOCTL_SERIAL_SET_BAUD_RATE\n"));
if (pIrpStackLocation->Parameters.DeviceIoControl.InputBufferLength < sizeof(SERIAL_BAUD_RATE))
{
status = STATUS_BUFFER_TOO_SMALL;
break;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -