📄 intrwr.c
字号:
//
if(deviceExtension->SSEnable) {
KeWaitForSingleObject(&deviceExtension->NoIdleReqPendEvent,
Executive,
KernelMode,
FALSE,
NULL);
}
if(fileObject && fileObject->FsContext) {
pipeInformation = fileObject->FsContext;
if(UsbdPipeTypeInterrupt != pipeInformation->PipeType) {
KdPrint( ("Usbd pipe type is not int\n"));
ntStatus = STATUS_INVALID_HANDLE;
goto IntUsb_DispatchReadWrite_Exit;
}
}
else {
KdPrint( ("Invalid handle\n"));
ntStatus = STATUS_INVALID_HANDLE;
goto IntUsb_DispatchReadWrite_Exit;
}
rwContext = (PINTUSB_RW_CONTEXT)
ExAllocatePool(NonPagedPool,
sizeof(INTUSB_RW_CONTEXT));
if(rwContext == NULL) {
KdPrint( ("Failed to alloc mem for rwContext\n"));
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
goto IntUsb_DispatchReadWrite_Exit;
}
// Get the length from the current Write Request
if(Irp->AssociatedIrp.SystemBuffer) {
Length = IrpStack->Parameters.Write.Length;
}
if(Length > INTUSB_TEST_BOARD_TRANSFER_BUFFER_SIZE) {
KdPrint( ("Transfer length > buffer\n"));
ntStatus = STATUS_INVALID_PARAMETER;
ExFreePool(rwContext);
goto IntUsb_DispatchReadWrite_Exit;
}
urbFlags |= USBD_TRANSFER_DIRECTION_OUT;
KdPrint( ("Write operation\n"));
urb = ExAllocatePool(NonPagedPool,
sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER));
if(urb == NULL) {
KdPrint( ("Failed to alloc mem for urb\n"));
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
ExFreePool(rwContext);
goto IntUsb_DispatchReadWrite_Exit;
}
UsbBuildInterruptOrBulkTransferRequest(
urb,
sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER),
pipeInformation->PipeHandle,
Irp->AssociatedIrp.SystemBuffer,
NULL,
Length,
urbFlags,
NULL);
//
// set INTUSB_RW_CONTEXT parameters.
//
rwContext->Urb = urb;
rwContext->Length = Length;
rwContext->Numxfer = 0;
rwContext->DeviceExtension = deviceExtension;
//
// use the original read/write irp as an internal device control irp
//
nextStack = IoGetNextIrpStackLocation(Irp);
nextStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
nextStack->Parameters.Others.Argument1 = (PVOID) urb;
nextStack->Parameters.DeviceIoControl.IoControlCode =
IOCTL_INTERNAL_USB_SUBMIT_URB;
IoSetCompletionRoutine(Irp,
(PIO_COMPLETION_ROUTINE)IntUsb_WriteCompletion,
rwContext,
TRUE,
TRUE,
TRUE);
//
// since we return STATUS_PENDING call IoMarkIrpPending.
//
IoMarkIrpPending(Irp);
KdPrint( ("IntUsb_DispatchReadWrite::"));
IntUsb_IoIncrement(deviceExtension);
ntStatus = IoCallDriver(deviceExtension->TopOfStackDeviceObject,
Irp);
if(!NT_SUCCESS(ntStatus)) {
KdPrint( ("IoCallDriver fails with status %X\n", ntStatus));
//
// if the device was removed, then the pipeInformation
// field is invalid.
// similarly if the request was cancelled, then we need not
// invoked reset pipe/device.
//
if((ntStatus != STATUS_CANCELLED) &&
(ntStatus != STATUS_DEVICE_NOT_CONNECTED)) {
ntStatus = IntUsb_ResetPipe(DeviceObject,
pipeInformation);
if(!NT_SUCCESS(ntStatus)) {
KdPrint( ("IntUsb_ResetPipe failed\n"));
ntStatus = IntUsb_ResetDevice(DeviceObject);
}
}
else {
KdPrint( ("ntStatus is STATUS_CANCELLED or "
"STATUS_DEVICE_NOT_CONNECTED\n"));
}
}
//
// we return STATUS_PENDING and not the status returned by the lower layer.
//
return STATUS_PENDING;
IntUsb_DispatchReadWrite_Exit:
Irp->IoStatus.Status = ntStatus;
Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
KdPrint( ("IntUsb_DispatchReadWrite - ends\n"));
return ntStatus;
}
NTSTATUS
IntUsb_WriteCompletion(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID Context
)
/*++
Routine Description:
This is the completion routine for writes
Arguments:
DeviceObject - pointer to device object
Irp - I/O request packet
Context - context passed to the completion routine.
Return Value:
NT status value
--*/
{
ULONG stageLength;
NTSTATUS ntStatus;
PIO_STACK_LOCATION nextStack;
PINTUSB_RW_CONTEXT rwContext;
//
// initialize variables
//
rwContext = (PINTUSB_RW_CONTEXT) Context;
ntStatus = Irp->IoStatus.Status;
UNREFERENCED_PARAMETER(DeviceObject);
KdPrint( ("IntUsb_WriteCompletion - begins\n"));
//
// successfully performed a transfer.
//
if(NT_SUCCESS(ntStatus))
Irp->IoStatus.Information = rwContext->Urb->UrbBulkOrInterruptTransfer.TransferBufferLength;
else
KdPrint( ("ReadWriteCompletion - failed with status = %X\n",
ntStatus));
if(rwContext) {
//
// dump rwContext
//
KdPrint( ("rwContext->Urb = %X\n",
rwContext->Urb));
KdPrint( ("rwContext->Mdl = %X\n",
rwContext->Mdl));
KdPrint( ("rwContext->Length = %d\n",
rwContext->Length));
KdPrint( ("rwContext->Numxfer = %d\n",
rwContext->Numxfer));
KdPrint( ("rwContext->DeviceExtension = %X\n",
rwContext->DeviceExtension));
KdPrint( ("IntUsb_ReadWriteCompletion::"));
IntUsb_IoDecrement(rwContext->DeviceExtension);
ExFreePool(rwContext->Urb);
ExFreePool(rwContext);
}
KdPrint( ("IntUsb_WriteCompletion - ends\n"));
return ntStatus;
}
NTSTATUS
IntUsb_DispatchRead(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
/*++
Routine Description:
Dispatch routine for read requests.
Arguments:
DeviceObject - pointer to device object
Irp - I/O request packet
Return Value:
NT status value
--*/
{
NTSTATUS status;
PDEVICE_EXTENSION deviceExtension;
UCHAR localBuffer[12];
ULONG info = 0;
KdPrint( ("IntUsb_DispatchRead - begins\n"));
deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
IntUsb_IoIncrement(deviceExtension);
// If an interrupt request is already outstanding, use that interrupt to service
// this IRP instead of waiting for another interrupt.
// The deviceExtension variable numintsIN tracks the number of interrupts
// which have occurred but not been serviced.
if (InterlockedDecrement(&deviceExtension->numintsIN) >= 0)
{
// Exchange data between the Polling URB and the Servicing IRP
RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer,&deviceExtension->intdataIN,deviceExtension->intdataLength);
RtlZeroMemory(&deviceExtension->intdataIN, MAX_TRANSFER_SIZE);
info = deviceExtension->intdataLength; // Length is always 12 bytes when successful
status = STATUS_SUCCESS;
}
else // Pend this Read Request until an interrupt occurs
{
InterlockedIncrement(&deviceExtension->numintsIN);
if(deviceExtension->NumCachedRequests <= 4)
status = CacheReadRequest(deviceExtension, Irp, &deviceExtension->InterruptIrp);
else
status = STATUS_DEVICE_BUSY;
}
//IoCompleteRequest(Irp, IO_NO_INCREMENT);
KdPrint( ("IntUsb_DispatchRead - ends\n"));
IntUsb_IoDecrement(deviceExtension);
return status == STATUS_PENDING ? status : CompleteRequest(Irp, status, info);;
}
PIRP UncacheReadRequest(
PDEVICE_EXTENSION DeviceExtension,
PIRP* pIrp
)
/*++
Routine Description:
This routine will return a pointer to a Cached Read Request
if such a request has been cached.
Arguments:
deviceExtension - Pointer to the device Extension
pIrp - Where to save pointer to uncached IRP
Return Value:
None
--*/
{
KIRQL oldirql;
PIRP Irp;
KeAcquireSpinLock(&(DeviceExtension->Cachelock), &oldirql);
Irp = (PIRP) InterlockedExchangePointer(pIrp, NULL);
if(Irp)
{
// If an IRP has been cached then a Cancel routine
// has already been set, and this call to IoSetCancelRoutine
// will return that Cancel routine.
if(IoSetCancelRoutine(Irp, NULL))
{
// Since we now know we have a Cached IRP we can
// now retrieve it.
RemoveEntryList(&Irp->Tail.Overlay.ListEntry);
}
else
Irp = NULL;
}
DeviceExtension->NumCachedRequests--;
KeReleaseSpinLock(&(DeviceExtension->Cachelock), oldirql);
return Irp;
}
NTSTATUS CacheReadRequest(
PDEVICE_EXTENSION DeviceExtension,
PIRP Irp,
PIRP* pIrp
)
/*++
Routine Description:
This routine will cache a Read Request until it can
be serviced by an interrupt in the OnInterruptIN routine.
Arguments:
deviceExtension - Pointer to the device Extension
Irp - IRP to cache
pIrp - Where to save pointer to cached IRP
Return Value:
NTSTATUS value.
www.
--*/
{
KIRQL oldirql;
NTSTATUS status;
PIO_STACK_LOCATION stack;
PFILE_OBJECT fileObject;
ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
// Make sure there's an extra stack location for us to use
if (Irp->CurrentLocation <= 1)
return STATUS_INVALID_PARAMETER; // no stack for us
// Acquire a lock on cache access.
KeAcquireSpinLock(&(DeviceExtension->Cachelock), &oldirql);
if (*pIrp)
status = STATUS_UNSUCCESSFUL; // something already cached here
else
{ // try to cache IRP
// Install a cancel routine
IoSetCancelRoutine(Irp, OnCancelReadRequest);
// Check to see if this Irp has already been cancelled
if (Irp->Cancel && IoSetCancelRoutine(Irp, NULL))
status = STATUS_CANCELLED; // already cancelled
// Cache this IRP in our list of Pending Read Requests.
else
{ // cache it
IoMarkIrpPending(Irp);
status = STATUS_PENDING;
stack = IoGetCurrentIrpStackLocation(Irp);
stack->Parameters.Others.Argument1 = (PVOID) pIrp;
//Install a completion routine to nullify the cache pointer.
IoSetCompletionRoutine(Irp, (PIO_COMPLETION_ROUTINE) OnCompleteReadRequest, (PVOID) DeviceExtension, TRUE, TRUE, TRUE);
IoSetNextIrpStackLocation(Irp); // so our completion routine will get called
fileObject = stack->FileObject;
stack = IoGetCurrentIrpStackLocation(Irp);
stack->DeviceObject = DeviceExtension->FunctionalDeviceObject; // so CancelIrp can give us right ptr
stack->FileObject = fileObject; // for cleanup
*pIrp = Irp;
// Add this request to our list of Read Requests
InsertTailList(&DeviceExtension->Pending_IOCTL_READINT_List, &Irp->Tail.Overlay.ListEntry);
DeviceExtension->NumCachedRequests++;
} // cache it
} // try to cache IRP
KeReleaseSpinLock(&(DeviceExtension->Cachelock), oldirql);
return status;
}
//////////////////////////////////////////////////////////////////////////////
#pragma LOCKEDCODE
NTSTATUS OnCompleteReadRequest(
PDEVICE_OBJECT DeviceObject,
PIRP Irp,
PDEVICE_EXTENSION DeviceExtension
)
/*++
Routine Description:
This routine is called upon completion of an IRP associated
with a Read Request.
Arguments:
DeviceObject - pointer to device object
Irp - IRP which has finished
deviceExtension - Pointer to the device Extension
Return Value:
NTSTATUS value.
--*/
{
KIRQL oldirql;
PIRP* pIrp;
KeAcquireSpinLock(&DeviceExtension->Cachelock, &oldirql);
pIrp = (PIRP*) IoGetCurrentIrpStackLocation(Irp)->Parameters.Others.Argument1;
if (*pIrp == Irp)
*pIrp = NULL;
KeReleaseSpinLock(&DeviceExtension->Cachelock, oldirql);
return STATUS_SUCCESS;
}
///////////////////////////////////////////////////////////////////////////////
#pragma LOCKEDCODE
VOID OnCancelReadRequest(
PDEVICE_OBJECT DeviceObject,
PIRP Irp
)
/*++
Routine Description:
This routine is called upon cancellation of an IRP associated
with a Read Request.
Arguments:
DeviceObject - pointer to device object
Irp - IRP which has been cancelled
Return Value:
NTSTATUS value.
--*/
{
PDEVICE_EXTENSION deviceExtension;
KIRQL oldirql;
oldirql= Irp->CancelIrql;
IoReleaseCancelSpinLock(DISPATCH_LEVEL);
deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
// Remove this request to our list of Read Requests
KeAcquireSpinLockAtDpcLevel(&deviceExtension->Cachelock);
RemoveEntryList(&Irp->Tail.Overlay.ListEntry);
KeReleaseSpinLock(&deviceExtension->Cachelock, oldirql);
// Complete the IRP
Irp->IoStatus.Status = STATUS_CANCELLED;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -