📄 usb.c
字号:
case IRP_MN_START_DEVICE:
KeInitializeEvent(&startDeviceEvent, NotificationEvent, FALSE);
IoCopyCurrentIrpStackLocationToNext(Irp);
IoSetCompletionRoutine(Irp,
USB_IrpCompletionRoutine,
&startDeviceEvent, // pass the event to the completion routine as the Context
TRUE, // invoke on success
TRUE, // invoke on error
TRUE); // invoke on cancellation
// let the PDO process the IRP
ntStatus = IoCallDriver(stackDeviceObject,
Irp);
// if PDO is not done yet, wait for the event to be set in our completion routine
if (ntStatus == STATUS_PENDING) {
// wait for irp to complete
waitStatus = KeWaitForSingleObject(
&startDeviceEvent,
Suspended,
KernelMode,
FALSE,
NULL);
ntStatus = Irp->IoStatus.Status;
}
if (NT_SUCCESS(ntStatus)) {
// Now we're ready to do our own startup processing.
// USB client drivers such as us set up URBs (USB Request Packets) to send requests
// to the host controller driver (HCD). The URB structure defines a format for all
// possible commands that can be sent to a USB device.
// Here, we request the device descriptor and store it,
// and configure the device.
ntStatus = USB_StartDevice(DeviceObject);
Irp->IoStatus.Status = ntStatus;
}
IoCompleteRequest (Irp,
IO_NO_INCREMENT
);
USB_DecrementIoCount(DeviceObject);
return ntStatus; // end, case IRP_MN_START_DEVICE
case IRP_MN_QUERY_STOP_DEVICE:
if (!deviceExtension->DeviceStarted) { // if get when never started, just pass on
USB_KdPrint( DBGLVL_MEDIUM,("USB_ProcessPnPIrp() IRP_MN_QUERY_STOP_DEVICE when device not started\n"));
IoSkipCurrentIrpStackLocation (Irp);
ntStatus = IoCallDriver (deviceExtension->TopOfStackDeviceObject, Irp);
USB_DecrementIoCount(DeviceObject);
return ntStatus;
}
// fail the request if we have any read/write IRPS pending
if( deviceExtension->StagedPendingIrpCount ) {
ntStatus = STATUS_UNSUCCESSFUL;
}
else {
deviceExtension->StopDeviceRequested = TRUE;
Irp->IoStatus.Status = STATUS_SUCCESS;
}
break; // end, case IRP_MN_QUERY_STOP_DEVICE
case IRP_MN_CANCEL_STOP_DEVICE:
// It is possible to receive this irp when the device has not been started
if (!deviceExtension->DeviceStarted) { // if get when never started, just pass on
USB_KdPrint( DBGLVL_MEDIUM,("USB_ProcessPnPIrp() IRP_MN_CANCEL_STOP_DEVICE when device not started\n"));
IoSkipCurrentIrpStackLocation (Irp);
ntStatus = IoCallDriver (deviceExtension->TopOfStackDeviceObject, Irp);
USB_DecrementIoCount(DeviceObject);
return ntStatus;
}
// Reset this flag so new IOCTL and IO Irp processing will be re-enabled
deviceExtension->StopDeviceRequested = FALSE;
Irp->IoStatus.Status = STATUS_SUCCESS;
break; // end, case IRP_MN_CANCEL_STOP_DEVICE
case IRP_MN_STOP_DEVICE:
// Cancel any pending io requests. (there shouldn't be any)
USB_CancelPendingIo( DeviceObject );
//
// Send the select configuration urb with a NULL pointer for the configuration
// handle, this closes the configuration and puts the device in the 'unconfigured'
// state.
//
ntStatus = USB_StopDevice(DeviceObject);
Irp->IoStatus.Status = ntStatus;
break; // end, case IRP_MN_STOP_DEVICE
case IRP_MN_QUERY_REMOVE_DEVICE:
if (!deviceExtension->DeviceStarted) { // if get when never started, just pass on
USB_KdPrint( DBGLVL_MEDIUM,("USB_ProcessPnPIrp() IRP_MN_QUERY_STOP_DEVICE when device not started\n"));
IoSkipCurrentIrpStackLocation (Irp);
ntStatus = IoCallDriver (deviceExtension->TopOfStackDeviceObject, Irp);
USB_DecrementIoCount(DeviceObject);
return ntStatus;
}
// Once RemoveDeviceRequested is set no new IOCTL or read/write irps will be passed
// down the stack to lower drivers; all will be quickly failed
deviceExtension->RemoveDeviceRequested = TRUE;
// Wait for any io request pending in our driver to
// complete before returning success.
// This event is set when deviceExtension->PendingIoCount goes to 1
waitStatus = KeWaitForSingleObject(
&deviceExtension->NoPendingIoEvent,
Suspended,
KernelMode,
FALSE,
NULL);
Irp->IoStatus.Status = STATUS_SUCCESS;
break; // end, case IRP_MN_QUERY_REMOVE_DEVICE
case IRP_MN_CANCEL_REMOVE_DEVICE:
// The PnP Manager uses this IRP to inform the drivers
// for a device that the device will not be removed.
// It is sent only after a successful IRP_MN_QUERY_REMOVE_DEVICE.
if (!deviceExtension->DeviceStarted) { // if get when never started, just pass on
USB_KdPrint( DBGLVL_MEDIUM,("USB_ProcessPnPIrp() IRP_MN_CANCEL_REMOVE_DEVICE when device not started\n"));
IoSkipCurrentIrpStackLocation (Irp);
ntStatus = IoCallDriver (deviceExtension->TopOfStackDeviceObject, Irp);
USB_DecrementIoCount(DeviceObject);
return ntStatus;
}
// Reset this flag so new IOCTL and IO Irp processing will be re-enabled
deviceExtension->RemoveDeviceRequested = FALSE;
Irp->IoStatus.Status = STATUS_SUCCESS;
break; // end, case IRP_MN_CANCEL_REMOVE_DEVICE
case IRP_MN_SURPRISE_REMOVAL:
USB_KdPrint( DBGLVL_MEDIUM,("USB_ProcessPnPIrp() IRP_MN_SURPRISE_REMOVAL\n"));
USB_DecrementIoCount(DeviceObject);
//
// Once DeviceRemoved is set no new IOCTL or read/write irps will be passed
// down the stack to lower drivers; all will be quickly failed
//
deviceExtension->DeviceRemoved = TRUE;
// Cancel any pending io requests; we may not have gotten a query first!
USB_CancelPendingIo( DeviceObject );
// If any pipes are still open, call USBD with URB_FUNCTION_ABORT_PIPE
// This call will also close the pipes; if any user close calls get through,
// they will be noops
USB_AbortPipes( DeviceObject );
//
// Mark this handled
//
Irp->IoStatus.Status = STATUS_SUCCESS;
// We don't explicitly wait for the below driver to complete, but just make
// the call and go on, finishing cleanup
IoCopyCurrentIrpStackLocationToNext(Irp);
ntStatus = IoCallDriver(stackDeviceObject,
Irp);
return ntStatus;
case IRP_MN_REMOVE_DEVICE:
USB_DecrementIoCount(DeviceObject);
//
// Once DeviceRemoved is set no new IOCTL or read/write irps will be passed
// down the stack to lower drivers; all will be quickly failed
//
deviceExtension->DeviceRemoved = TRUE;
IoCopyCurrentIrpStackLocationToNext(Irp);
ntStatus = IoCallDriver(stackDeviceObject,
Irp);
USB_DecrementIoCount(DeviceObject);
USB_RemoveDevice(DeviceObject);
USB_KdPrint( DBGLVL_DEFAULT,("USB_ProcessPnPIrp() Detaching from %08X\n",
deviceExtension->TopOfStackDeviceObject));
IoDetachDevice(deviceExtension->TopOfStackDeviceObject);
USB_KdPrint( DBGLVL_DEFAULT,("USB_ProcessPnPIrp() Deleting %08X\n",
DeviceObject));
IoDeleteDevice (DeviceObject);
return ntStatus; // end, case IRP_MN_REMOVE_DEVICE
default:
USB_KdPrint( DBGLVL_MAXIMUM,("USB_ProcessPnPIrp() Minor PnP IOCTL not handled\n"));
} /* case MinorFunction */
if (!NT_SUCCESS(ntStatus)) {
// if anything went wrong, return failure without passing Irp down
Irp->IoStatus.Status = ntStatus;
IoCompleteRequest (Irp,
IO_NO_INCREMENT
);
USB_DecrementIoCount(DeviceObject);
USB_KdPrint( DBGLVL_MAXIMUM,("USB_ProcessPnPIrp() Exit USB_ProcessPnPIrp FAILURE %x\n", ntStatus));
return ntStatus;
}
IoCopyCurrentIrpStackLocationToNext(Irp);
//
// All PNP_POWER messages get passed to the TopOfStackDeviceObject
// we were given in PnPAddDevice
//
USB_KdPrint( DBGLVL_MAXIMUM,("USB_ProcessPnPIrp() Passing PnP Irp down, status = %x\n", ntStatus));
ntStatus = IoCallDriver(stackDeviceObject,
Irp);
USB_DecrementIoCount(DeviceObject);
USB_KdPrint( DBGLVL_MAXIMUM,("USB_ProcessPnPIrp() Exit USB_ProcessPnPIrp %x\n", ntStatus));
return ntStatus;
}
NTSTATUS
USB_PnPAddDevice(
IN PDRIVER_OBJECT DriverObject,
IN PDEVICE_OBJECT PhysicalDeviceObject
)
{
NTSTATUS ntStatus = STATUS_SUCCESS;
PDEVICE_OBJECT deviceObject = NULL;
PDEVICE_EXTENSION deviceExtension;
USBD_VERSION_INFORMATION versionInformation;
ULONG i;
USB_KdPrint( DBGLVL_DEFAULT,("进入 USB_PnPAddDevice()\n"));
//
// create our funtional device object (FDO)
//
ntStatus =
USB_CreateDeviceObject(DriverObject, PhysicalDeviceObject, &deviceObject);
if (NT_SUCCESS(ntStatus)) {
deviceExtension = deviceObject->DeviceExtension;
//
// we support direct io for read/write
//
deviceObject->Flags |= DO_DIRECT_IO;
deviceObject->Flags |= DO_POWER_PAGABLE;
// initialize our device extension
//
// remember the Physical device Object
//
deviceExtension->PhysicalDeviceObject=PhysicalDeviceObject;
//
// Attach to the PDO
//
deviceExtension->TopOfStackDeviceObject =
IoAttachDeviceToDeviceStack(deviceObject, PhysicalDeviceObject);
USB_QueryCapabilities(deviceExtension->TopOfStackDeviceObject,
&deviceExtension->DeviceCapabilities);
// We want to determine what level to auto-powerdown to; This is the lowest
// sleeping level that is LESS than D3;
// If all are set to D3, auto powerdown/powerup will be disabled.
deviceExtension->PowerDownLevel = PowerDeviceUnspecified; // init to disabled
for (i=PowerSystemSleeping1; i<= PowerSystemSleeping3; i++) {
if ( deviceExtension->DeviceCapabilities.DeviceState[i] < PowerDeviceD3 )
deviceExtension->PowerDownLevel = deviceExtension->DeviceCapabilities.DeviceState[i];
}
USB_IncrementIoCount(deviceObject);
}
USBD_GetUSBDIVersion(&versionInformation);
if( NT_SUCCESS( ntStatus ) )
{
NTSTATUS actStat;
// try to power down device until IO actually requested
actStat = USB_SelfSuspendOrActivate( deviceObject, TRUE );
deviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
}
USB_KdPrint( DBGLVL_DEFAULT,("退出 USB_PnPAddDevice() (%x)\n", ntStatus));
return ntStatus;
}
NTSTATUS
USB_StartDevice(
IN PDEVICE_OBJECT DeviceObject
)
{
PDEVICE_EXTENSION deviceExtension;
NTSTATUS ntStatus;
PUSB_DEVICE_DESCRIPTOR deviceDescriptor = NULL;
PURB urb;
ULONG siz;
USB_KdPrint( DBGLVL_DEFAULT,("enter USB_StartDevice\n"));
deviceExtension = DeviceObject->DeviceExtension;
urb = USB_ExAllocatePool(NonPagedPool,
sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST));
USB_KdPrintCond( DBGLVL_HIGH,!urb, ("USB_StartDevice() FAILED USB_ExAllocatePool() for URB\n"));
if (urb) {
siz = sizeof(USB_DEVICE_DESCRIPTOR);
deviceDescriptor = USB_ExAllocatePool(NonPagedPool,
siz);
USB_KdPrintCond( DBGLVL_HIGH, !deviceDescriptor, ("USB_StartDevice() FAILED USB_ExAllocatePool() for deviceDescriptor\n"));
if (deviceDescriptor) {
UsbBuildGetDescriptorRequest(urb,
(USHORT) sizeof (struct _URB_CONTROL_DESCRIPTOR_REQUEST),
USB_DEVICE_DESCRIPTOR_TYPE,
0,
0,
deviceDescriptor,
NULL,
siz,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -