272 lines
7.9 KiB
C
272 lines
7.9 KiB
C
/*++
|
|
|
|
Copyright (c) 1999 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
recovery.c
|
|
|
|
|
|
Author:
|
|
|
|
ervinp
|
|
|
|
Environment:
|
|
|
|
Kernel mode
|
|
|
|
Revision History:
|
|
|
|
|
|
--*/
|
|
|
|
#include <WDM.H>
|
|
|
|
#include <usbdi.h>
|
|
#include <usbdlib.h>
|
|
#include <usbioctl.h>
|
|
|
|
#include "usb8023.h"
|
|
#include "debug.h"
|
|
|
|
|
|
/*
|
|
* USB- and WDM- specific prototypes (won't compile in common header)
|
|
*/
|
|
NTSTATUS CallDriverSync(PDEVICE_OBJECT devObj, PIRP irp);
|
|
|
|
|
|
/*
|
|
* ServiceReadDeficit
|
|
*
|
|
* If we "owe" the BULK IN pipe some read packets, send them down now.
|
|
*/
|
|
VOID ServiceReadDeficit(ADAPTEREXT *adapter)
|
|
{
|
|
ULONG numReadsToTry;
|
|
KIRQL oldIrql;
|
|
|
|
ASSERT(adapter->sig == DRIVER_SIG);
|
|
|
|
/*
|
|
* If there is a read deficit, try to fulfill it now.
|
|
* Careful not to get into an infinite loop, since TryReadUSB
|
|
* will re-increment readDeficit if there are still no packets.
|
|
*/
|
|
KeAcquireSpinLock(&adapter->adapterSpinLock, &oldIrql);
|
|
ASSERT(adapter->readDeficit <= NUM_READ_PACKETS);
|
|
numReadsToTry = adapter->readDeficit;
|
|
while ((adapter->readDeficit > 0) && (numReadsToTry > 0) && !adapter->halting){
|
|
DBGWARN(("RndisReturnMessageHandler attempting to fill read DEFICIT (=%d)", adapter->readDeficit));
|
|
|
|
adapter->readDeficit--;
|
|
numReadsToTry--;
|
|
|
|
KeReleaseSpinLock(&adapter->adapterSpinLock, oldIrql);
|
|
TryReadUSB(adapter);
|
|
KeAcquireSpinLock(&adapter->adapterSpinLock, &oldIrql);
|
|
}
|
|
KeReleaseSpinLock(&adapter->adapterSpinLock, oldIrql);
|
|
}
|
|
|
|
|
|
#if DO_FULL_RESET
|
|
|
|
VOID AdapterFullResetAndRestore(ADAPTEREXT *adapter)
|
|
{
|
|
NTSTATUS status;
|
|
|
|
DBGWARN(("AdapterFullResetAndRestore"));
|
|
|
|
adapter->numHardResets++;
|
|
adapter->needFullReset = FALSE;
|
|
|
|
if (adapter->halting){
|
|
DBGWARN(("AdapterFullResetAndRestore - skipping since device is halting"));
|
|
}
|
|
else {
|
|
ULONG portStatus;
|
|
|
|
ASSERT(!adapter->resetting);
|
|
adapter->resetting = TRUE;
|
|
|
|
status = GetUSBPortStatus(adapter, &portStatus);
|
|
if (NT_SUCCESS(status) && (portStatus & USBD_PORT_CONNECTED)){
|
|
|
|
CancelAllPendingPackets(adapter);
|
|
|
|
// RNDIS Halt seems to put the device out of whack until power cycle
|
|
// SimulateRNDISHalt(adapter);
|
|
|
|
AbortPipe(adapter, adapter->readPipeHandle);
|
|
ResetPipe(adapter, adapter->readPipeHandle);
|
|
|
|
AbortPipe(adapter, adapter->writePipeHandle);
|
|
ResetPipe(adapter, adapter->writePipeHandle);
|
|
|
|
if (adapter->notifyPipeHandle){
|
|
AbortPipe(adapter, adapter->notifyPipeHandle);
|
|
ResetPipe(adapter, adapter->notifyPipeHandle);
|
|
}
|
|
|
|
/*
|
|
* Now, bring the adapter back to the run state
|
|
* if it was previously.
|
|
*/
|
|
if (adapter->initialized){
|
|
|
|
/*
|
|
* Simulate RNDIS messages for INIT and set-packet-filter.
|
|
* These simulation functions need to read and throw away
|
|
* the response on the notify and control pipes, so do
|
|
* this before starting the read loop on the notify pipe.
|
|
*/
|
|
status = SimulateRNDISInit(adapter);
|
|
if (NT_SUCCESS(status)){
|
|
SimulateRNDISSetPacketFilter(adapter);
|
|
SimulateRNDISSetCurrentAddress(adapter);
|
|
|
|
/*
|
|
* Restart the read loops.
|
|
*/
|
|
if (adapter->notifyPipeHandle){
|
|
SubmitNotificationRead(adapter, FALSE);
|
|
}
|
|
StartUSBReadLoop(adapter);
|
|
}
|
|
else {
|
|
adapter->initialized = FALSE;
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
DBGWARN(("AdapterFullResetAndRestore - skipping since device is no longer connected"));
|
|
}
|
|
|
|
adapter->resetting = FALSE;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
NTSTATUS GetUSBPortStatus(ADAPTEREXT *adapter, PULONG portStatus)
|
|
{
|
|
NTSTATUS status;
|
|
PIRP irp;
|
|
|
|
*portStatus = 0;
|
|
|
|
irp = IoAllocateIrp(adapter->nextDevObj->StackSize, FALSE);
|
|
if (irp){
|
|
PIO_STACK_LOCATION nextSp;
|
|
|
|
nextSp = IoGetNextIrpStackLocation(irp);
|
|
nextSp->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
|
|
nextSp->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_GET_PORT_STATUS;
|
|
nextSp->Parameters.Others.Argument1 = portStatus;
|
|
|
|
status = CallDriverSync(adapter->nextDevObj, irp);
|
|
|
|
IoFreeIrp(irp);
|
|
}
|
|
else {
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
NTSTATUS AbortPipe(ADAPTEREXT *adapter, PVOID pipeHandle)
|
|
{
|
|
NTSTATUS status;
|
|
PIRP irp;
|
|
ULONG portStatus;
|
|
|
|
status = GetUSBPortStatus(adapter, &portStatus);
|
|
if (NT_SUCCESS(status) && (portStatus & USBD_PORT_CONNECTED)){
|
|
|
|
irp = IoAllocateIrp(adapter->nextDevObj->StackSize, FALSE);
|
|
if (irp){
|
|
PIO_STACK_LOCATION nextSp;
|
|
URB urb = {0};
|
|
|
|
urb.UrbHeader.Length = sizeof (struct _URB_PIPE_REQUEST);
|
|
urb.UrbHeader.Function = URB_FUNCTION_ABORT_PIPE;
|
|
urb.UrbPipeRequest.PipeHandle = pipeHandle;
|
|
|
|
nextSp = IoGetNextIrpStackLocation(irp);
|
|
nextSp->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
|
|
nextSp->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_URB;
|
|
nextSp->Parameters.Others.Argument1 = &urb;
|
|
|
|
status = CallDriverSync(adapter->nextDevObj, irp);
|
|
if (NT_SUCCESS(status)){
|
|
}
|
|
else {
|
|
DBGWARN(("AbortPipe failed with %xh (urb status %xh).", status, urb.UrbHeader.Status));
|
|
}
|
|
|
|
IoFreeIrp(irp);
|
|
}
|
|
else {
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
}
|
|
else {
|
|
DBGWARN(("AbortPipe - skipping abort because device not connected (status=%xh)", status));
|
|
status = STATUS_SUCCESS;
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
NTSTATUS ResetPipe(ADAPTEREXT *adapter, PVOID pipeHandle)
|
|
{
|
|
NTSTATUS status;
|
|
PIRP irp;
|
|
ULONG portStatus;
|
|
|
|
status = GetUSBPortStatus(adapter, &portStatus);
|
|
if (NT_SUCCESS(status) && (portStatus & USBD_PORT_CONNECTED)){
|
|
|
|
irp = IoAllocateIrp(adapter->nextDevObj->StackSize, FALSE);
|
|
if (irp){
|
|
PIO_STACK_LOCATION nextSp;
|
|
URB urb = {0};
|
|
|
|
urb.UrbHeader.Length = sizeof (struct _URB_PIPE_REQUEST);
|
|
urb.UrbHeader.Function = URB_FUNCTION_RESET_PIPE;
|
|
urb.UrbPipeRequest.PipeHandle = pipeHandle;
|
|
|
|
nextSp = IoGetNextIrpStackLocation(irp);
|
|
nextSp->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
|
|
nextSp->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_URB;
|
|
nextSp->Parameters.Others.Argument1 = &urb;
|
|
|
|
status = CallDriverSync(adapter->nextDevObj, irp);
|
|
if (NT_SUCCESS(status)){
|
|
}
|
|
else {
|
|
DBGWARN(("ResetPipe failed with %xh (urb status %xh).", status, urb.UrbHeader.Status));
|
|
}
|
|
|
|
IoFreeIrp(irp);
|
|
}
|
|
else {
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
}
|
|
else {
|
|
DBGWARN(("ResetPipe - skipping reset because device not connected (status=%xh)", status));
|
|
status = STATUS_SUCCESS;
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
#endif
|
|
|
|
|