Something went wrong. Try again.
Reactos
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262/* * PROJECT: ReactOS Universal Serial Bus Bulk Storage Driver * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later) * PURPOSE: USB block storage device driver. * COPYRIGHT: 2005-2006 James Tabor * 2011-2012 Michael Martin (michael.martin@reactos.org) * 2011-2013 Johannes Anderwald (johannes.anderwald@reactos.org) * 2019 Victor Perevertkin (victor.perevertkin@reactos.org) */
#include "usbstor.h"
#define NDEBUG#include <debug.h>
NTSTATUSUSBSTOR_GetEndpointStatus( IN PDEVICE_OBJECT DeviceObject, IN UCHAR bEndpointAddress, OUT PUSHORT Value){ PURB Urb; NTSTATUS Status;
DPRINT("Allocating URB\n"); Urb = (PURB)AllocateItem(NonPagedPool, sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST)); if (!Urb) { DPRINT1("OutofMemory!\n"); return STATUS_INSUFFICIENT_RESOURCES; }
// build status UsbBuildGetStatusRequest(Urb, URB_FUNCTION_GET_STATUS_FROM_ENDPOINT, bEndpointAddress & 0x0F, Value, NULL, NULL);
// send the request DPRINT1("Sending Request DeviceObject %p, Urb %p\n", DeviceObject, Urb); Status = USBSTOR_SyncUrbRequest(DeviceObject, Urb);
FreeItem(Urb); return Status;}
NTSTATUSUSBSTOR_ResetPipeWithHandle( IN PDEVICE_OBJECT DeviceObject, IN USBD_PIPE_HANDLE PipeHandle){ PURB Urb; NTSTATUS Status;
DPRINT("Allocating URB\n"); Urb = (PURB)AllocateItem(NonPagedPool, sizeof(struct _URB_PIPE_REQUEST)); if (!Urb) { DPRINT1("OutofMemory!\n"); return STATUS_INSUFFICIENT_RESOURCES; }
Urb->UrbPipeRequest.Hdr.Length = sizeof(struct _URB_PIPE_REQUEST); Urb->UrbPipeRequest.Hdr.Function = URB_FUNCTION_SYNC_RESET_PIPE_AND_CLEAR_STALL; Urb->UrbPipeRequest.PipeHandle = PipeHandle;
// send the request DPRINT1("Sending Request DeviceObject %p, Urb %p\n", DeviceObject, Urb); Status = USBSTOR_SyncUrbRequest(DeviceObject, Urb);
FreeItem(Urb); return Status;}
VOIDNTAPIUSBSTOR_ResetPipeWorkItemRoutine( IN PDEVICE_OBJECT FdoDevice, IN PVOID Ctx){ NTSTATUS Status; PFDO_DEVICE_EXTENSION FDODeviceExtension = (PFDO_DEVICE_EXTENSION)Ctx; PIRP_CONTEXT Context = &FDODeviceExtension->CurrentIrpContext;
// clear stall on the corresponding pipe Status = USBSTOR_ResetPipeWithHandle(FDODeviceExtension->LowerDeviceObject, Context->Urb.UrbBulkOrInterruptTransfer.PipeHandle); DPRINT1("USBSTOR_ResetPipeWithHandle Status %x\n", Status);
// now resend the csw as the stall got cleared USBSTOR_SendCSWRequest(FDODeviceExtension, Context->Irp);}
VOIDNTAPIUSBSTOR_ResetDeviceWorkItemRoutine( IN PDEVICE_OBJECT FdoDevice, IN PVOID Context){ PFDO_DEVICE_EXTENSION FDODeviceExtension; UINT32 ix; NTSTATUS Status; KIRQL OldIrql;
DPRINT("USBSTOR_ResetDeviceWorkItemRoutine\n");
FDODeviceExtension = FdoDevice->DeviceExtension;
for (ix = 0; ix < 3; ++ix) { // first perform a mass storage reset step 1 in 5.3.4 USB Mass Storage Bulk Only Specification Status = USBSTOR_ResetDevice(FDODeviceExtension->LowerDeviceObject, FDODeviceExtension); if (NT_SUCCESS(Status)) { // step 2 reset bulk in pipe section 5.3.4 Status = USBSTOR_ResetPipeWithHandle(FDODeviceExtension->LowerDeviceObject, FDODeviceExtension->InterfaceInformation->Pipes[FDODeviceExtension->BulkInPipeIndex].PipeHandle); if (NT_SUCCESS(Status)) { // finally reset bulk out pipe Status = USBSTOR_ResetPipeWithHandle(FDODeviceExtension->LowerDeviceObject, FDODeviceExtension->InterfaceInformation->Pipes[FDODeviceExtension->BulkOutPipeIndex].PipeHandle); if (NT_SUCCESS(Status)) { break; } } } }
KeAcquireSpinLock(&FDODeviceExtension->CommonLock, &OldIrql); FDODeviceExtension->Flags &= ~USBSTOR_FDO_FLAGS_DEVICE_RESETTING; KeReleaseSpinLock(&FDODeviceExtension->CommonLock, OldIrql);
USBSTOR_QueueNextRequest(FdoDevice);}
VOIDNTAPIUSBSTOR_QueueResetPipe( IN PFDO_DEVICE_EXTENSION FDODeviceExtension){ DPRINT("USBSTOR_QueueResetPipe\n");
IoQueueWorkItem(FDODeviceExtension->ResetDeviceWorkItem, USBSTOR_ResetPipeWorkItemRoutine, CriticalWorkQueue, FDODeviceExtension);}
VOIDNTAPIUSBSTOR_QueueResetDevice( IN PFDO_DEVICE_EXTENSION FDODeviceExtension){ KIRQL OldIrql;
DPRINT("USBSTOR_QueueResetDevice\n");
KeAcquireSpinLock(&FDODeviceExtension->CommonLock, &OldIrql); FDODeviceExtension->Flags |= USBSTOR_FDO_FLAGS_DEVICE_RESETTING; KeReleaseSpinLock(&FDODeviceExtension->CommonLock, OldIrql);
IoQueueWorkItem(FDODeviceExtension->ResetDeviceWorkItem, USBSTOR_ResetDeviceWorkItemRoutine, CriticalWorkQueue, NULL);}
VOIDNTAPIUSBSTOR_TimerWorkerRoutine( IN PVOID Context){ PFDO_DEVICE_EXTENSION FDODeviceExtension; NTSTATUS Status; PERRORHANDLER_WORKITEM_DATA WorkItemData = (PERRORHANDLER_WORKITEM_DATA)Context;
FDODeviceExtension = (PFDO_DEVICE_EXTENSION)WorkItemData->DeviceObject->DeviceExtension; ASSERT(FDODeviceExtension->Common.IsFDO);
// first perform a mass storage reset step 1 in 5.3.4 USB Mass Storage Bulk Only Specification Status = USBSTOR_ResetDevice(FDODeviceExtension->LowerDeviceObject, FDODeviceExtension); if (NT_SUCCESS(Status)) { // step 2 reset bulk in pipe section 5.3.4 Status = USBSTOR_ResetPipeWithHandle(FDODeviceExtension->LowerDeviceObject, FDODeviceExtension->InterfaceInformation->Pipes[FDODeviceExtension->BulkInPipeIndex].PipeHandle); if (NT_SUCCESS(Status)) { // finally reset bulk out pipe Status = USBSTOR_ResetPipeWithHandle(FDODeviceExtension->LowerDeviceObject, FDODeviceExtension->InterfaceInformation->Pipes[FDODeviceExtension->BulkOutPipeIndex].PipeHandle); } } DPRINT1("Status %x\n", Status);
// clear timer srb FDODeviceExtension->LastTimerActiveSrb = NULL;
// re-schedule request //USBSTOR_HandleExecuteSCSI(WorkItemData->Context->PDODeviceExtension->Self, WorkItemData->Context->Irp, Context->RetryCount + 1);
// do not retry for the same packet again FDODeviceExtension->TimerWorkQueueEnabled = FALSE;
ExFreePoolWithTag(WorkItemData, USB_STOR_TAG);}
VOIDNTAPIUSBSTOR_TimerRoutine( PDEVICE_OBJECT DeviceObject, PVOID Context){ PFDO_DEVICE_EXTENSION FDODeviceExtension; BOOLEAN ResetDevice = FALSE; PERRORHANDLER_WORKITEM_DATA WorkItemData;
FDODeviceExtension = (PFDO_DEVICE_EXTENSION)Context; DPRINT1("[USBSTOR] TimerRoutine entered\n"); // DPRINT1("[USBSTOR] ActiveSrb %p ResetInProgress %x LastTimerActiveSrb %p\n", FDODeviceExtension->ActiveSrb, FDODeviceExtension->ResetInProgress, FDODeviceExtension->LastTimerActiveSrb);
KeAcquireSpinLockAtDpcLevel(&FDODeviceExtension->IrpListLock);
// is there an active srb and no global reset is in progress if (FDODeviceExtension->ActiveSrb && /* FDODeviceExtension->ResetInProgress == FALSE && */ FDODeviceExtension->TimerWorkQueueEnabled) { if (FDODeviceExtension->LastTimerActiveSrb != NULL && FDODeviceExtension->LastTimerActiveSrb == FDODeviceExtension->ActiveSrb) { // check if empty DPRINT1("[USBSTOR] ActiveSrb %p hang detected\n", FDODeviceExtension->ActiveSrb); ResetDevice = TRUE; } else { // update pointer FDODeviceExtension->LastTimerActiveSrb = FDODeviceExtension->ActiveSrb; } } else { // reset srb FDODeviceExtension->LastTimerActiveSrb = NULL; }
KeReleaseSpinLockFromDpcLevel(&FDODeviceExtension->IrpListLock);
if (ResetDevice && FDODeviceExtension->TimerWorkQueueEnabled && FDODeviceExtension->SrbErrorHandlingActive == FALSE) { WorkItemData = ExAllocatePoolWithTag(NonPagedPool, sizeof(ERRORHANDLER_WORKITEM_DATA), USB_STOR_TAG); if (WorkItemData) { // Initialize and queue the work item to handle the error ExInitializeWorkItem(&WorkItemData->WorkQueueItem, USBSTOR_TimerWorkerRoutine, WorkItemData);
WorkItemData->DeviceObject = FDODeviceExtension->FunctionalDeviceObject;
DPRINT1("[USBSTOR] Queing Timer WorkItem\n"); ExQueueWorkItem(&WorkItemData->WorkQueueItem, DelayedWorkQueue); } }}