📄 rw.c
字号:
}
else {
// This IRP was just canceled and the cancel routine was (or will be) called.
// The cancel routine will complete this IRP as soon as we drop the spin lock,
// so don't do anything with the IRP.
// Also, the cancel routine will try to dequeue the IRP,
// so make the IRP's listEntry point to itself.
ASSERT(nextIrp->Cancel);
InitializeListHead(&nextIrp->Tail.Overlay.ListEntry);
nextIrp = NULL;
}
}
KeReleaseSpinLock(&deviceExtension->ReadQueueSpinLock, oldIrql);
DbgPrint("DequeueReadIrp Exit\n");
return nextIrp;
}
VOID IrpCancelRoutine(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
{
PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
KIRQL oldIrql;
DbgPrint("IrpCancelRoutine Enter\n");
// Release the global cancel spin lock.
// Do this while not holding any other spin locks so that we exit at the right IRQL.
IoReleaseCancelSpinLock(Irp->CancelIrql);
//
// Dequeue and complete the IRP.
// The enqueue and dequeue functions synchronize properly so that if this cancel routine is called,
// the dequeue is safe and only the cancel routine will complete the IRP. Hold the spin lock for the IRP
// queue while we do this.
//
KeAcquireSpinLock(&deviceExtension->ReadQueueSpinLock, &oldIrql);
RemoveEntryList(&Irp->Tail.Overlay.ListEntry);
KeReleaseSpinLock(&deviceExtension->ReadQueueSpinLock, oldIrql);
// Complete the IRP. This is a call outside the driver, so all spin locks must be released by this point.
Irp->IoStatus.Status = STATUS_CANCELLED;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
DbgPrint("IrpCancelRoutine Exit\n");
return;
}
VOID
InitIntUrb(
IN PURB urb,
IN USBD_PIPE_HANDLE PipeHandle,
IN PUCHAR TransferBuffer,
IN ULONG length,
IN BOOLEAN Read
)
{
USHORT siz = sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER);
if (urb) {
RtlZeroMemory(urb, siz);
urb->UrbBulkOrInterruptTransfer.Hdr.Length = (USHORT) siz;
urb->UrbBulkOrInterruptTransfer.Hdr.Function =
URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER;
urb->UrbBulkOrInterruptTransfer.PipeHandle = PipeHandle;
urb->UrbBulkOrInterruptTransfer.TransferFlags =
Read ? USBD_TRANSFER_DIRECTION_IN : 0;
// short packet is not treated as an error.
urb->UrbBulkOrInterruptTransfer.TransferFlags |=
USBD_SHORT_TRANSFER_OK;
//
// not using linked urb's
//
urb->UrbBulkOrInterruptTransfer.UrbLink = NULL;
urb->UrbBulkOrInterruptTransfer.TransferBufferMDL = NULL;
urb->UrbBulkOrInterruptTransfer.TransferBuffer = TransferBuffer;
urb->UrbBulkOrInterruptTransfer.TransferBufferLength = length;
}
}
NTSTATUS
StartReadIntUrb(
IN PDEVICE_OBJECT DeviceObject,
IN PUSBD_PIPE_INFORMATION PipeInfo
)
{
NTSTATUS ntStatus = STATUS_SUCCESS;
PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
PIO_STACK_LOCATION nextStack;
PURB urb;
PIRP irp;
CHAR stackSize;
int i;
KIRQL oldIrql;
DbgPrint("StartReadIntUrb Enter.\n");
for(i=0; i<MAX_READ_INT_URBS; i++)
{
if ( !USB2COM_CanAcceptIoRequests( DeviceObject ) ) {
// got sudden remove! ( i.e. plug was yanked )
PIRP CurrentOpIrp;
KeAcquireSpinLock(&deviceExtension->ReadQueueSpinLock, &oldIrql);
CurrentOpIrp = InterlockedExchangePointer(&deviceExtension->CurrentReadIrp, NULL);
if(CurrentOpIrp) {
CurrentOpIrp->IoStatus.Status = STATUS_DELETE_PENDING;
CurrentOpIrp->IoStatus.Information = 0;
IoCompleteRequest( CurrentOpIrp, IO_NO_INCREMENT );
}
KeReleaseSpinLock(&deviceExtension->ReadQueueSpinLock, oldIrql);
return STATUS_DELETE_PENDING;
}
stackSize = (CCHAR) (deviceExtension->TopOfStackDeviceObject->StackSize + 1);
irp = IoAllocateIrp(stackSize, FALSE);
if(irp == NULL) {
return STATUS_INSUFFICIENT_RESOURCES;
}
urb = USB2COM_ExAllocatePool(NonPagedPool,
sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER));
if(urb == NULL)
{
IoFreeIrp(irp);
return STATUS_INSUFFICIENT_RESOURCES;
}
deviceExtension->ReadIntUrbs[i].Irp = irp;
deviceExtension->ReadIntUrbs[i].Urb = urb;
deviceExtension->ReadIntUrbs[i].deviceObject = DeviceObject;
deviceExtension->ReadIntUrbs[i].PipeInfo = PipeInfo;
InitIntUrb(urb,
PipeInfo->PipeHandle,
deviceExtension->ReadIntUrbs[i].TransferBuffer,
sizeof(deviceExtension->ReadIntUrbs[i].TransferBuffer),
TRUE);
nextStack = IoGetNextIrpStackLocation(irp);
USB2COM_ASSERT(nextStack != NULL);
USB2COM_ASSERT(DeviceObject->StackSize>1);
nextStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
nextStack->Parameters.Others.Argument1 = urb;
nextStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_URB;
IoSetCompletionRoutine(irp,
ReadIntUrbComplete,
&deviceExtension->ReadIntUrbs[i], // pass the context array element to completion routine
TRUE, // invoke on success
TRUE, // invoke on error
TRUE); // invoke on cancellation of the Irp
USB2COM_IncrementIoCount(DeviceObject);
ntStatus = IoCallDriver(deviceExtension->TopOfStackDeviceObject, irp );
//ASSERT( ntStatus == STATUS_PENDING);
}
DbgPrint("StartReadIntUrb Exit\n");
return ntStatus;
}
NTSTATUS
StopReadIntUrb(
IN PDEVICE_EXTENSION deviceExtension
)
{
KIRQL oldIrql;
int i;
DbgPrint("StopReadIntUrb Enter\n");
KeAcquireSpinLock(&deviceExtension->ReadQueueSpinLock, &oldIrql);
for(i=0; i<MAX_READ_INT_URBS; i++)
{
if(deviceExtension->ReadIntUrbs[i].Irp)
{
IoCancelIrp(deviceExtension->ReadIntUrbs[i].Irp);
}
}
KeReleaseSpinLock(&deviceExtension->ReadQueueSpinLock, oldIrql);
DbgPrint("StopReadIntUrb Exit\n");
return STATUS_SUCCESS;
}
NTSTATUS
ReadIntUrbComplete(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID Context
)
{
PDEVICE_OBJECT deviceObject;
NTSTATUS ntStatus;
USBD_STATUS usbdStatus;
PDEVICE_EXTENSION deviceExtension;
PIO_STACK_LOCATION nextStack;
PINT_URBS pIntUrbs;
PIRP irp;
PURB urb;
ULONG ioLength;
PUCHAR ioBuffer;
KIRQL oldIrql;
PIRP CurrentOpIrp;
DbgPrint("ReadIntUrbComplete Enter: DeviceObject=%p, Irp=%p, Context=%p\n",
DeviceObject,
Irp,
Context);
pIntUrbs = (PINT_URBS)Context;
irp = pIntUrbs->Irp;
urb = pIntUrbs->Urb;
deviceObject = pIntUrbs->deviceObject;
deviceExtension = (PDEVICE_EXTENSION)deviceObject->DeviceExtension;
DbgPrint("irp = %p, urb = %p, deviceObject = %p\n",irp,urb,deviceObject);
ASSERT(irp == Irp);
ASSERT(pIntUrbs->TransferBuffer == urb->UrbBulkOrInterruptTransfer.TransferBuffer);
ntStatus = irp->IoStatus.Status;
usbdStatus = urb->UrbHeader.Status;
DbgPrint("ntStatus=%x,usbdStatus=%x\n",ntStatus,usbdStatus);
if((ntStatus == STATUS_CANCELLED)
|| (ntStatus == STATUS_DEVICE_NOT_CONNECTED)
|| (usbdStatus == STATUS_DEVICE_NOT_CONNECTED))
{
KeAcquireSpinLock(&deviceExtension->ReadQueueSpinLock, &oldIrql);
IoFreeIrp(Irp);
pIntUrbs->Irp = NULL;
USB2COM_ExFreePool(pIntUrbs->Urb);
pIntUrbs->Urb = NULL;
CurrentOpIrp = InterlockedExchangePointer(&deviceExtension->CurrentReadIrp, NULL);
if(CurrentOpIrp) {
CurrentOpIrp->IoStatus.Status = STATUS_DELETE_PENDING;
CurrentOpIrp->IoStatus.Information = 0;
IoCompleteRequest( CurrentOpIrp, IO_NO_INCREMENT );
}
KeReleaseSpinLock(&deviceExtension->ReadQueueSpinLock, oldIrql);
USB2COM_DecrementIoCount(deviceObject);
return STATUS_MORE_PROCESSING_REQUIRED;
}
if(USBD_SUCCESS(usbdStatus))
{
DbgPrint("ReadIntUrbComplete: length = %d\n",urb->UrbBulkOrInterruptTransfer.TransferBufferLength);
if(urb->UrbBulkOrInterruptTransfer.TransferBufferLength > 1)
{
KeAcquireSpinLock(&deviceExtension->InputBufferLock, &oldIrql);
PushCircularBufferEntry(
&deviceExtension->InputBuffer,
&pIntUrbs->TransferBuffer[1],
pIntUrbs->TransferBuffer[0]);
KeReleaseSpinLock(&deviceExtension->InputBufferLock, oldIrql);
IoAcquireCancelSpinLock(&oldIrql);
deviceExtension->HistoryMask |= SERIAL_EV_RXCHAR;
if(deviceExtension->CurrentWaitIrp &&
(deviceExtension->HistoryMask & deviceExtension->WaitMask))
{
IoReleaseCancelSpinLock(oldIrql);
SerialCompleteCurrentWait(
deviceExtension->CurrentWaitIrp,
deviceExtension->HistoryMask & deviceExtension->WaitMask);
}else
IoReleaseCancelSpinLock(oldIrql);
}
}
//check whether we can complete the current Read Irp;
if(deviceExtension->CurrentReadIrp == NULL)
deviceExtension->CurrentReadIrp = DequeueReadIrp(deviceExtension);
if(deviceExtension->CurrentReadIrp)
{
ULONG haveLen;
BOOLEAN returnWhatsPresent = FALSE;
if(deviceExtension->SerialTimeOuts.ReadIntervalTimeout &&
( deviceExtension->SerialTimeOuts.ReadTotalTimeoutMultiplier == 0) &&
( deviceExtension->SerialTimeOuts.ReadTotalTimeoutConstant == 0)
){
returnWhatsPresent = TRUE;
}
ioBuffer = MmGetSystemAddressForMdlSafe(deviceExtension->CurrentReadIrp->MdlAddress,NormalPagePriority );
ioLength = MmGetMdlByteCount(deviceExtension->CurrentReadIrp->MdlAddress);
KeAcquireSpinLock(&deviceExtension->InputBufferLock, &oldIrql);
haveLen = CircularBufferDataLen(&deviceExtension->InputBuffer);
if( (ioLength <= haveLen) || (returnWhatsPresent && (haveLen > 0)))
{
ioLength = (ioLength < haveLen) ? ioLength : haveLen;
DbgPrint("Complete CurrentReadIrp ioLength = %d\n",ioLength);
ntStatus = PopCircularBufferEntry(&deviceExtension->InputBuffer,ioBuffer,ioLength);
KeReleaseSpinLock(&deviceExtension->InputBufferLock, oldIrql);
deviceExtension->CurrentReadIrp->IoStatus.Information = ioLength;
deviceExtension->CurrentReadIrp->IoStatus.Status = ntStatus;
IoCompleteRequest(deviceExtension->CurrentReadIrp,IO_NO_INCREMENT);
deviceExtension->CurrentReadIrp = DequeueReadIrp(deviceExtension);
}else
KeReleaseSpinLock(&deviceExtension->InputBufferLock, oldIrql);
}
if ( !USB2COM_CanAcceptIoRequests( deviceObject )
|| (deviceExtension->PipeInfo[0].fPipeOpened == FALSE)
)
{
// got sudden remove! ( i.e. plug was yanked )
DbgPrint("fPipeOpened %d\n",deviceExtension->PipeInfo[0].fPipeOpened);
KeAcquireSpinLock(&deviceExtension->ReadQueueSpinLock, &oldIrql);
pIntUrbs->Irp = NULL;
IoFreeIrp(Irp);
USB2COM_ExFreePool(pIntUrbs->Urb);
pIntUrbs->Urb = NULL;
CurrentOpIrp = InterlockedExchangePointer(&deviceExtension->CurrentReadIrp, NULL);
if(CurrentOpIrp) {
CurrentOpIrp->IoStatus.Status = STATUS_DELETE_PENDING;
CurrentOpIrp->IoStatus.Information = 0;
IoCompleteRequest( CurrentOpIrp, IO_NO_INCREMENT );
}
KeReleaseSpinLock(&deviceExtension->ReadQueueSpinLock, oldIrql);
USB2COM_DecrementIoCount(deviceObject);
return STATUS_MORE_PROCESSING_REQUIRED;
}
USB2COM_DecrementIoCount(deviceObject);
//
//circulate the irps.
//
DbgPrint("Circulate the irp\n");
// IoReuseIrp(Irp,STATUS_SUCCESS);
InitIntUrb(urb,
pIntUrbs->PipeInfo->PipeHandle,
pIntUrbs->TransferBuffer,
sizeof(pIntUrbs->TransferBuffer),
TRUE);
nextStack = IoGetNextIrpStackLocation(Irp);
USB2COM_ASSERT(nextStack != NULL);
USB2COM_ASSERT(deviceObject->StackSize>1);
nextStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
nextStack->Parameters.Others.Argument1 = urb;
nextStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_URB;
IoSetCompletionRoutine(Irp,
ReadIntUrbComplete,
pIntUrbs, // pass the context array element to completion routine
TRUE, // invoke on success
TRUE, // invoke on error
TRUE); // invoke on cancellation of the Irp
USB2COM_IncrementIoCount(deviceObject);
ntStatus = IoCallDriver(deviceExtension->TopOfStackDeviceObject, Irp );
ASSERT( ntStatus == STATUS_PENDING);
DbgPrint("ReadIntUrbComplete Exit\n");
return STATUS_MORE_PROCESSING_REQUIRED;
}
NTSTATUS
PrepareWriteIntUrb(
IN PDEVICE_OBJECT DeviceObject,
IN PUSBD_PIPE_INFORMATION PipeInfo
)
{
NTSTATUS ntStatus = STATUS_SUCCESS;
PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
CHAR stackSize;
DbgPrint("PrepareWriteIntUrb Enter.\n");
if(deviceExtension->WriteIntUrb.Irp == NULL)
{
stackSize = (CCHAR) (deviceExtension->TopOfStackDeviceObject->StackSize + 1);
deviceExtension->WriteIntUrb.Irp = IoAllocateIrp(stackSize, FALSE);
if(deviceExtension->WriteIntUrb.Irp == NULL) {
return STATUS_INSUFFICIENT_RESOURCES;
}
}
if(deviceExtension->WriteIntUrb.Urb == NULL)
{
deviceExtension->WriteIntUrb.Urb = USB2COM_ExAllocatePool(NonPagedPool,
sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER));
if(deviceExtension->WriteIntUrb.Urb == NULL)
{
IoFreeIrp(deviceExtension->WriteIntUrb.Irp);
return STATUS_INSUFFICIENT_RESOURCES;
}
}
deviceExtension->WriteIntUrb.Idle = TRUE;
deviceExtension->WriteIntUrb.deviceObject = DeviceObject;
deviceExtension->WriteIntUrb.PipeInfo = PipeInfo;
DbgPrint("PrepareWriteIntUrb Exit\n");
return ntStatus;
}
NTSTATUS
StartWriteIntUrb(
PDEVICE_OBJECT DeviceObject
)
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -