?? bulkdev.c
字號:
ntStatus = STATUS_SUCCESS;
}
else {
BulkUsb_DbgPrint(1, ("BulkUsb_ResetPipe - failed\n"));
}
return ntStatus;
}
NTSTATUS
BulkUsb_ResetDevice(
IN PDEVICE_OBJECT DeviceObject
)
/*++
Routine Description:
This routine invokes BulkUsb_ResetParentPort to reset the device
Arguments:
DeviceObject - pointer to device object
Return Value:
NT status value
--*/
{
NTSTATUS ntStatus;
ULONG portStatus;
BulkUsb_DbgPrint(3, ("BulkUsb_ResetDevice - begins\n"));
ntStatus = BulkUsb_GetPortStatus(DeviceObject, &portStatus);
if((NT_SUCCESS(ntStatus)) &&
(!(portStatus & USBD_PORT_ENABLED)) &&
(portStatus & USBD_PORT_CONNECTED)) {
ntStatus = BulkUsb_ResetParentPort(DeviceObject);
}
BulkUsb_DbgPrint(3, ("BulkUsb_ResetDevice - ends\n"));
return ntStatus;
}
NTSTATUS
BulkUsb_GetPortStatus(
IN PDEVICE_OBJECT DeviceObject,
IN OUT PULONG PortStatus
)
/*++
Routine Description:
This routine retrieves the status value
Arguments:
DeviceObject - pointer to device object
PortStatus - port status
Return Value:
NT status value
--*/
{
NTSTATUS ntStatus;
KEVENT event;
PIRP irp;
IO_STATUS_BLOCK ioStatus;
PIO_STACK_LOCATION nextStack;
PDEVICE_EXTENSION deviceExtension;
//
// initialize variables
//
deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
*PortStatus = 0;
BulkUsb_DbgPrint(3, ("BulkUsb_GetPortStatus - begins\n"));
KeInitializeEvent(&event, NotificationEvent, FALSE);
irp = IoBuildDeviceIoControlRequest(
IOCTL_INTERNAL_USB_GET_PORT_STATUS,
deviceExtension->TopOfStackDeviceObject,
NULL,
0,
NULL,
0,
TRUE,
&event,
&ioStatus);
if(NULL == irp) {
BulkUsb_DbgPrint(1, ("memory alloc for irp failed\n"));
return STATUS_INSUFFICIENT_RESOURCES;
}
nextStack = IoGetNextIrpStackLocation(irp);
ASSERT(nextStack != NULL);
nextStack->Parameters.Others.Argument1 = PortStatus;
ntStatus = IoCallDriver(deviceExtension->TopOfStackDeviceObject, irp);
if(STATUS_PENDING == ntStatus) {
KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
}
else {
ioStatus.Status = ntStatus;
}
ntStatus = ioStatus.Status;
BulkUsb_DbgPrint(3, ("BulkUsb_GetPortStatus - ends\n"));
return ntStatus;
}
NTSTATUS
BulkUsb_ResetParentPort(
IN PDEVICE_OBJECT DeviceObject
)
/*++
Routine Description:
This routine sends an IOCTL_INTERNAL_USB_RESET_PORT
synchronously down the stack.
Arguments:
Return Value:
--*/
{
NTSTATUS ntStatus;
KEVENT event;
PIRP irp;
IO_STATUS_BLOCK ioStatus;
PIO_STACK_LOCATION nextStack;
PDEVICE_EXTENSION deviceExtension;
//
// initialize variables
//
deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
BulkUsb_DbgPrint(3, ("BulkUsb_ResetParentPort - begins\n"));
KeInitializeEvent(&event, NotificationEvent, FALSE);
irp = IoBuildDeviceIoControlRequest(
IOCTL_INTERNAL_USB_RESET_PORT,
deviceExtension->TopOfStackDeviceObject,
NULL,
0,
NULL,
0,
TRUE,
&event,
&ioStatus);
if(NULL == irp) {
BulkUsb_DbgPrint(1, ("memory alloc for irp failed\n"));
return STATUS_INSUFFICIENT_RESOURCES;
}
nextStack = IoGetNextIrpStackLocation(irp);
ASSERT(nextStack != NULL);
ntStatus = IoCallDriver(deviceExtension->TopOfStackDeviceObject, irp);
if(STATUS_PENDING == ntStatus) {
KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
}
else {
ioStatus.Status = ntStatus;
}
ntStatus = ioStatus.Status;
BulkUsb_DbgPrint(3, ("BulkUsb_ResetParentPort - ends\n"));
return ntStatus;
}
NTSTATUS
SubmitIdleRequestIrp(
IN PDEVICE_EXTENSION DeviceExtension
)
/*++
Routine Description:
This routine builds an idle request irp with an associated callback routine
and a completion routine in the driver and passes the irp down the stack.
Arguments:
DeviceExtension - pointer to device extension
Return Value:
NT status value
--*/
{
PIRP irp;
NTSTATUS ntStatus;
KIRQL oldIrql;
PUSB_IDLE_CALLBACK_INFO idleCallbackInfo;
PIO_STACK_LOCATION nextStack;
//
// initialize variables
//
irp = NULL;
idleCallbackInfo = NULL;
BulkUsb_DbgPrint(3, ("SubmitIdleRequest - begins\n"));
ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
if(PowerDeviceD0 != DeviceExtension->DevPower) {
ntStatus = STATUS_POWER_STATE_INVALID;
goto SubmitIdleRequestIrp_Exit;
}
KeAcquireSpinLock(&DeviceExtension->IdleReqStateLock, &oldIrql);
if(InterlockedExchange(&DeviceExtension->IdleReqPend, 1)) {
BulkUsb_DbgPrint(1, ("Idle request pending..\n"));
KeReleaseSpinLock(&DeviceExtension->IdleReqStateLock, oldIrql);
ntStatus = STATUS_DEVICE_BUSY;
goto SubmitIdleRequestIrp_Exit;
}
//
// clear the NoIdleReqPendEvent because we are about
// to submit an idle request. Since we are so early
// to clear this event, make sure that if we fail this
// request we set back the event.
//
KeClearEvent(&DeviceExtension->NoIdleReqPendEvent);
idleCallbackInfo = ExAllocatePool(NonPagedPool,
sizeof(struct _USB_IDLE_CALLBACK_INFO));
if(idleCallbackInfo) {
idleCallbackInfo->IdleCallback = IdleNotificationCallback;
idleCallbackInfo->IdleContext = (PVOID)DeviceExtension;
ASSERT(DeviceExtension->IdleCallbackInfo == NULL);
DeviceExtension->IdleCallbackInfo = idleCallbackInfo;
//
// we use IoAllocateIrp to create an irp to selectively suspend the
// device. This irp lies pending with the hub driver. When appropriate
// the hub driver will invoked callback, where we power down. The completion
// routine is invoked when we power back.
//
irp = IoAllocateIrp(DeviceExtension->TopOfStackDeviceObject->StackSize,
FALSE);
if(irp == NULL) {
BulkUsb_DbgPrint(1, ("cannot build idle request irp\n"));
KeSetEvent(&DeviceExtension->NoIdleReqPendEvent,
IO_NO_INCREMENT,
FALSE);
InterlockedExchange(&DeviceExtension->IdleReqPend, 0);
KeReleaseSpinLock(&DeviceExtension->IdleReqStateLock, oldIrql);
ExFreePool(idleCallbackInfo);
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
goto SubmitIdleRequestIrp_Exit;
}
nextStack = IoGetNextIrpStackLocation(irp);
nextStack->MajorFunction =
IRP_MJ_INTERNAL_DEVICE_CONTROL;
nextStack->Parameters.DeviceIoControl.IoControlCode =
IOCTL_INTERNAL_USB_SUBMIT_IDLE_NOTIFICATION;
nextStack->Parameters.DeviceIoControl.Type3InputBuffer =
idleCallbackInfo;
nextStack->Parameters.DeviceIoControl.InputBufferLength =
sizeof(struct _USB_IDLE_CALLBACK_INFO);
IoSetCompletionRoutine(irp,
IdleNotificationRequestComplete,
DeviceExtension,
TRUE,
TRUE,
TRUE);
DeviceExtension->PendingIdleIrp = irp;
//
// we initialize the count to 2.
// The reason is, if the CancelSelectSuspend routine manages
// to grab the irp from the device extension, then the last of the
// CancelSelectSuspend routine/IdleNotificationRequestComplete routine
// to execute will free this irp. We need to have this schema so that
// 1. completion routine does not attempt to touch the irp freed by
// CancelSelectSuspend routine.
// 2. CancelSelectSuspend routine doesnt wait for ever for the completion
// routine to complete!
//
DeviceExtension->FreeIdleIrpCount = 2;
KeReleaseSpinLock(&DeviceExtension->IdleReqStateLock, oldIrql);
//
// check if the device is idle.
// A check here ensures that a race condition did not
// completely reverse the call sequence of SubmitIdleRequestIrp
// and CancelSelectiveSuspend
//
if(!CanDeviceSuspend(DeviceExtension) ||
PowerDeviceD0 != DeviceExtension->DevPower) {
//
// IRPs created using IoBuildDeviceIoControlRequest should be
// completed by calling IoCompleteRequest and not merely
// deallocated.
//
BulkUsb_DbgPrint(1, ("Device is not idle\n"));
KeAcquireSpinLock(&DeviceExtension->IdleReqStateLock, &oldIrql);
DeviceExtension->IdleCallbackInfo = NULL;
DeviceExtension->PendingIdleIrp = NULL;
KeSetEvent(&DeviceExtension->NoIdleReqPendEvent,
IO_NO_INCREMENT,
FALSE);
InterlockedExchange(&DeviceExtension->IdleReqPend, 0);
KeReleaseSpinLock(&DeviceExtension->IdleReqStateLock, oldIrql);
if(idleCallbackInfo) {
ExFreePool(idleCallbackInfo);
}
//
// it is still safe to touch the local variable "irp" here.
// the irp has not been passed down the stack, the irp has
// no cancellation routine. The worse position is that the
// CancelSelectSuspend has run after we released the spin
// lock above. It is still essential to free the irp.
//
if(irp) {
IoFreeIrp(irp);
}
ntStatus = STATUS_UNSUCCESSFUL;
goto SubmitIdleRequestIrp_Exit;
}
BulkUsb_DbgPrint(3, ("Cancel the timers\n"));
//
// Cancel the timer so that the DPCs are no longer fired.
// Thus, we are making judicious usage of our resources.
// we do not need DPCs because we already have an idle irp pending.
// The timers are re-initialized in the completion routine.
//
KeCancelTimer(&DeviceExtension->Timer);
ntStatus = IoCallDriver(DeviceExtension->TopOfStackDeviceObject, irp);
if(!NT_SUCCESS(ntStatus)) {
BulkUsb_DbgPrint(1, ("IoCallDriver failed\n"));
goto SubmitIdleRequestIrp_Exit;
}
}
else {
BulkUsb_DbgPrint(1, ("Memory allocation for idleCallbackInfo failed\n"));
KeSetEvent(&DeviceExtension->NoIdleReqPendEvent,
IO_NO_INCREMENT,
FALSE);
InterlockedExchange(&DeviceExtension->IdleReqPend, 0);
KeReleaseSpinLock(&DeviceExtension->IdleReqStateLock, oldIrql);
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
}
SubmitIdleRequestIrp_Exit:
BulkUsb_DbgPrint(3, ("SubmitIdleRequest - ends\n"));
return ntStatus;
}
VOID
IdleNotificationCallback(
IN PDEVICE_EXTENSION DeviceExtension
)
/*++
Routine Description:
"A pointer to a callback function in your driver is passed down the stack with
this IOCTL, and it is this callback function that is called by USBHUB when it
safe for your device to power down."
"When the callback in your driver is called, all you really need to do is to
to first ensure that a WaitWake Irp has been submitted for your device, if
remote wake is possible for your device and then request a SetD2 (or DeviceWake)"
Arguments:
DeviceExtension - pointer to device extension
Return Value:
NT status value
--*/
{
NTSTATUS ntStatus;
POWER_STATE powerState;
KEVENT irpCompletionEvent;
PIRP_COMPLETION_CONTEXT irpContext;
BulkUsb_DbgPrint(3, ("IdleNotificationCallback - begins\n"));
//
// Dont idle, if the device was just disconnected or being stopped
// i.e. return for the following DeviceState(s)
// NotStarted, Stopped, PendingStop, PendingRemove, SurpriseRemoved, Removed
//
if(DeviceExtension->DeviceState != Working) {
return;
}
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -