📄 ezusbsys.c
字号:
// #define DRIVER
//
// Include files needed for WDM driver support
//
#include <wdm.h>
#include "stdarg.h"
#include "stdio.h"
//
// Include files needed for USB support
//
#include "usbdi.h"
#include "usbdlib.h"
//
// Include file for the Ezusb Device
//
#include "ezusbsys.h"
///////////////////////////////////////////////////////////////////////////////
// @func Handle completion of a request by a lower-level driver
// @parm Functional device object
// @parm I/O request which has completed
// @parm Context argument supplied to IoSetCompletionRoutine, namely address of
// KEVENT object on which ForwardAndWait is waiting
// @comm This is the completion routine used for requests forwarded by ForwardAndWait. It
// sets the event object and thereby awakens ForwardAndWait.
// @comm Note that it's *not* necessary for this particular completion routine to test
// the PendingReturned flag in the IRP and then call IoMarkIrpPending. You do that in many
// completion routines because the dispatch routine can't know soon enough that the
// lower layer has returned STATUS_PENDING. In our case, we're never going to pass a
// STATUS_PENDING back up the driver chain, so we don't need to worry about this.
NTSTATUS
OnRequestComplete(
IN PDEVICE_OBJECT fdo,
IN PIRP Irp,
IN PKEVENT pev
)
/*++
Routine Description:
Handle completion of a request by a lower-level driver
Arguments:
DriverObject - Functional device object
Irp - I/O request which has completed
pev - Context argument supplied to IoSetCompletionRoutine, namely address of
KEVENT object on which ForwardAndWait is waiting
Return Value:
STATUS_MORE_PROCESSING_REQUIRED
--*/
{
KeSetEvent(pev, 0, FALSE);
return STATUS_MORE_PROCESSING_REQUIRED;
}
NTSTATUS
CompleteRequest(
IN PIRP Irp,
IN NTSTATUS status,
IN ULONG info
)
/*++
Routine Description:
Mark I/O request complete
Arguments:
Irp - I/O request in question
status - Standard status code
info Additional information related to status code
Return Value:
STATUS_SUCCESS if successful,
STATUS_UNSUCCESSFUL otherwise
--*/
{
Irp->IoStatus.Status = status;
Irp->IoStatus.Information = info;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return status;
}
NTSTATUS
Ezusb_CallUSBD(
IN PDEVICE_OBJECT fdo,
IN PURB Urb
)
/*++
Routine Description:
Passes a Usb Request Block (URB) to the USB class driver (USBD)
Note that we create our own IRP here and use it to send the request to
the USB software subsystem. This means that this routine is essentially
independent of the IRP that caused this driver to be called in the first
place. The IRP for this transfer is created, used, and then destroyed
in this routine.
However, note that this routine uses the Usb Request Block (urb) passed
in by the caller as the request block for the USB software stack.
Implementation of this routine may be changed depending on the specific
requirements of your driver. For example, while this routine issues a
synchronous request to the USB stack, you may wish to implement this as an
asynchronous request in which you set an IoCompletionRoutine to be called
when the request is complete.
Arguments:
fdo - pointer to the device object for this instance of an Ezusb Device
Urb - pointer to Urb request block
Return Value:
STATUS_SUCCESS if successful,
STATUS_UNSUCCESSFUL otherwise
--*/
{
NTSTATUS ntStatus, status = STATUS_SUCCESS;
PDEVICE_EXTENSION pdx;
PIRP irp;
KEVENT event;
IO_STATUS_BLOCK ioStatus;
PIO_STACK_LOCATION nextStack;
Ezusb_KdPrint (("enter Ezusb_CallUSBD\n"));
pdx = fdo->DeviceExtension;
// issue a synchronous request (see notes above)
KeInitializeEvent(&event, NotificationEvent, FALSE);
irp = IoBuildDeviceIoControlRequest(
IOCTL_INTERNAL_USB_SUBMIT_URB,
pdx->StackDeviceObject,
NULL,
0,
NULL,
0,
TRUE, /* INTERNAL */
&event,
&ioStatus);
// Prepare for calling the USB driver stack
nextStack = IoGetNextIrpStackLocation(irp);
ASSERT(nextStack != NULL);
// Set up the URB ptr to pass to the USB driver stack
nextStack->Parameters.Others.Argument1 = Urb;
Ezusb_KdPrint (("Calling USB Driver Stack\n"));
//
// Call the USB class driver to perform the operation. If the returned status
// is PENDING, wait for the request to complete.
//
ntStatus = IoCallDriver(pdx->StackDeviceObject,
irp);
Ezusb_KdPrint (("return from IoCallDriver USBD %x\n", ntStatus));
if (ntStatus == STATUS_PENDING)
{
Ezusb_KdPrint (("Wait for single object\n"));
status = KeWaitForSingleObject(
&event,
Suspended,
KernelMode,
FALSE,
NULL);
Ezusb_KdPrint (("Wait for single object, returned %x\n", status));
}
else
{
ioStatus.Status = ntStatus;
}
Ezusb_KdPrint (("URB status = %x status = %x irp status %x\n",
Urb->UrbHeader.Status, status, ioStatus.Status));
//
// USBD maps the error code for us. USBD uses error codes in its URB
// structure that are more insightful into USB behavior. In order to
// match the NT Status codes, USBD maps its error codes into more general NT
// error categories so higher level drivers can decipher the error codes
// based on standard NT error code definitions.
//
ntStatus = ioStatus.Status;
//
// If the URB status was not USBD_STATUS_SUCCESS, we save a copy of the
// URB status in the device extension. After a failure, another IOCTL,
// IOCTL_EZUSB_GET_LAST_ERROR can be used to retrieve the URB status
// for the most recently failed URB. Of course, this status gets
// overwritten by subsequent failures, but it's better than nothing.
//
if (!(USBD_SUCCESS(Urb->UrbHeader.Status)))
pdx->LastFailedUrbStatus = Urb->UrbHeader.Status;
//
// if ioStatus.Status indicates an error (ie. the IRP failed) then return that.
// If ioStatus.Status indicates success, it is still possible that what we were
// trying to do failed. For example, if the IRP is cancelled, the status returned
// by the I/O manager for the IRP will not indicate an error. In that case, we
// should check the URB status. If it indicates anything other than
// USBD_SUCCESS, then we should return STATUS_UNSUCCESSFUL.
//
if (NT_SUCCESS(ntStatus))
{
if (!(USBD_SUCCESS(Urb->UrbHeader.Status)))
ntStatus = STATUS_UNSUCCESSFUL;
}
Ezusb_KdPrint(("exit Ezusb_CallUSBD (%x)\n", ntStatus));
return ntStatus;
}
NTSTATUS
Ezusb_Read_Write(
IN PDEVICE_OBJECT fdo,
IN PIRP Irp
)
/*++
Routine Description:
Arguments:
Return Value:
NT status code
STATUS_SUCCESS: Read was done successfully
STATUS_INVALID_PARAMETER_3: The Endpoint Index does not specify an IN pipe
STATUS_NO_MEMORY: Insufficient data memory was supplied to perform the READ
This routine fills the status code into the Irp
--*/
{
PDEVICE_EXTENSION pdx = fdo->DeviceExtension;
NTSTATUS ntStatus;
PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation (Irp);
PBULK_TRANSFER_CONTROL bulkControl =
(PBULK_TRANSFER_CONTROL)Irp->AssociatedIrp.SystemBuffer;
ULONG bufferLength =
irpStack->Parameters.DeviceIoControl.OutputBufferLength;
PURB urb = NULL;
ULONG urbSize = 0;
ULONG transferFlags = 0;
PUSBD_INTERFACE_INFORMATION interfaceInfo = NULL;
PUSBD_PIPE_INFORMATION pipeInfo = NULL;
USBD_PIPE_HANDLE pipeHandle = NULL;
Ezusb_KdPrint(("enter Ezusb_Read_Write()\n"));
//
// verify that the selected pipe is valid, and get a handle to it. If anything
// is wrong, return an error
//
interfaceInfo = pdx->Interface;
if (!interfaceInfo)
{
Ezusb_KdPrint(("Ezusb_Read_Write() no interface info - Exiting\n"));
return STATUS_UNSUCCESSFUL;
}
if (bulkControl->pipeNum > interfaceInfo->NumberOfPipes)
{
Ezusb_KdPrint(("Ezusb_Read_Write() invalid pipe - Exiting\n"));
return STATUS_INVALID_PARAMETER;
}
pipeInfo = &(interfaceInfo->Pipes[bulkControl->pipeNum]);
if (!((pipeInfo->PipeType == UsbdPipeTypeBulk) ||
(pipeInfo->PipeType == UsbdPipeTypeInterrupt)))
{
Ezusb_KdPrint(("Ezusb_Read_Write() invalid pipe - Exiting\n"));
return STATUS_INVALID_PARAMETER;
}
pipeHandle = pipeInfo->PipeHandle;
if (!pipeHandle)
{
Ezusb_KdPrint(("Ezusb_Read_Write() invalid pipe - Exiting\n"));
return STATUS_UNSUCCESSFUL;
}
if (bufferLength > pipeInfo->MaximumTransferSize)
{
Ezusb_KdPrint(("Ezusb_Read_Write() invalid transfer size - Exiting\n"));
return STATUS_INVALID_PARAMETER;
}
//
// allocate and fill in the Usb request (URB)
//
urbSize = sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER);
urb = ExAllocatePool(NonPagedPool,urbSize);
if (!urb)
{
Ezusb_KdPrint(("Ezusb_Read_Write() unable to alloc URB - Exiting\n"));
return STATUS_NO_MEMORY;
}
transferFlags = USBD_SHORT_TRANSFER_OK;
//
// get direction info from the endpoint address
//
if (USB_ENDPOINT_DIRECTION_IN(pipeInfo->EndpointAddress))
transferFlags |= USBD_TRANSFER_DIRECTION_IN;
UsbBuildInterruptOrBulkTransferRequest(urb, //ptr to urb
(USHORT) urbSize, //size of urb
pipeHandle, //usbd pipe handle
NULL, //TransferBuffer
Irp->MdlAddress, //mdl
bufferLength, //bufferlength
transferFlags, //flags
NULL); //link
//
// Call the USB Stack.
//
ntStatus = Ezusb_CallUSBD(fdo, urb);
//
// If the transfer was successful, report the length of the transfer to the
// caller by setting IoStatus.Information
//
if (NT_SUCCESS(ntStatus))
{
Irp->IoStatus.Information = urb->UrbBulkOrInterruptTransfer.TransferBufferLength;
Ezusb_KdPrint(("Successfully transfered 0x%x bytes\n",Irp->IoStatus.Information));
}
//
// free the URB
//
ExFreePool(urb);
return ntStatus;
}
ULONG
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -