https://git.reactos.org/?p=reactos.git;a=commitdiff;h=94e0942644cc8f7c2f923b...
commit 94e0942644cc8f7c2f923bc19299068cded76662 Author: Amine Khaldi amine.khaldi@reactos.org AuthorDate: Sun Jan 21 13:51:07 2018 +0100 Commit: Amine Khaldi amine.khaldi@reactos.org CommitDate: Sun Jan 21 13:51:07 2018 +0100
[USBSTOR_NEW] Create usbstor_new based on usbstor in order to contain Vadim Galyant's work. --- drivers/usb/CMakeLists.txt | 1 + drivers/usb/usbstor_new/CMakeLists.txt | 25 + drivers/usb/usbstor_new/descriptor.c | 549 ++++++++++++ drivers/usb/usbstor_new/disk.c | 691 +++++++++++++++ drivers/usb/usbstor_new/error.c | 410 +++++++++ drivers/usb/usbstor_new/fdo.c | 461 +++++++++++ drivers/usb/usbstor_new/guid.c | 9 + drivers/usb/usbstor_new/misc.c | 520 ++++++++++++ drivers/usb/usbstor_new/pdo.c | 1376 ++++++++++++++++++++++++++++++ drivers/usb/usbstor_new/queue.c | 670 +++++++++++++++ drivers/usb/usbstor_new/scsi.c | 1429 ++++++++++++++++++++++++++++++++ drivers/usb/usbstor_new/usbstor.c | 295 +++++++ drivers/usb/usbstor_new/usbstor.h | 550 ++++++++++++ drivers/usb/usbstor_new/usbstor.rc | 5 + 14 files changed, 6991 insertions(+)
diff --git a/drivers/usb/CMakeLists.txt b/drivers/usb/CMakeLists.txt index 05817b0f82..17fc45d14e 100644 --- a/drivers/usb/CMakeLists.txt +++ b/drivers/usb/CMakeLists.txt @@ -6,5 +6,6 @@ add_subdirectory(usbhub) add_subdirectory(usbohci) #add_subdirectory(usbohci_new) add_subdirectory(usbport) +#add_subdirectory(usbport_new) add_subdirectory(usbstor) add_subdirectory(usbuhci) diff --git a/drivers/usb/usbstor_new/CMakeLists.txt b/drivers/usb/usbstor_new/CMakeLists.txt new file mode 100644 index 0000000000..3bb2eed0f2 --- /dev/null +++ b/drivers/usb/usbstor_new/CMakeLists.txt @@ -0,0 +1,25 @@ + +add_definitions(-DDEBUG_MODE) +include_directories(${REACTOS_SOURCE_DIR}/ntoskrnl/include) + +list(APPEND SOURCE + descriptor.c + disk.c + fdo.c + misc.c + pdo.c + queue.c + error.c + scsi.c + usbstor.c + usbstor.h) + +add_library(usbstor SHARED + ${SOURCE} + guid.c + usbstor.rc) + +set_module_type(usbstor kernelmodedriver) +add_importlibs(usbstor ntoskrnl hal usbd) +add_pch(usbstor usbstor.h SOURCE) +add_cd_file(TARGET usbstor DESTINATION reactos/system32/drivers NO_CAB FOR all) diff --git a/drivers/usb/usbstor_new/descriptor.c b/drivers/usb/usbstor_new/descriptor.c new file mode 100644 index 0000000000..3df36a671c --- /dev/null +++ b/drivers/usb/usbstor_new/descriptor.c @@ -0,0 +1,549 @@ +/* + * PROJECT: ReactOS Universal Serial Bus Bulk Storage Driver + * LICENSE: GPL - See COPYING in the top level directory + * FILE: drivers/usb/usbstor/descriptor.c + * PURPOSE: USB block storage device driver. + * PROGRAMMERS: + * James Tabor + * Michael Martin (michael.martin@reactos.org) + * Johannes Anderwald (johannes.anderwald@reactos.org) + */ + +#include "usbstor.h" + +#define NDEBUG +#include <debug.h> + +NTSTATUS +NTAPI +USBSTOR_GetDescriptor( + IN PDEVICE_OBJECT DeviceObject, + IN UCHAR DescriptorType, + IN ULONG DescriptorLength, + IN UCHAR DescriptorIndex, + IN LANGID LanguageId, + OUT PVOID *OutDescriptor) +{ + PURB Urb; + NTSTATUS Status; + PVOID Descriptor; + + // + // sanity checks + // + ASSERT(DeviceObject); + ASSERT(OutDescriptor); + ASSERT(DescriptorLength); + + // + // first allocate descriptor buffer + // + Descriptor = AllocateItem(NonPagedPool, DescriptorLength); + if (!Descriptor) + { + // + // no memory + // + return STATUS_INSUFFICIENT_RESOURCES; + } + + // + // allocate urb + // + Urb = (PURB) AllocateItem(NonPagedPool, sizeof(URB)); + if (!Urb) + { + // + // no memory + // + FreeItem(Descriptor); + return STATUS_INSUFFICIENT_RESOURCES; + } + + // + // initialize urb + // + UsbBuildGetDescriptorRequest(Urb, + sizeof(Urb->UrbControlDescriptorRequest), + DescriptorType, + DescriptorIndex, + LanguageId, + Descriptor, + NULL, + DescriptorLength, + NULL); + + // + // submit urb + // + Status = USBSTOR_SyncUrbRequest(DeviceObject, Urb); + + // + // free urb + // + FreeItem(Urb); + + if (NT_SUCCESS(Status)) + { + // + // store result + // + *OutDescriptor = Descriptor; + } + + // + // done + // + return Status; +} + + +NTSTATUS +USBSTOR_GetDescriptors( + IN PDEVICE_OBJECT DeviceObject) +{ + NTSTATUS Status; + PFDO_DEVICE_EXTENSION DeviceExtension; + USHORT DescriptorLength; + + // + // get device extension + // + DeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension; + + // + // first get device descriptor + // + Status = USBSTOR_GetDescriptor(DeviceExtension->LowerDeviceObject, USB_DEVICE_DESCRIPTOR_TYPE, sizeof(USB_DEVICE_DESCRIPTOR), 0, 0, (PVOID*)&DeviceExtension->DeviceDescriptor); + if (!NT_SUCCESS(Status)) + { + // + // failed to get device descriptor + // + DeviceExtension->DeviceDescriptor = NULL; + return Status; + } + + // + // now get basic configuration descriptor + // + Status = USBSTOR_GetDescriptor(DeviceExtension->LowerDeviceObject, USB_CONFIGURATION_DESCRIPTOR_TYPE, sizeof(USB_CONFIGURATION_DESCRIPTOR), 0, 0, (PVOID*)&DeviceExtension->ConfigurationDescriptor); + if (!NT_SUCCESS(Status)) + { + // + // failed to get configuration descriptor + // + FreeItem(DeviceExtension->DeviceDescriptor); + DeviceExtension->DeviceDescriptor = NULL; + return Status; + } + + // + // backup length + // + DescriptorLength = DeviceExtension->ConfigurationDescriptor->wTotalLength; + + // + // release basic descriptor + // + FreeItem(DeviceExtension->ConfigurationDescriptor); + DeviceExtension->ConfigurationDescriptor = NULL; + + // + // allocate full descriptor + // + Status = USBSTOR_GetDescriptor(DeviceExtension->LowerDeviceObject, USB_CONFIGURATION_DESCRIPTOR_TYPE, DescriptorLength, 0, 0, (PVOID*)&DeviceExtension->ConfigurationDescriptor); + if (!NT_SUCCESS(Status)) + { + // + // failed to get configuration descriptor + // + FreeItem(DeviceExtension->DeviceDescriptor); + DeviceExtension->DeviceDescriptor = NULL; + return Status; + } + + // + // check if there is a serial number provided + // + if (DeviceExtension->DeviceDescriptor->iSerialNumber) + { + // + // get serial number + // + Status = USBSTOR_GetDescriptor(DeviceExtension->LowerDeviceObject, USB_STRING_DESCRIPTOR_TYPE, 100 * sizeof(WCHAR), DeviceExtension->DeviceDescriptor->iSerialNumber, 0x0409, (PVOID*)&DeviceExtension->SerialNumber); + if (!NT_SUCCESS(Status)) + { + // + // failed to get serial number descriptor, free device descriptor + // + FreeItem(DeviceExtension->DeviceDescriptor); + DeviceExtension->DeviceDescriptor = NULL; + + // + // free configuration descriptor + // + FreeItem(DeviceExtension->ConfigurationDescriptor); + DeviceExtension->ConfigurationDescriptor = NULL; + + // + // set serial number to zero + // + DeviceExtension->SerialNumber = NULL; + return Status; + } + } + + return Status; +} + +NTSTATUS +NTAPI +USBSTOR_ScanConfigurationDescriptor( + IN PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor, + OUT PUSB_INTERFACE_DESCRIPTOR * OutInterfaceDescriptor, + OUT PUSB_ENDPOINT_DESCRIPTOR * InEndpointDescriptor, + OUT PUSB_ENDPOINT_DESCRIPTOR * OutEndpointDescriptor) +{ + PUSB_CONFIGURATION_DESCRIPTOR CurrentDescriptor; + PUSB_ENDPOINT_DESCRIPTOR EndpointDescriptor; + + // + // sanity checks + // + ASSERT(ConfigurationDescriptor); + ASSERT(OutInterfaceDescriptor); + ASSERT(InEndpointDescriptor); + ASSERT(OutEndpointDescriptor); + + // + // nullify pointers + // + *OutInterfaceDescriptor = NULL; + *InEndpointDescriptor = NULL; + *OutEndpointDescriptor = NULL; + + // + // start scanning + // + CurrentDescriptor = ConfigurationDescriptor; + + do + { + // + // check current descriptor type + // + if (CurrentDescriptor->bDescriptorType == USB_INTERFACE_DESCRIPTOR_TYPE) + { + // + // found interface descriptor + // + if (*OutInterfaceDescriptor) + { + // + // we only process the first interface descriptor as ms does -> see documentation + // + break; + } + + // + // store interface descriptor + // + *OutInterfaceDescriptor = (PUSB_INTERFACE_DESCRIPTOR)CurrentDescriptor; + } + else if (CurrentDescriptor->bDescriptorType == USB_ENDPOINT_DESCRIPTOR_TYPE) + { + // + // convert to endpoint descriptor + // + EndpointDescriptor = (PUSB_ENDPOINT_DESCRIPTOR)CurrentDescriptor; + + // + // sanity check + // + ASSERT(*OutInterfaceDescriptor); + + // + // get endpoint type + // + if ((EndpointDescriptor->bmAttributes & USB_ENDPOINT_TYPE_MASK) == USB_ENDPOINT_TYPE_BULK) + { + // + // bulk endpoint type + // + if (USB_ENDPOINT_DIRECTION_IN(EndpointDescriptor->bEndpointAddress)) + { + // + // bulk in + // + *InEndpointDescriptor = EndpointDescriptor; + } + else + { + // + // bulk out + // + *OutEndpointDescriptor = EndpointDescriptor; + } + } + else if ((EndpointDescriptor->bmAttributes & USB_ENDPOINT_TYPE_MASK) == USB_ENDPOINT_TYPE_INTERRUPT) + { + // + // interrupt endpoint type + // + UNIMPLEMENTED; + } + } + + // + // move to next descriptor + // + CurrentDescriptor = (PUSB_CONFIGURATION_DESCRIPTOR)((ULONG_PTR)CurrentDescriptor + CurrentDescriptor->bLength); + + // + // was it the last descriptor + // + if ((ULONG_PTR)CurrentDescriptor >= ((ULONG_PTR)ConfigurationDescriptor + ConfigurationDescriptor->wTotalLength)) + { + // + // reached last descriptor + // + break; + } + + }while(TRUE); + + // + // check if everything has been found + // + if (*OutInterfaceDescriptor == NULL || *InEndpointDescriptor == NULL || *OutEndpointDescriptor == NULL) + { + // + // failed to find interface / endpoint descriptor + // + DPRINT1("USBSTOR_ScanConfigurationDescriptor: Failed to find InterfaceDescriptor %p InEndpointDescriptor %p OutEndpointDescriptor %p\n", *OutInterfaceDescriptor, *InEndpointDescriptor, *OutEndpointDescriptor); + return STATUS_UNSUCCESSFUL; + } + + // + // completed successfully + // + return STATUS_SUCCESS; +} + +VOID +DumpConfigurationDescriptor(PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor) +{ + DPRINT1("Dumping ConfigurationDescriptor %p\n", ConfigurationDescriptor); + DPRINT1("bLength %x\n", ConfigurationDescriptor->bLength); + DPRINT1("bDescriptorType %x\n", ConfigurationDescriptor->bDescriptorType); + DPRINT1("wTotalLength %x\n", ConfigurationDescriptor->wTotalLength); + DPRINT1("bNumInterfaces %x\n", ConfigurationDescriptor->bNumInterfaces); + DPRINT1("bConfigurationValue %x\n", ConfigurationDescriptor->bConfigurationValue); + DPRINT1("iConfiguration %x\n", ConfigurationDescriptor->iConfiguration); + DPRINT1("bmAttributes %x\n", ConfigurationDescriptor->bmAttributes); + DPRINT1("MaxPower %x\n", ConfigurationDescriptor->MaxPower); +} + +NTSTATUS +USBSTOR_SelectConfigurationAndInterface( + IN PDEVICE_OBJECT DeviceObject, + IN PFDO_DEVICE_EXTENSION DeviceExtension) +{ + PUSB_INTERFACE_DESCRIPTOR InterfaceDescriptor; + PUSB_ENDPOINT_DESCRIPTOR InEndpointDescriptor, OutEndpointDescriptor; + NTSTATUS Status; + PURB Urb; + PUSBD_INTERFACE_LIST_ENTRY InterfaceList; + + // + // now scan configuration descriptors + // + Status = USBSTOR_ScanConfigurationDescriptor(DeviceExtension->ConfigurationDescriptor, &InterfaceDescriptor, &InEndpointDescriptor, &OutEndpointDescriptor); + if (!NT_SUCCESS(Status)) + { + // + // failed to scan + // + return Status; + } + + // + // now allocate one interface entry and terminating null entry + // + InterfaceList = (PUSBD_INTERFACE_LIST_ENTRY)AllocateItem(PagedPool, sizeof(USBD_INTERFACE_LIST_ENTRY) * 2); + if (!InterfaceList) + { + // + // no memory + // + return STATUS_INSUFFICIENT_RESOURCES; + } + + // + // initialize interface list entry + // + InterfaceList[0].InterfaceDescriptor = InterfaceDescriptor; + + // + // now allocate the urb + // + Urb = USBD_CreateConfigurationRequestEx(DeviceExtension->ConfigurationDescriptor, InterfaceList); + if (!Urb) + { + // + // no memory + // + FreeItem(InterfaceList); + return STATUS_INSUFFICIENT_RESOURCES; + } + + // + // sanity check + // + ASSERT(InterfaceList[0].Interface); + + // + // submit urb + // + Status = USBSTOR_SyncUrbRequest(DeviceExtension->LowerDeviceObject, Urb); + if (!NT_SUCCESS(Status)) + { + // + // failed to set configuration + // + DPRINT1("USBSTOR_SelectConfiguration failed to set interface %x\n", Status); + FreeItem(InterfaceList); + ExFreePoolWithTag(Urb, 0); + return Status; + } + + // + // backup interface information + // + DeviceExtension->InterfaceInformation = (PUSBD_INTERFACE_INFORMATION)AllocateItem(NonPagedPool, Urb->UrbSelectConfiguration.Interface.Length); + if (!DeviceExtension->InterfaceInformation) + { + // + // failed to allocate interface information structure + // + FreeItem(InterfaceList); + ExFreePoolWithTag(Urb, 0); + return STATUS_INSUFFICIENT_RESOURCES; + } + + // + // copy interface information + // + RtlCopyMemory(DeviceExtension->InterfaceInformation, &Urb->UrbSelectConfiguration.Interface, Urb->UrbSelectConfiguration.Interface.Length); + + // + // store pipe handle + // + DeviceExtension->ConfigurationHandle = Urb->UrbSelectConfiguration.ConfigurationHandle; + + // + // now prepare interface urb + // + UsbBuildSelectInterfaceRequest(Urb, GET_SELECT_INTERFACE_REQUEST_SIZE(InterfaceDescriptor->bNumEndpoints), DeviceExtension->ConfigurationHandle, InterfaceDescriptor->bInterfaceNumber, InterfaceDescriptor->bAlternateSetting); + + // + // copy interface information structure back - as offset for SelectConfiguration / SelectInterface request do differ + // + RtlCopyMemory(&Urb->UrbSelectInterface.Interface, DeviceExtension->InterfaceInformation, DeviceExtension->InterfaceInformation->Length); + + // + // now select the interface + // + Status = USBSTOR_SyncUrbRequest(DeviceExtension->LowerDeviceObject, Urb); + + // + // did it succeed + // + if (NT_SUCCESS(Status)) + { + // + // update configuration info + // + ASSERT(Urb->UrbSelectInterface.Interface.Length == DeviceExtension->InterfaceInformation->Length); + RtlCopyMemory(DeviceExtension->InterfaceInformation, &Urb->UrbSelectInterface.Interface, Urb->UrbSelectInterface.Interface.Length); + } + + // + // free interface list & urb + // + FreeItem(InterfaceList); + ExFreePoolWithTag(Urb, 0); + + // + // done + // + return Status; +} + +NTSTATUS +USBSTOR_GetPipeHandles( + IN PFDO_DEVICE_EXTENSION DeviceExtension) +{ + ULONG Index; + BOOLEAN BulkInFound = FALSE, BulkOutFound = FALSE; + + // + // no enumerate all pipes and extract bulk-in / bulk-out pipe handle + // + for(Index = 0; Index < DeviceExtension->InterfaceInformation->NumberOfPipes; Index++) + { + // + // check pipe type + // + if (DeviceExtension->InterfaceInformation->Pipes[Index].PipeType == UsbdPipeTypeBulk) + { + // + // check direction + // + if (USB_ENDPOINT_DIRECTION_IN(DeviceExtension->InterfaceInformation->Pipes[Index].EndpointAddress)) + { + // + // bulk in pipe + // + DeviceExtension->BulkInPipeIndex = Index; + + // + // there should not be another bulk in pipe + // + ASSERT(BulkInFound == FALSE); + BulkInFound = TRUE; + } + else + { + // + // bulk out pipe + // + DeviceExtension->BulkOutPipeIndex = Index; + + // + // there should not be another bulk out pipe + // + ASSERT(BulkOutFound == FALSE); + BulkOutFound = TRUE; + } + } + } + + // + // check if both bulk pipes have been found + // + if (!BulkInFound || !BulkOutFound) + { + // + // WTF? usb port driver does not give us bulk pipe access + // + DPRINT1("USBSTOR_GetPipeHandles> BulkInFound %c BulkOutFound %c missing!!!\n", BulkInFound, BulkOutFound); + return STATUS_DEVICE_CONFIGURATION_ERROR; + } + + // + // device is configured + // + return STATUS_SUCCESS; +} diff --git a/drivers/usb/usbstor_new/disk.c b/drivers/usb/usbstor_new/disk.c new file mode 100644 index 0000000000..604f621c91 --- /dev/null +++ b/drivers/usb/usbstor_new/disk.c @@ -0,0 +1,691 @@ +/* + * PROJECT: ReactOS Universal Serial Bus Bulk Storage Driver + * LICENSE: GPL - See COPYING in the top level directory + * FILE: drivers/usb/usbstor/disk.c + * PURPOSE: USB block storage device driver. + * PROGRAMMERS: + * James Tabor + * Michael Martin (michael.martin@reactos.org) + * Johannes Anderwald (johannes.anderwald@reactos.org) + */ + +#include "usbstor.h" + +#define NDEBUG +#include <debug.h> + +NTSTATUS +USBSTOR_HandleInternalDeviceControl( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp) +{ + PIO_STACK_LOCATION IoStack; + PSCSI_REQUEST_BLOCK Request; + PPDO_DEVICE_EXTENSION PDODeviceExtension; + NTSTATUS Status; + + // + // get current stack location + // + IoStack = IoGetCurrentIrpStackLocation(Irp); + + // + // get request block + // + Request = (PSCSI_REQUEST_BLOCK)IoStack->Parameters.Others.Argument1; + + // + // sanity check + // + ASSERT(Request); + + // + // get device extension + // + PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension; + + // + // sanity check + // + ASSERT(PDODeviceExtension->Common.IsFDO == FALSE); + + switch(Request->Function) + { + case SRB_FUNCTION_EXECUTE_SCSI: + { + DPRINT("SRB_FUNCTION_EXECUTE_SCSI\n"); + + // + // check if request is valid + // + if (Request->SrbFlags & (SRB_FLAGS_DATA_IN | SRB_FLAGS_DATA_OUT)) + { + // + // data is transferred with this irp + // + if ((Request->SrbFlags & (SRB_FLAGS_DATA_IN | SRB_FLAGS_DATA_OUT)) == (SRB_FLAGS_DATA_IN | SRB_FLAGS_DATA_OUT) || + Request->DataTransferLength == 0 || + Irp->MdlAddress == NULL) + { + // + // invalid parameter + // + Status = STATUS_INVALID_PARAMETER; + break; + } + } + else + { + // + // sense buffer request + // + if (Request->DataTransferLength || + Request->DataBuffer || + Irp->MdlAddress) + { + // + // invalid parameter + // + Status = STATUS_INVALID_PARAMETER; + break; + } + } + + // + // add the request + // + if (!USBSTOR_QueueAddIrp(PDODeviceExtension->LowerDeviceObject, Irp)) + { + // + // irp was not added to the queue + // + IoStartPacket(PDODeviceExtension->LowerDeviceObject, Irp, &Request->QueueSortKey, USBSTOR_CancelIo); + } + + // + // irp pending + // + return STATUS_PENDING; + } + case SRB_FUNCTION_RELEASE_DEVICE: + { + DPRINT1("SRB_FUNCTION_RELEASE_DEVICE\n"); + // + // sanity check + // + ASSERT(PDODeviceExtension->Claimed == TRUE); + + // + // release claim + // + PDODeviceExtension->Claimed = FALSE; + Status = STATUS_SUCCESS; + break; + } + case SRB_FUNCTION_CLAIM_DEVICE: + { + DPRINT1("SRB_FUNCTION_CLAIM_DEVICE\n"); + // + // check if the device has been claimed + // + if (PDODeviceExtension->Claimed) + { + // + // device has already been claimed + // + Status = STATUS_DEVICE_BUSY; + Request->SrbStatus = SRB_STATUS_BUSY; + break; + } + + // + // claim device + // + PDODeviceExtension->Claimed = TRUE; + + // + // output device object + // + Request->DataBuffer = DeviceObject; + + // + // completed successfully + // + Status = STATUS_SUCCESS; + break; + } + case SRB_FUNCTION_RELEASE_QUEUE: + { + DPRINT1("SRB_FUNCTION_RELEASE_QUEUE\n"); + + // + // release queue + // + USBSTOR_QueueRelease(PDODeviceExtension->LowerDeviceObject); + + // + // set status success + // + Request->SrbStatus = SRB_STATUS_SUCCESS; + Status = STATUS_SUCCESS; + break; + } + + case SRB_FUNCTION_SHUTDOWN: + case SRB_FUNCTION_FLUSH: + case SRB_FUNCTION_FLUSH_QUEUE: + { + DPRINT1("SRB_FUNCTION_FLUSH / SRB_FUNCTION_FLUSH_QUEUE / SRB_FUNCTION_SHUTDOWN\n"); + + // HACK: don't flush pending requests +#if 0 // we really need a proper storage stack + // + // wait for pending requests to finish + // + USBSTOR_QueueWaitForPendingRequests(PDODeviceExtension->LowerDeviceObject); +#endif + // + // set status success + // + Request->SrbStatus = SRB_STATUS_SUCCESS; + Status = STATUS_SUCCESS; + break; + } + default: + { + // + // not supported + // + Status = STATUS_NOT_SUPPORTED; + Request->SrbStatus = SRB_STATUS_ERROR; + } + } + + // + // complete request + // + Irp->IoStatus.Status = Status; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + return Status; +} + +ULONG +USBSTOR_GetFieldLength( + IN PUCHAR Name, + IN ULONG MaxLength) +{ + ULONG Index; + ULONG LastCharacterPosition = 0; + + // + // scan the field and return last position which contains a valid character + // + for(Index = 0; Index < MaxLength; Index++) + { + if (Name[Index] != ' ') + { + // + // trim white spaces from field + // + LastCharacterPosition = Index; + } + } + + // + // convert from zero based index to length + // + return LastCharacterPosition + 1; +} + +NTSTATUS +USBSTOR_HandleQueryProperty( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp) +{ + PIO_STACK_LOCATION IoStack; + PSTORAGE_PROPERTY_QUERY PropertyQuery; + PSTORAGE_DESCRIPTOR_HEADER DescriptorHeader; + PSTORAGE_ADAPTER_DESCRIPTOR AdapterDescriptor; + ULONG FieldLengthVendor, FieldLengthProduct, FieldLengthRevision, TotalLength, FieldLengthSerialNumber; + PPDO_DEVICE_EXTENSION PDODeviceExtension; + PUFI_INQUIRY_RESPONSE InquiryData; + PSTORAGE_DEVICE_DESCRIPTOR DeviceDescriptor; + PUCHAR Buffer; + PFDO_DEVICE_EXTENSION FDODeviceExtension; + UNICODE_STRING SerialNumber; + ANSI_STRING AnsiString; + NTSTATUS Status; + + DPRINT("USBSTOR_HandleQueryProperty\n"); + + // + // get current stack location + // + IoStack = IoGetCurrentIrpStackLocation(Irp); + + // + // sanity check + // + ASSERT(IoStack->Parameters.DeviceIoControl.InputBufferLength >= sizeof(STORAGE_PROPERTY_QUERY)); + ASSERT(Irp->AssociatedIrp.SystemBuffer); + + // + // get property query + // + PropertyQuery = (PSTORAGE_PROPERTY_QUERY)Irp->AssociatedIrp.SystemBuffer; + + // + // check property type + // + if (PropertyQuery->PropertyId != StorageDeviceProperty && + PropertyQuery->PropertyId != StorageAdapterProperty) + { + // + // only device property / adapter property are supported + // + return STATUS_INVALID_PARAMETER_1; + } + + // + // check query type + // + if (PropertyQuery->QueryType == PropertyExistsQuery) + { + // + // device property / adapter property is supported + // + return STATUS_SUCCESS; + } + + if (PropertyQuery->QueryType != PropertyStandardQuery) + { + // + // only standard query and exists query are supported + // + return STATUS_INVALID_PARAMETER_2; + } + + // + // check if it is a device property + // + if (PropertyQuery->PropertyId == StorageDeviceProperty) + { + DPRINT("USBSTOR_HandleQueryProperty StorageDeviceProperty OutputBufferLength %lu\n", IoStack->Parameters.DeviceIoControl.OutputBufferLength); + + // + // get device extension + // + PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension; + ASSERT(PDODeviceExtension); + ASSERT(PDODeviceExtension->Common.IsFDO == FALSE); + + // + // get device extension + // + FDODeviceExtension = (PFDO_DEVICE_EXTENSION)PDODeviceExtension->LowerDeviceObject->DeviceExtension; + ASSERT(FDODeviceExtension); + ASSERT(FDODeviceExtension->Common.IsFDO); + + // + // get inquiry data + // + InquiryData = (PUFI_INQUIRY_RESPONSE)PDODeviceExtension->InquiryData; + ASSERT(InquiryData); + + // + // compute extra parameters length + // + FieldLengthVendor = USBSTOR_GetFieldLength(InquiryData->Vendor, 8); + FieldLengthProduct = USBSTOR_GetFieldLength(InquiryData->Product, 16); + FieldLengthRevision = USBSTOR_GetFieldLength(InquiryData->Revision, 4); + + // + // is there a serial number + // + if (FDODeviceExtension->SerialNumber) + { + // + // get length + // + FieldLengthSerialNumber = wcslen(FDODeviceExtension->SerialNumber->bString); + } + else + { + // + // no serial number + // + FieldLengthSerialNumber = 0; + } + + // + // total length required is sizeof(STORAGE_DEVICE_DESCRIPTOR) + FieldLength + 4 extra null bytes - 1 + // -1 due STORAGE_DEVICE_DESCRIPTOR contains one byte length of parameter data + // + TotalLength = sizeof(STORAGE_DEVICE_DESCRIPTOR) + FieldLengthVendor + FieldLengthProduct + FieldLengthRevision + FieldLengthSerialNumber + 3; + + // + // check if output buffer is long enough + // + if (IoStack->Parameters.DeviceIoControl.OutputBufferLength < TotalLength) + { + // + // buffer too small + // + DescriptorHeader = (PSTORAGE_DESCRIPTOR_HEADER)Irp->AssociatedIrp.SystemBuffer; + ASSERT(IoStack->Parameters.DeviceIoControl.OutputBufferLength >= sizeof(STORAGE_DESCRIPTOR_HEADER)); + + // + // return required size + // + DescriptorHeader->Version = TotalLength; + DescriptorHeader->Size = TotalLength; + + Irp->IoStatus.Information = sizeof(STORAGE_DESCRIPTOR_HEADER); + return STATUS_SUCCESS; + } + + // + // get device descriptor + // + DeviceDescriptor = (PSTORAGE_DEVICE_DESCRIPTOR)Irp->AssociatedIrp.SystemBuffer; + + // + // initialize device descriptor + // + DeviceDescriptor->Version = TotalLength; + DeviceDescriptor->Size = TotalLength; + DeviceDescriptor->DeviceType = InquiryData->DeviceType; + DeviceDescriptor->DeviceTypeModifier = (InquiryData->RMB & 0x7F); + DeviceDescriptor->RemovableMedia = (InquiryData->RMB & 0x80) ? TRUE : FALSE; + DeviceDescriptor->CommandQueueing = FALSE; + DeviceDescriptor->BusType = BusTypeUsb; + DeviceDescriptor->VendorIdOffset = sizeof(STORAGE_DEVICE_DESCRIPTOR) - sizeof(UCHAR); + DeviceDescriptor->ProductIdOffset = DeviceDescriptor->VendorIdOffset + FieldLengthVendor + 1; + DeviceDescriptor->ProductRevisionOffset = DeviceDescriptor->ProductIdOffset + FieldLengthProduct + 1; + DeviceDescriptor->SerialNumberOffset = (FieldLengthSerialNumber > 0 ? DeviceDescriptor->ProductRevisionOffset + FieldLengthRevision + 1 : 0); + DeviceDescriptor->RawPropertiesLength = FieldLengthVendor + FieldLengthProduct + FieldLengthRevision + FieldLengthSerialNumber + 3 + (FieldLengthSerialNumber > 0 ? + 1 : 0); + + // + // copy descriptors + // + Buffer = (PUCHAR)((ULONG_PTR)DeviceDescriptor + sizeof(STORAGE_DEVICE_DESCRIPTOR) - sizeof(UCHAR)); + + // + // copy vendor + // + RtlCopyMemory(Buffer, InquiryData->Vendor, FieldLengthVendor); + Buffer[FieldLengthVendor] = '\0'; + Buffer += FieldLengthVendor + 1; + + // + // copy product + // + RtlCopyMemory(Buffer, InquiryData->Product, FieldLengthProduct); + Buffer[FieldLengthProduct] = '\0'; + Buffer += FieldLengthProduct + 1; + + // + // copy revision + // + RtlCopyMemory(Buffer, InquiryData->Revision, FieldLengthRevision); + Buffer[FieldLengthRevision] = '\0'; + Buffer += FieldLengthRevision + 1; + + // + // copy serial number + // + if (FieldLengthSerialNumber) + { + // + // init unicode string + // + RtlInitUnicodeString(&SerialNumber, FDODeviceExtension->SerialNumber->bString); + + // + // init ansi string + // + AnsiString.Buffer = (PCHAR)Buffer; + AnsiString.Length = 0; + AnsiString.MaximumLength = FieldLengthSerialNumber * sizeof(WCHAR); + + // + // convert to ansi code + // + Status = RtlUnicodeStringToAnsiString(&AnsiString, &SerialNumber, FALSE); + ASSERT(Status == STATUS_SUCCESS); + } + + + DPRINT("Vendor %s\n", (LPCSTR)((ULONG_PTR)DeviceDescriptor + DeviceDescriptor->VendorIdOffset)); + DPRINT("Product %s\n", (LPCSTR)((ULONG_PTR)DeviceDescriptor + DeviceDescriptor->ProductIdOffset)); + DPRINT("Revision %s\n", (LPCSTR)((ULONG_PTR)DeviceDescriptor + DeviceDescriptor->ProductRevisionOffset)); + DPRINT("Serial %s\n", (LPCSTR)((ULONG_PTR)DeviceDescriptor + DeviceDescriptor->SerialNumberOffset)); + + // + // done + // + Irp->IoStatus.Information = TotalLength; + return STATUS_SUCCESS; + } + else + { + // + // adapter property query request + // + DPRINT("USBSTOR_HandleQueryProperty StorageAdapterProperty OutputBufferLength %lu\n", IoStack->Parameters.DeviceIoControl.OutputBufferLength); + + if (IoStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(STORAGE_ADAPTER_DESCRIPTOR)) + { + // + // buffer too small + // + DescriptorHeader = (PSTORAGE_DESCRIPTOR_HEADER)Irp->AssociatedIrp.SystemBuffer; + ASSERT(IoStack->Parameters.DeviceIoControl.OutputBufferLength >= sizeof(STORAGE_DESCRIPTOR_HEADER)); + + // + // return required size + // + DescriptorHeader->Version = sizeof(STORAGE_ADAPTER_DESCRIPTOR); + DescriptorHeader->Size = sizeof(STORAGE_ADAPTER_DESCRIPTOR); + + Irp->IoStatus.Information = sizeof(STORAGE_DESCRIPTOR_HEADER); + return STATUS_SUCCESS; + } + + // + // get adapter descriptor, information is returned in the same buffer + // + AdapterDescriptor = (PSTORAGE_ADAPTER_DESCRIPTOR)Irp->AssociatedIrp.SystemBuffer; + + // + // fill out descriptor + // + AdapterDescriptor->Version = sizeof(STORAGE_ADAPTER_DESCRIPTOR); + AdapterDescriptor->Size = sizeof(STORAGE_ADAPTER_DESCRIPTOR); + AdapterDescriptor->MaximumTransferLength = MAXULONG; //FIXME compute some sane value + AdapterDescriptor->MaximumPhysicalPages = 25; //FIXME compute some sane value + AdapterDescriptor->AlignmentMask = 0; + AdapterDescriptor->AdapterUsesPio = FALSE; + AdapterDescriptor->AdapterScansDown = FALSE; + AdapterDescriptor->CommandQueueing = FALSE; + AdapterDescriptor->AcceleratedTransfer = FALSE; + AdapterDescriptor->BusType = BusTypeUsb; + AdapterDescriptor->BusMajorVersion = 0x2; //FIXME verify + AdapterDescriptor->BusMinorVersion = 0x00; //FIXME + + // + // store returned length + // + Irp->IoStatus.Information = sizeof(STORAGE_ADAPTER_DESCRIPTOR); + + // + // done + // + return STATUS_SUCCESS; + } +} + +NTSTATUS +USBSTOR_HandleDeviceControl( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp) +{ + PIO_STACK_LOCATION IoStack; + NTSTATUS Status; + PPDO_DEVICE_EXTENSION PDODeviceExtension; + PSCSI_ADAPTER_BUS_INFO BusInfo; + PSCSI_INQUIRY_DATA InquiryData; + PINQUIRYDATA ScsiInquiryData; + PUFI_INQUIRY_RESPONSE UFIInquiryResponse; + + // + // get current stack location + // + IoStack = IoGetCurrentIrpStackLocation(Irp); + + if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_STORAGE_QUERY_PROPERTY) + { + // + // query property + // + Status = USBSTOR_HandleQueryProperty(DeviceObject, Irp); + } + else if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_SCSI_PASS_THROUGH) + { + // + // query scsi pass through + // + DPRINT1("USBSTOR_HandleDeviceControl IOCTL_SCSI_PASS_THROUGH NOT implemented\n"); + Status = STATUS_NOT_SUPPORTED; + } + else if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_SCSI_PASS_THROUGH_DIRECT) + { + // + // query scsi pass through direct + // + DPRINT1("USBSTOR_HandleDeviceControl IOCTL_SCSI_PASS_THROUGH_DIRECT NOT implemented\n"); + Status = STATUS_NOT_SUPPORTED; + } + else if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_STORAGE_GET_MEDIA_SERIAL_NUMBER) + { + // + // query serial number + // + DPRINT1("USBSTOR_HandleDeviceControl IOCTL_STORAGE_GET_MEDIA_SERIAL_NUMBER NOT implemented\n"); + Status = STATUS_NOT_SUPPORTED; + } + else if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_SCSI_GET_CAPABILITIES) + { + PIO_SCSI_CAPABILITIES Capabilities; + + /* Legacy port capability query */ + if (IoStack->Parameters.DeviceIoControl.OutputBufferLength == sizeof(PVOID)) + { + Capabilities = *((PVOID *)Irp->AssociatedIrp.SystemBuffer) = ExAllocatePoolWithTag(NonPagedPool, + sizeof(IO_SCSI_CAPABILITIES), + USB_STOR_TAG); + Irp->IoStatus.Information = sizeof(PVOID); + } + else + { + Capabilities = Irp->AssociatedIrp.SystemBuffer; + Irp->IoStatus.Information = sizeof(IO_SCSI_CAPABILITIES); + } + + if (Capabilities) + { + Capabilities->MaximumTransferLength = MAXULONG; + Capabilities->MaximumPhysicalPages = 25; + Capabilities->SupportedAsynchronousEvents = 0; + Capabilities->AlignmentMask = 0; + Capabilities->TaggedQueuing = FALSE; + Capabilities->AdapterScansDown = FALSE; + Capabilities->AdapterUsesPio = FALSE; + Status = STATUS_SUCCESS; + } + else + { + Status = STATUS_INSUFFICIENT_RESOURCES; + } + } + else if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_SCSI_GET_INQUIRY_DATA) + { + // + // get device extension + // + PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension; + ASSERT(PDODeviceExtension); + ASSERT(PDODeviceExtension->Common.IsFDO == FALSE); + + // + // get parameters + // + BusInfo = Irp->AssociatedIrp.SystemBuffer; + InquiryData = (PSCSI_INQUIRY_DATA)(BusInfo + 1); + ScsiInquiryData = (PINQUIRYDATA)InquiryData->InquiryData; + + + // + // get inquiry data + // + UFIInquiryResponse = (PUFI_INQUIRY_RESPONSE)PDODeviceExtension->InquiryData; + ASSERT(UFIInquiryResponse); + + + BusInfo->NumberOfBuses = 1; + BusInfo->BusData[0].NumberOfLogicalUnits = 1; //FIXME + BusInfo->BusData[0].InitiatorBusId = 0; + BusInfo->BusData[0].InquiryDataOffset = sizeof(SCSI_ADAPTER_BUS_INFO); + + InquiryData->PathId = 0; + InquiryData->TargetId = 0; + InquiryData->Lun = PDODeviceExtension->LUN & MAX_LUN; + InquiryData->DeviceClaimed = PDODeviceExtension->Claimed; + InquiryData->InquiryDataLength = sizeof(INQUIRYDATA); + InquiryData->NextInquiryDataOffset = 0; + + RtlZeroMemory(ScsiInquiryData, sizeof(INQUIRYDATA)); + ScsiInquiryData->DeviceType = UFIInquiryResponse->DeviceType; + ScsiInquiryData->DeviceTypeQualifier = (UFIInquiryResponse->RMB & 0x7F); + + /* Hack for IoReadPartitionTable call in disk.sys */ + ScsiInquiryData->RemovableMedia = ((ScsiInquiryData->DeviceType != DIRECT_ACCESS_DEVICE) ? ((UFIInquiryResponse->RMB & 0x80) ? 1 : 0) : 0); + + ScsiInquiryData->Versions = 0x04; + ScsiInquiryData->ResponseDataFormat = 0x02; + ScsiInquiryData->AdditionalLength = 31; + ScsiInquiryData->SoftReset = 0; + ScsiInquiryData->CommandQueue = 0; + ScsiInquiryData->LinkedCommands = 0; + ScsiInquiryData->RelativeAddressing = 0; + + RtlCopyMemory(&ScsiInquiryData->VendorId, UFIInquiryResponse->Vendor, USBSTOR_GetFieldLength(UFIInquiryResponse->Vendor, 8)); + RtlCopyMemory(&ScsiInquiryData->ProductId, UFIInquiryResponse->Product, USBSTOR_GetFieldLength(UFIInquiryResponse->Product, 16)); + + Irp->IoStatus.Information = sizeof(SCSI_ADAPTER_BUS_INFO) + sizeof(SCSI_INQUIRY_DATA) + sizeof(INQUIRYDATA) - 1; + Status = STATUS_SUCCESS; + } + else if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_SCSI_GET_ADDRESS) + { + PSCSI_ADDRESS Address = Irp->AssociatedIrp.SystemBuffer; + + Address->Length = sizeof(SCSI_ADDRESS); + Address->PortNumber = 0; + Address->PathId = 0; + Address->TargetId = 0; + Address->Lun = (((PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->LUN & MAX_LUN); + Irp->IoStatus.Information = sizeof(SCSI_ADDRESS); + + Status = STATUS_SUCCESS; + } + else + { + // + // unsupported + // + DPRINT("USBSTOR_HandleDeviceControl IoControl %x not supported\n", IoStack->Parameters.DeviceIoControl.IoControlCode); + Status = STATUS_NOT_SUPPORTED; + } + + return Status; +} diff --git a/drivers/usb/usbstor_new/error.c b/drivers/usb/usbstor_new/error.c new file mode 100644 index 0000000000..e920d353d1 --- /dev/null +++ b/drivers/usb/usbstor_new/error.c @@ -0,0 +1,410 @@ +/* + * PROJECT: ReactOS Universal Serial Bus Bulk Storage Driver + * LICENSE: GPL - See COPYING in the top level directory + * FILE: drivers/usb/usbstor/error.c + * PURPOSE: USB block storage device driver. + * PROGRAMMERS: + * James Tabor + * Michael Martin (michael.martin@reactos.org) + * Johannes Anderwald (johannes.anderwald@reactos.org) + */ + +#include "usbstor.h" + +#define NDEBUG +#include <debug.h> + +NTSTATUS +USBSTOR_GetEndpointStatus( + IN PDEVICE_OBJECT DeviceObject, + IN UCHAR bEndpointAddress, + OUT PUSHORT Value) +{ + PURB Urb; + NTSTATUS Status; + + // + // allocate urb + // + DPRINT("Allocating URB\n"); + Urb = (PURB)AllocateItem(NonPagedPool, sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST)); + if (!Urb) + { + // + // out of memory + // + 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); + + // + // free urb + // + FreeItem(Urb); + + // + // done + // + return Status; +} + + + +NTSTATUS +USBSTOR_ResetPipeWithHandle( + IN PDEVICE_OBJECT DeviceObject, + IN USBD_PIPE_HANDLE PipeHandle) +{ + PURB Urb; + NTSTATUS Status; + + // + // allocate urb + // + DPRINT("Allocating URB\n"); + Urb = (PURB)AllocateItem(NonPagedPool, sizeof(struct _URB_PIPE_REQUEST)); + if (!Urb) + { + // + // out of memory + // + DPRINT1("OutofMemory!\n"); + return STATUS_INSUFFICIENT_RESOURCES; + } + + // + // initialize the urb + // + 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); + + // + // free urb + // + FreeItem(Urb); + + // + // done + // + return Status; +} + + +NTSTATUS +USBSTOR_HandleTransferError( + PDEVICE_OBJECT DeviceObject, + PIRP_CONTEXT Context) +{ + NTSTATUS Status = STATUS_SUCCESS; + PIO_STACK_LOCATION Stack; + PSCSI_REQUEST_BLOCK Request; + PCDB pCDB; + + // + // sanity checks + // + ASSERT(Context); + ASSERT(Context->PDODeviceExtension); + ASSERT(Context->PDODeviceExtension->Self); + ASSERT(Context->Irp); + + // + // first perform a mass storage reset step 1 in 5.3.4 USB Mass Storage Bulk Only Specification + // + Status = USBSTOR_ResetDevice(Context->FDODeviceExtension->LowerDeviceObject, Context->FDODeviceExtension); + if (NT_SUCCESS(Status)) + { + // + // step 2 reset bulk in pipe section 5.3.4 + // + Status = USBSTOR_ResetPipeWithHandle(Context->FDODeviceExtension->LowerDeviceObject, Context->FDODeviceExtension->InterfaceInformation->Pipes[Context->FDODeviceExtension->BulkInPipeIndex].PipeHandle); + if (NT_SUCCESS(Status)) + { + // + // finally reset bulk out pipe + // + Status = USBSTOR_ResetPipeWithHandle(Context->FDODeviceExtension->LowerDeviceObject, Context->FDODeviceExtension->InterfaceInformation->Pipes[Context->FDODeviceExtension->BulkOutPipeIndex].PipeHandle); + } + } + + // + // get next stack location + // + Stack = IoGetCurrentIrpStackLocation(Context->Irp); + + // + // get request block + // + Request = (PSCSI_REQUEST_BLOCK)Stack->Parameters.Others.Argument1; + ASSERT(Request); + + // + // obtain request type + // + pCDB = (PCDB)Request->Cdb; + ASSERT(pCDB); + + if (Status != STATUS_SUCCESS || Context->RetryCount >= 1) + { + // + // Complete the master IRP + // + Context->Irp->IoStatus.Status = Status; + Context->Irp->IoStatus.Information = 0; + USBSTOR_QueueTerminateRequest(Context->PDODeviceExtension->LowerDeviceObject, Context->Irp); + IoCompleteRequest(Context->Irp, IO_NO_INCREMENT); + + // + // Start the next request + // + USBSTOR_QueueNextRequest(Context->PDODeviceExtension->LowerDeviceObject); + + // + // srb handling finished + // + Context->FDODeviceExtension->SrbErrorHandlingActive = FALSE; + + // + // clear timer srb + // + Context->FDODeviceExtension->LastTimerActiveSrb = NULL; + } + else + { + DPRINT1("Retrying Count %lu %p\n", Context->RetryCount, Context->PDODeviceExtension->Self); + + // + // re-schedule request + // + USBSTOR_HandleExecuteSCSI(Context->PDODeviceExtension->Self, Context->Irp, Context->RetryCount + 1); + + // + // srb error handling finished + // + Context->FDODeviceExtension->SrbErrorHandlingActive = FALSE; + + // + // srb error handling finished + // + Context->FDODeviceExtension->TimerWorkQueueEnabled = TRUE; + + // + // clear timer srb + // + Context->FDODeviceExtension->LastTimerActiveSrb = NULL; + } + + // + // cleanup irp context + // + FreeItem(Context->cbw); + FreeItem(Context); + + + DPRINT1("USBSTOR_HandleTransferError returning with Status %x\n", Status); + return Status; +} + +VOID +NTAPI +USBSTOR_ResetHandlerWorkItemRoutine( + PVOID Context) +{ + NTSTATUS Status; + PERRORHANDLER_WORKITEM_DATA WorkItemData = (PERRORHANDLER_WORKITEM_DATA)Context; + + // + // clear stall on BulkIn pipe + // + Status = USBSTOR_ResetPipeWithHandle(WorkItemData->Context->FDODeviceExtension->LowerDeviceObject, WorkItemData->Context->FDODeviceExtension->InterfaceInformation->Pipes[WorkItemData->Context->FDODeviceExtension->BulkInPipeIndex].PipeHandle); + DPRINT1("USBSTOR_ResetPipeWithHandle Status %x\n", Status); + + // + // now resend the csw as the stall got cleared + // + USBSTOR_SendCSW(WorkItemData->Context, WorkItemData->Irp); +} + +VOID +NTAPI +ErrorHandlerWorkItemRoutine( + PVOID Context) +{ + PERRORHANDLER_WORKITEM_DATA WorkItemData = (PERRORHANDLER_WORKITEM_DATA)Context; + + if (WorkItemData->Context->ErrorIndex == 2) + { + // + // reset device + // + USBSTOR_HandleTransferError(WorkItemData->DeviceObject, WorkItemData->Context); + } + else + { + // + // clear stall + // + USBSTOR_ResetHandlerWorkItemRoutine(WorkItemData); + } + + // + // Free Work Item Data + // + ExFreePoolWithTag(WorkItemData, USB_STOR_TAG); +} + +VOID +NTAPI +USBSTOR_TimerWorkerRoutine( + IN PVOID Context) +{ + PFDO_DEVICE_EXTENSION FDODeviceExtension; + NTSTATUS Status; + PERRORHANDLER_WORKITEM_DATA WorkItemData = (PERRORHANDLER_WORKITEM_DATA)Context; + + // + // get device extension + // + 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; + + // + // Free Work Item Data + // + ExFreePoolWithTag(WorkItemData, USB_STOR_TAG); +} + + +VOID +NTAPI +USBSTOR_TimerRoutine( + PDEVICE_OBJECT DeviceObject, + PVOID Context) +{ + PFDO_DEVICE_EXTENSION FDODeviceExtension; + BOOLEAN ResetDevice = FALSE; + PERRORHANDLER_WORKITEM_DATA WorkItemData; + + // + // get device extension + // + 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); + + // + // acquire spinlock + // + 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; + } + + // + // release lock + // + 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); + } + } +} diff --git a/drivers/usb/usbstor_new/fdo.c b/drivers/usb/usbstor_new/fdo.c new file mode 100644 index 0000000000..e3707041f5 --- /dev/null +++ b/drivers/usb/usbstor_new/fdo.c @@ -0,0 +1,461 @@ +/* + * PROJECT: ReactOS Universal Serial Bus Bulk Storage Driver + * LICENSE: GPL - See COPYING in the top level directory + * FILE: drivers/usb/usbstor/fdo.c + * PURPOSE: USB block storage device driver. + * PROGRAMMERS: + * James Tabor + * Michael Martin (michael.martin@reactos.org) + * Johannes Anderwald (johannes.anderwald@reactos.org) + */ + +#include "usbstor.h" + +#define NDEBUG +#include <debug.h> + +VOID +USBSTOR_DumpDeviceDescriptor(PUSB_DEVICE_DESCRIPTOR DeviceDescriptor) +{ + DPRINT1("Dumping Device Descriptor %p\n", DeviceDescriptor); + DPRINT1("bLength %x\n", DeviceDescriptor->bLength); + DPRINT1("bDescriptorType %x\n", DeviceDescriptor->bDescriptorType); + DPRINT1("bcdUSB %x\n", DeviceDescriptor->bcdUSB); + DPRINT1("bDeviceClass %x\n", DeviceDescriptor->bDeviceClass); + DPRINT1("bDeviceSubClass %x\n", DeviceDescriptor->bDeviceSubClass); + DPRINT1("bDeviceProtocol %x\n", DeviceDescriptor->bDeviceProtocol); + DPRINT1("bMaxPacketSize0 %x\n", DeviceDescriptor->bMaxPacketSize0); + DPRINT1("idVendor %x\n", DeviceDescriptor->idVendor); + DPRINT1("idProduct %x\n", DeviceDescriptor->idProduct); + DPRINT1("bcdDevice %x\n", DeviceDescriptor->bcdDevice); + DPRINT1("iManufacturer %x\n", DeviceDescriptor->iManufacturer); + DPRINT1("iProduct %x\n", DeviceDescriptor->iProduct); + DPRINT1("iSerialNumber %x\n", DeviceDescriptor->iSerialNumber); + DPRINT1("bNumConfigurations %x\n", DeviceDescriptor->bNumConfigurations); +} + +NTSTATUS +USBSTOR_FdoHandleDeviceRelations( + IN PFDO_DEVICE_EXTENSION DeviceExtension, + IN OUT PIRP Irp) +{ + ULONG DeviceCount = 0; + LONG Index; + PDEVICE_RELATIONS DeviceRelations; + PIO_STACK_LOCATION IoStack; + + // + // get current irp stack location + // + IoStack = IoGetCurrentIrpStackLocation(Irp); + + // + // check if relation type is BusRelations + // + if (IoStack->Parameters.QueryDeviceRelations.Type != BusRelations) + { + // + // FDO always only handles bus relations + // + return USBSTOR_SyncForwardIrp(DeviceExtension->LowerDeviceObject, Irp); + } + + // + // go through array and count device objects + // + for (Index = 0; Index < max(DeviceExtension->MaxLUN, 1); Index++) + { + if (DeviceExtension->ChildPDO[Index]) + { + // + // child pdo + // + DeviceCount++; + } + } + + // + // allocate device relations + // + DeviceRelations = (PDEVICE_RELATIONS)AllocateItem(PagedPool, sizeof(DEVICE_RELATIONS) + (DeviceCount > 1 ? (DeviceCount-1) * sizeof(PDEVICE_OBJECT) : 0)); + if (!DeviceRelations) + { + // + // no memory + // + return STATUS_INSUFFICIENT_RESOURCES; + } + + // + // add device objects + // + for(Index = 0; Index < max(DeviceExtension->MaxLUN, 1); Index++) + { + if (DeviceExtension->ChildPDO[Index]) + { + // + // store child pdo + // + DeviceRelations->Objects[DeviceRelations->Count] = DeviceExtension->ChildPDO[Index]; + + // + // add reference + // + ObReferenceObject(DeviceExtension->ChildPDO[Index]); + + // + // increment count + // + DeviceRelations->Count++; + } + } + + // + // store result + // + Irp->IoStatus.Information = (ULONG_PTR)DeviceRelations; + + // + // request completed successfully + // + return STATUS_SUCCESS; +} + +NTSTATUS +USBSTOR_FdoHandleRemoveDevice( + IN PDEVICE_OBJECT DeviceObject, + IN PFDO_DEVICE_EXTENSION DeviceExtension, + IN OUT PIRP Irp) +{ + NTSTATUS Status; + ULONG Index; + + DPRINT("Handling FDO removal %p\n", DeviceObject); + + /* FIXME: wait for devices finished processing */ + for(Index = 0; Index < 16; Index++) + { + if (DeviceExtension->ChildPDO[Index] != NULL) + { + DPRINT("Deleting PDO %p RefCount %x AttachedDevice %p \n", DeviceExtension->ChildPDO[Index], DeviceExtension->ChildPDO[Index]->ReferenceCount, DeviceExtension->ChildPDO[Index]->AttachedDevice); + IoDeleteDevice(DeviceExtension->ChildPDO[Index]); + } + } + + /* Send the IRP down the stack */ + IoSkipCurrentIrpStackLocation(Irp); + Status = IoCallDriver(DeviceExtension->LowerDeviceObject, Irp); + + /* Detach from the device stack */ + IoDetachDevice(DeviceExtension->LowerDeviceObject); + + /* Delete the device object */ + IoDeleteDevice(DeviceObject); + + return Status; +} + +NTSTATUS +USBSTOR_FdoHandleStartDevice( + IN PDEVICE_OBJECT DeviceObject, + IN PFDO_DEVICE_EXTENSION DeviceExtension, + IN OUT PIRP Irp) +{ + PUSB_INTERFACE_DESCRIPTOR InterfaceDesc; + NTSTATUS Status; + UCHAR Index = 0; + + // + // forward irp to lower device + // + Status = USBSTOR_SyncForwardIrp(DeviceExtension->LowerDeviceObject, Irp); + if (!NT_SUCCESS(Status)) + { + // + // failed to start + // + DPRINT1("USBSTOR_FdoHandleStartDevice Lower device failed to start %x\n", Status); + return Status; + } + + // + // initialize irp queue + // + USBSTOR_QueueInitialize(DeviceExtension); + + // + // first get device & configuration & string descriptor + // + Status = USBSTOR_GetDescriptors(DeviceObject); + if (!NT_SUCCESS(Status)) + { + // + // failed to get device descriptor + // + DPRINT1("USBSTOR_FdoHandleStartDevice failed to get device descriptor with %x\n", Status); + return Status; + } + + // + // dump device descriptor + // + USBSTOR_DumpDeviceDescriptor(DeviceExtension->DeviceDescriptor); + + // + // Check that this device uses bulk transfers and is SCSI + // + InterfaceDesc = (PUSB_INTERFACE_DESCRIPTOR)((ULONG_PTR)DeviceExtension->ConfigurationDescriptor + sizeof(USB_CONFIGURATION_DESCRIPTOR)); + + // + // sanity check + // + ASSERT(InterfaceDesc->bDescriptorType == USB_INTERFACE_DESCRIPTOR_TYPE); + ASSERT(InterfaceDesc->bLength == sizeof(USB_INTERFACE_DESCRIPTOR)); + + DPRINT("bInterfaceSubClass %x\n", InterfaceDesc->bInterfaceSubClass); + if (InterfaceDesc->bInterfaceProtocol != 0x50) + { + DPRINT1("USB Device is not a bulk only device and is not currently supported\n"); + return STATUS_NOT_SUPPORTED; + } + + if (InterfaceDesc->bInterfaceSubClass != 0x06) + { + // + // FIXME: need to pad CDBs to 12 byte + // mode select commands must be translated from 1AH / 15h to 5AH / 55h + // + DPRINT1("[USBSTOR] Error: need to pad CDBs\n"); + return STATUS_NOT_IMPLEMENTED; + } + + // + // now select an interface + // + Status = USBSTOR_SelectConfigurationAndInterface(DeviceObject, DeviceExtension); + if (!NT_SUCCESS(Status)) + { + // + // failed to get device descriptor + // + DPRINT1("USBSTOR_FdoHandleStartDevice failed to select configuration / interface with %x\n", Status); + return Status; + } + + // + // check if we got a bulk in + bulk out endpoint + // + Status = USBSTOR_GetPipeHandles(DeviceExtension); + if (!NT_SUCCESS(Status)) + { + // + // failed to get pipe handles descriptor + // + DPRINT1("USBSTOR_FdoHandleStartDevice no pipe handles %x\n", Status); + return Status; + } + + // + // get num of lun which are supported + // + Status = USBSTOR_GetMaxLUN(DeviceExtension->LowerDeviceObject, DeviceExtension); + if (!NT_SUCCESS(Status)) + { + // + // failed to get max LUN + // + DPRINT1("USBSTOR_FdoHandleStartDevice failed to get max lun %x\n", Status); + return Status; + } + + // + // now create for each LUN a device object, 1 minimum + // + do + { + // + // create pdo + // + Status = USBSTOR_CreatePDO(DeviceObject, Index); + + // + // check for failure + // + if (!NT_SUCCESS(Status)) + { + // + // failed to create child pdo + // + DPRINT1("USBSTOR_FdoHandleStartDevice USBSTOR_CreatePDO failed for Index %lu with Status %x\n", Index, Status); + return Status; + } + + // + // increment pdo index + // + Index++; + DeviceExtension->InstanceCount++; + + }while(Index < DeviceExtension->MaxLUN); + +#if 0 + // + // finally get usb device interface + // + Status = USBSTOR_GetBusInterface(DeviceExtension->LowerDeviceObject, &DeviceExtension->BusInterface); + if (!NT_SUCCESS(Status)) + { + // + // failed to device interface + // + DPRINT1("USBSTOR_FdoHandleStartDevice failed to get device interface %x\n", Status); + return Status; + } +#endif + + + // + // start the timer + // + //IoStartTimer(DeviceObject); + + + // + // fdo is now initialized + // + DPRINT("USBSTOR_FdoHandleStartDevice FDO is initialized\n"); + return STATUS_SUCCESS; +} + +NTSTATUS +USBSTOR_FdoHandlePnp( + IN PDEVICE_OBJECT DeviceObject, + IN OUT PIRP Irp) +{ + PIO_STACK_LOCATION IoStack; + PFDO_DEVICE_EXTENSION DeviceExtension; + NTSTATUS Status; + + // + // get current stack location + // + IoStack = IoGetCurrentIrpStackLocation(Irp); + + // + // get device extension + // + DeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension; + + // + // sanity check + // + ASSERT(DeviceExtension->Common.IsFDO); + + switch(IoStack->MinorFunction) + { + case IRP_MN_SURPRISE_REMOVAL: + { + DPRINT("IRP_MN_SURPRISE_REMOVAL %p\n", DeviceObject); + Irp->IoStatus.Status = STATUS_SUCCESS; + + // + // forward irp to next device object + // + IoSkipCurrentIrpStackLocation(Irp); + return IoCallDriver(DeviceExtension->LowerDeviceObject, Irp); + } + case IRP_MN_QUERY_DEVICE_RELATIONS: + { + DPRINT("IRP_MN_QUERY_DEVICE_RELATIONS %p\n", DeviceObject); + Status = USBSTOR_FdoHandleDeviceRelations(DeviceExtension, Irp); + break; + } + case IRP_MN_STOP_DEVICE: + { + DPRINT1("USBSTOR_FdoHandlePnp: IRP_MN_STOP_DEVICE unimplemented\n"); + IoStopTimer(DeviceObject); + Irp->IoStatus.Status = STATUS_SUCCESS; + + // + // forward irp to next device object + // + IoSkipCurrentIrpStackLocation(Irp); + return IoCallDriver(DeviceExtension->LowerDeviceObject, Irp); + } + case IRP_MN_REMOVE_DEVICE: + { + DPRINT("IRP_MN_REMOVE_DEVICE\n"); + + return USBSTOR_FdoHandleRemoveDevice(DeviceObject, DeviceExtension, Irp); + } + case IRP_MN_QUERY_CAPABILITIES: + { + // + // FIXME: set custom capabilities + // + IoSkipCurrentIrpStackLocation(Irp); + return IoCallDriver(DeviceExtension->LowerDeviceObject, Irp); + } + case IRP_MN_QUERY_STOP_DEVICE: + case IRP_MN_QUERY_REMOVE_DEVICE: + { +#if 0 + // + // we can if nothing is pending + // + if (DeviceExtension->IrpPendingCount != 0 || + DeviceExtension->ActiveSrb != NULL) +#else + if (TRUE) +#endif + { + /* We have pending requests */ + DPRINT1("Failing removal/stop request due to pending requests present\n"); + Status = STATUS_UNSUCCESSFUL; + } + else + { + /* We're all clear */ + Irp->IoStatus.Status = STATUS_SUCCESS; + + IoSkipCurrentIrpStackLocation(Irp); + return IoCallDriver(DeviceExtension->LowerDeviceObject, Irp); + } + break; + } + case IRP_MN_START_DEVICE: + { + Status = USBSTOR_FdoHandleStartDevice(DeviceObject, DeviceExtension, Irp); + break; + } + default: + { + // + // forward irp to next device object + // + IoSkipCurrentIrpStackLocation(Irp); + return IoCallDriver(DeviceExtension->LowerDeviceObject, Irp); + } + } + + // + // complete request + // + if (Status != STATUS_PENDING) + { + // + // store result + // + Irp->IoStatus.Status = Status; + + // + // complete request + // + IoCompleteRequest(Irp, IO_NO_INCREMENT); + } + + // + // done processing + // + return Status; +} diff --git a/drivers/usb/usbstor_new/guid.c b/drivers/usb/usbstor_new/guid.c new file mode 100644 index 0000000000..2fd41c6e0b --- /dev/null +++ b/drivers/usb/usbstor_new/guid.c @@ -0,0 +1,9 @@ +/* DO NOT USE THE PRECOMPILED HEADER FOR THIS FILE! */ + +#include <ntdef.h> +#include <miniport.h> +#include <usb.h> +#include <initguid.h> +#include <usbbusif.h> + +/* NO CODE HERE, THIS IS JUST REQUIRED FOR THE GUID DEFINITIONS */ diff --git a/drivers/usb/usbstor_new/misc.c b/drivers/usb/usbstor_new/misc.c new file mode 100644 index 0000000000..6b60cf828e --- /dev/null +++ b/drivers/usb/usbstor_new/misc.c @@ -0,0 +1,520 @@ +/* + * PROJECT: ReactOS Universal Serial Bus Bulk Storage Driver + * LICENSE: GPL - See COPYING in the top level directory + * FILE: drivers/usb/usbstor/misc.c + * PURPOSE: USB block storage device driver. + * PROGRAMMERS: + * James Tabor + * Michael Martin (michael.martin@reactos.org) + * Johannes Anderwald (johannes.anderwald@reactos.org) + */ + +#include "usbstor.h" + +#define NDEBUG +#include <debug.h> + +// +// driver verifier +// +IO_COMPLETION_ROUTINE SyncForwardIrpCompletionRoutine; + +NTSTATUS +NTAPI +USBSTOR_SyncForwardIrpCompletionRoutine( + PDEVICE_OBJECT DeviceObject, + PIRP Irp, + PVOID Context) +{ + if (Irp->PendingReturned) + { + KeSetEvent((PKEVENT)Context, IO_NO_INCREMENT, FALSE); + } + return STATUS_MORE_PROCESSING_REQUIRED; +} + +NTSTATUS +NTAPI +USBSTOR_SyncForwardIrp(PDEVICE_OBJECT DeviceObject, PIRP Irp) +{ + KEVENT Event; + NTSTATUS Status; + + // + // initialize event + // + KeInitializeEvent(&Event, NotificationEvent, FALSE); + + // + // copy irp stack location + // + IoCopyCurrentIrpStackLocationToNext(Irp); + + // + // set completion routine + // + IoSetCompletionRoutine(Irp, USBSTOR_SyncForwardIrpCompletionRoutine, &Event, TRUE, TRUE, TRUE); + + + // + // call driver + // + Status = IoCallDriver(DeviceObject, Irp); + + // + // check if pending + // + if (Status == STATUS_PENDING) + { + // + // wait for the request to finish + // + KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL); + + // + // copy status code + // + Status = Irp->IoStatus.Status; + } + + // + // done + // + return Status; +} + +NTSTATUS +NTAPI +USBSTOR_GetBusInterface( + IN PDEVICE_OBJECT DeviceObject, + OUT PUSB_BUS_INTERFACE_USBDI_V2 BusInterface) +{ + KEVENT Event; + NTSTATUS Status; + PIRP Irp; + IO_STATUS_BLOCK IoStatus; + PIO_STACK_LOCATION Stack; + + // + // sanity checks + // + ASSERT(DeviceObject); + ASSERT(BusInterface); + + + // + // initialize event + // + KeInitializeEvent(&Event, NotificationEvent, FALSE); + + + // + // create irp + // + Irp = IoBuildSynchronousFsdRequest(IRP_MJ_PNP, + DeviceObject, + NULL, + 0, + NULL, + &Event, + &IoStatus); + + // + // was irp built + // + if (Irp == NULL) + { + // + // no memory + // + return STATUS_INSUFFICIENT_RESOURCES; + } + + // + // initialize request + // + Stack=IoGetNextIrpStackLocation(Irp); + Stack->MajorFunction = IRP_MJ_PNP; + Stack->MinorFunction = IRP_MN_QUERY_INTERFACE; + Stack->Parameters.QueryInterface.Size = sizeof(BUS_INTERFACE_STANDARD); + Stack->Parameters.QueryInterface.InterfaceType = (LPGUID)&USB_BUS_INTERFACE_USBDI_GUID; + Stack->Parameters.QueryInterface.Version = 2; + Stack->Parameters.QueryInterface.Interface = (PINTERFACE)BusInterface; + Stack->Parameters.QueryInterface.InterfaceSpecificData = NULL; + Irp->IoStatus.Status = STATUS_NOT_SUPPORTED; + + // + // call driver + // + Status= IoCallDriver(DeviceObject, Irp); + + // + // did operation complete + // + if (Status == STATUS_PENDING) + { + // + // wait for completion + // + KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL); + + // + // collect status + // + Status=IoStatus.Status; + } + + return Status; +} + +NTSTATUS +USBSTOR_SyncUrbRequest( + IN PDEVICE_OBJECT DeviceObject, + OUT PURB UrbRequest) +{ + PIRP Irp; + PIO_STACK_LOCATION IoStack; + KEVENT Event; + NTSTATUS Status; + + // + // allocate irp + // + Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE); + if (!Irp) + { + // + // no memory + // + return STATUS_INSUFFICIENT_RESOURCES; + } + + // + // initialize event + // + KeInitializeEvent(&Event, NotificationEvent, FALSE); + + + // + // get next stack location + // + IoStack = IoGetNextIrpStackLocation(Irp); + + // + // initialize stack location + // + IoStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL; + IoStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_URB; + IoStack->Parameters.Others.Argument1 = (PVOID)UrbRequest; + IoStack->Parameters.DeviceIoControl.InputBufferLength = UrbRequest->UrbHeader.Length; + Irp->IoStatus.Status = STATUS_SUCCESS; + + // + // setup completion routine + // + IoSetCompletionRoutine(Irp, USBSTOR_SyncForwardIrpCompletionRoutine, &Event, TRUE, TRUE, TRUE); + + // + // call driver + // + Status = IoCallDriver(DeviceObject, Irp); + + // + // check if request is pending + // + if (Status == STATUS_PENDING) + { + // + // wait for completion + // + KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL); + + // + // update status + // + Status = Irp->IoStatus.Status; + } + + // + // free irp + // + IoFreeIrp(Irp); + + // + // done + // + return Status; +} + +PVOID +AllocateItem( + IN POOL_TYPE PoolType, + IN ULONG ItemSize) +{ + // + // allocate item + // + PVOID Item = ExAllocatePoolWithTag(PoolType, ItemSize, USB_STOR_TAG); + + if (Item) + { + // + // zero item + // + RtlZeroMemory(Item, ItemSize); + } + + // + // return element + // + return Item; +} + +VOID +FreeItem( + IN PVOID Item) +{ + // + // free item + // + ExFreePoolWithTag(Item, USB_STOR_TAG); +} + +NTSTATUS +USBSTOR_ClassRequest( + IN PDEVICE_OBJECT DeviceObject, + IN PFDO_DEVICE_EXTENSION DeviceExtension, + IN UCHAR RequestType, + IN USHORT Index, + IN ULONG TransferFlags, + IN ULONG TransferBufferLength, + IN PVOID TransferBuffer) + +{ + PURB Urb; + NTSTATUS Status; + + // + // first allocate urb + // + Urb = (PURB)AllocateItem(NonPagedPool, sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST)); + if (!Urb) + { + // + // no memory + // + return STATUS_INSUFFICIENT_RESOURCES; + } + + // + // initialize vendor request + // + Urb->UrbControlVendorClassRequest.Hdr.Length = sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST); + Urb->UrbControlVendorClassRequest.Hdr.Function = URB_FUNCTION_CLASS_INTERFACE; + Urb->UrbControlVendorClassRequest.TransferFlags = TransferFlags; + Urb->UrbControlVendorClassRequest.TransferBufferLength = TransferBufferLength; + Urb->UrbControlVendorClassRequest.TransferBuffer = TransferBuffer; + Urb->UrbControlVendorClassRequest.Request = RequestType; + Urb->UrbControlVendorClassRequest.Index = Index; + + // + // submit request + // + Status = USBSTOR_SyncUrbRequest(DeviceObject, Urb); + + // + // free urb + // + FreeItem(Urb); + + // + // done + // + return Status; +} + + +NTSTATUS +USBSTOR_GetMaxLUN( + IN PDEVICE_OBJECT DeviceObject, + IN PFDO_DEVICE_EXTENSION DeviceExtension) +{ + PUCHAR Buffer; + NTSTATUS Status; + + // + // allocate 1-byte buffer + // + Buffer = (PUCHAR)AllocateItem(NonPagedPool, sizeof(UCHAR)); + if (!Buffer) + { + // + // no memory + // + FreeItem(Buffer); + return STATUS_INSUFFICIENT_RESOURCES; + } + + // + // execute request + // + Status = USBSTOR_ClassRequest(DeviceObject, DeviceExtension, USB_BULK_GET_MAX_LUN, DeviceExtension->InterfaceInformation->InterfaceNumber, USBD_TRANSFER_DIRECTION_IN, sizeof(UCHAR), Buffer); + + DPRINT("MaxLUN: %x\n", *Buffer); + + if (NT_SUCCESS(Status)) + { + if (*Buffer > 0xF) + { + // + // invalid response documented in usb mass storage specification + // + Status = STATUS_DEVICE_DATA_ERROR; + } + else + { + // + // store maxlun + // + DeviceExtension->MaxLUN = *Buffer; + } + } + else + { + // + // "USB Mass Storage Class. Bulk-Only Transport. Revision 1.0" + // 3.2 Get Max LUN (class-specific request) : + // Devices that do not support multiple LUNs may STALL this command. + // + USBSTOR_ResetDevice(DeviceExtension->LowerDeviceObject, DeviceExtension); + + DeviceExtension->MaxLUN = 0; + Status = STATUS_SUCCESS; + } + + // + // free buffer + // + FreeItem(Buffer); + + // + // done + // + return Status; + +} + +NTSTATUS +USBSTOR_ResetDevice( + IN PDEVICE_OBJECT DeviceObject, + IN PFDO_DEVICE_EXTENSION DeviceExtension) +{ + NTSTATUS Status; + + // + // execute request + // + Status = USBSTOR_ClassRequest(DeviceObject, DeviceExtension, USB_BULK_RESET_DEVICE, DeviceExtension->InterfaceInformation->InterfaceNumber, USBD_TRANSFER_DIRECTION_OUT, 0, NULL); + + // + // done + // + return Status; + +} + +BOOLEAN +USBSTOR_IsFloppy( + IN PUCHAR Buffer, + IN ULONG BufferLength, + OUT PUCHAR MediumTypeCode) +{ + PUFI_CAPACITY_FORMAT_HEADER FormatHeader; + PUFI_CAPACITY_DESCRIPTOR Descriptor; + ULONG Length, Index, BlockCount, BlockLength; + + // + // get format header + // + FormatHeader = (PUFI_CAPACITY_FORMAT_HEADER)Buffer; + + // + // sanity checks + // + ASSERT(FormatHeader->Reserved1 == 0x00); + ASSERT(FormatHeader->Reserved2 == 0x00); + ASSERT(FormatHeader->Reserved3 == 0x00); + + // + // is there capacity data + // + if (!FormatHeader->CapacityLength) + { + // + // no data provided + // + DPRINT1("[USBSTOR] No capacity length\n"); + return FALSE; + } + + // + // the format header are always 8 bytes in length + // + ASSERT((FormatHeader->CapacityLength & 0x7) == 0); + DPRINT1("CapacityLength %x\n", FormatHeader->CapacityLength); + + // + // grab length and locate first descriptor + // + Length = FormatHeader->CapacityLength; + Descriptor = (PUFI_CAPACITY_DESCRIPTOR)(FormatHeader + 1); + for(Index = 0; Index < Length / sizeof(UFI_CAPACITY_DESCRIPTOR); Index++) + { + // + // blocks are little endian format + // + BlockCount = NTOHL(Descriptor->BlockCount); + + // + // get block length + // + BlockLength = NTOHL((Descriptor->BlockLengthByte0 << 24 | Descriptor->BlockLengthByte1 << 16 | Descriptor->BlockLengthByte2 << 8)); + + DPRINT1("BlockCount %x BlockLength %x Code %x\n", BlockCount, BlockLength, Descriptor->Code); + + if (BlockLength == 512 && BlockCount == 1440) + { + // + // 720 KB DD + // + *MediumTypeCode = 0x1E; + return TRUE; + } + else if (BlockLength == 1024 && BlockCount == 1232) + { + // + // 1,25 MB + // + *MediumTypeCode = 0x93; + return TRUE; + } + else if (BlockLength == 512 && BlockCount == 2880) + { + // + // 1,44MB KB DD + // + *MediumTypeCode = 0x94; + return TRUE; + } + + // + // move to next descriptor + // + Descriptor = (Descriptor + 1); + } + + // + // no floppy detected + // + return FALSE; +} diff --git a/drivers/usb/usbstor_new/pdo.c b/drivers/usb/usbstor_new/pdo.c new file mode 100644 index 0000000000..6ce5d8f746 --- /dev/null +++ b/drivers/usb/usbstor_new/pdo.c @@ -0,0 +1,1376 @@ +/* + * PROJECT: ReactOS Universal Serial Bus Bulk Storage Driver + * LICENSE: GPL - See COPYING in the top level directory + * FILE: drivers/usb/usbstor/pdo.c + * PURPOSE: USB block storage device driver. + * PROGRAMMERS: + * James Tabor + * Michael Martin (michael.martin@reactos.org) + * Johannes Anderwald (johannes.anderwald@reactos.org) + */ + +#include "usbstor.h" + +#define NDEBUG +#include <debug.h> + +LPCSTR +USBSTOR_GetDeviceType( + IN PUFI_INQUIRY_RESPONSE InquiryData, + IN UCHAR IsFloppy) +{ + // + // check if device type is zero + // + if (InquiryData->DeviceType == 0) + { + if (IsFloppy) + { + // + // floppy device + // + return "SFloppy"; + } + + // + // direct access device + // + return "Disk"; + } + + // + // FIXME: use constant - derived from http://en.wikipedia.org/wiki/SCSI_Peripheral_Device_Type + // + switch (InquiryData->DeviceType) + { + case 1: + { + // + // sequential device, i.e magnetic tape + // + return "Sequential"; + } + case 4: + { + // + // write once device + // + return "Worm"; + } + case 5: + { + // + // CDROM device + // + return "CdRom"; + } + case 7: + { + // + // optical memory device + // + return "Optical"; + } + case 8: + { + // + // medium change device + // + return "Changer"; + } + default: + { + // + // other device + // + return "Other"; + } + } +} + +LPCSTR +USBSTOR_GetGenericType( + IN PUFI_INQUIRY_RESPONSE InquiryData, + IN UCHAR IsFloppy) +{ + // + // check if device type is zero + // + if (InquiryData->DeviceType == 0) + { + if (IsFloppy) + { + // + // floppy device + // + return "GenSFloppy"; + } + + // + // direct access device + // + return "GenDisk"; + } + + // + // FIXME: use constant - derived from http://en.wikipedia.org/wiki/SCSI_Peripheral_Device_Type + // + switch (InquiryData->DeviceType) + { + case 1: + { + // + // sequential device, i.e magnetic tape + // + return "GenSequential"; + } + case 4: + { + // + // write once device + // + return "GenWorm"; + } + case 5: + { + // + // CDROM device + // + return "GenCdRom"; + } + case 7: + { + // + // optical memory device + // + return "GenOptical"; + } + case 8: + { + // + // medium change device + // + return "GenChanger"; + } + default: + { + // + // other device + // + return "UsbstorOther"; + } + } +} + + +ULONG +CopyField( + IN PUCHAR Name, + IN PCHAR Buffer, + IN ULONG MaxLength) +{ + ULONG Index; + + for(Index = 0; Index < MaxLength; Index++) + { + if (Name[Index] <= ' ' || Name[Index] >= 0x7F /* last printable ascii character */ || Name[Index] == ',') + { + // + // convert to underscore + // + Buffer[Index] = '_'; + } + else + { + // + // just copy character + // + Buffer[Index] = Name[Index]; + } + } + + return MaxLength; +} + +NTSTATUS +USBSTOR_PdoHandleQueryDeviceText( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp) +{ + //PPDO_DEVICE_EXTENSION DeviceExtension; + PIO_STACK_LOCATION IoStack; + LPWSTR Buffer; + static WCHAR DeviceText[] = L"USB Mass Storage Device"; + + // + // get current stack location + // + IoStack = IoGetCurrentIrpStackLocation(Irp); + + if (IoStack->Parameters.QueryDeviceText.DeviceTextType == DeviceTextDescription) + { + DPRINT("USBSTOR_PdoHandleQueryDeviceText DeviceTextDescription\n"); + + // + // allocate item + // + Buffer = (LPWSTR)AllocateItem(PagedPool, sizeof(DeviceText)); + if (!Buffer) + { + // + // no memory + // + Irp->IoStatus.Information = 0; + return STATUS_INSUFFICIENT_RESOURCES; + } + + // + // copy buffer + // + wcscpy(Buffer, DeviceText); + + // + // save result + // + Irp->IoStatus.Information = (ULONG_PTR)Buffer; + return STATUS_SUCCESS; + } + else + { + DPRINT("USBSTOR_PdoHandleQueryDeviceText DeviceTextLocationInformation\n"); + + // + // allocate item + // + Buffer = (LPWSTR)AllocateItem(PagedPool, sizeof(DeviceText)); + if (!Buffer) + { + // + // no memory + // + Irp->IoStatus.Information = 0; + return STATUS_INSUFFICIENT_RESOURCES; + } + + // + // copy buffer + // + wcscpy(Buffer, DeviceText); + + // + // save result + // + Irp->IoStatus.Information = (ULONG_PTR)Buffer; + return STATUS_SUCCESS; + } + +} + + +NTSTATUS +USBSTOR_PdoHandleQueryDeviceId( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp) +{ + PPDO_DEVICE_EXTENSION DeviceExtension; + NTSTATUS Status; + CHAR Buffer[100]; + LPCSTR DeviceType; + ULONG Offset = 0; + PUFI_INQUIRY_RESPONSE InquiryData; + ANSI_STRING AnsiString; + UNICODE_STRING DeviceId; + + // + // get device extension + // + DeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension; + + // + // sanity check + // + ASSERT(DeviceExtension->InquiryData); + + // + // get inquiry data + // + InquiryData = (PUFI_INQUIRY_RESPONSE)DeviceExtension->InquiryData; + + // + // get device type + // + DeviceType = USBSTOR_GetDeviceType(InquiryData, DeviceExtension->IsFloppy); + + // + // zero buffer + // + RtlZeroMemory(Buffer, sizeof(Buffer)); + + // + // lets create device string + // + Offset = sprintf(&Buffer[Offset], "USBSTOR\"); + Offset += sprintf(&Buffer[Offset], DeviceType); + Offset += sprintf(&Buffer[Offset], "&Ven_"); + Offset += CopyField(InquiryData->Vendor, &Buffer[Offset], 8); + Offset += sprintf(&Buffer[Offset], "&Prod_"); + Offset += CopyField(InquiryData->Product, &Buffer[Offset], 16); + Offset += sprintf(&Buffer[Offset], "&Rev_"); + Offset += CopyField(InquiryData->Revision, &Buffer[Offset], 4); + + // + // now initialize ansi string + // + RtlInitAnsiString(&AnsiString, (PCSZ)Buffer); + + // + // allocate DeviceId string + // + DeviceId.Length = 0; + DeviceId.MaximumLength = (strlen((PCHAR)Buffer) + 1) * sizeof(WCHAR); + DeviceId.Buffer = (LPWSTR)AllocateItem(PagedPool, DeviceId.MaximumLength); + if (!DeviceId.Buffer) + { + // + // no memory + // + Irp->IoStatus.Information = 0; + return STATUS_INSUFFICIENT_RESOURCES; + } + + + // + // convert to unicode + // + Status = RtlAnsiStringToUnicodeString(&DeviceId, &AnsiString, FALSE); + + if (NT_SUCCESS(Status)) + { + // + // store result + // + Irp->IoStatus.Information = (ULONG_PTR)DeviceId.Buffer; + } + + DPRINT("DeviceId %wZ Status %x\n", &DeviceId, Status); + + // + // done + // + return Status; +} + +VOID +USBSTOR_ConvertToUnicodeString( + IN CHAR * Buffer, + IN ULONG ResultBufferLength, + IN ULONG ResultBufferOffset, + OUT LPWSTR ResultBuffer, + OUT PULONG NewResultBufferOffset) +{ + UNICODE_STRING DeviceString; + ANSI_STRING AnsiString; + NTSTATUS Status; + + ASSERT(ResultBufferLength); + ASSERT(ResultBufferLength > ResultBufferOffset); + + DPRINT("ResultBufferOffset %lu ResultBufferLength %lu Buffer %s Length %lu\n", ResultBufferOffset, ResultBufferLength, Buffer, strlen(Buffer)); + + // + // construct destination string + // + DeviceString.Buffer = &ResultBuffer[ResultBufferOffset]; + DeviceString.Length = 0; + DeviceString.MaximumLength = (ResultBufferLength - ResultBufferOffset) * sizeof(WCHAR); + + // + // initialize source string + // + RtlInitAnsiString(&AnsiString, Buffer); + + // + // convert to unicode + // + Status = RtlAnsiStringToUnicodeString(&DeviceString, &AnsiString, FALSE); + ASSERT(Status == STATUS_SUCCESS); + + // + // subtract consumed bytes + // + ResultBufferLength -= (DeviceString.Length + sizeof(WCHAR)) / sizeof(WCHAR); + ResultBufferOffset += (DeviceString.Length + sizeof(WCHAR)) / sizeof(WCHAR); + + // + // store new offset + // + *NewResultBufferOffset = ResultBufferOffset; +} + + + +NTSTATUS +USBSTOR_PdoHandleQueryHardwareId( + IN PDEVICE_OBJECT DeviceObject, + IN OUT PIRP Irp) +{ + PPDO_DEVICE_EXTENSION PDODeviceExtension; + PFDO_DEVICE_EXTENSION FDODeviceExtension; + LPCSTR GenericType, DeviceType; + LPWSTR Buffer; + CHAR Id1[50], Id2[50], Id3[50], Id4[50], Id5[50], Id6[50]; + ULONG Id1Length, Id2Length, Id3Length, Id4Length, Id5Length,Id6Length; + ULONG Offset, TotalLength, Length; + PUFI_INQUIRY_RESPONSE InquiryData; + + // + // get PDO device extension + // + PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension; + + // + // get FDO device extension + // + FDODeviceExtension = (PFDO_DEVICE_EXTENSION)PDODeviceExtension->LowerDeviceObject->DeviceExtension; + + // + // sanity check + // + ASSERT(FDODeviceExtension->DeviceDescriptor); + + // + // get inquiry data + // + InquiryData = (PUFI_INQUIRY_RESPONSE)PDODeviceExtension->InquiryData; + + + // + // get device type and generic type + // + DeviceType = USBSTOR_GetDeviceType(InquiryData, PDODeviceExtension->IsFloppy); + GenericType = USBSTOR_GetGenericType(InquiryData, PDODeviceExtension->IsFloppy); + + ASSERT(GenericType); + + // + // generate id 1 + // USBSTOR\SCSIType_Vendor(8)_Product(16)_Revision(4) + // + RtlZeroMemory(Id1, sizeof(Id1)); + Offset = 0; + Offset = sprintf(&Id1[Offset], "USBSTOR\"); + Offset += sprintf(&Id1[Offset], DeviceType); + Offset += CopyField(InquiryData->Vendor, &Id1[Offset], 8); + Offset += CopyField(InquiryData->Product, &Id1[Offset], 16); + Offset += CopyField(InquiryData->Revision, &Id1[Offset], 4); + Id1Length = strlen(Id1) + 1; + DPRINT("USBSTOR_PdoHandleQueryHardwareId HardwareId1 %s\n", Id1); + + // + // generate id 2 + // USBSTOR\SCSIType_VENDOR(8)_Product(16) + // + RtlZeroMemory(Id2, sizeof(Id2)); + Offset = 0; + Offset = sprintf(&Id2[Offset], "USBSTOR\"); + Offset += sprintf(&Id2[Offset], DeviceType); + Offset += CopyField(InquiryData->Vendor, &Id2[Offset], 8); + Offset += CopyField(InquiryData->Product, &Id2[Offset], 16); + Id2Length = strlen(Id2) + 1; + DPRINT("USBSTOR_PdoHandleQueryHardwareId HardwareId2 %s\n", Id2); + + // + // generate id 3 + // USBSTOR\SCSIType_VENDOR(8) + // + RtlZeroMemory(Id3, sizeof(Id3)); + Offset = 0; + Offset = sprintf(&Id3[Offset], "USBSTOR\"); + Offset += sprintf(&Id3[Offset], DeviceType); + Offset += CopyField(InquiryData->Vendor, &Id3[Offset], 8); + Id3Length = strlen(Id3) + 1; + DPRINT("USBSTOR_PdoHandleQueryHardwareId HardwareId3 %s\n", Id3); + + // + // generate id 4 + // USBSTOR\SCSIType_VENDOR(8)_Product(16)_Revision(1) + // + RtlZeroMemory(Id4, sizeof(Id4)); + Offset = 0; + Offset = sprintf(&Id4[Offset], "USBSTOR\"); + Offset += sprintf(&Id4[Offset], DeviceType); + Offset += CopyField(InquiryData->Vendor, &Id4[Offset], 8); + Offset += CopyField(InquiryData->Product, &Id4[Offset], 16); + Offset += CopyField(InquiryData->Revision, &Id4[Offset], 1); + Id4Length = strlen(Id4) + 1; + DPRINT("USBSTOR_PdoHandleQueryHardwareId HardwareId4 %s\n", Id4); + + // + // generate id 5 + // USBSTOR\SCSIType + // + RtlZeroMemory(Id5, sizeof(Id5)); + Offset = 0; + Offset = sprintf(&Id5[Offset], "USBSTOR\"); + Offset += sprintf(&Id5[Offset], GenericType); + Id5Length = strlen(Id5) + 1; + DPRINT("USBSTOR_PdoHandleQueryHardwareId HardwareId5 %s\n", Id5); + + // + // generate id 6 + // SCSIType + // + RtlZeroMemory(Id6, sizeof(Id6)); + Offset = 0; + Offset = sprintf(&Id6[Offset], GenericType); + Id6Length = strlen(Id6) + 1; + DPRINT("USBSTOR_PdoHandleQueryHardwareId HardwareId6 %s\n", Id6); + + // + // compute total length + // + TotalLength = Id1Length + Id2Length + Id3Length + Id4Length + Id5Length + Id6Length + 1; + + // + // allocate buffer + // + Buffer = (LPWSTR)AllocateItem(PagedPool, TotalLength * sizeof(WCHAR)); + if (!Buffer) + { + // + // no memory + // + Irp->IoStatus.Information = 0; + return STATUS_INSUFFICIENT_RESOURCES; + } + + // + // reset offset + // + Offset = 0; + Length = TotalLength; + + USBSTOR_ConvertToUnicodeString(Id1, Length, Offset, Buffer, &Offset); + USBSTOR_ConvertToUnicodeString(Id2, Length, Offset, Buffer, &Offset); + USBSTOR_ConvertToUnicodeString(Id3, Length, Offset, Buffer, &Offset); + USBSTOR_ConvertToUnicodeString(Id4, Length, Offset, Buffer, &Offset); + USBSTOR_ConvertToUnicodeString(Id5, Length, Offset, Buffer, &Offset); + USBSTOR_ConvertToUnicodeString(Id6, Length, Offset, Buffer, &Offset); + + // + // sanity check + // + ASSERT(Offset + 1 == Length); + + // + // store result + // + Irp->IoStatus.Information = (ULONG_PTR)Buffer; + + // + // done + // + return STATUS_SUCCESS; +} + +NTSTATUS +USBSTOR_PdoHandleQueryCompatibleId( + IN PDEVICE_OBJECT DeviceObject, + IN OUT PIRP Irp) +{ + PPDO_DEVICE_EXTENSION PDODeviceExtension; + PFDO_DEVICE_EXTENSION FDODeviceExtension; + CHAR Buffer[100]; + ULONG Length, Offset; + LPWSTR InstanceId; + LPCSTR DeviceType; + + // + // get PDO device extension + // + PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension; + + // + // get FDO device extension + // + FDODeviceExtension = (PFDO_DEVICE_EXTENSION)PDODeviceExtension->LowerDeviceObject->DeviceExtension; + + // + // sanity check + // + ASSERT(FDODeviceExtension->DeviceDescriptor); + + // + // get target device type + // + DeviceType = USBSTOR_GetDeviceType((PUFI_INQUIRY_RESPONSE)PDODeviceExtension->InquiryData, PDODeviceExtension->IsFloppy); + + // + // zero memory + // + RtlZeroMemory(Buffer, sizeof(Buffer)); + + // + // format instance id + // + Length = sprintf(Buffer, "USBSTOR\%s", DeviceType) + 1; + Length += sprintf(&Buffer[Length], "USBSTOR\%s", "RAW") + 2; + + // + // allocate instance id + // + InstanceId = (LPWSTR)AllocateItem(PagedPool, Length * sizeof(WCHAR)); + if (!InstanceId) + { + // + // no memory + // + Irp->IoStatus.Information = 0; + return STATUS_INSUFFICIENT_RESOURCES; + } + + USBSTOR_ConvertToUnicodeString(Buffer, Length, 0, InstanceId, &Offset); + USBSTOR_ConvertToUnicodeString(&Buffer[Offset], Length, Offset, InstanceId, &Offset); + + DPRINT("USBSTOR_PdoHandleQueryCompatibleId %S\n", InstanceId); + + // + // store result + // + Irp->IoStatus.Information = (ULONG_PTR)InstanceId; + + // + // completed successfully + // + return STATUS_SUCCESS; +} + +NTSTATUS +USBSTOR_PdoHandleQueryInstanceId( + IN PDEVICE_OBJECT DeviceObject, + IN OUT PIRP Irp) +{ + PPDO_DEVICE_EXTENSION PDODeviceExtension; + PFDO_DEVICE_EXTENSION FDODeviceExtension; + WCHAR Buffer[100]; + ULONG Length; + LPWSTR InstanceId; + + // + // get PDO device extension + // + PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension; + + // + // get FDO device extension + // + FDODeviceExtension = (PFDO_DEVICE_EXTENSION)PDODeviceExtension->LowerDeviceObject->DeviceExtension; + + // + // format instance id + // + if (FDODeviceExtension->SerialNumber) + { + // + // using serial number from device + // + swprintf(Buffer, L"%s&%c", FDODeviceExtension->SerialNumber->bString, PDODeviceExtension->LUN); + } + else + { + // + // use instance count and LUN + // + swprintf(Buffer, L"%04lu&%c", FDODeviceExtension->InstanceCount, PDODeviceExtension->LUN); + } + + // + // calculate length + // + Length = wcslen(Buffer) + 1; + + // + // allocate instance id + // + InstanceId = (LPWSTR)AllocateItem(PagedPool, Length * sizeof(WCHAR)); + if (!InstanceId) + { + // + // no memory + // + Irp->IoStatus.Information = 0; + return STATUS_INSUFFICIENT_RESOURCES; + } + + // + // copy instance id + // + wcscpy(InstanceId, Buffer); + + DPRINT("USBSTOR_PdoHandleQueryInstanceId %S\n", InstanceId); + + // + // store result + // + Irp->IoStatus.Information = (ULONG_PTR)InstanceId; + + // + // completed successfully + // + return STATUS_SUCCESS; +} + +NTSTATUS +USBSTOR_PdoHandleDeviceRelations( + IN PDEVICE_OBJECT DeviceObject, + IN OUT PIRP Irp) +{ + PDEVICE_RELATIONS DeviceRelations; + PIO_STACK_LOCATION IoStack; + + DPRINT("USBSTOR_PdoHandleDeviceRelations\n"); + + // + // get current irp stack location + // + IoStack = IoGetCurrentIrpStackLocation(Irp); + + // + // check if relation type is BusRelations + // + if (IoStack->Parameters.QueryDeviceRelations.Type != TargetDeviceRelation) + { + // + // PDO handles only target device relation + // + return Irp->IoStatus.Status; + } + + // + // allocate device relations + // + DeviceRelations = (PDEVICE_RELATIONS)AllocateItem(PagedPool, sizeof(DEVICE_RELATIONS)); + if (!DeviceRelations) + { + // + // no memory + // + return STATUS_INSUFFICIENT_RESOURCES; + } + + // + // initialize device relations + // + DeviceRelations->Count = 1; + DeviceRelations->Objects[0] = DeviceObject; + ObReferenceObject(DeviceObject); + + // + // store result + // + Irp->IoStatus.Information = (ULONG_PTR)DeviceRelations; + + // + // completed successfully + // + return STATUS_SUCCESS; +} + + +NTSTATUS +USBSTOR_PdoHandlePnp( + IN PDEVICE_OBJECT DeviceObject, + IN OUT PIRP Irp) +{ + PIO_STACK_LOCATION IoStack; + PPDO_DEVICE_EXTENSION DeviceExtension; + NTSTATUS Status; + PDEVICE_CAPABILITIES Caps; + ULONG bDelete; + + // + // get current stack location + // + IoStack = IoGetCurrentIrpStackLocation(Irp); + + // + // get device extension + // + DeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension; + + // + // sanity check + // + ASSERT(DeviceExtension->Common.IsFDO == FALSE); + + switch(IoStack->MinorFunction) + { + case IRP_MN_QUERY_DEVICE_RELATIONS: + { + Status = USBSTOR_PdoHandleDeviceRelations(DeviceObject, Irp); + break; + } + case IRP_MN_QUERY_DEVICE_TEXT: + { + Status = USBSTOR_PdoHandleQueryDeviceText(DeviceObject, Irp); + break; + } + case IRP_MN_QUERY_ID: + { + if (IoStack->Parameters.QueryId.IdType == BusQueryDeviceID) + { + // + // handle query device id + // + Status = USBSTOR_PdoHandleQueryDeviceId(DeviceObject, Irp); + break; + } + else if (IoStack->Parameters.QueryId.IdType == BusQueryHardwareIDs) + { + // + // handle instance id + // + Status = USBSTOR_PdoHandleQueryHardwareId(DeviceObject, Irp); + break; + } + else if (IoStack->Parameters.QueryId.IdType == BusQueryInstanceID) + { + // + // handle instance id + // + Status = USBSTOR_PdoHandleQueryInstanceId(DeviceObject, Irp); + break; + } + else if (IoStack->Parameters.QueryId.IdType == BusQueryCompatibleIDs) + { + // + // handle instance id + // + Status = USBSTOR_PdoHandleQueryCompatibleId(DeviceObject, Irp); + break; + } + + DPRINT1("USBSTOR_PdoHandlePnp: IRP_MN_QUERY_ID IdType %x unimplemented\n", IoStack->Parameters.QueryId.IdType); + Status = STATUS_NOT_SUPPORTED; + Irp->IoStatus.Information = 0; + break; + } + case IRP_MN_REMOVE_DEVICE: + { + DPRINT("IRP_MN_REMOVE_DEVICE\n"); + + if(*DeviceExtension->PDODeviceObject != NULL) + { + // + // clear entry in FDO pdo list + // + *DeviceExtension->PDODeviceObject = NULL; + bDelete = TRUE; + } + else + { + // + // device object already marked for deletion + // + bDelete = FALSE; + } + + /* Complete the IRP */ + Irp->IoStatus.Status = STATUS_SUCCESS; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + + if (bDelete) + { + /* Delete the device object */ + IoDeleteDevice(DeviceObject); + } + return STATUS_SUCCESS; + } + case IRP_MN_QUERY_CAPABILITIES: + { + // + // just forward irp to lower device + // + Status = USBSTOR_SyncForwardIrp(DeviceExtension->LowerDeviceObject, Irp); + ASSERT(Status == STATUS_SUCCESS); + + if (NT_SUCCESS(Status)) + { + // + // check if no unique id + // + Caps = (PDEVICE_CAPABILITIES)IoStack->Parameters.DeviceCapabilities.Capabilities; + Caps->UniqueID = FALSE; // no unique id is supported + Caps->Removable = TRUE; //FIXME + } + break; + } + case IRP_MN_QUERY_REMOVE_DEVICE: + case IRP_MN_QUERY_STOP_DEVICE: + { +#if 0 + // + // if we're not claimed it's ok + // + if (DeviceExtension->Claimed) +#else + if (TRUE) +#endif + { + Status = STATUS_UNSUCCESSFUL; + DPRINT1("[USBSTOR] Request %x fails because device is still claimed\n", IoStack->MinorFunction); + } + else + Status = STATUS_SUCCESS; + break; + } + case IRP_MN_START_DEVICE: + { + // + // no-op for PDO + // + Status = STATUS_SUCCESS; + break; + } + case IRP_MN_SURPRISE_REMOVAL: + { + Status = STATUS_SUCCESS; + break; + } + default: + { + // + // do nothing + // + Status = Irp->IoStatus.Status; + } + } + + // + // complete request + // + if (Status != STATUS_PENDING) + { + // + // store result + // + Irp->IoStatus.Status = Status; + + // + // complete request + // + IoCompleteRequest(Irp, IO_NO_INCREMENT); + } + + // + // done processing + // + return Status; +} + +NTSTATUS +NTAPI +USBSTOR_CompletionRoutine( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp, + IN PVOID Ctx) +{ + PKEVENT Event = (PKEVENT)Ctx; + + // + // signal event + // + KeSetEvent(Event, 0, FALSE); + return STATUS_MORE_PROCESSING_REQUIRED; +} + +NTSTATUS +USBSTOR_AllocateIrp( + IN PDEVICE_OBJECT DeviceObject, + IN ULONG DataTransferLength, + IN UCHAR OpCode, + IN PKEVENT Event, + OUT PSCSI_REQUEST_BLOCK *OutRequest, + OUT PIRP *OutIrp) +{ + PIRP Irp; + PIO_STACK_LOCATION IoStack; + PSCSI_REQUEST_BLOCK Request; + PCDB pCDB; + + // + // allocate irp + // + Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE); + if (!Irp) + { + // + // no memory + // + return STATUS_INSUFFICIENT_RESOURCES; + } + + // + // get next stack location + // + IoStack = IoGetNextIrpStackLocation(Irp); + + // + // create scsi block + // + Request = ExAllocatePoolWithTag(NonPagedPool, + sizeof(SCSI_REQUEST_BLOCK), + USB_STOR_TAG); + if (!Request) + { + // + // no memory + // + IoFreeIrp(Irp); + return STATUS_INSUFFICIENT_RESOURCES; + } + + // + // init request + // + RtlZeroMemory(Request, sizeof(SCSI_REQUEST_BLOCK)); + + // + // allocate data transfer block + // + Request->DataBuffer = ExAllocatePoolWithTag(NonPagedPool, + DataTransferLength, + USB_STOR_TAG); + if (!Request->DataBuffer) + { + // + // no memory + // + IoFreeIrp(Irp); + ExFreePoolWithTag(Request, USB_STOR_TAG); + return STATUS_INSUFFICIENT_RESOURCES; + } + + // + // allocate MDL + // + Irp->MdlAddress = IoAllocateMdl(Request->DataBuffer, DataTransferLength, FALSE, FALSE, NULL); + if (!Irp->MdlAddress) + { + // + // no memory + // + IoFreeIrp(Irp); + ExFreePoolWithTag(Request->DataBuffer, USB_STOR_TAG); + ExFreePoolWithTag(Request, USB_STOR_TAG); + return STATUS_INSUFFICIENT_RESOURCES; + } + + // + // non paged pool + // + MmBuildMdlForNonPagedPool(Irp->MdlAddress); + + // + // init scsi block + // + Request->DataTransferLength = DataTransferLength; + Request->Function = SRB_FUNCTION_EXECUTE_SCSI; + Request->SrbFlags = SRB_FLAGS_DATA_IN; + + RtlZeroMemory(Request->DataBuffer, DataTransferLength); + + + // + // get SCSI command data block + // + pCDB = (PCDB)Request->Cdb; + + // + // set op code + // + pCDB->AsByte[0] = OpCode; + + // + // store result + // + IoStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL; + IoStack->Parameters.Others.Argument1 = Request; + IoStack->DeviceObject = DeviceObject; + + // + // init event + // + KeInitializeEvent(Event, NotificationEvent, FALSE); + + // + // lets setup a completion routine + // + IoSetCompletionRoutine(Irp, USBSTOR_CompletionRoutine, (PVOID)Event, TRUE, TRUE, TRUE); + + // + // output result + // + *OutIrp = Irp; + *OutRequest = Request; + return STATUS_SUCCESS; +} + +NTSTATUS +USBSTOR_SendIrp( + IN PDEVICE_OBJECT PDODeviceObject, + IN ULONG DataTransferLength, + IN UCHAR OpCode, + OUT PVOID *OutData) +{ + NTSTATUS Status; + PIRP Irp; + KEVENT Event; + PPDO_DEVICE_EXTENSION PDODeviceExtension; + PSCSI_REQUEST_BLOCK Request; + + // + // let's allocate an irp + // + Status = USBSTOR_AllocateIrp(PDODeviceObject, DataTransferLength, OpCode, &Event, &Request, &Irp); + if (!NT_SUCCESS(Status)) + { + // + // failed + // + DPRINT1("[USBSTOR] Failed to build irp\n"); + return Status; + } + + // + // get device extension + // + PDODeviceExtension = (PPDO_DEVICE_EXTENSION)PDODeviceObject->DeviceExtension; + + // + // send irp + // + ASSERT(Irp); + ASSERT(PDODeviceExtension->LowerDeviceObject); + Status = IoCallDriver(PDODeviceExtension->Self, Irp); + + if (Status == STATUS_PENDING) + { + // + // wait for completion + // + KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL); + Status = Irp->IoStatus.Status; + } + + if (NT_SUCCESS(Status)) + { + // + // store result + // + *OutData = Request->DataBuffer; + } + else + { + // + // free the data + // + ExFreePoolWithTag(Request->DataBuffer, USB_STOR_TAG); + *OutData = NULL; + } + + // + // free resources + // + ExFreePoolWithTag(Request, USB_STOR_TAG); + IoFreeMdl(Irp->MdlAddress); + IoFreeIrp(Irp); + return Status; +} + +NTSTATUS +USBSTOR_SendInquiryIrp( + IN PDEVICE_OBJECT PDODeviceObject) +{ + NTSTATUS Status; + PPDO_DEVICE_EXTENSION PDODeviceExtension; + PUFI_INQUIRY_RESPONSE Response; + + // + // get device extension + // + PDODeviceExtension = (PPDO_DEVICE_EXTENSION)PDODeviceObject->DeviceExtension; + + // + // send request + // + Status = USBSTOR_SendIrp(PDODeviceObject, sizeof(UFI_INQUIRY_RESPONSE), SCSIOP_INQUIRY, (PVOID*)&Response); + if (!NT_SUCCESS(Status)) + { + // + // command failed + // + DPRINT1("USBSTOR_SendInquiryIrp Failed with %x\n", Status); + return Status; + } + + DPRINT1("Response %p\n", Response); + DPRINT1("DeviceType %x\n", Response->DeviceType); + DPRINT1("RMB %x\n", Response->RMB); + DPRINT1("Version %x\n", Response->Version); + DPRINT1("Format %x\n", Response->Format); + DPRINT1("Length %x\n", Response->Length); + DPRINT1("Reserved %p\n", Response->Reserved); + DPRINT1("Vendor %c%c%c%c%c%c%c%c\n", Response->Vendor[0], Response->Vendor[1], Response->Vendor[2], Response->Vendor[3], Response->Vendor[4], Response->Vendor[5], Response->Vendor[6], Response->Vendor[7]); + DPRINT1("Product %c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c\n", Response->Product[0], Response->Product[1], Response->Product[2], Response->Product[3], + Response->Product[4], Response->Product[5], Response->Product[6], Response->Product[7], + Response->Product[8], Response->Product[9], Response->Product[10], Response->Product[11], + Response->Product[12], Response->Product[13], Response->Product[14], Response->Product[15]); + + DPRINT1("Revision %c%c%c%c\n", Response->Revision[0], Response->Revision[1], Response->Revision[2], Response->Revision[3]); + + // + // store result + // + PDODeviceExtension->InquiryData = (PVOID)Response; + return Status; +} + +NTSTATUS +USBSTOR_SendFormatCapacityIrp( + IN PDEVICE_OBJECT PDODeviceObject) +{ + NTSTATUS Status; + PPDO_DEVICE_EXTENSION PDODeviceExtension; + PUCHAR Response; + + // + // get device extension + // + PDODeviceExtension = (PPDO_DEVICE_EXTENSION)PDODeviceObject->DeviceExtension; + + // + // send request + // + Status = USBSTOR_SendIrp(PDODeviceObject, 0xFC, SCSIOP_READ_FORMATTED_CAPACITY, (PVOID*)&Response); + if (!NT_SUCCESS(Status)) + { + // + // command failed + // + return Status; + } + + // + // check if its a floppy + // + PDODeviceExtension->IsFloppy = USBSTOR_IsFloppy(Response, 0xFC /*FIXME*/, &PDODeviceExtension->MediumTypeCode); + + // + // free response + // + ExFreePoolWithTag(Response, USB_STOR_TAG); + return Status; +} + + + +NTSTATUS +USBSTOR_CreatePDO( + IN PDEVICE_OBJECT DeviceObject, + IN UCHAR LUN) +{ + PDEVICE_OBJECT PDO; + NTSTATUS Status; + PPDO_DEVICE_EXTENSION PDODeviceExtension; + PUFI_INQUIRY_RESPONSE Response; + PFDO_DEVICE_EXTENSION FDODeviceExtension; + + // + // get device extension + // + FDODeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension; + + + // + // create child device object + // + Status = IoCreateDevice(DeviceObject->DriverObject, sizeof(PDO_DEVICE_EXTENSION), NULL, FILE_DEVICE_MASS_STORAGE, FILE_AUTOGENERATED_DEVICE_NAME | FILE_DEVICE_SECURE_OPEN, FALSE, &PDO); + if (!NT_SUCCESS(Status)) + { + // + // failed to create device + // + return Status; + } + + // + // patch the stack size + // + PDO->StackSize = DeviceObject->StackSize; + + // + // get device extension + // + PDODeviceExtension = (PPDO_DEVICE_EXTENSION)PDO->DeviceExtension; + + // + // initialize device extension + // + RtlZeroMemory(PDODeviceExtension, sizeof(PDO_DEVICE_EXTENSION)); + PDODeviceExtension->Common.IsFDO = FALSE; + PDODeviceExtension->LowerDeviceObject = DeviceObject; + PDODeviceExtension->PDODeviceObject = &FDODeviceExtension->ChildPDO[LUN]; + PDODeviceExtension->Self = PDO; + PDODeviceExtension->LUN = LUN; + + // + // set device flags + // + PDO->Flags |= DO_DIRECT_IO | DO_MAP_IO_BUFFER; + + // + // device is initialized + // + PDO->Flags &= ~DO_DEVICE_INITIALIZING; + + // + // output device object + // + FDODeviceExtension->ChildPDO[LUN] = PDO; + + // + // send inquiry command by irp + // + Status = USBSTOR_SendInquiryIrp(PDO); + ASSERT(Status == STATUS_SUCCESS); + + // + // check response data + // + Response = (PUFI_INQUIRY_RESPONSE)PDODeviceExtension->InquiryData; + ASSERT(Response); + + if (Response->DeviceType == 0) + { + // + // check if it is a floppy + // + Status = USBSTOR_SendFormatCapacityIrp(PDO); + + // + // display result + // + DPRINT1("[USBSTOR] Status %x IsFloppy %x MediumTypeCode %x\n", Status, PDODeviceExtension->IsFloppy, PDODeviceExtension->MediumTypeCode); + + // + // failing command is non critical + // + Status = STATUS_SUCCESS; + } + + // + // done + // + return Status; +} diff --git a/drivers/usb/usbstor_new/queue.c b/drivers/usb/usbstor_new/queue.c new file mode 100644 index 0000000000..a945ab97c9 --- /dev/null +++ b/drivers/usb/usbstor_new/queue.c @@ -0,0 +1,670 @@ +/* + * PROJECT: ReactOS Universal Serial Bus Bulk Storage Driver + * LICENSE: GPL - See COPYING in the top level directory + * FILE: drivers/usb/usbstor/queue.c + * PURPOSE: USB block storage device driver. + * PROGRAMMERS: + * James Tabor + * Michael Martin (michael.martin@reactos.org) + * Johannes Anderwald (johannes.anderwald@reactos.org) + */ + +#include "usbstor.h" + +#define NDEBUG +#include <debug.h> + +VOID +USBSTOR_QueueInitialize( + PFDO_DEVICE_EXTENSION FDODeviceExtension) +{ + // + // sanity check + // + ASSERT(FDODeviceExtension->Common.IsFDO); + + // + // initialize queue lock + // + KeInitializeSpinLock(&FDODeviceExtension->IrpListLock); + + // + // initialize irp list head + // + InitializeListHead(&FDODeviceExtension->IrpListHead); + + // + // initialize event + // + KeInitializeEvent(&FDODeviceExtension->NoPendingRequests, NotificationEvent, TRUE); +} + +VOID +NTAPI +USBSTOR_CancelIo( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp) +{ + PFDO_DEVICE_EXTENSION FDODeviceExtension; + + // + // get FDO device extension + // + FDODeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension; + + // + // sanity check + // + ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL); + ASSERT(FDODeviceExtension->Common.IsFDO); + + // + // this IRP isn't in our list here + // + + // + // now release the cancel lock + // + IoReleaseCancelSpinLock(Irp->CancelIrql); + + // + // set cancel status + // + Irp->IoStatus.Status = STATUS_CANCELLED; + + // + // now cancel the irp + // + USBSTOR_QueueTerminateRequest(DeviceObject, Irp); + IoCompleteRequest(Irp, IO_NO_INCREMENT); + + // + // start the next one + // + USBSTOR_QueueNextRequest(DeviceObject); +} + +VOID +NTAPI +USBSTOR_Cancel( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp) +{ + PFDO_DEVICE_EXTENSION FDODeviceExtension; + + // + // get FDO device extension + // + FDODeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension; + + // + // sanity check + // + ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL); + ASSERT(FDODeviceExtension->Common.IsFDO); + + // + // acquire irp list lock + // + KeAcquireSpinLockAtDpcLevel(&FDODeviceExtension->IrpListLock); + + // + // remove the irp from the list + // + RemoveEntryList(&Irp->Tail.Overlay.ListEntry); + + // + // release irp list lock + // + KeReleaseSpinLockFromDpcLevel(&FDODeviceExtension->IrpListLock); + + // + // now release the cancel lock + // + IoReleaseCancelSpinLock(Irp->CancelIrql); + + // + // set cancel status + // + Irp->IoStatus.Status = STATUS_CANCELLED; + + // + // now cancel the irp + // + USBSTOR_QueueTerminateRequest(DeviceObject, Irp); + IoCompleteRequest(Irp, IO_NO_INCREMENT); + + // + // start the next one + // + USBSTOR_QueueNextRequest(DeviceObject); +} + +BOOLEAN +USBSTOR_QueueAddIrp( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp) +{ + PDRIVER_CANCEL OldDriverCancel; + KIRQL OldLevel; + PFDO_DEVICE_EXTENSION FDODeviceExtension; + BOOLEAN IrpListFreeze; + BOOLEAN SrbProcessing; + PIO_STACK_LOCATION IoStack = IoGetCurrentIrpStackLocation(Irp); + PSCSI_REQUEST_BLOCK Request = (PSCSI_REQUEST_BLOCK)IoStack->Parameters.Others.Argument1; + + // + // get FDO device extension + // + FDODeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension; + + // + // sanity check + // + ASSERT(FDODeviceExtension->Common.IsFDO); + + // + // mark irp pending + // + IoMarkIrpPending(Irp); + + // + // acquire lock + // + KeAcquireSpinLock(&FDODeviceExtension->IrpListLock, &OldLevel); + + // + // check if there are irp pending + // + SrbProcessing = FDODeviceExtension->IrpPendingCount != 0; + + if (SrbProcessing) + { + // + // add irp to queue + // + InsertTailList(&FDODeviceExtension->IrpListHead, &Irp->Tail.Overlay.ListEntry); + } + + // + // increment pending count + // + FDODeviceExtension->IrpPendingCount++; + + + // + // clear the no requests pending event + // + KeClearEvent(&FDODeviceExtension->NoPendingRequests); + + // + // check if queue is freezed + // + IrpListFreeze = FDODeviceExtension->IrpListFreeze; + + // + // release list lock + // + KeReleaseSpinLock(&FDODeviceExtension->IrpListLock, OldLevel); + + // + // synchronize with cancellations by holding the cancel lock + // + IoAcquireCancelSpinLock(&Irp->CancelIrql); + + // + // now set the driver cancel routine + // + if (SrbProcessing) + { + ASSERT(FDODeviceExtension->ActiveSrb != NULL); + + OldDriverCancel = IoSetCancelRoutine(Irp, USBSTOR_Cancel); + } + else + { + ASSERT(FDODeviceExtension->ActiveSrb == NULL); + + FDODeviceExtension->ActiveSrb = Request; + OldDriverCancel = IoSetCancelRoutine(Irp, USBSTOR_CancelIo); + } + + // + // check if the irp has already been cancelled + // + if (Irp->Cancel && OldDriverCancel == NULL) + { + // + // cancel irp + // + Irp->CancelRoutine(DeviceObject, Irp); + + // + // irp was cancelled + // + return FALSE; + } + + // + // release the cancel lock + // + IoReleaseCancelSpinLock(Irp->CancelIrql); + + // + // if list is freezed, dont start this packet + // + DPRINT("IrpListFreeze: %lu IrpPendingCount %lu\n", IrpListFreeze, FDODeviceExtension->IrpPendingCount); + + return (IrpListFreeze || SrbProcessing); +} + +PIRP +USBSTOR_RemoveIrp( + IN PDEVICE_OBJECT DeviceObject) +{ + KIRQL OldLevel; + PFDO_DEVICE_EXTENSION FDODeviceExtension; + PLIST_ENTRY Entry; + PIRP Irp = NULL; + + // + // get FDO device extension + // + FDODeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension; + + // + // sanity check + // + ASSERT(FDODeviceExtension->Common.IsFDO); + + // + // acquire lock + // + KeAcquireSpinLock(&FDODeviceExtension->IrpListLock, &OldLevel); + + // + // check if list is empty + // + if (!IsListEmpty(&FDODeviceExtension->IrpListHead)) + { + // + // remove entry + // + Entry = RemoveHeadList(&FDODeviceExtension->IrpListHead); + + // + // get offset to start of irp + // + Irp = (PIRP)CONTAINING_RECORD(Entry, IRP, Tail.Overlay.ListEntry); + } + + // + // release list lock + // + KeReleaseSpinLock(&FDODeviceExtension->IrpListLock, OldLevel); + + // + // return result + // + return Irp; +} + +VOID +USBSTOR_QueueWaitForPendingRequests( + IN PDEVICE_OBJECT DeviceObject) +{ + PFDO_DEVICE_EXTENSION FDODeviceExtension; + + // + // get FDO device extension + // + FDODeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension; + + // + // perform the wait + // + KeWaitForSingleObject(&FDODeviceExtension->NoPendingRequests, + Executive, + KernelMode, + FALSE, + NULL); +} + +VOID +USBSTOR_QueueTerminateRequest( + IN PDEVICE_OBJECT FDODeviceObject, + IN PIRP Irp) +{ + KIRQL OldLevel; + PFDO_DEVICE_EXTENSION FDODeviceExtension; + PIO_STACK_LOCATION IoStack = IoGetCurrentIrpStackLocation(Irp); + PSCSI_REQUEST_BLOCK Request = (PSCSI_REQUEST_BLOCK)IoStack->Parameters.Others.Argument1; + + // + // get FDO device extension + // + FDODeviceExtension = (PFDO_DEVICE_EXTENSION)FDODeviceObject->DeviceExtension; + + // + // sanity check + // + ASSERT(FDODeviceExtension->Common.IsFDO); + + // + // acquire lock + // + KeAcquireSpinLock(&FDODeviceExtension->IrpListLock, &OldLevel); + + // + // decrement pending irp count + // + FDODeviceExtension->IrpPendingCount--; + + // + // check if this was our current active SRB + // + if (FDODeviceExtension->ActiveSrb == Request) + { + // + // indicate processing is completed + // + FDODeviceExtension->ActiveSrb = NULL; + } + + // + // Set the event if nothing else is pending + // + if (FDODeviceExtension->IrpPendingCount == 0 && + FDODeviceExtension->ActiveSrb == NULL) + { + KeSetEvent(&FDODeviceExtension->NoPendingRequests, IO_NO_INCREMENT, FALSE); + } + + // + // release lock + // + KeReleaseSpinLock(&FDODeviceExtension->IrpListLock, OldLevel); + +} + +VOID +USBSTOR_QueueNextRequest( + IN PDEVICE_OBJECT DeviceObject) +{ + PFDO_DEVICE_EXTENSION FDODeviceExtension; + PIRP Irp; + PIO_STACK_LOCATION IoStack; + PSCSI_REQUEST_BLOCK Request; + + // + // get pdo device extension + // + FDODeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension; + + // + // sanity check + // + ASSERT(FDODeviceExtension->Common.IsFDO); + + // + // check first if there's already a request pending or the queue is frozen + // + if (FDODeviceExtension->ActiveSrb != NULL || + FDODeviceExtension->IrpListFreeze) + { + // + // no work to do yet + // + return; + } + + // + // remove first irp from list + // + Irp = USBSTOR_RemoveIrp(DeviceObject); + + // + // is there an irp pending + // + if (!Irp) + { + // + // no work to do + // + IoStartNextPacket(DeviceObject, TRUE); + return; + } + + // + // get current stack location + // + IoStack = IoGetCurrentIrpStackLocation(Irp); + + // + // get srb + // + Request = (PSCSI_REQUEST_BLOCK)IoStack->Parameters.Others.Argument1; + + // + // sanity check + // + ASSERT(Request); + + // + // set the active SRB + // + FDODeviceExtension->ActiveSrb = Request; + + // + // start next packet + // + IoStartPacket(DeviceObject, Irp, &Request->QueueSortKey, USBSTOR_CancelIo); + + // + // start next request + // + IoStartNextPacket(DeviceObject, TRUE); +} + +VOID +USBSTOR_QueueRelease( + IN PDEVICE_OBJECT DeviceObject) +{ + PFDO_DEVICE_EXTENSION FDODeviceExtension; + PIRP Irp; + KIRQL OldLevel; + PIO_STACK_LOCATION IoStack; + PSCSI_REQUEST_BLOCK Request; + + // + // get FDO device extension + // + FDODeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension; + + // + // sanity check + // + ASSERT(FDODeviceExtension->Common.IsFDO); + + // + // acquire lock + // + KeAcquireSpinLock(&FDODeviceExtension->IrpListLock, &OldLevel); + + // + // clear freezed status + // + FDODeviceExtension->IrpListFreeze = FALSE; + + // + // release irp list lock + // + KeReleaseSpinLock(&FDODeviceExtension->IrpListLock, OldLevel); + + // + // grab newest irp + // + Irp = USBSTOR_RemoveIrp(DeviceObject); + + // + // is there an irp + // + if (!Irp) + { + // + // no irp + // + return; + } + + // + // get current irp stack location + // + IoStack = IoGetCurrentIrpStackLocation(Irp); + + // + // get srb + // + Request = (PSCSI_REQUEST_BLOCK)IoStack->Parameters.Others.Argument1; + + // + // start new packet + // + IoStartPacket(DeviceObject, + Irp, + &Request->QueueSortKey, + USBSTOR_CancelIo); +} + + +VOID +NTAPI +USBSTOR_StartIo( + PDEVICE_OBJECT DeviceObject, + PIRP Irp) +{ + PIO_STACK_LOCATION IoStack; + PFDO_DEVICE_EXTENSION FDODeviceExtension; + PPDO_DEVICE_EXTENSION PDODeviceExtension; + KIRQL OldLevel; + BOOLEAN ResetInProgress; + + DPRINT("USBSTOR_StartIo\n"); + + // + // get FDO device extension + // + FDODeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension; + + // + // sanity check + // + ASSERT(FDODeviceExtension->Common.IsFDO); + + // + // acquire cancel spinlock + // + IoAcquireCancelSpinLock(&OldLevel); + + // + // set cancel routine to zero + // + IoSetCancelRoutine(Irp, NULL); + + // + // check if the irp has been cancelled + // + if (Irp->Cancel) + { + // + // irp has been cancelled, release cancel spinlock + // + IoReleaseCancelSpinLock(OldLevel); + + // + // irp is cancelled + // + Irp->IoStatus.Status = STATUS_CANCELLED; + Irp->IoStatus.Information = 0; + + // + // terminate request + // + USBSTOR_QueueTerminateRequest(DeviceObject, Irp); + + // + // complete request + // + IoCompleteRequest(Irp, IO_NO_INCREMENT); + + // + // queue next request + // + USBSTOR_QueueNextRequest(DeviceObject); + + // + // done + // + return; + } + + // + // release cancel spinlock + // + IoReleaseCancelSpinLock(OldLevel); + + // + // acquire lock + // + KeAcquireSpinLock(&FDODeviceExtension->IrpListLock, &OldLevel); + + // + // check reset is in progress + // + ResetInProgress = FDODeviceExtension->ResetInProgress; + ASSERT(ResetInProgress == FALSE); + + // + // release lock + // + KeReleaseSpinLock(&FDODeviceExtension->IrpListLock, OldLevel); + + // + // get current irp stack location + // + IoStack = IoGetCurrentIrpStackLocation(Irp); + + // + // get pdo device extension + // + PDODeviceExtension = (PPDO_DEVICE_EXTENSION)IoStack->DeviceObject->DeviceExtension; + + // + // sanity check + // + ASSERT(PDODeviceExtension->Common.IsFDO == FALSE); + + // + // is a reset in progress + // + if (ResetInProgress) + { + // + // hard reset is in progress + // + Irp->IoStatus.Information = 0; + Irp->IoStatus.Status = STATUS_DEVICE_DOES_NOT_EXIST; + USBSTOR_QueueTerminateRequest(DeviceObject, Irp); + IoCompleteRequest(Irp, IO_NO_INCREMENT); + return; + } + + // + // execute scsi + // + USBSTOR_HandleExecuteSCSI(IoStack->DeviceObject, Irp, 0); + + // + // FIXME: handle error + // +} diff --git a/drivers/usb/usbstor_new/scsi.c b/drivers/usb/usbstor_new/scsi.c new file mode 100644 index 0000000000..ee5bfba189 --- /dev/null +++ b/drivers/usb/usbstor_new/scsi.c @@ -0,0 +1,1429 @@ +/* + * PROJECT: ReactOS Universal Serial Bus Bulk Storage Driver + * LICENSE: GPL - See COPYING in the top level directory + * FILE: drivers/usb/usbstor/pdo.c + * PURPOSE: USB block storage device driver. + * PROGRAMMERS: + * James Tabor + * Michael Martin (michael.martin@reactos.org) + * Johannes Anderwald (johannes.anderwald@reactos.org) + */ + +#include "usbstor.h" + +#define NDEBUG +#include <debug.h> + +NTSTATUS +USBSTOR_BuildCBW( + IN ULONG Tag, + IN ULONG DataTransferLength, + IN UCHAR LUN, + IN UCHAR CommandBlockLength, + IN PUCHAR CommandBlock, + IN OUT PCBW Control) +{ + // + // sanity check + // + ASSERT(CommandBlockLength <= 16); + + // + // now initialize CBW + // + Control->Signature = CBW_SIGNATURE; + Control->Tag = Tag; + Control->DataTransferLength = DataTransferLength; + Control->Flags = (CommandBlock[0] != SCSIOP_WRITE) ? 0x80 : 0x00; + Control->LUN = (LUN & MAX_LUN); + Control->CommandBlockLength = CommandBlockLength; + + // + // copy command block + // + RtlCopyMemory(Control->CommandBlock, CommandBlock, CommandBlockLength); + + // + // done + // + return STATUS_SUCCESS; +} + +PIRP_CONTEXT +USBSTOR_AllocateIrpContext() +{ + PIRP_CONTEXT Context; + + // + // allocate irp context + // + Context = (PIRP_CONTEXT)AllocateItem(NonPagedPool, sizeof(IRP_CONTEXT)); + if (!Context) + { + // + // no memory + // + return NULL; + } + + // + // allocate cbw block + // + Context->cbw = (PCBW)AllocateItem(NonPagedPool, 512); + if (!Context->cbw) + { + // + // no memory + // + FreeItem(Context); + return NULL; + } + + // + // done + // + return Context; + +} + +BOOLEAN +USBSTOR_IsCSWValid( + PIRP_CONTEXT Context) +{ + // + // sanity checks + // + if (Context->csw->Signature != CSW_SIGNATURE) + { + DPRINT1("[USBSTOR] Expected Signature %x but got %x\n", CSW_SIGNATURE, Context->csw->Signature); + return FALSE; + } + + if (Context->csw->Tag != (ULONG)Context->csw) + { + DPRINT1("[USBSTOR] Expected Tag %x but got %x\n", (ULONG)Context->csw, Context->csw->Tag); + return FALSE; + } + + if (Context->csw->Status != 0x00) + { + DPRINT1("[USBSTOR] Expected Status 0x00 but got %x\n", Context->csw->Status); + return FALSE; + } + + // + // CSW is valid + // + return TRUE; + +} + +NTSTATUS +USBSTOR_QueueWorkItem( + PIRP_CONTEXT Context, + PIRP Irp) +{ + PERRORHANDLER_WORKITEM_DATA ErrorHandlerWorkItemData; + + // + // Allocate Work Item Data + // + ErrorHandlerWorkItemData = ExAllocatePoolWithTag(NonPagedPool, sizeof(ERRORHANDLER_WORKITEM_DATA), USB_STOR_TAG); + if (!ErrorHandlerWorkItemData) + { + // + // no memory + // + return STATUS_INSUFFICIENT_RESOURCES; + } + + // + // error handling started + // + Context->FDODeviceExtension->SrbErrorHandlingActive = TRUE; + + // + // srb error handling finished + // + Context->FDODeviceExtension->TimerWorkQueueEnabled = FALSE; + + // + // Initialize and queue the work item to handle the error + // + ExInitializeWorkItem(&ErrorHandlerWorkItemData->WorkQueueItem, + ErrorHandlerWorkItemRoutine, + ErrorHandlerWorkItemData); + + ErrorHandlerWorkItemData->DeviceObject = Context->FDODeviceExtension->FunctionalDeviceObject; + ErrorHandlerWorkItemData->Context = Context; + ErrorHandlerWorkItemData->Irp = Irp; + ErrorHandlerWorkItemData->DeviceObject = Context->FDODeviceExtension->FunctionalDeviceObject; + + DPRINT1("Queuing WorkItemROutine\n"); + ExQueueWorkItem(&ErrorHandlerWorkItemData->WorkQueueItem, DelayedWorkQueue); + return STATUS_MORE_PROCESSING_REQUIRED; +} + + +// +// driver verifier +// +IO_COMPLETION_ROUTINE USBSTOR_CSWCompletionRoutine; + +NTSTATUS +NTAPI +USBSTOR_CSWCompletionRoutine( + PDEVICE_OBJECT DeviceObject, + PIRP Irp, + PVOID Ctx) +{ + PIRP_CONTEXT Context; + PIO_STACK_LOCATION IoStack; + PSCSI_REQUEST_BLOCK Request; + PCDB pCDB; + PREAD_CAPACITY_DATA_EX CapacityDataEx; + PREAD_CAPACITY_DATA CapacityData; + PUFI_CAPACITY_RESPONSE Response; + NTSTATUS Status; + + // + // access context + // + Context = (PIRP_CONTEXT)Ctx; + + // ... 2103 lines suppressed ...