📄 readwrite.cpp
字号:
// 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;
// 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))
{
InterlockedExchangeAdd((PLONG) &ctx->numxfer, (LONG) 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
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,
0, 1, -1, -1, -1);
if (!pid)
{
KdPrint((DRIVERNAME " - No alternatate interface defined\n"));
return STATUS_DEVICE_CONFIGURATION_ERROR;
}
// Verify the characteristics of the interface
PUSB_CONFIGURATION_DESCRIPTOR pcd = pdx->pcd;
PUSB_ENDPOINT_DESCRIPTOR ped = (PUSB_ENDPOINT_DESCRIPTOR) pid;
ped = (PUSB_ENDPOINT_DESCRIPTOR) USBD_ParseDescriptors(pcd, pcd->wTotalLength, ped, USB_ENDPOINT_DESCRIPTOR_TYPE);
if (!ped || ped->bmAttributes != USB_ENDPOINT_TYPE_ISOCHRONOUS || ped->wMaxPacketSize < 16)
{
KdPrint((DRIVERNAME " - Alternate interface has wrong attributes\n"));
return STATUS_DEVICE_CONFIGURATION_ERROR;
}
// Allocate an URB big enough to describe the alternate interface. First determine
// how many pipes will be opened
ULONG size = GET_SELECT_INTERFACE_REQUEST_SIZE(pid->bNumEndpoints);
PURB urb = (PURB) ExAllocatePool(NonPagedPool, size);
if (!urb)
{
KdPrint((DRIVERNAME " - can't allocate %d bytes for Select Interface URB\n", size));
return STATUS_INSUFFICIENT_RESOURCES;
}
RtlZeroMemory(urb, size);
// Build and submit the URB
UsbBuildSelectInterfaceRequest(urb, (USHORT) size, pdx->hconfig, 0, 1);
urb->UrbSelectInterface.Interface.Length = GET_USBD_INTERFACE_SIZE(pid->bNumEndpoints);
urb->UrbSelectInterface.Interface.Pipes[0].MaximumTransferSize = PAGE_SIZE;
status = SendAwaitUrb(fdo, urb);
if (NT_SUCCESS(status))
{
pdx->hinpipe = urb->UrbSelectInterface.Interface.Pipes[0].PipeHandle;
MSGUSBSTRING(fdo, DRIVERNAME " - Selecting interface named %ws\n", pid->iInterface);
status = STATUS_SUCCESS;
}
else
KdPrint((DRIVERNAME " - Error %X trying to select alternate interface\n", status));
ExFreePool(urb);
return status;
} // SelectAlternateInterface
///////////////////////////////////////////////////////////////////////////////
#pragma PAGEDCODE
NTSTATUS SelectDefaultInterface(PDEVICE_OBJECT fdo)
{ // SelectDefaultInterface
NTSTATUS status;
PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION) fdo->DeviceExtension;
// Allocate an URB big enough to describe the default interface. First determine
// how many pipes will be opened
PUSB_INTERFACE_DESCRIPTOR pid = USBD_ParseConfigurationDescriptorEx(pdx->pcd, pdx->pcd,
0, 0, -1, -1, -1);
ASSERT(pid);
ULONG size = GET_SELECT_INTERFACE_REQUEST_SIZE(pid->bNumEndpoints);
PURB urb = (PURB) ExAllocatePool(NonPagedPool, size);
if (!urb)
{
KdPrint((DRIVERNAME " - can't allocate %d bytes for Select Interface URB\n", size));
return STATUS_INSUFFICIENT_RESOURCES;
}
RtlZeroMemory(urb, size);
// Build and submit the URB
UsbBuildSelectInterfaceRequest(urb, (USHORT) size, pdx->hconfig, 0, 0);
urb->UrbSelectInterface.Interface.Length = GET_USBD_INTERFACE_SIZE(pid->bNumEndpoints);
status = SendAwaitUrb(fdo, urb);
if (NT_SUCCESS(status))
{
pdx->hinpipe = NULL;
MSGUSBSTRING(fdo, DRIVERNAME " - Selecting interface named %ws\n", pid->iInterface);
status = STATUS_SUCCESS;
}
else
KdPrint((DRIVERNAME " - Error %X trying to select default interface\n", status));
ExFreePool(urb);
return status;
} // SelectDefaultInterface
///////////////////////////////////////////////////////////////////////////////
#pragma PAGEDCODE
NTSTATUS SendAwaitUrb(PDEVICE_OBJECT fdo, PURB urb)
{ // SendAwaitUrb
PAGED_CODE();
ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION) fdo->DeviceExtension;
KEVENT event;
KeInitializeEvent(&event, NotificationEvent, FALSE);
IO_STATUS_BLOCK iostatus;
PIRP Irp = IoBuildDeviceIoControlRequest(IOCTL_INTERNAL_USB_SUBMIT_URB,
pdx->LowerDeviceObject, NULL, 0, NULL, 0, TRUE, &event, &iostatus);
if (!Irp)
{
KdPrint((DRIVERNAME " - Unable to allocate IRP for sending URB\n"));
return STATUS_INSUFFICIENT_RESOURCES;
}
PIO_STACK_LOCATION stack = IoGetNextIrpStackLocation(Irp);
stack->Parameters.Others.Argument1 = (PVOID) urb;
NTSTATUS status = IoCallDriver(pdx->LowerDeviceObject, Irp);
if (status == STATUS_PENDING)
{
KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
status = iostatus.Status;
}
return status;
} // SendAwaitUrb
///////////////////////////////////////////////////////////////////////////////
#pragma PAGEDCODE
NTSTATUS StartDevice(PDEVICE_OBJECT fdo, PCM_PARTIAL_RESOURCE_LIST raw, PCM_PARTIAL_RESOURCE_LIST translated)
{ // StartDevice
PAGED_CODE();
NTSTATUS status;
PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION) fdo->DeviceExtension;
URB urb; // URB for use in this subroutine
// Read our device descriptor. The only real purpose to this would be to find out how many
// configurations there are so we can read their descriptors. In this simplest of examples,
// there's only one configuration.
UsbBuildGetDescriptorRequest(&urb, sizeof(_URB_CONTROL_DESCRIPTOR_REQUEST), USB_DEVICE_DESCRIPTOR_TYPE,
0, 0, &pdx->dd, NULL, sizeof(pdx->dd), NULL);
status = SendAwaitUrb(fdo, &urb);
if (!NT_SUCCESS(status))
{
KdPrint((DRIVERNAME " - Error %X trying to read device descriptor\n", status));
return status;
}
MSGUSBSTRING(fdo, DRIVERNAME " - Configuring device from %ws\n", pdx->dd.iManufacturer);
MSGUSBSTRING(fdo, DRIVERNAME " - Product is %ws\n", pdx->dd.iProduct);
MSGUSBSTRING(fdo, DRIVERNAME " - Serial number is %ws\n", pdx->dd.iSerialNumber);
// Read the descriptor of the first configuration. This requires two steps. The first step
// reads the fixed-size configuration descriptor alone. The second step reads the
// configuration descriptor plus all imbedded interface and endpoint descriptors.
USB_CONFIGURATION_DESCRIPTOR tcd;
UsbBuildGetDescriptorRequest(&urb, sizeof(_URB_CONTROL_DESCRIPTOR_REQUEST), USB_CONFIGURATION_DESCRIPTOR_TYPE,
0, 0, &tcd, NULL, sizeof(tcd), NULL);
status = SendAwaitUrb(fdo, &urb);
if (!NT_SUCCESS(status))
{
KdPrint((DRIVERNAME " - Error %X trying to read configuration descriptor 1\n", status));
return status;
}
ULONG size = tcd.wTotalLength;
PUSB_CONFIGURATION_DESCRIPTOR pcd = (PUSB_CONFIGURATION_DESCRIPTOR) ExAllocatePool(NonPagedPool, size);
if (!pcd)
{
KdPrint((DRIVERNAME " - Unable to allocate %X bytes for configuration descriptor\n", size));
return STATUS_INSUFFICIENT_RESOURCES;
}
__try
{
UsbBuildGetDescriptorRequest(&urb, sizeof(_URB_CONTROL_DESCRIPTOR_REQUEST), USB_CONFIGURATION_DESCRIPTOR_TYPE,
0, 0, pcd, NULL, size, NULL);
status = SendAwaitUrb(fdo, &urb);
if (!NT_SUCCESS(status))
{
KdPrint((DRIVERNAME " - Error %X trying to read configuration descriptor 1\n", status));
return status;
}
MSGUSBSTRING(fdo, DRIVERNAME " - Selecting configuration named %ws\n", pcd->iConfiguration);
// Locate the descriptor for the one and only interface we expect to find
PUSB_INTERFACE_DESCRIPTOR pid = USBD_ParseConfigurationDescriptorEx(pcd, pcd,
-1, -1, -1, -1, -1);
ASSERT(pid);
MSGUSBSTRING(fdo, DRIVERNAME " - Selecting interface named %ws\n", pid->iInterface);
// Create a URB to use in selecting a configuration.
USBD_INTERFACE_LIST_ENTRY interfaces[2] = {
{pid, NULL},
{NULL, NULL}, // fence to terminate the array
};
PURB selurb = USBD_CreateConfigurationRequestEx(pcd, interfaces);
if (!selurb)
{
KdPrint((DRIVERNAME " - Unable to create configuration request\n"));
return STATUS_INSUFFICIENT_RESOURCES;
}
__try
{
// Verify that the interface describes exactly the endpoints we expect
if (pid->bNumEndpoints != 0)
{
KdPrint((DRIVERNAME " - %d is the wrong number of endpoints\n", pid->bNumEndpoints));
return STATUS_DEVICE_CONFIGURATION_ERROR;
}
PUSBD_INTERFACE_INFORMATION pii = interfaces[0].Interface;
ASSERT(pii->NumberOfPipes == pid->bNumEndpoints);
// Submit the set-configuration request
status = SendAwaitUrb(fdo, selurb);
if (!NT_SUCCESS(status))
{
KdPrint((DRIVERNAME " - Error %X trying to select configuration\n", status));
return status;
}
// Save the configuration and pipe handles
pdx->hconfig = selurb->UrbSelectConfiguration.ConfigurationHandle;
pdx->hinpipe = NULL;
// Transfer ownership of the configuration descriptor to the device extension
pdx->pcd = pcd;
pcd = NULL;
}
__finally
{
ExFreePool(selurb);
}
}
__finally
{
if (pcd)
ExFreePool(pcd);
}
return STATUS_SUCCESS;
} // StartDevice
///////////////////////////////////////////////////////////////////////////////
#pragma PAGEDCODE
VOID StopDevice(IN PDEVICE_OBJECT fdo, BOOLEAN oktouch /* = FALSE */)
{ // StopDevice
PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION) fdo->DeviceExtension;
// If it's okay to touch our hardware (i.e., we're processing an IRP_MN_STOP_DEVICE),
// deconfigure the device.
if (oktouch)
{ // deconfigure device
URB urb;
UsbBuildSelectConfigurationRequest(&urb, sizeof(_URB_SELECT_CONFIGURATION), NULL);
NTSTATUS status = SendAwaitUrb(fdo, &urb);
if (!NT_SUCCESS(status))
KdPrint((DRIVERNAME " - Error %X trying to deconfigure device\n", status));
} // deconfigure device
if (pdx->pcd)
ExFreePool(pdx->pcd);
pdx->pcd = NULL;
} // StopDevice
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -