📄 readwrite.cpp
字号:
// If the IRP/URB construction loop finished early, there must have been a memory allocation
// error.
if (i < numirps)
status = STATUS_INSUFFICIENT_RESOURCES;
// See if the main IRP has already been cancelled.
else
{ // check for cancellation
IoSetCancelRoutine(Irp, OnCancelReadWrite);
if (Irp->Cancel)
{
status = STATUS_CANCELLED;
// The main IRP has been cancelled. If the cancellation just happened and our
// cancel routine was called, the following call to IoSetCancelRoutine will
// return NULL. In this case, both our cleanup code (see below) and the cancel
// routine will be calling DestroyContextStructure. One or the other of those
// calls will finish the cleanup of the structure. Otherwise, it will no longer
// be possible for our cancel routine to get called and we should get rid of
// its now-unnecessary claim on the structure.
if (IoSetCancelRoutine(Irp, NULL))
--ctx->refcnt;
}
else
status = STATUS_SUCCESS;
} // check for cancellation
// Install a completion routine for the main IRP. It will normally be called when
// the last stage IRP finishes. It might get called pretty soon, though, if we
// fail the IRP before submitting the stage IRPs.
IoSetCompletionRoutine(Irp, (PIO_COMPLETION_ROUTINE) OnReadWriteComplete,
(PVOID) ctx, TRUE, TRUE, TRUE);
IoMarkIrpPending(Irp);
IoSetNextIrpStackLocation(Irp); // so our completion routine will get called
// If we need to fail the main IRP, cleanup and fail it now.
if (!NT_SUCCESS(status))
{ // abort now
for (i = 0; i < numirps; ++i)
{ // release memory we were able to allocate
if (ctx->sub[i].urb)
ExFreePool(ctx->sub[i].urb);
if (ctx->sub[i].mdl)
IoFreeMdl(ctx->sub[i].mdl);
} // release memory we were able to allocate
CompleteRequest(Irp, status, 0); // will trigger completion routine
return STATUS_PENDING;
} // abort now
ASSERT(length == 0); // IRP construction loop didn't work right if not true
// Install a completion routine for the main IRP. Once this is in place, submit the
// subsidiary IRPs. Note that we can't touch the main IRP pointer after we submit the
// subsidiary IRPs because the sub-IRP completion routine (OnStageComplete) may complete it.
for (i = 0; i < numirps; ++i)
IoCallDriver(pdx->LowerDeviceObject, ctx->sub[i].irp);
return STATUS_PENDING;
} // DispatchRead
///////////////////////////////////////////////////////////////////////////////
#pragma PAGEDCODE
NTSTATUS GetStringDescriptor(PDEVICE_OBJECT fdo, UCHAR istring, PUNICODE_STRING s)
{ // GetStringDescriptor
NTSTATUS status;
PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION) fdo->DeviceExtension;
URB urb;
UCHAR data[256]; // maximum-length buffer
// If this is the first time here, read string descriptor zero and arbitrarily select
// the first language identifer as the one to use in subsequent get-descriptor calls.
if (!pdx->langid)
{ // determine default language id
UsbBuildGetDescriptorRequest(&urb, sizeof(_URB_CONTROL_DESCRIPTOR_REQUEST), USB_STRING_DESCRIPTOR_TYPE,
0, 0, data, NULL, sizeof(data), NULL);
status = SendAwaitUrb(fdo, &urb);
if (!NT_SUCCESS(status))
return status;
pdx->langid = *(LANGID*)(data + 2);
} // determine default language id
// Fetch the designated string descriptor.
UsbBuildGetDescriptorRequest(&urb, sizeof(_URB_CONTROL_DESCRIPTOR_REQUEST), USB_STRING_DESCRIPTOR_TYPE,
istring, pdx->langid, data, NULL, sizeof(data), NULL);
status = SendAwaitUrb(fdo, &urb);
if (!NT_SUCCESS(status))
return status;
ULONG nchars = (data[0] - 2) / 2;
PWSTR p = (PWSTR) ExAllocatePool(PagedPool, data[0]);
if (!p)
return STATUS_INSUFFICIENT_RESOURCES;
memcpy(p, data + 2, nchars*2);
p[nchars] = 0;
s->Length = (USHORT) (2 * nchars);
s->MaximumLength = (USHORT) ((2 * nchars) + 2);
s->Buffer = p;
return STATUS_SUCCESS;
} // GetStringDescriptor
///////////////////////////////////////////////////////////////////////////////
#pragma LOCKEDCODE
VOID OnCancelReadWrite(PDEVICE_OBJECT fdo, PIRP Irp)
{ // OnCancelReadWrite
IoReleaseCancelSpinLock(Irp->CancelIrql);
// Attempt to cancel all the subsidiary IRPs for this IRP. The main IRP cannot
// have progressed in the cancellation process past our own completion routine,
// so it's safe to use DriverContext as a pointer to the context structure.
PRWCONTEXT ctx = (PRWCONTEXT) Irp->Tail.Overlay.DriverContext[0];
for (ULONG i = 0; i < ctx->numirps; ++i)
IoCancelIrp(ctx->sub[i].irp);
// Release our claim on the context structure and subsidiary IRP pointers. If
// the completion routine has already run, it's up to us to finish the
// completion process for this IRP.
PDEVICE_EXTENSION pdx = ctx->pdx;
if (DestroyContextStructure(ctx))
{ // we're last
CompleteRequest(Irp, STATUS_CANCELLED, 0);
IoReleaseRemoveLock(&pdx->RemoveLock, Irp);
} // we're last
} // OnCancelReadWrite
///////////////////////////////////////////////////////////////////////////////
#pragma LOCKEDCODE
NTSTATUS OnReadWriteComplete(PDEVICE_OBJECT fdo, PIRP Irp, PRWCONTEXT ctx)
{ // OnReadWriteComplete
ASSERT(ctx->mainirp == Irp);
PDEVICE_EXTENSION pdx = ctx->pdx;
if (NT_SUCCESS(Irp->IoStatus.Status))
Irp->IoStatus.Information = ctx->numxfer;
else
InterlockedIncrement(&pdx->inerror);
// Release the context structure. If the cancel routine has run (or can't ever
// run), we'll return a normal status. If the cancel routine is working now as
// well, however, return STATUS_MORE_PROCESSING_REQUIRED to stop the completion
// process for the time being.
if (DestroyContextStructure(ctx))
{ // we're last
IoReleaseRemoveLock(&pdx->RemoveLock, Irp);
return STATUS_SUCCESS;
} // we're last
else
return STATUS_MORE_PROCESSING_REQUIRED;
} // OnReadWriteComplete
///////////////////////////////////////////////////////////////////////////////
#pragma LOCKEDCODE
NTSTATUS OnStageComplete(PDEVICE_OBJECT fdo, PIRP Irp, PRWCONTEXT ctx)
{ // OnStageComplete
PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(Irp);
PIRP mainirp = ctx->mainirp;
PURB urb = (PURB) stack->Parameters.Others.Argument1;
NTSTATUS status = Irp->IoStatus.Status;
if (NT_SUCCESS(status))
ctx->numxfer += urb->UrbIsochronousTransfer.TransferBufferLength;
else
{
KdPrint((DRIVERNAME " - read failed with status %X (USBD status %X)\n", status, URB_STATUS(urb)));
ctx->status = status;
}
#if DBG
KdPrint((DRIVERNAME " - iso transfer started in frame %8.8lX, %d packets had errors\n",
urb->UrbIsochronousTransfer.StartFrame, urb->UrbIsochronousTransfer.ErrorCount));
for (ULONG i = 0; i < urb->UrbIsochronousTransfer.NumberOfPackets; ++i)
{ // for each packet
PUSBD_ISO_PACKET_DESCRIPTOR pipd = &urb->UrbIsochronousTransfer.IsoPacket[i];
KdPrint((DRIVERNAME " - Packet %d, %d bytes, ending status %8.8lX\n", i, pipd->Length, pipd->Status));
} // for each packet
#endif
ExFreePool(urb);
IoFreeMdl((PMDL) stack->Parameters.Others.Argument2);
if (InterlockedDecrement(&ctx->numpending) == 0)
{ // complete main IRP
// Clear the main IRP's cancel pointer in preparation for completing it. If
// the cancel routine has already run (or is now running), it called/will call
// DestroyContextStructure. If IoSetCancelRoutine returns a non-NULL value,
// however, it means that the cancel routine can never be called. We should
// therefore use up its reference to the context structure so the main
// completion routine can delete it.
if (IoSetCancelRoutine(mainirp, NULL))
InterlockedDecrement(&ctx->refcnt); // cancel routine can no longer run
mainirp->IoStatus.Status = ctx->status;
IoCompleteRequest(mainirp, IO_NO_INCREMENT);
} // complete main IRP
// Return STATUS_MORE_PROCESSING_REQUIRED to prevent IoCompleteRequest from
// queuing an APC to release the memory for this subsidiary IRP. A comment
// in OnReadWriteComplete explains what's going on here
return STATUS_MORE_PROCESSING_REQUIRED;
} // OnStageComplete
//////////////////////////////////////////////////////////////////////////////
#pragma PAGEDCODE
VOID ResetDevice(PDEVICE_OBJECT fdo)
{ // ResetDevice
PAGED_CODE();
PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION) fdo->DeviceExtension;
KEVENT event;
KeInitializeEvent(&event, NotificationEvent, FALSE);
IO_STATUS_BLOCK iostatus;
PIRP Irp = IoBuildDeviceIoControlRequest(IOCTL_INTERNAL_USB_RESET_PORT,
pdx->LowerDeviceObject, NULL, 0, NULL, 0, TRUE, &event, &iostatus);
if (!Irp)
return;
NTSTATUS status = IoCallDriver(pdx->LowerDeviceObject, Irp);
if (status == STATUS_PENDING)
{
KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
status = iostatus.Status;
}
if (!NT_SUCCESS(status))
KdPrint((DRIVERNAME " - Error %X trying to reset device\n", status));
} // ResetDevice
///////////////////////////////////////////////////////////////////////////////
#pragma PAGEDCODE
NTSTATUS ResetPipe(PDEVICE_OBJECT fdo, USBD_PIPE_HANDLE hpipe)
{ // ResetPipe
PAGED_CODE();
PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION) fdo->DeviceExtension;
URB urb;
urb.UrbHeader.Length = (USHORT) sizeof(_URB_PIPE_REQUEST);
urb.UrbHeader.Function = URB_FUNCTION_RESET_PIPE;
urb.UrbPipeRequest.PipeHandle = hpipe;
NTSTATUS status = SendAwaitUrb(fdo, &urb);
if (!NT_SUCCESS(status))
KdPrint((DRIVERNAME " - Error %X trying to reset a pipe\n", status));
return status;
} // ResetPipe
///////////////////////////////////////////////////////////////////////////////
#pragma PAGEDCODE
NTSTATUS SelectAlternateInterface(PDEVICE_OBJECT fdo)
{ // SelectAlternateInterface
NTSTATUS status;
PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION) fdo->DeviceExtension;
// Locate the descriptor for the alternate interface we want
PUSB_INTERFACE_DESCRIPTOR pid = USBD_ParseConfigurationDescriptorEx(pdx->pcd, pdx->pcd,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -