/*++ Copyright (c) 1999 Microsoft Corporation Module Name: recovery.c Author: ervinp Environment: Kernel mode Revision History: --*/ #include #include #include #include #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