diff --git a/drivers/usb/CMakeLists.txt b/drivers/usb/CMakeLists.txt index 05817b0f828..17fc45d14ef 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 00000000000..3bb2eed0f25 --- /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 00000000000..3df36a671cc --- /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 + +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 00000000000..604f621c916 --- /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 + +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 00000000000..e920d353d1b --- /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 + +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 00000000000..e3707041f58 --- /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 + +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 00000000000..2fd41c6e0b5 --- /dev/null +++ b/drivers/usb/usbstor_new/guid.c @@ -0,0 +1,9 @@ +/* DO NOT USE THE PRECOMPILED HEADER FOR THIS FILE! */ + +#include +#include +#include +#include +#include + +/* 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 00000000000..6b60cf828e7 --- /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 + +// +// 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 00000000000..6ce5d8f7460 --- /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 + +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 00000000000..a945ab97c95 --- /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 + +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 00000000000..ee5bfba1894 --- /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 + +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; + + // + // is there a mdl + // + if (Context->TransferBufferMDL) + { + // + // is there an irp associated + // + if (Context->Irp) + { + // + // did we allocate the mdl + // + if (Context->TransferBufferMDL != Context->Irp->MdlAddress) + { + // + // free mdl + // + IoFreeMdl(Context->TransferBufferMDL); + } + } + else + { + // + // free mdl + // + IoFreeMdl(Context->TransferBufferMDL); + } + } + + DPRINT("USBSTOR_CSWCompletionRoutine Status %x\n", Irp->IoStatus.Status); + + if (!NT_SUCCESS(Irp->IoStatus.Information)) + { + if (Context->ErrorIndex == 0) + { + // + // increment error index + // + Context->ErrorIndex = 1; + + // + // clear stall and resend cbw + // + Status = USBSTOR_QueueWorkItem(Context, Irp); + ASSERT(Status == STATUS_MORE_PROCESSING_REQUIRED); + return STATUS_MORE_PROCESSING_REQUIRED; + } + + // + // perform reset recovery + // + Context->ErrorIndex = 2; + IoFreeIrp(Irp); + Status = USBSTOR_QueueWorkItem(Context, NULL); + ASSERT(Status == STATUS_MORE_PROCESSING_REQUIRED); + return STATUS_MORE_PROCESSING_REQUIRED; + } + + if (!USBSTOR_IsCSWValid(Context)) + { + // + // perform reset recovery + // + Context->ErrorIndex = 2; + IoFreeIrp(Irp); + Status = USBSTOR_QueueWorkItem(Context, NULL); + ASSERT(Status == STATUS_MORE_PROCESSING_REQUIRED); + return STATUS_MORE_PROCESSING_REQUIRED; + } + + + // + // get current stack location + // + IoStack = IoGetCurrentIrpStackLocation(Context->Irp); + + // + // get request block + // + Request = (PSCSI_REQUEST_BLOCK)IoStack->Parameters.Others.Argument1; + ASSERT(Request); + + Status = Irp->IoStatus.Status; + + // + // get SCSI command data block + // + pCDB = (PCDB)Request->Cdb; + Request->SrbStatus = SRB_STATUS_SUCCESS; + + // + // read capacity needs special work + // + if (pCDB->AsByte[0] == SCSIOP_READ_CAPACITY) + { + // + // get output buffer + // + Response = (PUFI_CAPACITY_RESPONSE)Context->TransferData; + + // + // store in pdo + // + Context->PDODeviceExtension->BlockLength = NTOHL(Response->BlockLength); + Context->PDODeviceExtension->LastLogicBlockAddress = NTOHL(Response->LastLogicalBlockAddress); + + if (Request->DataTransferLength == sizeof(READ_CAPACITY_DATA_EX)) + { + // + // get input buffer + // + CapacityDataEx = (PREAD_CAPACITY_DATA_EX)Request->DataBuffer; + + // + // set result + // + CapacityDataEx->BytesPerBlock = Response->BlockLength; + CapacityDataEx->LogicalBlockAddress.QuadPart = Response->LastLogicalBlockAddress; + Irp->IoStatus.Information = sizeof(READ_CAPACITY_DATA_EX); + } + else + { + // + // get input buffer + // + CapacityData = (PREAD_CAPACITY_DATA)Request->DataBuffer; + + // + // set result + // + CapacityData->BytesPerBlock = Response->BlockLength; + CapacityData->LogicalBlockAddress = Response->LastLogicalBlockAddress; + Irp->IoStatus.Information = sizeof(READ_CAPACITY_DATA); + } + + // + // free response + // + FreeItem(Context->TransferData); + } + + // + // free cbw + // + FreeItem(Context->cbw); + + // + // FIXME: check status + // + Context->Irp->IoStatus.Status = Irp->IoStatus.Status; + Context->Irp->IoStatus.Information = Context->TransferDataLength; + + // + // terminate current request + // + USBSTOR_QueueTerminateRequest(Context->PDODeviceExtension->LowerDeviceObject, Context->Irp); + + // + // complete request + // + IoCompleteRequest(Context->Irp, IO_NO_INCREMENT); + + // + // start next request + // + USBSTOR_QueueNextRequest(Context->PDODeviceExtension->LowerDeviceObject); + + // + // free our allocated irp + // + IoFreeIrp(Irp); + + // + // free context + // + FreeItem(Context); + + // + // done + // + return STATUS_MORE_PROCESSING_REQUIRED; +} + +VOID +USBSTOR_SendCSW( + PIRP_CONTEXT Context, + PIRP Irp) +{ + PIO_STACK_LOCATION IoStack; + + // + // get next irp stack location + // + IoStack = IoGetNextIrpStackLocation(Irp); + + // + // now initialize the urb for sending the csw + // + UsbBuildInterruptOrBulkTransferRequest(&Context->Urb, + sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER), + Context->FDODeviceExtension->InterfaceInformation->Pipes[Context->FDODeviceExtension->BulkInPipeIndex].PipeHandle, + Context->csw, + NULL, + 512, //FIXME + USBD_TRANSFER_DIRECTION_IN | USBD_SHORT_TRANSFER_OK, + NULL); + + // + // initialize stack location + // + IoStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL; + IoStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_URB; + IoStack->Parameters.Others.Argument1 = (PVOID)&Context->Urb; + IoStack->Parameters.DeviceIoControl.InputBufferLength = Context->Urb.UrbHeader.Length; + Irp->IoStatus.Status = STATUS_SUCCESS; + + + // + // setup completion routine + // + IoSetCompletionRoutine(Irp, USBSTOR_CSWCompletionRoutine, Context, TRUE, TRUE, TRUE); + + // + // call driver + // + IoCallDriver(Context->FDODeviceExtension->LowerDeviceObject, Irp); +} + + +// +// driver verifier +// +IO_COMPLETION_ROUTINE USBSTOR_DataCompletionRoutine; + +NTSTATUS +NTAPI +USBSTOR_DataCompletionRoutine( + PDEVICE_OBJECT DeviceObject, + PIRP Irp, + PVOID Ctx) +{ + PIRP_CONTEXT Context; + NTSTATUS Status; + + + DPRINT("USBSTOR_DataCompletionRoutine Irp %p Ctx %p Status %x\n", Irp, Ctx, Irp->IoStatus.Status); + + // + // access context + // + Context = (PIRP_CONTEXT)Ctx; + + if (!NT_SUCCESS(Irp->IoStatus.Status)) + { + // + // clear stall and resend cbw + // + Context->ErrorIndex = 1; + Status = USBSTOR_QueueWorkItem(Context, Irp); + ASSERT(Status == STATUS_MORE_PROCESSING_REQUIRED); + return STATUS_MORE_PROCESSING_REQUIRED; + } + + // + // send csw + // + USBSTOR_SendCSW(Context, Irp); + + // + // cancel completion + // + return STATUS_MORE_PROCESSING_REQUIRED; +} + +// +// driver verifier +// +IO_COMPLETION_ROUTINE USBSTOR_CBWCompletionRoutine; + +NTSTATUS +NTAPI +USBSTOR_CBWCompletionRoutine( + PDEVICE_OBJECT DeviceObject, + PIRP Irp, + PVOID Ctx) +{ + PIRP_CONTEXT Context; + PIO_STACK_LOCATION IoStack; + UCHAR Code; + USBD_PIPE_HANDLE PipeHandle; + + DPRINT("USBSTOR_CBWCompletionRoutine Irp %p Ctx %p Status %x\n", Irp, Ctx, Irp->IoStatus.Status); + + // + // access context + // + Context = (PIRP_CONTEXT)Ctx; + + // + // get next stack location + // + IoStack = IoGetNextIrpStackLocation(Irp); + + // + // is there data to be submitted + // + if (Context->TransferDataLength) + { + // + // get command code + // + Code = Context->cbw->CommandBlock[0]; + + if (Code == SCSIOP_WRITE) + { + // + // write request use bulk out pipe + // + PipeHandle = Context->FDODeviceExtension->InterfaceInformation->Pipes[Context->FDODeviceExtension->BulkOutPipeIndex].PipeHandle; + } + else + { + // + // default bulk in pipe + // + PipeHandle = Context->FDODeviceExtension->InterfaceInformation->Pipes[Context->FDODeviceExtension->BulkInPipeIndex].PipeHandle; + } + + // + // now initialize the urb for sending data + // + UsbBuildInterruptOrBulkTransferRequest(&Context->Urb, + sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER), + PipeHandle, + NULL, + Context->TransferBufferMDL, + Context->TransferDataLength, + ((Code == SCSIOP_WRITE) ? USBD_TRANSFER_DIRECTION_OUT : (USBD_TRANSFER_DIRECTION_IN | USBD_SHORT_TRANSFER_OK)), + NULL); + + // + // setup completion routine + // + IoSetCompletionRoutine(Irp, USBSTOR_DataCompletionRoutine, Context, TRUE, TRUE, TRUE); + } + else + { + // + // now initialize the urb for sending the csw + // + + UsbBuildInterruptOrBulkTransferRequest(&Context->Urb, + sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER), + Context->FDODeviceExtension->InterfaceInformation->Pipes[Context->FDODeviceExtension->BulkInPipeIndex].PipeHandle, + Context->csw, + NULL, + 512, //FIXME + USBD_TRANSFER_DIRECTION_IN | USBD_SHORT_TRANSFER_OK, + NULL); + + // + // setup completion routine + // + IoSetCompletionRoutine(Irp, USBSTOR_CSWCompletionRoutine, Context, TRUE, TRUE, TRUE); + } + + // + // initialize stack location + // + IoStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL; + IoStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_URB; + IoStack->Parameters.Others.Argument1 = (PVOID)&Context->Urb; + IoStack->Parameters.DeviceIoControl.InputBufferLength = Context->Urb.UrbHeader.Length; + Irp->IoStatus.Status = STATUS_SUCCESS; + + // + // call driver + // + IoCallDriver(Context->FDODeviceExtension->LowerDeviceObject, Irp); + + return STATUS_MORE_PROCESSING_REQUIRED; +} + +VOID +DumpCBW( + PUCHAR Block) +{ + DPRINT("%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", + Block[0] & 0xFF, Block[1] & 0xFF, Block[2] & 0xFF, Block[3] & 0xFF, Block[4] & 0xFF, Block[5] & 0xFF, Block[6] & 0xFF, Block[7] & 0xFF, Block[8] & 0xFF, Block[9] & 0xFF, + Block[10] & 0xFF, Block[11] & 0xFF, Block[12] & 0xFF, Block[13] & 0xFF, Block[14] & 0xFF, Block[15] & 0xFF, Block[16] & 0xFF, Block[17] & 0xFF, Block[18] & 0xFF, Block[19] & 0xFF, + Block[20] & 0xFF, Block[21] & 0xFF, Block[22] & 0xFF, Block[23] & 0xFF, Block[24] & 0xFF, Block[25] & 0xFF, Block[26] & 0xFF, Block[27] & 0xFF, Block[28] & 0xFF, Block[29] & 0xFF, + Block[30] & 0xFF); + +} + +NTSTATUS +USBSTOR_SendCBW( + PIRP_CONTEXT Context, + PIRP Irp) +{ + PIO_STACK_LOCATION IoStack; + + // + // 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)&Context->Urb; + IoStack->Parameters.DeviceIoControl.InputBufferLength = Context->Urb.UrbHeader.Length; + Irp->IoStatus.Status = STATUS_SUCCESS; + + // + // setup completion routine + // + IoSetCompletionRoutine(Irp, USBSTOR_CBWCompletionRoutine, Context, TRUE, TRUE, TRUE); + + // + // call driver + // + return IoCallDriver(Context->FDODeviceExtension->LowerDeviceObject, Irp); +} + +NTSTATUS +USBSTOR_SendRequest( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP OriginalRequest, + IN UCHAR CommandLength, + IN PUCHAR Command, + IN ULONG TransferDataLength, + IN PUCHAR TransferData, + IN ULONG RetryCount) +{ + PIRP_CONTEXT Context; + PPDO_DEVICE_EXTENSION PDODeviceExtension; + PFDO_DEVICE_EXTENSION FDODeviceExtension; + PIRP Irp; + PUCHAR MdlVirtualAddress; + + // + // first allocate irp context + // + Context = USBSTOR_AllocateIrpContext(); + if (!Context) + { + // + // no memory + // + return STATUS_INSUFFICIENT_RESOURCES; + } + + // + // get PDO device extension + // + PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension; + + // + // get FDO device extension + // + FDODeviceExtension = (PFDO_DEVICE_EXTENSION)PDODeviceExtension->LowerDeviceObject->DeviceExtension; + + // + // now build the cbw + // + USBSTOR_BuildCBW((ULONG)Context->cbw, + TransferDataLength, + PDODeviceExtension->LUN, + CommandLength, + Command, + Context->cbw); + + DPRINT("CBW %p\n", Context->cbw); + DumpCBW((PUCHAR)Context->cbw); + + // + // now initialize the urb + // + UsbBuildInterruptOrBulkTransferRequest(&Context->Urb, + sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER), + FDODeviceExtension->InterfaceInformation->Pipes[FDODeviceExtension->BulkOutPipeIndex].PipeHandle, + Context->cbw, + NULL, + sizeof(CBW), + USBD_TRANSFER_DIRECTION_OUT, + NULL); + + // + // initialize rest of context + // + Context->Irp = OriginalRequest; + Context->TransferData = TransferData; + Context->TransferDataLength = TransferDataLength; + Context->FDODeviceExtension = FDODeviceExtension; + Context->PDODeviceExtension = PDODeviceExtension; + Context->RetryCount = RetryCount; + + // + // is there transfer data + // + if (Context->TransferDataLength) + { + // + // check if the original request already does have an mdl associated + // + if (OriginalRequest) + { + if ((OriginalRequest->MdlAddress != NULL) && + (Context->TransferData == NULL || Command[0] == SCSIOP_READ || Command[0] == SCSIOP_WRITE)) + { + // + // Sanity check that the Mdl does describe the TransferData for read/write + // + if (CommandLength == UFI_READ_WRITE_CMD_LEN) + { + MdlVirtualAddress = MmGetMdlVirtualAddress(OriginalRequest->MdlAddress); + + // + // is there an offset + // + if (MdlVirtualAddress != Context->TransferData) + { + // + // lets build an mdl + // + Context->TransferBufferMDL = IoAllocateMdl(Context->TransferData, MmGetMdlByteCount(OriginalRequest->MdlAddress), FALSE, FALSE, NULL); + if (!Context->TransferBufferMDL) + { + // + // failed to allocate MDL + // + FreeItem(Context->cbw); + FreeItem(Context); + return STATUS_INSUFFICIENT_RESOURCES; + } + + // + // now build the partial mdl + // + IoBuildPartialMdl(OriginalRequest->MdlAddress, Context->TransferBufferMDL, Context->TransferData, Context->TransferDataLength); + } + } + + if (!Context->TransferBufferMDL) + { + // + // I/O paging request + // + Context->TransferBufferMDL = OriginalRequest->MdlAddress; + } + } + else + { + // + // allocate mdl for buffer, buffer must be allocated from NonPagedPool + // + Context->TransferBufferMDL = IoAllocateMdl(Context->TransferData, Context->TransferDataLength, FALSE, FALSE, NULL); + if (!Context->TransferBufferMDL) + { + // + // failed to allocate MDL + // + FreeItem(Context->cbw); + FreeItem(Context); + return STATUS_INSUFFICIENT_RESOURCES; + } + + // + // build mdl for nonpaged pool + // + MmBuildMdlForNonPagedPool(Context->TransferBufferMDL); + } + } + else + { + // + // allocate mdl for buffer, buffer must be allocated from NonPagedPool + // + Context->TransferBufferMDL = IoAllocateMdl(Context->TransferData, Context->TransferDataLength, FALSE, FALSE, NULL); + if (!Context->TransferBufferMDL) + { + // + // failed to allocate MDL + // + FreeItem(Context->cbw); + FreeItem(Context); + return STATUS_INSUFFICIENT_RESOURCES; + } + + // + // build mdl for nonpaged pool + // + MmBuildMdlForNonPagedPool(Context->TransferBufferMDL); + } + } + + // + // now allocate the request + // + Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE); + if (!Irp) + { + FreeItem(Context->cbw); + FreeItem(Context); + return STATUS_INSUFFICIENT_RESOURCES; + } + + if (OriginalRequest) + { + // + // mark orignal irp as pending + // + IoMarkIrpPending(OriginalRequest); + } + + // + // send request + // + USBSTOR_SendCBW(Context, Irp); + + // + // done + // + return STATUS_PENDING; +} + +NTSTATUS +USBSTOR_SendFormatCapacity( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp, + IN ULONG RetryCount) +{ + UFI_READ_FORMAT_CAPACITY Cmd; + PPDO_DEVICE_EXTENSION PDODeviceExtension; + PIO_STACK_LOCATION IoStack; + PSCSI_REQUEST_BLOCK Request; + + // + // get current stack location + // + IoStack = IoGetCurrentIrpStackLocation(Irp); + + // + // get PDO device extension + // + PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension; + + // + // get request block + // + Request = (PSCSI_REQUEST_BLOCK)IoStack->Parameters.Others.Argument1; + + // + // initialize inquiry cmd + // + RtlZeroMemory(&Cmd, sizeof(UFI_READ_FORMAT_CAPACITY)); + Cmd.Code = SCSIOP_READ_FORMATTED_CAPACITY; + Cmd.LUN = (PDODeviceExtension->LUN & MAX_LUN); + Cmd.AllocationLengthMsb = HTONS(Request->DataTransferLength & 0xFFFF) >> 8; + Cmd.AllocationLengthLsb = HTONS(Request->DataTransferLength & 0xFFFF) & 0xFF; + + // + // now send the request + // + return USBSTOR_SendRequest(DeviceObject, Irp, UFI_READ_FORMAT_CAPACITY_CMD_LEN, (PUCHAR)&Cmd, Request->DataTransferLength, (PUCHAR)Request->DataBuffer, RetryCount); +} + +NTSTATUS +USBSTOR_SendInquiry( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp, + IN ULONG RetryCount) +{ + UFI_INQUIRY_CMD Cmd; + PPDO_DEVICE_EXTENSION PDODeviceExtension; + PIO_STACK_LOCATION IoStack; + PSCSI_REQUEST_BLOCK Request; + + // + // get current stack location + // + IoStack = IoGetCurrentIrpStackLocation(Irp); + + // + // get request block + // + Request = (PSCSI_REQUEST_BLOCK)IoStack->Parameters.Others.Argument1; + + // + // get PDO device extension + // + PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension; + + // + // initialize inquiry cmd + // + RtlZeroMemory(&Cmd, sizeof(UFI_INQUIRY_CMD)); + Cmd.Code = SCSIOP_INQUIRY; + Cmd.LUN = (PDODeviceExtension->LUN & MAX_LUN); + Cmd.AllocationLength = sizeof(UFI_INQUIRY_RESPONSE); + + // + // sanity check + // + ASSERT(Request->DataTransferLength >= sizeof(UFI_INQUIRY_RESPONSE)); + + // + // now send the request + // + return USBSTOR_SendRequest(DeviceObject, Irp, UFI_INQUIRY_CMD_LEN, (PUCHAR)&Cmd, Request->DataTransferLength, (PUCHAR)Request->DataBuffer, RetryCount); +} + +NTSTATUS +USBSTOR_SendCapacity( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp, + IN ULONG RetryCount) +{ + UFI_CAPACITY_CMD Cmd; + PUFI_CAPACITY_RESPONSE Response; + PPDO_DEVICE_EXTENSION PDODeviceExtension; + + // + // get PDO device extension + // + PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension; + + // + // allocate capacity response + // + Response = (PUFI_CAPACITY_RESPONSE)AllocateItem(NonPagedPool, PAGE_SIZE); + if (!Response) + { + // + // no memory + // + return STATUS_INSUFFICIENT_RESOURCES; + } + + // + // initialize capacity cmd + // + RtlZeroMemory(&Cmd, sizeof(UFI_INQUIRY_CMD)); + Cmd.Code = SCSIOP_READ_CAPACITY; + Cmd.LUN = (PDODeviceExtension->LUN & MAX_LUN); + + // + // send request, response will be freed in completion routine + // + return USBSTOR_SendRequest(DeviceObject, Irp, UFI_READ_CAPACITY_CMD_LEN, (PUCHAR)&Cmd, sizeof(UFI_CAPACITY_RESPONSE), (PUCHAR)Response, RetryCount); +} + +NTSTATUS +USBSTOR_SendModeSense( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp, + IN ULONG RetryCount) +{ +#if 0 + UFI_SENSE_CMD Cmd; + NTSTATUS Status; + PVOID Response; + PCBW OutControl; + PCDB pCDB; + PUFI_MODE_PARAMETER_HEADER Header; +#endif + PPDO_DEVICE_EXTENSION PDODeviceExtension; + PIO_STACK_LOCATION IoStack; + PSCSI_REQUEST_BLOCK Request; + + // + // get PDO device extension + // + PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension; + + // + // sanity check + // + ASSERT(PDODeviceExtension->Common.IsFDO == FALSE); + + // + // get current stack location + // + IoStack = IoGetCurrentIrpStackLocation(Irp); + + // + // get request block + // + Request = (PSCSI_REQUEST_BLOCK)IoStack->Parameters.Others.Argument1; + + RtlZeroMemory(Request->DataBuffer, Request->DataTransferLength); + Request->SrbStatus = SRB_STATUS_SUCCESS; + Irp->IoStatus.Information = Request->DataTransferLength; + Irp->IoStatus.Status = STATUS_SUCCESS; + USBSTOR_QueueTerminateRequest(PDODeviceExtension->LowerDeviceObject, Irp); + IoCompleteRequest(Irp, IO_NO_INCREMENT); + + // + // start next request + // + USBSTOR_QueueNextRequest(PDODeviceExtension->LowerDeviceObject); + + return STATUS_SUCCESS; + +#if 0 + // + // get SCSI command data block + // + pCDB = (PCDB)Request->Cdb; + + // + // get PDO device extension + // + PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension; + + // + // allocate sense response from non paged pool + // + Response = (PUFI_CAPACITY_RESPONSE)AllocateItem(NonPagedPool, Request->DataTransferLength); + if (!Response) + { + // + // no memory + // + return STATUS_INSUFFICIENT_RESOURCES; + } + + // + // sanity check + // + + + // Supported pages + // MODE_PAGE_ERROR_RECOVERY + // MODE_PAGE_FLEXIBILE + // MODE_PAGE_LUN_MAPPING + // MODE_PAGE_FAULT_REPORTING + // MODE_SENSE_RETURN_ALL + + // + // initialize mode sense cmd + // + RtlZeroMemory(&Cmd, sizeof(UFI_INQUIRY_CMD)); + Cmd.Code = SCSIOP_MODE_SENSE; + Cmd.LUN = (PDODeviceExtension->LUN & MAX_LUN); + Cmd.PageCode = pCDB->MODE_SENSE.PageCode; + Cmd.PC = pCDB->MODE_SENSE.Pc; + Cmd.AllocationLength = HTONS(pCDB->MODE_SENSE.AllocationLength); + + DPRINT1("PageCode %x\n", pCDB->MODE_SENSE.PageCode); + DPRINT1("PC %x\n", pCDB->MODE_SENSE.Pc); + + // + // now send mode sense cmd + // + Status = USBSTOR_SendCBW(DeviceObject, UFI_SENSE_CMD_LEN, (PUCHAR)&Cmd, Request->DataTransferLength, &OutControl); + if (!NT_SUCCESS(Status)) + { + // + // failed to send CBW + // + DPRINT1("USBSTOR_SendCapacityCmd> USBSTOR_SendCBW failed with %x\n", Status); + FreeItem(Response); + ASSERT(FALSE); + return Status; + } + + // + // now send data block response + // + Status = USBSTOR_SendData(DeviceObject, Request->DataTransferLength, Response); + if (!NT_SUCCESS(Status)) + { + // + // failed to send CBW + // + DPRINT1("USBSTOR_SendCapacityCmd> USBSTOR_SendData failed with %x\n", Status); + FreeItem(Response); + ASSERT(FALSE); + return Status; + } + + Header = (PUFI_MODE_PARAMETER_HEADER)Response; + + // + // TODO: build layout + // + // first struct is the header + // MODE_PARAMETER_HEADER / _MODE_PARAMETER_HEADER10 + // + // followed by + // MODE_PARAMETER_BLOCK + // + // + UNIMPLEMENTED; + + // + // send csw + // + Status = USBSTOR_SendCSW(DeviceObject, OutControl, 512, &CSW); + + DPRINT1("------------------------\n"); + DPRINT1("CSW %p\n", &CSW); + DPRINT1("Signature %x\n", CSW.Signature); + DPRINT1("Tag %x\n", CSW.Tag); + DPRINT1("DataResidue %x\n", CSW.DataResidue); + DPRINT1("Status %x\n", CSW.Status); + + // + // FIXME: handle error + // + ASSERT(CSW.Status == 0); + ASSERT(CSW.DataResidue == 0); + + // + // calculate transfer length + // + *TransferBufferLength = Request->DataTransferLength - CSW.DataResidue; + + // + // copy buffer + // + RtlCopyMemory(Request->DataBuffer, Response, *TransferBufferLength); + + // + // free item + // + FreeItem(OutControl); + + // + // free response + // + FreeItem(Response); + + // + // done + // + return Status; +#endif +} + +NTSTATUS +USBSTOR_SendReadWrite( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp, + IN ULONG RetryCount) +{ + UFI_READ_WRITE_CMD Cmd; + PPDO_DEVICE_EXTENSION PDODeviceExtension; + PCDB pCDB; + ULONG BlockCount, Temp; + PIO_STACK_LOCATION IoStack; + PSCSI_REQUEST_BLOCK Request; + + // + // get current stack location + // + IoStack = IoGetCurrentIrpStackLocation(Irp); + + // + // get request block + // + Request = (PSCSI_REQUEST_BLOCK)IoStack->Parameters.Others.Argument1; + + // + // get SCSI command data block + // + pCDB = (PCDB)Request->Cdb; + + // + // get PDO device extension + // + PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension; + + // + // informal debug print + // + DPRINT("USBSTOR_SendReadWrite DataTransferLength %lu, BlockLength %lu\n", Request->DataTransferLength, PDODeviceExtension->BlockLength); + + // + // sanity check + // + ASSERT(PDODeviceExtension->BlockLength); + + // + // block count + // + BlockCount = Request->DataTransferLength / PDODeviceExtension->BlockLength; + + // + // initialize read cmd + // + RtlZeroMemory(&Cmd, sizeof(UFI_READ_WRITE_CMD)); + Cmd.Code = pCDB->AsByte[0]; + Cmd.LUN = (PDODeviceExtension->LUN & MAX_LUN); + Cmd.ContiguousLogicBlocksByte0 = pCDB->CDB10.TransferBlocksMsb; + Cmd.ContiguousLogicBlocksByte1 = pCDB->CDB10.TransferBlocksLsb; + Cmd.LogicalBlockByte0 = pCDB->CDB10.LogicalBlockByte0; + Cmd.LogicalBlockByte1 = pCDB->CDB10.LogicalBlockByte1; + Cmd.LogicalBlockByte2 = pCDB->CDB10.LogicalBlockByte2; + Cmd.LogicalBlockByte3 = pCDB->CDB10.LogicalBlockByte3; + + // + // sanity check + // + Temp = (Cmd.ContiguousLogicBlocksByte0 << 8 | Cmd.ContiguousLogicBlocksByte1); + ASSERT(Temp == BlockCount); + + DPRINT("USBSTOR_SendReadWrite BlockAddress %x%x%x%x BlockCount %lu BlockLength %lu\n", Cmd.LogicalBlockByte0, Cmd.LogicalBlockByte1, Cmd.LogicalBlockByte2, Cmd.LogicalBlockByte3, BlockCount, PDODeviceExtension->BlockLength); + + // + // send request + // + return USBSTOR_SendRequest(DeviceObject, Irp, UFI_READ_WRITE_CMD_LEN, (PUCHAR)&Cmd, Request->DataTransferLength, (PUCHAR)Request->DataBuffer, RetryCount); +} + +NTSTATUS +USBSTOR_SendTestUnit( + IN PDEVICE_OBJECT DeviceObject, + IN OUT PIRP Irp, + IN ULONG RetryCount) +{ + UFI_TEST_UNIT_CMD Cmd; + PPDO_DEVICE_EXTENSION PDODeviceExtension; + PIO_STACK_LOCATION IoStack; + PSCSI_REQUEST_BLOCK Request; + + // + // get current stack location + // + IoStack = IoGetCurrentIrpStackLocation(Irp); + + // + // get request block + // + Request = (PSCSI_REQUEST_BLOCK)IoStack->Parameters.Others.Argument1; + + // + // no transfer length + // + ASSERT(Request->DataTransferLength == 0); + + // + // get PDO device extension + // + PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension; + + // + // initialize test unit cmd + // + RtlZeroMemory(&Cmd, sizeof(UFI_TEST_UNIT_CMD)); + Cmd.Code = SCSIOP_TEST_UNIT_READY; + Cmd.LUN = (PDODeviceExtension->LUN & MAX_LUN); + + // + // send the request + // + return USBSTOR_SendRequest(DeviceObject, Irp, UFI_TEST_UNIT_CMD_LEN, (PUCHAR)&Cmd, 0, NULL, RetryCount); +} + +NTSTATUS +USBSTOR_SendUnknownRequest( + IN PDEVICE_OBJECT DeviceObject, + IN OUT PIRP Irp, + IN ULONG RetryCount) +{ + PPDO_DEVICE_EXTENSION PDODeviceExtension; + PIO_STACK_LOCATION IoStack; + PSCSI_REQUEST_BLOCK Request; + UFI_UNKNOWN_CMD Cmd; + + // + // get current stack location + // + IoStack = IoGetCurrentIrpStackLocation(Irp); + + // + // get request block + // + Request = IoStack->Parameters.Others.Argument1; + + // + // get PDO device extension + // + PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension; + + // + // check that we're sending to the right LUN + // + ASSERT(Request->Cdb[1] == (PDODeviceExtension->LUN & MAX_LUN)); + + // + // sanity check + // + ASSERT(Request->CdbLength <= sizeof(UFI_UNKNOWN_CMD)); + + // + // initialize test unit cmd + // + RtlCopyMemory(&Cmd, Request->Cdb, Request->CdbLength); + + // + // send the request + // + return USBSTOR_SendRequest(DeviceObject, Irp, Request->CdbLength, (PUCHAR)&Cmd, Request->DataTransferLength, Request->DataBuffer, RetryCount); +} + +NTSTATUS +USBSTOR_HandleExecuteSCSI( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp, + IN ULONG RetryCount) +{ + PCDB pCDB; + NTSTATUS Status; + PIO_STACK_LOCATION IoStack; + PSCSI_REQUEST_BLOCK Request; + PPDO_DEVICE_EXTENSION PDODeviceExtension; + + // + // get PDO device extension + // + PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension; + + // + // sanity check + // + ASSERT(PDODeviceExtension->Common.IsFDO == FALSE); + + // + // get current stack location + // + IoStack = IoGetCurrentIrpStackLocation(Irp); + + // + // get request block + // + Request = (PSCSI_REQUEST_BLOCK)IoStack->Parameters.Others.Argument1; + + // + // get SCSI command data block + // + pCDB = (PCDB)Request->Cdb; + + DPRINT("USBSTOR_HandleExecuteSCSI Operation Code %x\n", pCDB->AsByte[0]); + + if (pCDB->AsByte[0] == SCSIOP_READ_CAPACITY) + { + // + // sanity checks + // + ASSERT(Request->DataBuffer); + + DPRINT("SCSIOP_READ_CAPACITY Length %lu\n", Request->DataTransferLength); + Status = USBSTOR_SendCapacity(DeviceObject, Irp, RetryCount); + } + else if (pCDB->MODE_SENSE.OperationCode == SCSIOP_MODE_SENSE) + { + DPRINT("SCSIOP_MODE_SENSE DataTransferLength %lu\n", Request->DataTransferLength); + ASSERT(pCDB->MODE_SENSE.AllocationLength == Request->DataTransferLength); + ASSERT(Request->DataBuffer); + + // + // send mode sense command + // + Status = USBSTOR_SendModeSense(DeviceObject, Irp, RetryCount); + } + else if (pCDB->AsByte[0] == SCSIOP_READ_FORMATTED_CAPACITY) + { + DPRINT("SCSIOP_READ_FORMATTED_CAPACITY DataTransferLength %lu\n", Request->DataTransferLength); + + // + // send read format capacity + // + Status = USBSTOR_SendFormatCapacity(DeviceObject, Irp, RetryCount); + } + else if (pCDB->AsByte[0] == SCSIOP_INQUIRY) + { + DPRINT("SCSIOP_INQUIRY DataTransferLength %lu\n", Request->DataTransferLength); + + // + // send read format capacity + // + Status = USBSTOR_SendInquiry(DeviceObject, Irp, RetryCount); + } + else if (pCDB->MODE_SENSE.OperationCode == SCSIOP_READ || pCDB->MODE_SENSE.OperationCode == SCSIOP_WRITE) + { + DPRINT("SCSIOP_READ / SCSIOP_WRITE DataTransferLength %lu\n", Request->DataTransferLength); + + // + // send read / write command + // + Status = USBSTOR_SendReadWrite(DeviceObject, Irp, RetryCount); + } + else if (pCDB->AsByte[0] == SCSIOP_MEDIUM_REMOVAL) + { + DPRINT("SCSIOP_MEDIUM_REMOVAL\n"); + + // + // just complete the request + // + Request->SrbStatus = SRB_STATUS_SUCCESS; + Irp->IoStatus.Status = STATUS_SUCCESS; + Irp->IoStatus.Information = Request->DataTransferLength; + USBSTOR_QueueTerminateRequest(PDODeviceExtension->LowerDeviceObject, Irp); + IoCompleteRequest(Irp, IO_NO_INCREMENT); + + // + // start next request + // + USBSTOR_QueueNextRequest(PDODeviceExtension->LowerDeviceObject); + + return STATUS_SUCCESS; + } + else if (pCDB->MODE_SENSE.OperationCode == SCSIOP_TEST_UNIT_READY) + { + DPRINT("SCSIOP_TEST_UNIT_READY\n"); + + // + // send test unit command + // + Status = USBSTOR_SendTestUnit(DeviceObject, Irp, RetryCount); + } + else + { + // Unknown request. Simply forward + DPRINT1("Forwarding unknown Operation Code %x\n", pCDB->AsByte[0]); + Status = USBSTOR_SendUnknownRequest(DeviceObject, Irp, RetryCount); + } + + return Status; +} diff --git a/drivers/usb/usbstor_new/usbstor.c b/drivers/usb/usbstor_new/usbstor.c new file mode 100644 index 00000000000..b13969eddbb --- /dev/null +++ b/drivers/usb/usbstor_new/usbstor.c @@ -0,0 +1,295 @@ +/* + * PROJECT: ReactOS Universal Serial Bus Bulk Storage Driver + * LICENSE: GPL - See COPYING in the top level directory + * FILE: drivers/usb/usbstor/usbstor.c + * PURPOSE: USB block storage device driver. + * PROGRAMMERS: + * James Tabor + Johannes Anderwald + */ + +/* INCLUDES ******************************************************************/ + +#include "usbstor.h" + +#define NDEBUG +#include + +/* PUBLIC AND PRIVATE FUNCTIONS **********************************************/ + +NTSTATUS +NTAPI +USBSTOR_AddDevice( + IN PDRIVER_OBJECT DriverObject, + IN PDEVICE_OBJECT PhysicalDeviceObject) +{ + NTSTATUS Status; + PDEVICE_OBJECT DeviceObject; + PFDO_DEVICE_EXTENSION DeviceExtension; + + // + // lets create the device + // + Status = IoCreateDevice(DriverObject, sizeof(FDO_DEVICE_EXTENSION), 0, FILE_DEVICE_BUS_EXTENDER, FILE_AUTOGENERATED_DEVICE_NAME | FILE_DEVICE_SECURE_OPEN, FALSE, &DeviceObject); + + // + // check for success + // + if (!NT_SUCCESS(Status)) + { + DPRINT1("USBSTOR_AddDevice: Failed to create FDO Status %x\n", Status); + return Status; + } + + // + // get device extension + // + DeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension; + ASSERT(DeviceExtension); + + // + // zero device extension + // + RtlZeroMemory(DeviceExtension, sizeof(FDO_DEVICE_EXTENSION)); + + // + // initialize device extension + // + DeviceExtension->Common.IsFDO = TRUE; + DeviceExtension->FunctionalDeviceObject = DeviceObject; + DeviceExtension->PhysicalDeviceObject = PhysicalDeviceObject; + DeviceExtension->LowerDeviceObject = IoAttachDeviceToDeviceStack(DeviceObject, PhysicalDeviceObject); + + // + // init timer + // + IoInitializeTimer(DeviceObject, USBSTOR_TimerRoutine, (PVOID)DeviceExtension); + + // + // did attaching fail + // + if (!DeviceExtension->LowerDeviceObject) + { + // + // device removed + // + IoDeleteDevice(DeviceObject); + + return STATUS_DEVICE_REMOVED; + } + + // + // set device flags + // + DeviceObject->Flags |= DO_BUFFERED_IO | DO_POWER_PAGABLE; + + // + // device is initialized + // + DeviceObject->Flags &= ~DO_DEVICE_INITIALIZING; + + + // + // done + // + return STATUS_SUCCESS; +} + +VOID +NTAPI +USBSTOR_Unload( + PDRIVER_OBJECT DriverObject) +{ + // + // no-op + // +} + +NTSTATUS +NTAPI +USBSTOR_DispatchClose( + PDEVICE_OBJECT DeviceObject, + PIRP Irp) +{ + // + // function always succeeds ;) + // + DPRINT("USBSTOR_DispatchClose\n"); + Irp->IoStatus.Information = 0; + Irp->IoStatus.Status = STATUS_SUCCESS; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + return STATUS_SUCCESS; +} + + +NTSTATUS +NTAPI +USBSTOR_DispatchDeviceControl( + PDEVICE_OBJECT DeviceObject, + PIRP Irp) +{ + NTSTATUS Status; + + // + // handle requests + // + Status = USBSTOR_HandleDeviceControl(DeviceObject, Irp); + + // + // complete request + // + Irp->IoStatus.Status = Status; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + + // + // done + // + return Status; +} + + +NTSTATUS +NTAPI +USBSTOR_DispatchScsi( + PDEVICE_OBJECT DeviceObject, + PIRP Irp) +{ + // + // handle requests + // + return USBSTOR_HandleInternalDeviceControl(DeviceObject, Irp); +} + +NTSTATUS +NTAPI +USBSTOR_DispatchReadWrite( + PDEVICE_OBJECT DeviceObject, + PIRP Irp) +{ + // + // read write ioctl is not supported + // + Irp->IoStatus.Information = 0; + Irp->IoStatus.Status = STATUS_INVALID_PARAMETER; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + return STATUS_INVALID_PARAMETER; +} + +NTSTATUS +NTAPI +USBSTOR_DispatchPnp( + PDEVICE_OBJECT DeviceObject, + PIRP Irp) +{ + PUSBSTOR_COMMON_DEVICE_EXTENSION DeviceExtension; + + // + // get common device extension + // + DeviceExtension = (PUSBSTOR_COMMON_DEVICE_EXTENSION)DeviceObject->DeviceExtension; + + // + // is it for the FDO + // + if (DeviceExtension->IsFDO) + { + // + // dispatch pnp request to fdo pnp handler + // + return USBSTOR_FdoHandlePnp(DeviceObject, Irp); + } + else + { + // + // dispatch request to pdo pnp handler + // + return USBSTOR_PdoHandlePnp(DeviceObject, Irp); + } +} + +NTSTATUS +NTAPI +USBSTOR_DispatchPower( + PDEVICE_OBJECT DeviceObject, + PIRP Irp) +{ + PFDO_DEVICE_EXTENSION DeviceExtension; + + // get common device extension + DeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension; + + if (DeviceExtension->Common.IsFDO) + { + PoStartNextPowerIrp(Irp); + IoSkipCurrentIrpStackLocation(Irp); + return PoCallDriver(DeviceExtension->LowerDeviceObject, Irp); + } + else + { + PoStartNextPowerIrp(Irp); + Irp->IoStatus.Status = STATUS_SUCCESS; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + return STATUS_SUCCESS; + } +} + + + +NTSTATUS +NTAPI +DriverEntry( + IN PDRIVER_OBJECT DriverObject, + IN PUNICODE_STRING RegPath) +{ + + DPRINT("********* USB Storage *********\n"); + + // + // driver unload routine + // + DriverObject->DriverUnload = USBSTOR_Unload; + + // + // add device function + // + DriverObject->DriverExtension->AddDevice = USBSTOR_AddDevice; + + // + // driver start i/o routine + // + DriverObject->DriverStartIo = USBSTOR_StartIo; + + // + // create / close + // + DriverObject->MajorFunction[IRP_MJ_CREATE] = USBSTOR_DispatchClose; + DriverObject->MajorFunction[IRP_MJ_CLOSE] = USBSTOR_DispatchClose; + + // + // scsi pass through requests + // + DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = USBSTOR_DispatchDeviceControl; + + // + // irp dispatch read / write + // + DriverObject->MajorFunction[IRP_MJ_READ] = USBSTOR_DispatchReadWrite; + DriverObject->MajorFunction[IRP_MJ_WRITE] = USBSTOR_DispatchReadWrite; + + // + // scsi queue ioctl + // + DriverObject->MajorFunction[IRP_MJ_SCSI] = USBSTOR_DispatchScsi; + + // + // pnp processing + // + DriverObject->MajorFunction[IRP_MJ_PNP] = USBSTOR_DispatchPnp; + + // + // power processing + // + DriverObject->MajorFunction[IRP_MJ_POWER] = USBSTOR_DispatchPower; + + return STATUS_SUCCESS; +} diff --git a/drivers/usb/usbstor_new/usbstor.h b/drivers/usb/usbstor_new/usbstor.h new file mode 100644 index 00000000000..f477e9a1a04 --- /dev/null +++ b/drivers/usb/usbstor_new/usbstor.h @@ -0,0 +1,550 @@ +#ifndef _USBSTOR_H_ +#define _USBSTOR_H_ + +#include +#include +#include +#include +#include + +#define USB_STOR_TAG 'sbsu' +#define USB_MAXCHILDREN (16) + +#define HTONS(n) (((((unsigned short)(n) & 0xFF)) << 8) | (((unsigned short)(n) & 0xFF00) >> 8)) +#define NTOHS(n) (((((unsigned short)(n) & 0xFF)) << 8) | (((unsigned short)(n) & 0xFF00) >> 8)) + +#define HTONL(n) (((((unsigned long)(n) & 0xFF)) << 24) | \ + ((((unsigned long)(n) & 0xFF00)) << 8) | \ + ((((unsigned long)(n) & 0xFF0000)) >> 8) | \ + ((((unsigned long)(n) & 0xFF000000)) >> 24)) + + +#define NTOHL(n) (((((unsigned long)(n) & 0xFF)) << 24) | \ + ((((unsigned long)(n) & 0xFF00)) << 8) | \ + ((((unsigned long)(n) & 0xFF0000)) >> 8) | \ + ((((unsigned long)(n) & 0xFF000000)) >> 24)) + +#define USB_RECOVERABLE_ERRORS (USBD_STATUS_STALL_PID | USBD_STATUS_DEV_NOT_RESPONDING \ + | USBD_STATUS_ENDPOINT_HALTED | USBD_STATUS_NO_BANDWIDTH) + +typedef struct __COMMON_DEVICE_EXTENSION__ +{ + BOOLEAN IsFDO; + +}USBSTOR_COMMON_DEVICE_EXTENSION, *PUSBSTOR_COMMON_DEVICE_EXTENSION; + +typedef struct +{ + USBSTOR_COMMON_DEVICE_EXTENSION Common; // common device extension + + PDEVICE_OBJECT FunctionalDeviceObject; // functional device object + PDEVICE_OBJECT PhysicalDeviceObject; // physical device object + PDEVICE_OBJECT LowerDeviceObject; // lower device object + USB_BUS_INTERFACE_USBDI_V2 BusInterface; // bus interface of device + PUSB_DEVICE_DESCRIPTOR DeviceDescriptor; // usb device descriptor + PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor; // usb configuration descriptor + PUSB_STRING_DESCRIPTOR SerialNumber; // usb serial number + PUSBD_INTERFACE_INFORMATION InterfaceInformation; // usb interface information + USBD_CONFIGURATION_HANDLE ConfigurationHandle; // usb configuration handle + UCHAR BulkInPipeIndex; // bulk in pipe index + UCHAR BulkOutPipeIndex; // bulk out pipe index + UCHAR MaxLUN; // max lun for device + PDEVICE_OBJECT ChildPDO[16]; // max 16 child pdo devices + KSPIN_LOCK IrpListLock; // irp list lock + LIST_ENTRY IrpListHead; // irp list head + BOOLEAN IrpListFreeze; // if true the irp list is freezed + BOOLEAN ResetInProgress; // if hard reset is in progress + ULONG IrpPendingCount; // count of irp pending + PSCSI_REQUEST_BLOCK ActiveSrb; // stores the current active SRB + KEVENT NoPendingRequests; // set if no pending or in progress requests + PSCSI_REQUEST_BLOCK LastTimerActiveSrb; // last timer tick active srb + ULONG SrbErrorHandlingActive; // error handling of srb is activated + ULONG TimerWorkQueueEnabled; // timer work queue enabled + ULONG InstanceCount; // pdo instance count +}FDO_DEVICE_EXTENSION, *PFDO_DEVICE_EXTENSION; + +typedef struct +{ + USBSTOR_COMMON_DEVICE_EXTENSION Common; + PDEVICE_OBJECT LowerDeviceObject; // points to FDO + UCHAR LUN; // lun id + PVOID InquiryData; // USB SCSI inquiry data + PUCHAR FormatData; // USB SCSI Read Format Capacity Data + UCHAR Claimed; // indicating if it has been claimed by upper driver + ULONG BlockLength; // length of block + ULONG LastLogicBlockAddress; // last block address + PDEVICE_OBJECT *PDODeviceObject; // entry in pdo list + PDEVICE_OBJECT Self; // self + UCHAR MediumTypeCode; // floppy medium type code + UCHAR IsFloppy; // is device floppy +}PDO_DEVICE_EXTENSION, *PPDO_DEVICE_EXTENSION; + +// +// max lun command identifier +// +#define USB_BULK_GET_MAX_LUN 0xFE +#define USB_BULK_RESET_DEVICE 0xFF + +#include +typedef struct +{ + ULONG Signature; // CBW signature + ULONG Tag; // CBW Tag of operation + ULONG DataTransferLength; // data transfer length + UCHAR Flags; // CBW Flags endpoint direction + UCHAR LUN; // lun unit + UCHAR CommandBlockLength; // Command block length + UCHAR CommandBlock[16]; +}CBW, *PCBW; + +C_ASSERT(sizeof(CBW) == 31); + + +#define CBW_SIGNATURE 0x43425355 +#define CSW_SIGNATURE 0x53425355 + +#define MAX_LUN 0xF + +typedef struct +{ + ULONG Signature; // CSW signature + ULONG Tag; // CSW tag + ULONG DataResidue; // CSW data transfer diff + UCHAR Status; // CSW status +}CSW, *PCSW; + +//-------------------------------------------------------------------------------------------------------------------------------------------- +// +// UFI INQUIRY command +// +typedef struct +{ + UCHAR Code; // operation code 0x12 + UCHAR LUN; // lun address + UCHAR PageCode; // product data information, always 0x00 + UCHAR Reserved; // reserved 0x00 + UCHAR AllocationLength; // length of inquiry data to be returned, default 36 bytes + UCHAR Reserved1[7]; //reserved bytes 0x00 +}UFI_INQUIRY_CMD, *PUFI_INQUIRY_CMD; + +C_ASSERT(sizeof(UFI_INQUIRY_CMD) == 12); + +#define UFI_INQUIRY_CMD_LEN 0x6 + +// +// UFI INQUIRY command response +// +typedef struct +{ + UCHAR DeviceType; // device type + UCHAR RMB; // removable media bit + UCHAR Version; // contains version 0x00 + UCHAR Format; // response format + UCHAR Length; // additional length + UCHAR Reserved[3]; // reserved + UCHAR Vendor[8]; // vendor identification string + UCHAR Product[16]; // product identification string + UCHAR Revision[4]; // product revision code +}UFI_INQUIRY_RESPONSE, *PUFI_INQUIRY_RESPONSE; + +C_ASSERT(sizeof(UFI_INQUIRY_RESPONSE) == 36); + +//-------------------------------------------------------------------------------------------------------------------------------------------- +// +// UFI read cmd +// +typedef struct +{ + UCHAR Code; // operation code + UCHAR LUN; // lun + UCHAR LogicalBlockByte0; // lba byte 0 + UCHAR LogicalBlockByte1; // lba byte 1 + UCHAR LogicalBlockByte2; // lba byte 2 + UCHAR LogicalBlockByte3; // lba byte 3 + UCHAR Reserved; // reserved 0x00 + UCHAR ContiguousLogicBlocksByte0; // msb contiguous logic blocks byte + UCHAR ContiguousLogicBlocksByte1; // msb contiguous logic blocks + UCHAR Reserved1[3]; // reserved 0x00 +}UFI_READ_WRITE_CMD; + +C_ASSERT(sizeof(UFI_READ_WRITE_CMD) == 12); + +#define UFI_READ_WRITE_CMD_LEN (0xA) + +//-------------------------------------------------------------------------------------------------------------------------------------------- +// +// UFI read capacity cmd +// +typedef struct +{ + UCHAR Code; // operation code 0x25 + UCHAR LUN; // lun address + UCHAR LBA[4]; // logical block address, should be zero + UCHAR Reserved1[2]; // reserved 0x00 + UCHAR PMI; // PMI = 0x00 + UCHAR Reserved2[3]; // reserved 0x00 +}UFI_CAPACITY_CMD, *PUFI_CAPACITY_CMD; + +C_ASSERT(sizeof(UFI_CAPACITY_CMD) == 12); + +#define UFI_CAPACITY_CMD_LEN 0xA //FIXME support length 16 too if requested + +// +// UFI Read Capacity command response +// +typedef struct +{ + ULONG LastLogicalBlockAddress; // last logical block address + ULONG BlockLength; // block length in bytes +}UFI_CAPACITY_RESPONSE, *PUFI_CAPACITY_RESPONSE; + +#define UFI_READ_CAPACITY_CMD_LEN 0xA +C_ASSERT(sizeof(UFI_CAPACITY_RESPONSE) == 8); + +//-------------------------------------------------------------------------------------------------------------------------------------------- +// +// UFI sense mode cmd +// +typedef struct +{ + UCHAR Code; // operation code + UCHAR LUN; // lun address + UCHAR PageCode:6; // page code selector + UCHAR PC:2; // type of parameters to be returned + UCHAR Reserved[4]; // reserved 0x00 + USHORT AllocationLength; // parameters length + UCHAR Reserved1[3]; +}UFI_SENSE_CMD, *PUFI_SENSE_CMD; + +C_ASSERT(sizeof(UFI_SENSE_CMD) == 12); + +#define UFI_SENSE_CMD_LEN (6) + +typedef struct +{ + USHORT ModeDataLength; // length of parameters for sense cmd + UCHAR MediumTypeCode; // 00 for mass storage, 0x94 for floppy + UCHAR WP:1; // write protect bit + UCHAR Reserved1:2; // reserved 00 + UCHAR DPOFUA:1; // should be zero + UCHAR Reserved2:4; // reserved + UCHAR Reserved[4]; // reserved +}UFI_MODE_PARAMETER_HEADER, *PUFI_MODE_PARAMETER_HEADER; + + +C_ASSERT(sizeof(UFI_MODE_PARAMETER_HEADER) == 8); + +typedef struct +{ + UCHAR PC; + UCHAR PageLength; + UCHAR Reserved1; + UCHAR ITM; + UCHAR Flags; + UCHAR Reserved[3]; +}UFI_TIMER_PROTECT_PAGE, *PUFI_TIMER_PROTECT_PAGE; +C_ASSERT(sizeof(UFI_TIMER_PROTECT_PAGE) == 8); + +//-------------------------------------------------------------------------------------------------------------------------------------------- +// +// UFI read capacity cmd +// + +typedef struct +{ + UCHAR Code; + UCHAR LUN; + UCHAR Reserved[5]; + UCHAR AllocationLengthMsb; + UCHAR AllocationLengthLsb; + UCHAR Reserved1[3]; +}UFI_READ_FORMAT_CAPACITY, *PUFI_READ_FORMAT_CAPACITY; + +C_ASSERT(sizeof(UFI_READ_FORMAT_CAPACITY) == 12); + +#define UFI_READ_FORMAT_CAPACITY_CMD_LEN (10) + +typedef struct +{ + UCHAR Reserved1; + UCHAR Reserved2; + UCHAR Reserved3; + UCHAR CapacityLength; +}UFI_CAPACITY_FORMAT_HEADER, *PUFI_CAPACITY_FORMAT_HEADER; + +C_ASSERT(sizeof(UFI_CAPACITY_FORMAT_HEADER) == 4); + +typedef struct +{ + ULONG BlockCount; + UCHAR Code; + UCHAR BlockLengthByte0; + UCHAR BlockLengthByte1; + UCHAR BlockLengthByte2; +}UFI_CAPACITY_DESCRIPTOR, *PUFI_CAPACITY_DESCRIPTOR; + +#define UNFORMATTED_MEDIA_CODE_DESCRIPTORY_TYPE (1) +#define FORMAT_MEDIA_CODE_DESCRIPTOR_TYPE (2) +#define CARTRIDGE_MEDIA_CODE_DESCRIPTOR_TYPE (3) + + + + +//-------------------------------------------------------------------------------------------------------------------------------------------- +// +// UFI test unit command +// + +typedef struct +{ + UCHAR Code; // operation code 0x00 + UCHAR LUN; // lun + UCHAR Reserved[10]; // reserved 0x00 +}UFI_TEST_UNIT_CMD, *PUFI_TEST_UNIT_CMD; + +C_ASSERT(sizeof(UFI_TEST_UNIT_CMD) == 12); + +#define UFI_TEST_UNIT_CMD_LEN (6) + +//------------------------------------------------------------------------------------------------------------------------------------------- +typedef struct +{ + UCHAR Bytes[16]; +}UFI_UNKNOWN_CMD, *PUFI_UNKNOWN_CMD; + +typedef struct +{ + union + { + PCBW cbw; + PCSW csw; + }; + URB Urb; + PIRP Irp; + ULONG TransferDataLength; + PUCHAR TransferData; + PFDO_DEVICE_EXTENSION FDODeviceExtension; + PPDO_DEVICE_EXTENSION PDODeviceExtension; + PMDL TransferBufferMDL; + ULONG ErrorIndex; + ULONG RetryCount; +}IRP_CONTEXT, *PIRP_CONTEXT; + +typedef struct _ERRORHANDLER_WORKITEM_DATA +{ + PDEVICE_OBJECT DeviceObject; + PIRP_CONTEXT Context; + WORK_QUEUE_ITEM WorkQueueItem; + PIRP Irp; +} ERRORHANDLER_WORKITEM_DATA, *PERRORHANDLER_WORKITEM_DATA; + + +//--------------------------------------------------------------------- +// +// fdo.c routines +// +NTSTATUS +USBSTOR_FdoHandlePnp( + IN PDEVICE_OBJECT DeviceObject, + IN OUT PIRP Irp); + +//--------------------------------------------------------------------- +// +// pdo.c routines +// +NTSTATUS +USBSTOR_PdoHandlePnp( + IN PDEVICE_OBJECT DeviceObject, + IN OUT PIRP Irp); + +NTSTATUS +USBSTOR_CreatePDO( + IN PDEVICE_OBJECT DeviceObject, + IN UCHAR LUN); + +//--------------------------------------------------------------------- +// +// misc.c routines +// +NTSTATUS +NTAPI +USBSTOR_SyncForwardIrp( + IN PDEVICE_OBJECT DeviceObject, + IN OUT PIRP Irp); + +NTSTATUS +NTAPI +USBSTOR_GetBusInterface( + IN PDEVICE_OBJECT DeviceObject, + OUT PUSB_BUS_INTERFACE_USBDI_V2 BusInterface); + +PVOID +AllocateItem( + IN POOL_TYPE PoolType, + IN ULONG ItemSize); + +VOID +FreeItem( + IN PVOID Item); + +NTSTATUS +USBSTOR_SyncUrbRequest( + IN PDEVICE_OBJECT DeviceObject, + OUT PURB UrbRequest); + +NTSTATUS +USBSTOR_GetMaxLUN( + IN PDEVICE_OBJECT DeviceObject, + IN PFDO_DEVICE_EXTENSION DeviceExtension); + +NTSTATUS +NTAPI +USBSTOR_SyncForwardIrpCompletionRoutine( + PDEVICE_OBJECT DeviceObject, + PIRP Irp, + PVOID Context); + +NTSTATUS +USBSTOR_ResetDevice( + IN PDEVICE_OBJECT DeviceObject, + IN PFDO_DEVICE_EXTENSION DeviceExtension); + +BOOLEAN +USBSTOR_IsFloppy( + IN PUCHAR Buffer, + IN ULONG BufferLength, + OUT PUCHAR MediumTypeCode); + +//--------------------------------------------------------------------- +// +// descriptor.c routines +// + +NTSTATUS +USBSTOR_GetDescriptors( + IN PDEVICE_OBJECT DeviceObject); + +NTSTATUS +USBSTOR_SelectConfigurationAndInterface( + IN PDEVICE_OBJECT DeviceObject, + IN PFDO_DEVICE_EXTENSION DeviceExtension); + +NTSTATUS +USBSTOR_GetPipeHandles( + IN PFDO_DEVICE_EXTENSION DeviceExtension); + +//--------------------------------------------------------------------- +// +// scsi.c routines +// +NTSTATUS +USBSTOR_HandleExecuteSCSI( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp, + IN ULONG RetryCount); + +NTSTATUS +NTAPI +USBSTOR_CSWCompletionRoutine( + PDEVICE_OBJECT DeviceObject, + PIRP Irp, + PVOID Ctx); + +NTSTATUS +USBSTOR_SendCBW( + PIRP_CONTEXT Context, + PIRP Irp); + +VOID +USBSTOR_SendCSW( + PIRP_CONTEXT Context, + PIRP Irp); + + +//--------------------------------------------------------------------- +// +// disk.c routines +// +NTSTATUS +USBSTOR_HandleInternalDeviceControl( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp); + +NTSTATUS +USBSTOR_HandleDeviceControl( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp); + +//--------------------------------------------------------------------- +// +// queue.c routines +// +VOID +NTAPI +USBSTOR_StartIo( + PDEVICE_OBJECT DeviceObject, + PIRP Irp); + +VOID +USBSTOR_QueueWaitForPendingRequests( + IN PDEVICE_OBJECT DeviceObject); + +VOID +USBSTOR_QueueRelease( + IN PDEVICE_OBJECT DeviceObject); + +BOOLEAN +USBSTOR_QueueAddIrp( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp); + +VOID +NTAPI +USBSTOR_CancelIo( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp); + +VOID +USBSTOR_QueueInitialize( + PFDO_DEVICE_EXTENSION FDODeviceExtension); + +VOID +NTAPI +ErrorHandlerWorkItemRoutine( + PVOID Context); + +VOID +NTAPI +ResetHandlerWorkItemRoutine( + PVOID Context); + + + +VOID +USBSTOR_QueueNextRequest( + IN PDEVICE_OBJECT DeviceObject); + +VOID +USBSTOR_QueueTerminateRequest( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp); + +/* error.c */ +NTSTATUS +USBSTOR_GetEndpointStatus( + IN PDEVICE_OBJECT DeviceObject, + IN UCHAR bEndpointAddress, + OUT PUSHORT Value); + +NTSTATUS +USBSTOR_ResetPipeWithHandle( + IN PDEVICE_OBJECT DeviceObject, + IN USBD_PIPE_HANDLE PipeHandle); + +VOID +NTAPI +USBSTOR_TimerRoutine( + PDEVICE_OBJECT DeviceObject, + PVOID Context); + +#endif /* _USBSTOR_H_ */ diff --git a/drivers/usb/usbstor_new/usbstor.rc b/drivers/usb/usbstor_new/usbstor.rc new file mode 100644 index 00000000000..c2bbbb11892 --- /dev/null +++ b/drivers/usb/usbstor_new/usbstor.rc @@ -0,0 +1,5 @@ +#define REACTOS_VERSION_DLL +#define REACTOS_STR_FILE_DESCRIPTION "USB Storage Device Driver" +#define REACTOS_STR_INTERNAL_NAME "usbstor" +#define REACTOS_STR_ORIGINAL_FILENAME "usbstor.sys" +#include