📄 usb2com.read.cpp
字号:
// this irp will be completed as soon as we release the write queue spin lock
//
ASSERT(Irp->Cancel);
InitializeListHead(&Irp->Tail.Overlay.ListEntry);
Irp = 0;
}
}
return Irp;
}
//
// update read buffer
//
BOOLEAN Usb2ComUpdateReadBuffer(__in PUSB2COM_DEVICE_EXTENSION DevExt,__in PUCHAR Buffer,__in ULONG Length)
{
//
// buffer is full
//
if(DevExt->ReadBufferCharsCount >= 0x2000)
return FALSE;
BOOLEAN ReceivedEventChar = FALSE;
ULONG WritePos = (DevExt->FirstReadCharSlot + DevExt->ReadBufferCharsCount) % 0x2000;
for(ULONG i = 0; i < Length && DevExt->ReadBufferCharsCount <= 0x2000; i ++,WritePos = (WritePos + 1) % 0x2000,DevExt->ReadBufferCharsCount ++)
{
UCHAR Char = Buffer[i];
DevExt->ReadBuffer[WritePos] = Char;
if(Char == DevExt->SerialChars.EventChar && DevExt->SerialChars.EventChar)
ReceivedEventChar = TRUE;
}
return ReceivedEventChar;
}
//
// copy from read buffer
//
VOID Usb2ComCopyFromReadBuffer(__in PUSB2COM_DEVICE_EXTENSION DevExt,__in PUCHAR Buffer,__in ULONG Length)
{
ULONG LengthFirstTry = 0x2000 - DevExt->FirstReadCharSlot;
if(LengthFirstTry > Length)
LengthFirstTry = Length;
RtlCopyMemory(Buffer,DevExt->ReadBuffer + DevExt->FirstReadCharSlot,LengthFirstTry);
DevExt->FirstReadCharSlot = (DevExt->FirstReadCharSlot + LengthFirstTry) % 0x2000;
if(LengthFirstTry < Length)
{
ASSERT(!DevExt->FirstReadCharSlot);
RtlCopyMemory(Buffer + LengthFirstTry,DevExt->ReadBuffer,Length - LengthFirstTry);
DevExt->FirstReadCharSlot = Length - LengthFirstTry;
}
DevExt->ReadBufferCharsCount -= Length;
}
//
// process pending read
//
NTSTATUS Usb2ComProcessPendingReadIrps(__in PUSB2COM_DEVICE_EXTENSION DevExt,__out PLIST_ENTRY CompleteIrpListHead,__in BOOLEAN SetCancelRoutine)
{
NTSTATUS Status = STATUS_PENDING;
BOOLEAN FirstIrp = TRUE;
while(DevExt->CurrentReadIrp)
{
PIRP Irp = DevExt->CurrentReadIrp;
//
// set current read cancel routine
//
PDRIVER_CANCEL OldCancel = 0;
if(SetCancelRoutine)
OldCancel = IoSetCancelRoutine(Irp,&Usb2ComCurrentReadIrpCancel);
ASSERT(!OldCancel);
//
// IoCancelIrp called
//
if(Irp->Cancel)
{
OldCancel = IoSetCancelRoutine(Irp,0);
if(OldCancel)
{
Irp->IoStatus.Status = STATUS_CANCELLED;
InsertTailList(CompleteIrpListHead,&Irp->Tail.Overlay.ListEntry);
if(FirstIrp)
{
FirstIrp = FALSE;
Status = STATUS_CANCELLED;
}
}
else
{
IoMarkIrpPending(Irp);
FirstIrp = FALSE;
}
}
else
{
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
ULONG LengthInIrp = IrpSp->Parameters.Read.Length;
ULONG AlreadyReadCount = Irp->IoStatus.Information;
ULONG LeftCount = LengthInIrp - AlreadyReadCount;
PUCHAR IrpBuffer = static_cast<PUCHAR>(Irp->AssociatedIrp.SystemBuffer);
ULONG CopyCount = LeftCount > DevExt->ReadBufferCharsCount ? DevExt->ReadBufferCharsCount : LeftCount;
if(CopyCount)
{
//
// copy from read buffer to user irp buffer
//
Usb2ComCopyFromReadBuffer(DevExt,IrpBuffer + AlreadyReadCount,CopyCount);
//
// update irp's length
//
Irp->IoStatus.Information += CopyCount;
}
//
// we can complete the current irp
//
if(LeftCount == CopyCount)
{
OldCancel = IoSetCancelRoutine(Irp,0);
if(OldCancel)
{
ASSERT(OldCancel == &Usb2ComCurrentReadIrpCancel);
InsertTailList(CompleteIrpListHead,&Irp->Tail.Overlay.ListEntry);
Irp->IoStatus.Status = STATUS_SUCCESS;
}
else
{
IoMarkIrpPending(Irp);
}
if(FirstIrp)
{
FirstIrp = FALSE;
Status = OldCancel ? STATUS_SUCCESS : STATUS_PENDING;
}
}
else
{
IoMarkIrpPending(Irp);
break;
}
}
DevExt->CurrentReadIrp = Usb2ComGetNextReadIrp(DevExt);
SetCancelRoutine = TRUE;
}
return Status;
}
//
// bulk in urb complete routine
//
NTSTATUS Usb2ComBulkInUrbComplete(__in PDEVICE_OBJECT DeviceObject,__in PIRP Irp,__in PVOID Context)
{
PUSB2COM_DEVICE_EXTENSION DevExt = static_cast<PUSB2COM_DEVICE_EXTENSION>(Context);
NTSTATUS Status = Irp->IoStatus.Status;
PURB Urb = DevExt->BulkInUrb;
ULONG EventFlags = 0;
KIRQL SavedIrql;
KeAcquireSpinLock(&DevExt->ReadLock,&SavedIrql);
//
// current bulk in urb is finished
//
DevExt->BulkInUrbIsRunning = FALSE;
LIST_ENTRY CompleteIrpListHead;
InitializeListHead(&CompleteIrpListHead);
if(NT_SUCCESS(Status))
{
//
// update read buffer
//
if(Usb2ComUpdateReadBuffer(DevExt,static_cast<PUCHAR>(Urb->UrbBulkOrInterruptTransfer.TransferBuffer),Urb->UrbBulkOrInterruptTransfer.TransferBufferLength))
EventFlags |= SERIAL_EV_RXFLAG;
//
// process pending read
//
Usb2ComProcessPendingReadIrps(DevExt,&CompleteIrpListHead,FALSE);
if(DevExt->ReadBufferCharsCount)
EventFlags |= SERIAL_EV_RXCHAR;
if(DevExt->ReadBufferCharsCount > 0x2000 * 80 / 100)
EventFlags |= SERIAL_EV_RX80FULL;
}
Usb2ComStartBulkInUrb(DevExt,TRUE,SavedIrql);
if(EventFlags & SERIAL_EV_RXFLAG)
{
Usb2ComProcessEvent(DevExt,SERIAL_EV_RXFLAG);
EventFlags &= (~SERIAL_EV_RXFLAG);
}
if(EventFlags)
Usb2ComProcessEvent(DevExt,EventFlags);
while(!IsListEmpty(&CompleteIrpListHead))
{
PLIST_ENTRY ListEntry = RemoveHeadList(&CompleteIrpListHead);
PIRP Irp = CONTAINING_RECORD(ListEntry,IRP,Tail.Overlay.ListEntry);
IoCompleteRequest(Irp,IO_NO_INCREMENT);
IoReleaseRemoveLock(&DevExt->RemoveLock,Irp);
}
return STATUS_MORE_PROCESSING_REQUIRED;
}
//
// start bulk in urb
//
VOID Usb2ComStartBulkInUrb(__in PUSB2COM_DEVICE_EXTENSION DevExt,__in BOOLEAN AlreadyLocked,__in KIRQL SavedIrql)
{
BOOLEAN ReleaseLock = TRUE;
__try
{
//
// acquire read lock
//
if(!AlreadyLocked)
KeAcquireSpinLock(&DevExt->ReadLock,&SavedIrql);
//
// check read urb is running
//
if(!DevExt->BulkInUrbIsRunning)
{
//
// check hold condition
//
if(DevExt->RxHoldReason)
try_leave(NOTHING);
//
// reuse read irp
//
IoReuseIrp(DevExt->BulkInIrp,STATUS_SUCCESS);
UsbBuildInterruptOrBulkTransferRequest(DevExt->BulkInUrb,sizeof(_URB_BULK_OR_INTERRUPT_TRANSFER),DevExt->UsbInterfaceInfo->Pipes[2].PipeHandle,
DevExt->BulkInBuffer,0,0x40,USBD_TRANSFER_DIRECTION_IN | USBD_SHORT_TRANSFER_OK,0);
PIO_STACK_LOCATION NextIrpSp = IoGetNextIrpStackLocation(DevExt->BulkInIrp);
NextIrpSp->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
NextIrpSp->Parameters.Others.Argument1 = DevExt->BulkInUrb;
NextIrpSp->Parameters.Others.Argument2 = 0;
NextIrpSp->Parameters.Others.Argument3 = reinterpret_cast<PVOID>(IOCTL_INTERNAL_USB_SUBMIT_URB);
NextIrpSp->Parameters.Others.Argument4 = 0;
IoSetCompletionRoutine(DevExt->BulkInIrp,&Usb2ComBulkInUrbComplete,DevExt,TRUE,TRUE,TRUE);
if(!DevExt->ForceBulkInUrbStop)
{
DevExt->BulkInUrbIsRunning = TRUE;
KeResetEvent(&DevExt->BulkInUrbStopEvent);
KeReleaseSpinLock(&DevExt->ReadLock,SavedIrql);
ReleaseLock = FALSE;
IoCallDriver(DevExt->LowerDeviceObject,DevExt->BulkInIrp);
}
}
}
__finally
{
if(ReleaseLock)
{
BOOLEAN SetEvent = !DevExt->BulkInUrbIsRunning;
KeReleaseSpinLock(&DevExt->ReadLock,SavedIrql);
if(SetEvent)
KeSetEvent(&DevExt->BulkInUrbStopEvent,IO_NO_INCREMENT,FALSE);
}
}
}
//
// stop bulk in urb
//
VOID Usb2ComStopBulkInUrb(__in PUSB2COM_DEVICE_EXTENSION DevExt)
{
KIRQL SavedIrql;
KeAcquireSpinLock(&DevExt->ReadLock,&SavedIrql);
DevExt->ForceBulkInUrbStop = TRUE;
KeReleaseSpinLock(&DevExt->ReadLock,SavedIrql);
IoCancelIrp(DevExt->BulkInIrp);
}
//
// wait bulk in urb stop
//
VOID Usb2ComWaitBulkInUrbStopped(__in PUSB2COM_DEVICE_EXTENSION DevExt)
{
KeWaitForSingleObject(&DevExt->BulkInUrbStopEvent,Executive,KernelMode,FALSE,0);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -