📄 dev.c
字号:
/*
**********************************************************************
* Micrium, Inc.
* 949 Crestview Circle
* Weston, FL 33327-1848
*
* uC/USB-Bulk
*
* (c) Copyright 2003 - 2004, Micrium, Inc.
* All rights reserved.
*
***********************************************************************
----------------------------------------------------------------------
File : dev.c
Purpose : Part of the USB bulk driver
---------------------------END-OF-HEADER------------------------------
*/
#include "Main.h"
/*********************************************************************
*
* CompleteRequest
*
* Function description
* Generic IRP complete routine
*/
NTSTATUS CompleteRequest(IN PIRP Irp, IN NTSTATUS ntS, IN ULONG_PTR Info) {
Irp->IoStatus.Status = ntS;
Irp->IoStatus.Information = Info;
IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
return ntS;
}
/*********************************************************************
*
* PipeWithName
*
* Function description
* ??? (RS)
*/
PUSB_PIPE_CONTEXT PipeWithName(IN PDEVICE_OBJECT DeviceObject, IN PUNICODE_STRING FileName) {
LONG ix;
ULONG uval;
ULONG nameLength;
ULONG umultiplier;
DEVICE_EXTENSION * DevExt;
PUSB_PIPE_CONTEXT pipeContext;
pipeContext = NULL;
nameLength = (FileName->Length / sizeof(WCHAR));
DevExt = (DEVICE_EXTENSION *) DeviceObject->DeviceExtension;
if (nameLength != 0) {
DPRINT(("<usb> using pipe %ws\n", FileName->Buffer));
ix = nameLength - 1;
while ((ix > -1) && ((FileName->Buffer[ix] < (WCHAR) '0') || (FileName->Buffer[ix] > (WCHAR) '9'))) {
ix--;
}
if (ix > -1) {
uval = 0;
umultiplier = 1;
while ((ix > -1) && (FileName->Buffer[ix] >= (WCHAR) '0') && (FileName->Buffer[ix] <= (WCHAR) '9')) {
uval += (umultiplier * (ULONG) (FileName->Buffer[ix] - (WCHAR) '0'));
ix--;
umultiplier *= 10;
}
if (uval < 6 && DevExt->PipeContext) {
pipeContext = &DevExt->PipeContext[uval];
}
} else {
DPRINT(("<usb> error: invalid pipe name format\n"));
}
}
return pipeContext;
}
/*********************************************************************
*
* ResetParentPort
*
* Function description
* ??? (RS)
*/
NTSTATUS ResetParentPort(IN PDEVICE_OBJECT DeviceObject) {
NTSTATUS ntS;
KEVENT event;
PIRP irp;
IO_STATUS_BLOCK ioStatus;
PIO_STACK_LOCATION nextStack;
DEVICE_EXTENSION * DevExt;
DevExt = (DEVICE_EXTENSION *) DeviceObject->DeviceExtension;
KeInitializeEvent(&event, NotificationEvent, FALSE);
irp = IoBuildDeviceIoControlRequest(
IOCTL_INTERNAL_USB_RESET_PORT,
DevExt->TopOfStackDeviceObject,
NULL,
0,
NULL,
0,
TRUE,
&event,
&ioStatus);
if (irp == NULL) {
DPRINT(("<usb> error: allocating IRP\n"));
ntS = STATUS_INSUFFICIENT_RESOURCES;
} else {
nextStack = IoGetNextIrpStackLocation(irp);
ASSERT(nextStack != NULL);
ntS = IoCallDriver(DevExt->TopOfStackDeviceObject, irp);
if (STATUS_PENDING == ntS) {
KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
} else {
ioStatus.Status = ntS;
}
ntS = ioStatus.Status;
}
return ntS;
}
/*********************************************************************
*
* DispatchCreate
*
* Function description
* Callback for IRP_MJ_CREATE
*/
NTSTATUS DispatchCreate(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) {
ULONG i;
NTSTATUS ntS;
FILE_OBJECT * fileObject;
DEVICE_EXTENSION * DevExt;
IO_STACK_LOCATION * irpStack;
USB_PIPE_CONTEXT * pipeContext;
USBD_INTERFACE_INFORMATION * interface;
PAGED_CODE();
DPRINT(("<usb> IRP_MJ_CREATE\n"));
irpStack = IoGetCurrentIrpStackLocation(Irp);
fileObject = irpStack->FileObject;
DevExt = (DEVICE_EXTENSION *) DeviceObject->DeviceExtension;
// test device state
if (DevExt->DeviceState == Working) {
// test USB interface
interface = DevExt->UsbInterface;
if (interface) {
if (fileObject) {
fileObject->FsContext = NULL;
// opening a device
if (fileObject->FileName.Length == 0) {
DPRINT(("<usb> opening device"));
ntS = STATUS_SUCCESS;
InterlockedIncrement(&DevExt->OpenHandleCount);
// opening a pipe
} else {
DPRINT(("<usb> opening pipe"));
pipeContext = PipeWithName(DeviceObject, &fileObject->FileName);
if (pipeContext) {
for (i=0; i<interface->NumberOfPipes; i++) {
if (pipeContext == &DevExt->PipeContext[i]) {
// got a match
DPRINT(("<usb> open pipe %d\n", i));
fileObject->FsContext = &interface->Pipes[i];
ASSERT(fileObject->FsContext);
pipeContext->PipeOpen = TRUE;
InterlockedIncrement(&DevExt->OpenHandleCount);
ntS = STATUS_SUCCESS;
}
}
} else {
ntS = STATUS_INVALID_PARAMETER;
}
}
} else {
ntS = STATUS_INVALID_PARAMETER;
}
} else {
DPRINT(("<usb> USB interface not found\n"));
ntS = STATUS_INVALID_DEVICE_STATE;
}
} else {
ntS = STATUS_INVALID_DEVICE_STATE;
}
return(CompleteRequest(Irp, ntS, 0));
}
/*********************************************************************
*
* DispatchClose
*
* Function description
* Callback for IRP_MJ_CLOSE
*/
NTSTATUS DispatchClose(IN PDEVICE_OBJECT pDeviceObject, IN PIRP pIrp) {
NTSTATUS ntS;
PFILE_OBJECT pFileObject;
DEVICE_EXTENSION * pDevExt;
PIO_STACK_LOCATION pIrpStack;
PUSB_PIPE_CONTEXT pPipeContext;
PUSBD_PIPE_INFORMATION pPipeInformation;
PAGED_CODE();
pIrpStack = IoGetCurrentIrpStackLocation(pIrp);
pFileObject = pIrpStack->FileObject;
pPipeContext = NULL;
pPipeInformation = NULL;
pDevExt = (DEVICE_EXTENSION *) pDeviceObject->DeviceExtension;
if (pFileObject && pFileObject->FsContext) {
pPipeInformation = pFileObject->FsContext;
if (pFileObject->FileName.Length != 0) {
pPipeContext = PipeWithName(pDeviceObject, &pFileObject->FileName);
}
if(pPipeContext && pPipeContext->PipeOpen) {
pPipeContext->PipeOpen = FALSE;
}
}
ntS = STATUS_SUCCESS;
CompleteRequest(pIrp, ntS, 0);
InterlockedDecrement(&pDevExt->OpenHandleCount);
return(ntS);
}
/*********************************************************************
*
* DispatchClean
*
* Function description
* Callback for IRP_MJ_CLEAN
*/
NTSTATUS DispatchClean(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) {
DEVICE_EXTENSION * DevExt;
KIRQL oldIrql;
LIST_ENTRY cleanupList;
PLIST_ENTRY thisEntry,
nextEntry,
listHead;
PIRP pendingIrp;
PIO_STACK_LOCATION pendingIrpStack,
irpStack;
NTSTATUS ntS;
DevExt = (DEVICE_EXTENSION *) DeviceObject->DeviceExtension;
irpStack = IoGetCurrentIrpStackLocation(Irp);
InitializeListHead(&cleanupList);
DPRINT(("<usb> IRP_MJ_CLEAN\n"));
DevIoIncrement(DevExt);
KeAcquireSpinLock(&DevExt->QueueLock, &oldIrql);
// delete all fileobject related IRPs
listHead = &DevExt->NewRequestsQueue;
for (thisEntry=listHead->Flink, nextEntry=thisEntry->Flink;
thisEntry != listHead;
thisEntry=nextEntry, nextEntry=thisEntry->Flink) {
pendingIrp = CONTAINING_RECORD(thisEntry, IRP, Tail.Overlay.ListEntry);
pendingIrpStack = IoGetCurrentIrpStackLocation(pendingIrp);
if (irpStack->FileObject == pendingIrpStack->FileObject) {
RemoveEntryList(thisEntry);
// NULL cancel routine
if (IoSetCancelRoutine(pendingIrp, NULL) == NULL) {
InitializeListHead(thisEntry);
} else {
InsertTailList(&cleanupList, thisEntry);
}
}
}
KeReleaseSpinLock(&DevExt->QueueLock, oldIrql);
// walk thru the cleanup list and cancel all IRP
while (!IsListEmpty(&cleanupList)) {
// complete the Irp
thisEntry = RemoveHeadList(&cleanupList);
pendingIrp = CONTAINING_RECORD(thisEntry, IRP, Tail.Overlay.ListEntry);
CompleteRequest(pendingIrp, STATUS_CANCELLED, 0);
}
ntS = CompleteRequest(Irp, STATUS_SUCCESS, 0);
DevIoDecrement(DevExt);
return(ntS);
}
/*********************************************************************
*
* DispatchIoctl
*
* Function description
* Callback for IRP_MJ_DEVICE_CONTROL
*/
NTSTATUS DispatchIoctl(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) {
ULONG code;
PVOID ioBuffer;
ULONG inputBufferLength;
ULONG outputBufferLength;
ULONG info;
NTSTATUS ntS;
DEVICE_EXTENSION * DevExt;
PIO_STACK_LOCATION irpStack;
info = 0;
irpStack = IoGetCurrentIrpStackLocation(Irp);
code = irpStack->Parameters.DeviceIoControl.IoControlCode;
DevExt = (DEVICE_EXTENSION *) DeviceObject->DeviceExtension;
ioBuffer = Irp->AssociatedIrp.SystemBuffer;
inputBufferLength = irpStack->Parameters.DeviceIoControl.InputBufferLength;
outputBufferLength = irpStack->Parameters.DeviceIoControl.OutputBufferLength;
if (DevExt->DeviceState != Working) {
DPRINT(("<usb> error: invalid device state\n"));
return(CompleteRequest(Irp, STATUS_INVALID_DEVICE_STATE, 0));
}
DevIoIncrement(DevExt);
switch (code) {
case IOCTL_USB_BULK_RESET_PIPE: // reset pipe
{
PFILE_OBJECT fileObject;
PUSBD_PIPE_INFORMATION pipe;
DPRINT(("<usb> IOCTL_USB_BULK_RESET_PIPE"));
fileObject = irpStack->FileObject;
if (fileObject == NULL) {
ntS = STATUS_INVALID_PARAMETER;
break;
}
pipe = (PUSBD_PIPE_INFORMATION) fileObject->FsContext;
if (pipe) {
ntS = ResetPipe(DeviceObject, pipe);
} else {
ntS = STATUS_INVALID_PARAMETER;
}
break;
}
// get config descriptor
case IOCTL_USB_BULK_GET_CONFIG_DESCRIPTOR:
{
ULONG length;
DPRINT(("<usb> IOCTL_USB_BULK_GET_CONFIG_DESCRIPTOR"));
if (DevExt->UsbConfigurationDescriptor) {
length = DevExt->UsbConfigurationDescriptor->wTotalLength;
if (outputBufferLength >= length) {
RtlCopyMemory(ioBuffer, DevExt->UsbConfigurationDescriptor, length);
info = length;
ntS = STATUS_SUCCESS;
} else {
ntS = STATUS_BUFFER_TOO_SMALL;
}
} else {
ntS = STATUS_UNSUCCESSFUL;
}
break;
}
// reset device
case IOCTL_USB_BULK_RESET_DEVICE:
{
DPRINT(("<usb> IOCTL_USB_BULK_RESET_DEVICE"));
ntS = ResetDevice(DeviceObject);
break;
}
default:
ntS = STATUS_INVALID_DEVICE_REQUEST;
break;
}
CompleteRequest(Irp, ntS, info);
DevIoDecrement(DevExt);
return(ntS);
}
/*********************************************************************
*
* ResetPipe
*
* Function description
* // reset pipe by handle
*/
NTSTATUS ResetPipe(IN PDEVICE_OBJECT DeviceObject, IN PUSBD_PIPE_INFORMATION PipeInfo) {
PURB urb;
NTSTATUS ntS;
DEVICE_EXTENSION * DevExt;
urb = NULL;
DevExt = (DEVICE_EXTENSION *) DeviceObject->DeviceExtension;
urb = ExAllocatePool(NonPagedPool, sizeof(struct _URB_PIPE_REQUEST));
if (urb) {
urb->UrbHeader.Length = (USHORT) sizeof(struct _URB_PIPE_REQUEST);
urb->UrbHeader.Function = URB_FUNCTION_RESET_PIPE;
urb->UrbPipeRequest.PipeHandle = PipeInfo->PipeHandle;
ntS = CallUSBD(DeviceObject, urb);
if (!NT_SUCCESS(ntS)) {
DPRINT(("<usb> error: ResetPipe::CallUSBD %x"));
} else {
DPRINT(("<usb> pipe reseted\n"));
ntS = STATUS_SUCCESS;
}
ExFreePool(urb);
} else {
DPRINT(("<usb> error: allocating urb"));
ntS = STATUS_INSUFFICIENT_RESOURCES;
}
return(ntS);
}
/*********************************************************************
*
* GetPortStatus
*
* Function description
* ???
*/
static NTSTATUS _GetPortStatus(IN PDEVICE_OBJECT DeviceObject, IN OUT PULONG PortStatus) {
NTSTATUS ntS;
KEVENT event;
PIRP irp;
IO_STATUS_BLOCK ioStatus;
PIO_STACK_LOCATION nextStack;
DEVICE_EXTENSION * DevExt;
DevExt = (DEVICE_EXTENSION *) DeviceObject->DeviceExtension;
*PortStatus = 0;
KeInitializeEvent(&event, NotificationEvent, FALSE);
irp = IoBuildDeviceIoControlRequest(
IOCTL_INTERNAL_USB_GET_PORT_STATUS,
DevExt->TopOfStackDeviceObject,
NULL,
0,
NULL,
0,
TRUE,
&event,
&ioStatus);
if (irp == NULL) {
DPRINT(("<usb> error: allocating IRP\n"));
ntS = STATUS_INSUFFICIENT_RESOURCES;
} else {
nextStack = IoGetNextIrpStackLocation(irp);
ASSERT(nextStack != NULL);
nextStack->Parameters.Others.Argument1 = PortStatus;
ntS = IoCallDriver(DevExt->TopOfStackDeviceObject, irp);
if (ntS == STATUS_PENDING) {
KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
} else {
ioStatus.Status = ntS;
}
ntS = ioStatus.Status;
}
return(ntS);
}
/*********************************************************************
*
* ResetDevice
*
* Function description
* reset device ???
*/
NTSTATUS ResetDevice(IN PDEVICE_OBJECT DeviceObject) {
NTSTATUS ntS;
ULONG portStatus;
ntS = _GetPortStatus(DeviceObject, &portStatus);
if((NT_SUCCESS(ntS)) && (!(portStatus & USBD_PORT_ENABLED)) && (portStatus & USBD_PORT_CONNECTED)) {
ntS = ResetParentPort(DeviceObject);
}
return(ntS);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -