📄 isodev.c
字号:
default :
ntStatus = STATUS_INVALID_DEVICE_REQUEST;
break;
}
Irp->IoStatus.Status = ntStatus;
Irp->IoStatus.Information = info;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
IsoUsb_DbgPrint(3, ("IsoUsb_DispatchDevCtrl::"));
IsoUsb_IoDecrement(deviceExtension);
return ntStatus;
}
LONG
IsoUsb_ParseStringForPipeNumber(
IN PUNICODE_STRING PipeName
)
/*++
Routine Description:
This routine parses the PipeName for the Pipe#
Arguments:
PipeName - Unicode string for the pipe name.
Valid strings have the form:
\PIPE? or \PIPE?? or \pipe? or \pipe??
Where ? is 0..9
Return Value:
Pipe number 0..99, or -1 if the PipeName is invalid
--*/
{
ULONG digits;
ULONG uval;
ULONG umultiplier;
if (PipeName->Length == sizeof(L"\\PIPE0") - sizeof(L""))
{
digits = 1;
}
else if (PipeName->Length == sizeof(L"\\PIPE00") - sizeof(L""))
{
digits = 2;
}
else
{
return -1;
}
if ((PipeName->Buffer[0] != (WCHAR)'\\') ||
((PipeName->Buffer[1] != (WCHAR)'P') &&
(PipeName->Buffer[1] != (WCHAR)'p')) ||
((PipeName->Buffer[2] != (WCHAR)'I') &&
(PipeName->Buffer[2] != (WCHAR)'i')) ||
((PipeName->Buffer[3] != (WCHAR)'P') &&
(PipeName->Buffer[3] != (WCHAR)'p')) ||
((PipeName->Buffer[4] != (WCHAR)'E') &&
(PipeName->Buffer[4] != (WCHAR)'e')))
{
return -1;
}
if (PipeName->Buffer[5] < (WCHAR)'0' ||
PipeName->Buffer[5] > (WCHAR)'9')
{
return -1;
}
uval = PipeName->Buffer[5] - (WCHAR)'0';
if (digits == 2)
{
if (PipeName->Buffer[6] < (WCHAR)'0' ||
PipeName->Buffer[6] > (WCHAR)'9')
{
return -1;
}
uval *= 10;
uval += PipeName->Buffer[6] - (WCHAR)'0';
}
return uval;
}
NTSTATUS
IsoUsb_ResetDevice(
IN PDEVICE_OBJECT DeviceObject
)
/*++
Routine Description:
This routine resets the device
Arguments:
DeviceObject - pointer to device object
Return Value:
NT status value
--*/
{
NTSTATUS ntStatus;
ULONG portStatus;
IsoUsb_DbgPrint(3, ("IsoUsb_ResetDevice - begins\n"));
ntStatus = IsoUsb_GetPortStatus(DeviceObject, &portStatus);
if((NT_SUCCESS(ntStatus)) &&
(!(portStatus & USBD_PORT_ENABLED)) &&
(portStatus & USBD_PORT_CONNECTED)) {
ntStatus = IsoUsb_ResetParentPort(DeviceObject);
}
IsoUsb_DbgPrint(3, ("IsoUsb_ResetDevice - ends\n"));
return ntStatus;
}
NTSTATUS
IsoUsb_GetPortStatus(
IN PDEVICE_OBJECT DeviceObject,
IN OUT PULONG PortStatus
)
/*++
Routine Description:
This routine fetches the port status value
Arguments:
DeviceObject - pointer to device object
PortStatus - pointer to ULONG to contain the status value
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;
IsoUsb_DbgPrint(3, ("IsoUsb_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) {
IsoUsb_DbgPrint(1, ("memory alloc for irp failed\n"));
return STATUS_INSUFFICIENT_RESOURCES;
}
nextStack = IoGetNextIrpStackLocation(irp);
ASSERT(nextStack != NULL);
nextStack->Parameters.Others.Argument1 = PortStatus;
IsoUsb_DbgPrint(3, ("IsoUsb_GetPortStatus::"));
IsoUsb_IoIncrement(deviceExtension);
ntStatus = IoCallDriver(deviceExtension->TopOfStackDeviceObject, irp);
if(STATUS_PENDING == ntStatus) {
KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
}
else {
ioStatus.Status = ntStatus;
}
IsoUsb_DbgPrint(3, ("IsoUsb_GetPortStatus::"));
IsoUsb_IoDecrement(deviceExtension);
ntStatus = ioStatus.Status;
IsoUsb_DbgPrint(3, ("IsoUsb_GetPortStatus - ends\n"));
return ntStatus;
}
NTSTATUS
IsoUsb_ResetParentPort(
IN PDEVICE_OBJECT DeviceObject
)
/*++
Routine Description:
This routine will submit an IOCTL_INTERNAL_USB_RESET_PORT,
down the stack
Arguments:
DeviceObject - pointer to device object
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;
IsoUsb_DbgPrint(3, ("IsoUsb_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) {
IsoUsb_DbgPrint(1, ("memory alloc for irp failed\n"));
return STATUS_INSUFFICIENT_RESOURCES;
}
nextStack = IoGetNextIrpStackLocation(irp);
ASSERT(nextStack != NULL);
IsoUsb_DbgPrint(3, ("IsoUsb_ResetParentPort"));
IsoUsb_IoIncrement(deviceExtension);
ntStatus = IoCallDriver(deviceExtension->TopOfStackDeviceObject, irp);
if(STATUS_PENDING == ntStatus) {
KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
}
else {
ioStatus.Status = ntStatus;
}
IsoUsb_DbgPrint(3, ("IsoUsb_ResetParentPort"));
IsoUsb_IoDecrement(deviceExtension);
ntStatus = ioStatus.Status;
IsoUsb_DbgPrint(3, ("IsoUsb_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;
IsoUsb_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)) {
IsoUsb_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) {
IsoUsb_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) {
//
// device cannot suspend - abort.
// also irps created using IoAllocateIrp
// needs to be deallocated.
//
IsoUsb_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;
}
IsoUsb_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)) {
IsoUsb_DbgPrint(1, ("IoCallDriver failed\n"));
goto SubmitIdleRequestIrp_Exit;
}
}
else {
IsoUsb_DbgPrint(1, ("Memory allocation for idleCallbackInfo failed\n"));
KeSetEvent(&DeviceExtension->NoIdleReqPendEvent,
IO_NO_INCREMENT,
FALSE);
InterlockedExchange(&DeviceExtension->IdleReqPend, 0);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -