Index: drivers/usb/usbehci/hardware.cpp =================================================================== --- drivers/usb/usbehci/hardware.cpp (revision 70555) +++ drivers/usb/usbehci/hardware.cpp (working copy) @@ -107,6 +107,9 @@ // write register VOID EHCI_WRITE_REGISTER_ULONG(ULONG Offset, ULONG Value); + + PVOID m_DoubleBuffer; + ULONG m_DoublePhysBuffer; }; //================================================================================================= @@ -302,6 +305,7 @@ NTSTATUS Status; UCHAR Value; UCHAR PortCount; + PHYSICAL_ADDRESS HighestAddress = {{0xFFFFFFFF, 0}}; DPRINT("CUSBHardwareDevice::PnpStart\n"); for(Index = 0; Index < TranslatedResources->List[0].PartialResourceList.Count; Index++) @@ -420,6 +424,20 @@ DeviceDescription.InterfaceType = PCIBus; DeviceDescription.MaximumLength = MAXULONG; + // create doublebuffer for transfers + + //FIXME: relation <- (usbstor\disk.c:USBSTOR_HandleQueryProperty()) AdapterDescriptor->MaximumPhysicalPages = 25; //FIXME compute some sane value + m_DoubleBuffer = MmAllocateContiguousMemory(25 * PAGE_SIZE, HighestAddress); + if ( !m_DoubleBuffer ) + { + DPRINT1("PnpStart: Not created DoubleBuffer!\n"); + Status = STATUS_INSUFFICIENT_RESOURCES; + return Status; + } + RtlZeroMemory((PVOID)m_DoubleBuffer, 25 * PAGE_SIZE); //need ? + + m_DoublePhysBuffer = MmGetPhysicalAddress(m_DoubleBuffer).LowPart; + // // get dma adapter // @@ -476,7 +494,7 @@ // // Initialize the UsbQueue now that we have an AdapterObject. // - Status = m_UsbQueue->Initialize(PUSBHARDWAREDEVICE(this), m_Adapter, m_MemoryManager, &m_Lock); + Status = m_UsbQueue->Initialize(PUSBHARDWAREDEVICE(this), m_Adapter, m_MemoryManager, m_DoubleBuffer, m_DoublePhysBuffer, &m_Lock); if (!NT_SUCCESS(Status)) { DPRINT1("Failed to Initialize the UsbQueue\n"); Index: drivers/usb/usbehci/usb_queue.cpp =================================================================== --- drivers/usb/usbehci/usb_queue.cpp (revision 70555) +++ drivers/usb/usbehci/usb_queue.cpp (working copy) @@ -94,6 +94,9 @@ // contains the periodic queue heads LIST_ENTRY m_PeriodicQueueHeads; + + PVOID m_DoubleBuffer; + ULONG m_DoublePhysBuffer; }; //================================================================================================= @@ -121,6 +124,8 @@ IN PUSBHARDWAREDEVICE Hardware, IN PDMA_ADAPTER AdapterObject, IN PDMAMEMORYMANAGER MemManager, + IN PVOID DoubleBuffer, + IN ULONG DoublePhysBuffer, IN OPTIONAL PKSPIN_LOCK Lock) { NTSTATUS Status = STATUS_SUCCESS; @@ -129,6 +134,14 @@ ASSERT(Hardware); + DPRINT("Initialize: DoubleBuffer - %p, Len - 0x18000, DoublePhysBuffer - %p\n", DoubleBuffer, DoublePhysBuffer); + + m_DoubleBuffer = DoubleBuffer; + ASSERT(m_DoubleBuffer); + + m_DoublePhysBuffer = DoublePhysBuffer; + ASSERT(m_DoublePhysBuffer); + // // store device lock // @@ -360,7 +373,7 @@ NTSTATUS Status; *OutRequest = NULL; - Status = InternalCreateUSBRequest(&UsbRequest); + Status = InternalCreateUSBRequest(&UsbRequest, m_DoubleBuffer, m_DoublePhysBuffer); if (NT_SUCCESS(Status)) { Index: drivers/usb/usbehci/usb_request.cpp =================================================================== --- drivers/usb/usbehci/usb_request.cpp (revision 70555) +++ drivers/usb/usbehci/usb_request.cpp (working copy) @@ -45,6 +45,7 @@ UCHAR InternalGetPidDirection(); NTSTATUS BuildControlTransferQueueHead(PQUEUE_HEAD * OutHead); NTSTATUS BuildBulkInterruptTransferQueueHead(PQUEUE_HEAD * OutHead); + NTSTATUS BuildBulkInterruptDataTransferQueueHead(PQUEUE_HEAD * OutHead); NTSTATUS STDMETHODCALLTYPE CreateDescriptor(PQUEUE_TRANSFER_DESCRIPTOR *OutDescriptor); NTSTATUS CreateQueueHead(PQUEUE_HEAD *OutQueueHead); UCHAR STDMETHODCALLTYPE GetDeviceAddress(); @@ -135,6 +136,8 @@ // device speed USB_DEVICE_SPEED m_Speed; + PVOID m_DoubleBuffer; + ULONG m_DoublePhysBuffer; }; //---------------------------------------------------------------------------------------- @@ -147,6 +150,13 @@ return STATUS_UNSUCCESSFUL; } +VOID +CUSBRequest::GetDoubleBuffer(PVOID DoubleBuffer, ULONG DoublePhysBuffer) +{ + m_DoubleBuffer = DoubleBuffer; + m_DoublePhysBuffer = DoublePhysBuffer; +} + //---------------------------------------------------------------------------------------- NTSTATUS STDMETHODCALLTYPE @@ -306,6 +316,13 @@ m_TransferBufferMDL = Urb->UrbBulkOrInterruptTransfer.TransferBufferMDL; } + if (!(Urb->UrbBulkOrInterruptTransfer.TransferFlags & USBD_TRANSFER_DIRECTION_IN)) + { + RtlCopyMemory((PVOID)((ULONG_PTR)m_DoubleBuffer + m_TransferBufferMDL->ByteOffset), + (PVOID)((ULONG_PTR)m_TransferBufferMDL->StartVa + m_TransferBufferMDL->ByteOffset), + Urb->UrbBulkOrInterruptTransfer.TransferBufferLength); + } + // // save buffer length // @@ -408,6 +425,13 @@ Urb->UrbBulkOrInterruptTransfer.TransferBufferLength = InternalCalculateTransferLength(); } + if (Urb->UrbBulkOrInterruptTransfer.TransferFlags & USBD_TRANSFER_DIRECTION_IN) + { + RtlCopyMemory((PVOID)((ULONG_PTR)m_TransferBufferMDL->StartVa + m_TransferBufferMDL->ByteOffset), + (PVOID)((ULONG_PTR)m_DoubleBuffer + m_TransferBufferMDL->ByteOffset), + Urb->UrbBulkOrInterruptTransfer.TransferBufferLength); + } + DPRINT("Request %p Completing Irp %p NtStatusCode %x UrbStatusCode %x Transferred Length %lu\n", this, m_Irp, NtStatusCode, UrbStatusCode, Urb->UrbBulkOrInterruptTransfer.TransferBufferLength); // @@ -450,7 +474,7 @@ break; case USB_ENDPOINT_TYPE_INTERRUPT: case USB_ENDPOINT_TYPE_BULK: - Status = BuildBulkInterruptTransferQueueHead(OutHead); + Status = BuildBulkInterruptDataTransferQueueHead(OutHead);//BuildBulkInterruptTransferQueueHead break; case USB_ENDPOINT_TYPE_ISOCHRONOUS: DPRINT1("USB_ENDPOINT_TYPE_ISOCHRONOUS not implemented\n"); @@ -1215,6 +1239,252 @@ return STATUS_SUCCESS; } +NTSTATUS +CUSBRequest::BuildBulkInterruptDataTransferQueueHead( + PQUEUE_HEAD * OutHead) +{ + PQUEUE_TRANSFER_DESCRIPTOR FirstDescriptor; + PQUEUE_TRANSFER_DESCRIPTOR LastDescriptor; + PQUEUE_TRANSFER_DESCRIPTOR CurrentDescriptor; + PQUEUE_TRANSFER_DESCRIPTOR PreviousDescriptor = NULL; + PHYSICAL_ADDRESS Address; + PQUEUE_HEAD QueueHead; + NTSTATUS Status; + PVOID Base; + ULONG DescriptorLength; + ULONG ChainDescriptorLength; + ULONG MaxPacketSize = 0; + ULONG MaxTransferLength; + ULONG TransferSize; + PVOID TransferBuffer; + ULONG TransferBufferOffset = 0; + ULONG BufferLength; + ULONG Index; + ULONG Length = 0; + ULONG PageOffset; + UCHAR InitialDataToggle; + + + // Allocate the queue head + Status = CreateQueueHead(&QueueHead); + + if (!NT_SUCCESS(Status)) + { + // failed to allocate queue heads + return STATUS_INSUFFICIENT_RESOURCES; + } + + // sanity checks + PC_ASSERT(QueueHead); + PC_ASSERT(m_TransferBufferLength); + + if (!m_Base) + { + // get virtual base of mdl + m_Base = MmGetSystemAddressForMdlSafe(m_TransferBufferMDL, NormalPagePriority); + } + + // Increase the size of last transfer, 0 in case this is the first + Base = (PVOID)((ULONG_PTR)m_Base + m_TransferBufferLengthCompleted); + + // sanity check + PC_ASSERT(m_EndpointDescriptor); + PC_ASSERT(Base); + ASSERT(m_EndpointDescriptor); + + InitialDataToggle = m_EndpointDescriptor->DataToggle; + + // use 4 * PAGE_SIZE at max for each new request + MaxTransferLength = min(4 * PAGE_SIZE, m_TransferBufferLength - m_TransferBufferLengthCompleted); + + // build bulk transfer descriptor chain + + if (m_EndpointDescriptor) // is there an endpoint descriptor + { + // use endpoint packet size + MaxPacketSize = m_EndpointDescriptor->EndPointDescriptor.wMaxPacketSize; + } + + do + { + // allocate transfer descriptor + Status = CreateDescriptor(&CurrentDescriptor); + if (!NT_SUCCESS(Status)) + { + // failed to allocate transfer descriptor + return STATUS_INSUFFICIENT_RESOURCES; + } + + if (MaxPacketSize) + { + // transfer size is minimum available buffer or endpoint size + TransferSize = min(MaxTransferLength - TransferBufferOffset, MaxPacketSize); + } + else + { + // use available buffer + TransferSize = MaxTransferLength - TransferBufferOffset; + } + + ASSERT(TransferSize); // sanity check + + // now init the descriptor + TransferBuffer = (PVOID)((ULONG_PTR)Base + TransferBufferOffset); + + // init transfer descriptor + CurrentDescriptor->Token.Bits.PIDCode = InternalGetPidDirection(); + CurrentDescriptor->Token.Bits.TotalBytesToTransfer = 0; + CurrentDescriptor->Token.Bits.DataToggle = InitialDataToggle; + + // store buffers + + Index = 0; + ULONG PageNumber = 0; + + do + { + // store physical address of buffer + + Length = 0; + + // if transfer size >= 4096 (1 and more pages) + if (m_TransferBufferLength >= PAGE_SIZE) + { + PageNumber = (m_TransferBufferLengthCompleted >> PAGE_SHIFT) & 0x0000001F; + + if ( (PageNumber == 0) && (m_TransferBufferMDL->ByteOffset > 0) ) + Address.LowPart = m_DoublePhysBuffer + TransferBufferOffset + m_TransferBufferMDL->ByteOffset; + else + Address.LowPart = m_DoublePhysBuffer + TransferBufferOffset + PageNumber * PAGE_SIZE; + } + else + { + // if transfer size < 4096 (< 1 page) + Address.LowPart = m_DoublePhysBuffer + TransferBufferOffset + m_TransferBufferMDL->ByteOffset; + } + + if (Address.LowPart == 0) + { + // error + return STATUS_UNSUCCESSFUL; + } + + // use physical address + CurrentDescriptor->BufferPointer[Index] = Address.LowPart; + CurrentDescriptor->ExtendedBufferPointer[Index] = 0;//Address.HighPart; + + // Get the offset from page size + PageOffset = BYTE_OFFSET(CurrentDescriptor->BufferPointer[Index]); + + if (PageOffset != 0) + { + // move to next page + TransferBuffer = (PVOID)ROUND_TO_PAGES(TransferBuffer); + } + else + { + // move to next page + TransferBuffer = (PVOID)((ULONG_PTR)TransferBuffer + PAGE_SIZE); + } + + // calculate buffer length + BufferLength = min(TransferSize, PAGE_SIZE - PageOffset); + + // increment transfer bytes + CurrentDescriptor->Token.Bits.TotalBytesToTransfer += BufferLength; + CurrentDescriptor->TotalBytesToTransfer += BufferLength; + + Length += BufferLength; + + DPRINT("Index %lu TransferSize %lu PageOffset %x BufferLength %lu Buffer Phy %p TransferBuffer %p\n", + Index, TransferSize, PageOffset, BufferLength, CurrentDescriptor->BufferPointer[Index], TransferBuffer); + + TransferSize -= BufferLength; // decrement available byte count + + if (TransferSize == 0) + { + break; // end reached + } + + if (Index > 1) // sanity check + { + // no equal buffers + ASSERT(CurrentDescriptor->BufferPointer[Index] != CurrentDescriptor->BufferPointer[Index-1]); + } + + Index++; // next descriptor index + PageNumber++; + + } while (Index < 5); + + // store result + DescriptorLength = Length; + + // insert into queue head + InsertTailList(&QueueHead->TransferDescriptorListHead, &CurrentDescriptor->DescriptorEntry); + + // adjust offset + TransferBufferOffset += DescriptorLength; + + if (PreviousDescriptor) + { + // link to current descriptor + PreviousDescriptor->NextPointer = CurrentDescriptor->PhysicalAddr; + PreviousDescriptor = CurrentDescriptor; + } + else + { + // first descriptor in chain + PreviousDescriptor = FirstDescriptor = CurrentDescriptor; + } + + InitialDataToggle = !InitialDataToggle; // flip data toggle + + if(TransferBufferOffset == MaxTransferLength) + { + break; // end reached + } + + } while(TRUE); + + // store last descriptor + LastDescriptor = CurrentDescriptor; + + // store result data toggle + m_EndpointDescriptor->DataToggle = InitialDataToggle; + + // store offset + ChainDescriptorLength = TransferBufferOffset; + + //Status = STATUS_SUCCESS; + + // move to next offset + m_TransferBufferLengthCompleted += ChainDescriptorLength; + + // init queue head + QueueHead->EndPointCharacteristics.DeviceAddress = GetDeviceAddress(); + QueueHead->EndPointCharacteristics.EndPointNumber = m_EndpointDescriptor->EndPointDescriptor.bEndpointAddress & 0x0F; + QueueHead->EndPointCharacteristics.MaximumPacketLength = m_EndpointDescriptor->EndPointDescriptor.wMaxPacketSize; + + QueueHead->NextPointer = FirstDescriptor->PhysicalAddr; + QueueHead->CurrentLinkPointer = FirstDescriptor->PhysicalAddr; + QueueHead->AlternateNextPointer = TERMINATE_POINTER; + + ASSERT(QueueHead->EndPointCharacteristics.DeviceAddress); + ASSERT(QueueHead->EndPointCharacteristics.EndPointNumber); + ASSERT(QueueHead->EndPointCharacteristics.MaximumPacketLength); + ASSERT(QueueHead->NextPointer); + + // interrupt on last descriptor + LastDescriptor->Token.Bits.InterruptOnComplete = TRUE; + + *OutHead = QueueHead; // store result + + //DumpQueueHead(QueueHead); // dump status + + return STATUS_SUCCESS; // done +} + //---------------------------------------------------------------------------------------- NTSTATUS STDMETHODCALLTYPE @@ -1802,7 +2072,7 @@ NTSTATUS NTAPI InternalCreateUSBRequest( - PUSBREQUEST *OutRequest) + PUSBREQUEST *OutRequest, PVOID DoubleBuffer, ULONG DoublePhysBuffer) { PUSBREQUEST This; @@ -1823,6 +2093,8 @@ // This->AddRef(); + This->GetDoubleBuffer(DoubleBuffer, DoublePhysBuffer); + // // return result // Index: drivers/usb/usbehci/usbehci.h =================================================================== --- drivers/usb/usbehci/usbehci.h (revision 70555) +++ drivers/usb/usbehci/usbehci.h (working copy) @@ -31,6 +31,6 @@ // // usb_request.cpp // -NTSTATUS NTAPI InternalCreateUSBRequest(PUSBREQUEST *OutRequest); +NTSTATUS NTAPI InternalCreateUSBRequest(PUSBREQUEST *OutRequest, PVOID DoubleBuffer, ULONG DoublePhysBuffer); #endif /* USBEHCI_H__ */ Index: drivers/usb/usbhub/fdo.c =================================================================== --- drivers/usb/usbhub/fdo.c (revision 70555) +++ drivers/usb/usbhub/fdo.c (working copy) @@ -12,7 +12,7 @@ #include -#define NDEBUG +//#define NDEBUG #include NTSTATUS Index: drivers/usb/usbhub/pdo.c =================================================================== --- drivers/usb/usbhub/pdo.c (revision 70555) +++ drivers/usb/usbhub/pdo.c (working copy) @@ -13,7 +13,7 @@ #include -#define NDEBUG +//#define NDEBUG #include #define IO_METHOD_FROM_CTL_CODE(ctlCode) (ctlCode&0x00000003) Index: drivers/usb/usbohci/hardware.cpp =================================================================== --- drivers/usb/usbohci/hardware.cpp (revision 70555) +++ drivers/usb/usbohci/hardware.cpp (working copy) @@ -10,7 +10,7 @@ #include "usbohci.h" -#define NDEBUG +//#define NDEBUG #include typedef VOID __stdcall HD_INIT_CALLBACK(IN PVOID CallBackContext); @@ -105,6 +105,9 @@ volatile LONG m_StatusChangeWorkItemStatus; // work item active status ULONG m_SyncFramePhysAddr; // periodic frame list physical address ULONG m_IntervalValue; // periodic interval value + + PVOID m_DoubleBuffer; + ULONG m_DoublePhysBuffer; }; //================================================================================================= @@ -234,6 +237,7 @@ PVOID ResourceBase; NTSTATUS Status; ULONG Version; + PHYSICAL_ADDRESS HighestAddress = {{0xFFFFFFFF, 0}}; DPRINT("CUSBHardwareDevice::PnpStart\n"); for(Index = 0; Index < TranslatedResources->List[0].PartialResourceList.Count; Index++) @@ -321,6 +325,22 @@ DeviceDescription.InterfaceType = PCIBus; DeviceDescription.MaximumLength = MAXULONG; + // create double buffer for transfers + + //FIXME: relation <- (usbstor\disk.c:USBSTOR_HandleQueryProperty()) AdapterDescriptor->MaximumPhysicalPages = 25; //FIXME compute some sane value + m_DoubleBuffer = MmAllocateContiguousMemory(25 * PAGE_SIZE, HighestAddress); + + if ( !m_DoubleBuffer ) + { + DPRINT1("PnpStart: Not created DoubleBuffer!\n"); + Status = STATUS_INSUFFICIENT_RESOURCES; + return Status; + } + RtlZeroMemory((PVOID)m_DoubleBuffer, 25 * PAGE_SIZE); //it need ? + + m_DoublePhysBuffer = MmGetPhysicalAddress(m_DoubleBuffer).LowPart; + DPRINT("PnpStart: m_DoubleBuffer - %p, Len - 25 * PAGE_SIZE, PhysicalAddress - %p\n", m_DoubleBuffer, m_DoublePhysBuffer); + // // get dma adapter // @@ -370,7 +390,7 @@ // // Initialize the UsbQueue now that we have an AdapterObject. // - Status = m_UsbQueue->Initialize(this, m_Adapter, m_MemoryManager, NULL); + Status = m_UsbQueue->Initialize(this, m_Adapter, m_MemoryManager, m_DoubleBuffer, m_DoublePhysBuffer, NULL); if (!NT_SUCCESS(Status)) { DPRINT1("Failed to Initialize the UsbQueue\n"); @@ -1014,10 +1034,34 @@ NTSTATUS STDMETHODCALLTYPE CUSBHardwareDevice::ResetPort( - IN ULONG PortIndex) + IN ULONG PortId) { - ASSERT(FALSE); + ULONG PortStatus; + LARGE_INTEGER Timeout; + DPRINT("ResetPort: PortId - %x\n", PortId); + + // read port status + PortStatus = READ_REGISTER_ULONG((PULONG)((PUCHAR)m_Base + OHCI_RH_PORT_STATUS(PortId))); + + // assert + ASSERT((PortStatus & OHCI_RH_PORTSTATUS_CCS)); + + // reset port + WRITE_REGISTER_ULONG((PULONG)((PUCHAR)m_Base + OHCI_RH_PORT_STATUS(PortId)), OHCI_RH_PORTSTATUS_PRS); + + // delay is 50 ms for port reset as per USB 2.0 spec + Timeout.QuadPart = 100;//50; //FIXME testmode + DPRINT1("[EHCI] ResetPort: Waiting %lu milliseconds for port reset\n", Timeout.LowPart); + + // convert to 100 ns units (absolute) + Timeout.QuadPart *= -10000; + + // perform the wait + //KeDelayExecutionThread(KernelMode, FALSE, &Timeout); +KeStallExecutionProcessor(1000000); //FIXME testmode + + // an interrupt signals the reset completion return STATUS_SUCCESS; } Index: drivers/usb/usbohci/usb_queue.cpp =================================================================== --- drivers/usb/usbohci/usb_queue.cpp (revision 70555) +++ drivers/usb/usbohci/usb_queue.cpp (working copy) @@ -66,6 +66,9 @@ POHCI_ENDPOINT_DESCRIPTOR m_IsoHeadEndpointDescriptor; // isochronous head descriptor POHCI_ENDPOINT_DESCRIPTOR * m_InterruptEndpoints; LIST_ENTRY m_PendingRequestList; // pending request list + + PVOID m_DoubleBuffer; + ULONG m_DoublePhysBuffer; }; //================================================================================================= @@ -93,6 +96,8 @@ IN PUSBHARDWAREDEVICE Hardware, IN PDMA_ADAPTER AdapterObject, IN PDMAMEMORYMANAGER MemManager, + IN PVOID DoubleBuffer, + IN ULONG DoublePhysBuffer, IN OPTIONAL PKSPIN_LOCK Lock) { if (!Hardware) @@ -108,6 +113,15 @@ m_Hardware = POHCIHARDWAREDEVICE(Hardware); ASSERT(m_Hardware); + // store buffer pointers + DPRINT("Initialize: DoubleBuffer - %p, Len - 0x19000, DoublePhysBuffer - %p\n", DoubleBuffer, DoublePhysBuffer); + + m_DoubleBuffer = DoubleBuffer; + ASSERT(m_DoubleBuffer); + + m_DoublePhysBuffer = DoublePhysBuffer; + ASSERT(m_DoublePhysBuffer); + // // get bulk endpoint descriptor // @@ -356,7 +370,7 @@ NTSTATUS Status; *OutRequest = NULL; - Status = InternalCreateUSBRequest(&UsbRequest); + Status = InternalCreateUSBRequest(&UsbRequest, m_DoubleBuffer, m_DoublePhysBuffer); if (NT_SUCCESS(Status)) { Index: drivers/usb/usbohci/usb_request.cpp =================================================================== --- drivers/usb/usbohci/usb_request.cpp (revision 70555) +++ drivers/usb/usbohci/usb_request.cpp (working copy) @@ -10,7 +10,7 @@ #include "usbohci.h" -#define NDEBUG +//#define NDEBUG #include class CUSBRequest : public IOHCIRequest @@ -47,6 +47,7 @@ NTSTATUS BuildSetupPacketFromURB(); NTSTATUS BuildControlTransferDescriptor(POHCI_ENDPOINT_DESCRIPTOR * OutEndpointDescriptor); NTSTATUS BuildBulkInterruptEndpoint(POHCI_ENDPOINT_DESCRIPTOR * OutEndpointDescriptor); + NTSTATUS BuildBulkInterruptDataEndpoint(POHCI_ENDPOINT_DESCRIPTOR * OutEndpointDescriptor); NTSTATUS BuildIsochronousEndpoint(POHCI_ENDPOINT_DESCRIPTOR * OutEndpointDescriptor); NTSTATUS CreateGeneralTransferDescriptor(POHCI_GENERAL_TD* OutDescriptor, ULONG BufferSize); VOID FreeDescriptor(POHCI_GENERAL_TD Descriptor); @@ -143,6 +144,14 @@ // base buffer // PVOID m_Base; + + // + // TRUE if IRP have MDL + // + BOOLEAN m_RequestWithMdl; + + PVOID m_DoubleBuffer; + ULONG_PTR m_DoublePhysBuffer; }; //---------------------------------------------------------------------------------------- @@ -155,6 +164,13 @@ return STATUS_UNSUCCESSFUL; } +VOID +CUSBRequest::GetDoubleBuffer(PVOID DoubleBuffer, ULONG_PTR DoublePhysBuffer) +{ + m_DoubleBuffer = DoubleBuffer; + m_DoublePhysBuffer = DoublePhysBuffer; +} + //---------------------------------------------------------------------------------------- NTSTATUS STDMETHODCALLTYPE @@ -362,6 +378,8 @@ // // Create one using TransferBuffer // + m_RequestWithMdl = FALSE; + DPRINT("Creating Mdl from Urb Buffer %p Length %lu\n", m_Urb->UrbBulkOrInterruptTransfer.TransferBuffer, m_Urb->UrbBulkOrInterruptTransfer.TransferBufferLength); m_TransferBufferMDL = IoAllocateMdl(m_Urb->UrbBulkOrInterruptTransfer.TransferBuffer, m_Urb->UrbBulkOrInterruptTransfer.TransferBufferLength, @@ -390,8 +408,26 @@ else { m_TransferBufferMDL = m_Urb->UrbBulkOrInterruptTransfer.TransferBufferMDL; + m_RequestWithMdl = TRUE; } + { + if (m_Urb->UrbBulkOrInterruptTransfer.TransferFlags & USBD_TRANSFER_DIRECTION_IN) + { + DPRINT("InitializeWithIrp: USBD_TRANSFER_DIRECTION_IN\n"); + } + else + { + DPRINT("InitializeWithIrp: USBD_TRANSFER_DIRECTION_OUT\n"); + // + // copy from MDL buffer to Double Buffer + // + RtlCopyMemory((PVOID)((ULONG_PTR)m_DoubleBuffer + m_TransferBufferMDL->ByteOffset), + (PVOID)((ULONG_PTR)m_TransferBufferMDL->StartVa + m_TransferBufferMDL->ByteOffset), + m_Urb->UrbBulkOrInterruptTransfer.TransferBufferLength); + } + } + // // save buffer length // @@ -1088,6 +1124,11 @@ // store physical address of buffer // CurrentDescriptor->BufferPhysical = MmGetPhysicalAddress(TransferBuffer).LowPart; + if (CurrentDescriptor->BufferPhysical == 0) + { + DPRINT1("InitDescriptor: BufferPhysical == 0. CurrentDescriptor %p\n", CurrentDescriptor); + } + CurrentDescriptor->LastPhysicalByteAddress = CurrentDescriptor->BufferPhysical + TransferBufferLength - 1; DPRINT("CurrentDescriptor %p Addr %x TransferBufferLength %lu\n", CurrentDescriptor, CurrentDescriptor->PhysicalAddress.LowPart, TransferBufferLength); @@ -1346,6 +1387,153 @@ return STATUS_SUCCESS; } +NTSTATUS +CUSBRequest::BuildBulkInterruptDataEndpoint( + POHCI_ENDPOINT_DESCRIPTOR * OutEndpointDescriptor) +{ + NTSTATUS Status; + POHCI_ENDPOINT_DESCRIPTOR EndpointDescriptor; + POHCI_GENERAL_TD FirstDescriptor = NULL; + POHCI_GENERAL_TD LastDescriptor = NULL; + POHCI_GENERAL_TD CurrentDescriptor; + ULONG MaxTransferLength; + ULONG TransferBufferOffset = 0; + ULONG TransferSize; + ULONG MaxPacketSize = 0; + ULONG Direction; + PHYSICAL_ADDRESS Address; + ULONG PageNumber = 0; + + + // sanity check + ASSERT(m_TransferBufferMDL); + ASSERT(m_EndpointDescriptor); + + // allocate endpoint descriptor + Status = AllocateEndpointDescriptor(&EndpointDescriptor); + + // failed to create setup descriptor + if (!NT_SUCCESS(Status)) + return Status; + + //DPRINT("BuildBulkInterruptDataEndpoint: EndpointDescriptor - %p, CurrentThread - %p\n", EndpointDescriptor, PsGetCurrentThread()); + + ASSERT(m_EndpointDescriptor); + + // use 1 * PAGE_SIZE at max for each new request + MaxTransferLength = min(1 * PAGE_SIZE, m_TransferBufferLength - m_TransferBufferLengthCompleted); + + // for now use one page as maximum size + MaxPacketSize = PAGE_SIZE; + + // transfer size is minimum available buffer or endpoint size + if (MaxPacketSize) + TransferSize = min(MaxTransferLength - TransferBufferOffset, MaxPacketSize); + else // use available buffer + TransferSize = MaxTransferLength - TransferBufferOffset; + + do + { + // allocate transfer descriptor + Status = CreateGeneralTransferDescriptor(&CurrentDescriptor, 0); + + // failed to allocate transfer descriptor + if (!NT_SUCCESS(Status)) + return STATUS_INSUFFICIENT_RESOURCES; + + if (InternalGetPidDirection()) + Direction = OHCI_TD_DIRECTION_PID_IN; // input direction + else + Direction = OHCI_TD_DIRECTION_PID_OUT; // output direction + + // initialize descriptor + CurrentDescriptor->Flags = Direction | + OHCI_TD_BUFFER_ROUNDING | + OHCI_TD_SET_CONDITION_CODE(OHCI_TD_CONDITION_NOT_ACCESSED) | + OHCI_TD_SET_DELAY_INTERRUPT(OHCI_TD_INTERRUPT_NONE) | + OHCI_TD_TOGGLE_CARRY; + + // store physical address of buffer + + // if transfer size >= 4096 (1 and more pages) + if (m_TransferBufferLength >= PAGE_SIZE) + { + PageNumber = (m_TransferBufferLengthCompleted >> PAGE_SHIFT) & 0x0000001F; + + if ( (PageNumber == 0) && (m_TransferBufferMDL->ByteOffset > 0) ) + Address.LowPart = m_DoublePhysBuffer + m_TransferBufferMDL->ByteOffset; + else + Address.LowPart = m_DoublePhysBuffer + PageNumber * PAGE_SIZE; + } + else + { + // if transfer size < 4096 (< 1 page) + Address.LowPart = m_DoublePhysBuffer + m_TransferBufferMDL->ByteOffset; + } + + if (Address.LowPart == 0) + { + // error + return STATUS_UNSUCCESSFUL; + } + + CurrentDescriptor->BufferPhysical = Address.LowPart; + CurrentDescriptor->LastPhysicalByteAddress = CurrentDescriptor->BufferPhysical + TransferSize - 1; + + DPRINT("BuildBulkInterruptDataEndpoint: CurrentDescriptor->BufferPhysical - %p, TransferSize %x\n", CurrentDescriptor->BufferPhysical, TransferSize); + + // adjust offset + TransferBufferOffset += TransferSize; + + // is there a previous descriptor + if (LastDescriptor ) + { + // link descriptors + LastDescriptor->NextLogicalDescriptor = (PVOID)CurrentDescriptor; + LastDescriptor->NextPhysicalDescriptor = CurrentDescriptor->PhysicalAddress.LowPart; + } + else + { + // it is the first descriptor + FirstDescriptor = CurrentDescriptor; + } + + // end reached + if (MaxTransferLength == TransferBufferOffset) + break; + + } while (TRUE); + + // store last descriptor + LastDescriptor = CurrentDescriptor; + + // move to next offset + m_TransferBufferLengthCompleted += TransferBufferOffset; + + // first descriptor has no carry bit + FirstDescriptor->Flags &= ~OHCI_TD_TOGGLE_CARRY; + + // apply data toggle + FirstDescriptor->Flags |= (m_EndpointDescriptor->DataToggle ? OHCI_TD_TOGGLE_1 : OHCI_TD_TOGGLE_0); + + // clear interrupt mask for last transfer descriptor + LastDescriptor->Flags &= ~OHCI_TD_INTERRUPT_MASK; + + // fire interrupt as soon transfer is finished + LastDescriptor->Flags |= OHCI_TD_SET_DELAY_INTERRUPT(OHCI_TD_INTERRUPT_IMMEDIATE); + + // now link descriptor to endpoint + EndpointDescriptor->HeadPhysicalDescriptor = FirstDescriptor->PhysicalAddress.LowPart; + EndpointDescriptor->TailPhysicalDescriptor = (FirstDescriptor == LastDescriptor ? 0 : LastDescriptor->PhysicalAddress.LowPart); + EndpointDescriptor->HeadLogicalDescriptor = FirstDescriptor; + + //DumpEndpointDescriptor(EndpointDescriptor); // dump descriptor list + + *OutEndpointDescriptor = EndpointDescriptor; // store result + + return STATUS_SUCCESS; // done +} + VOID CUSBRequest::DumpEndpointDescriptor( POHCI_ENDPOINT_DESCRIPTOR Descriptor) @@ -1597,7 +1785,14 @@ break; case USB_ENDPOINT_TYPE_BULK: case USB_ENDPOINT_TYPE_INTERRUPT: - Status = BuildBulkInterruptEndpoint(OutDescriptor); + if (m_RequestWithMdl) + { + Status = BuildBulkInterruptDataEndpoint(OutDescriptor); + } + else + { + Status = BuildBulkInterruptDataEndpoint(OutDescriptor); //BuildBulkInterruptEndpoint testmode ? + } break; case USB_ENDPOINT_TYPE_ISOCHRONOUS: Status = BuildIsochronousEndpoint((POHCI_ENDPOINT_DESCRIPTOR*)OutDescriptor); @@ -1926,6 +2121,20 @@ // Urb = (PURB)IoStack->Parameters.Others.Argument1; + // copy from doublebuffer to MDL buffer + if (Urb->UrbBulkOrInterruptTransfer.TransferFlags & USBD_TRANSFER_DIRECTION_IN) + { + DPRINT("CompletionCallback: USBD_TRANSFER_DIRECTION_IN\n"); + + RtlCopyMemory((PVOID)((ULONG_PTR)m_TransferBufferMDL->StartVa + m_TransferBufferMDL->ByteOffset), + (PVOID)((ULONG_PTR)m_DoubleBuffer + m_TransferBufferMDL->ByteOffset), + Urb->UrbBulkOrInterruptTransfer.TransferBufferLength); + } + else + { + DPRINT("CompletionCallback: USBD_TRANSFER_DIRECTION_OUT\n"); + } + // // store urb status // @@ -1965,7 +2174,7 @@ NTSTATUS NTAPI InternalCreateUSBRequest( - PUSBREQUEST *OutRequest) + PUSBREQUEST *OutRequest, PVOID DoubleBuffer, ULONG DoublePhysBuffer) { PUSBREQUEST This; @@ -1986,6 +2195,8 @@ // This->AddRef(); + This->GetDoubleBuffer(DoubleBuffer, DoublePhysBuffer); + // // return result // Index: drivers/usb/usbohci/usbohci.h =================================================================== --- drivers/usb/usbohci/usbohci.h (revision 70555) +++ drivers/usb/usbohci/usbohci.h (working copy) @@ -48,7 +48,7 @@ // // usb_request.cpp // -NTSTATUS NTAPI InternalCreateUSBRequest(PUSBREQUEST *OutRequest); +NTSTATUS NTAPI InternalCreateUSBRequest(PUSBREQUEST *OutRequest, PVOID m_DoubleBuffer, ULONG m_DoublePhysBuffer); } #endif /* USBOHCI_H__ */ Index: drivers/usb/usbstor/disk.c =================================================================== --- drivers/usb/usbstor/disk.c (revision 70555) +++ drivers/usb/usbstor/disk.c (working copy) @@ -502,8 +502,8 @@ // 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->MaximumTransferLength = 0x10000; //MAXULONG; //FIXME compute some sane value + AdapterDescriptor->MaximumPhysicalPages = 17; //25; //FIXME compute some sane value AdapterDescriptor->AlignmentMask = 0; AdapterDescriptor->AdapterUsesPio = FALSE; AdapterDescriptor->AdapterScansDown = FALSE; Index: drivers/usb/usbstor/error.c =================================================================== --- drivers/usb/usbstor/error.c (revision 70555) +++ drivers/usb/usbstor/error.c (working copy) @@ -109,15 +109,50 @@ NTSTATUS +NTAPI +USBSTOR_ResetRecovery( + IN PFDO_DEVICE_EXTENSION FDODeviceExtension) +{ + NTSTATUS Status; + + DPRINT("USBSTOR_ResetRecovery\n"); + + // + // 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); + } + } + + return Status; +} + +NTSTATUS +NTAPI USBSTOR_HandleTransferError( - PDEVICE_OBJECT DeviceObject, - PIRP_CONTEXT Context) + PVOID ErrorContext) { NTSTATUS Status = STATUS_SUCCESS; PIO_STACK_LOCATION Stack; PSCSI_REQUEST_BLOCK Request; PCDB pCDB; + PERRORHANDLER_WORKITEM_DATA WorkItemData = (PERRORHANDLER_WORKITEM_DATA)ErrorContext; + PIRP_CONTEXT Context = WorkItemData->Context; + //DPRINT("USBSTOR_HandleTransferError: ErrorIndex - %x, RetryCount - %x\n", Context->ErrorIndex, Context->RetryCount); + // // sanity checks // @@ -127,23 +162,9 @@ ASSERT(Context->Irp); // - // first perform a mass storage reset step 1 in 5.3.4 USB Mass Storage Bulk Only Specification + // perform Reset Recovery // - 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); - } - } + USBSTOR_ResetRecovery(Context->FDODeviceExtension); // // get next stack location @@ -243,6 +264,32 @@ USBSTOR_SendCSW(WorkItemData->Context, WorkItemData->Irp); } +NTSTATUS +NTAPI +USBSTOR_HandleResetRecover( + PVOID ErrorContext) +{ + NTSTATUS Status; + PERRORHANDLER_WORKITEM_DATA WorkItemData = (PERRORHANDLER_WORKITEM_DATA)ErrorContext; + PIRP_CONTEXT Context = WorkItemData->Context; + + // + // perform Reset Recovery + // + Status = USBSTOR_ResetRecovery(Context->FDODeviceExtension); + DPRINT("Index %x, Count %x, ResetRecovery %x\n", Context->ErrorIndex, Context->RetryCount, Status); + + if (NT_SUCCESS(Status)) + { + // + // now send the CSW + // + USBSTOR_SendCSW(WorkItemData->Context, WorkItemData->Irp); + } + + return Status; +} + VOID NTAPI ErrorHandlerWorkItemRoutine( @@ -250,20 +297,27 @@ { PERRORHANDLER_WORKITEM_DATA WorkItemData = (PERRORHANDLER_WORKITEM_DATA)Context; - if (WorkItemData->Context->ErrorIndex == 2) + if (WorkItemData->Context->ErrorIndex == 1) { // - // reset device + // clear STALL // - USBSTOR_HandleTransferError(WorkItemData->DeviceObject, WorkItemData->Context); + USBSTOR_ResetHandlerWorkItemRoutine(WorkItemData); } - else + else if (WorkItemData->Context->ErrorIndex == 2) { // - // clear stall + // perform Reset Recovery and send the CSW // - USBSTOR_ResetHandlerWorkItemRoutine(WorkItemData); + USBSTOR_HandleResetRecover(WorkItemData); } + else if (WorkItemData->Context->ErrorIndex == 3) + { + // + // perform Reset Recovery and handle error + // + USBSTOR_HandleTransferError(WorkItemData); + } // // Free Work Item Data Index: drivers/usb/usbstor/misc.c =================================================================== --- drivers/usb/usbstor/misc.c (revision 70555) +++ drivers/usb/usbstor/misc.c (working copy) @@ -292,7 +292,6 @@ { PURB Urb; - PUCHAR Buffer; NTSTATUS Status; // @@ -308,19 +307,6 @@ } // - // allocate 1-byte buffer - // - Buffer = (PUCHAR)AllocateItem(NonPagedPool, sizeof(UCHAR)); - if (!Buffer) - { - // - // no memory - // - FreeItem(Buffer); - return STATUS_INSUFFICIENT_RESOURCES; - } - - // // initialize vendor request // Urb->UrbControlVendorClassRequest.Hdr.Length = sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST); @@ -369,6 +355,8 @@ return STATUS_INSUFFICIENT_RESOURCES; } + *Buffer = 0; + // // execute request // @@ -376,19 +364,34 @@ DPRINT("MaxLUN: %x\n", *Buffer); - if (*Buffer > 0xF) + if ( NT_SUCCESS(Status) ) { - // - // invalid response documented in usb mass storage specification - // - Status = STATUS_DEVICE_DATA_ERROR; + if (*Buffer > 0xF) + { + // + // invalid response documented in usb mass storage specification + // + Status = STATUS_DEVICE_DATA_ERROR; + } + else + { + // + // store maxlun + // + DeviceExtension->MaxLUN = *Buffer; + } } else { // - // store maxlun + // "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. // - DeviceExtension->MaxLUN = *Buffer; + USBSTOR_ResetDevice(DeviceExtension->LowerDeviceObject, DeviceExtension); + + DeviceExtension->MaxLUN = 0; + Status = STATUS_SUCCESS; } // Index: drivers/usb/usbstor/pdo.c =================================================================== --- drivers/usb/usbstor/pdo.c (revision 70555) +++ drivers/usb/usbstor/pdo.c (working copy) @@ -1342,12 +1342,12 @@ // // check if it is a floppy // - Status = USBSTOR_SendFormatCapacityIrp(PDO); + //Status = USBSTOR_SendFormatCapacityIrp(PDO); // // display result // - DPRINT1("[USBSTOR] Status %x IsFloppy %x MediumTypeCode %x\n", Status, PDODeviceExtension->IsFloppy, PDODeviceExtension->MediumTypeCode); + DPRINT1("[USBSTOR] Status %x IsFloppy %x MediumTypeCode %x. FIXME: is a floppy\n", Status, PDODeviceExtension->IsFloppy, PDODeviceExtension->MediumTypeCode); // // failing command is non critical Index: drivers/usb/usbstor/scsi.c =================================================================== --- drivers/usb/usbstor/scsi.c (revision 70555) +++ drivers/usb/usbstor/scsi.c (working copy) @@ -93,6 +93,12 @@ // // sanity checks // + if (sizeof(CSW) != 0x0d) + { + DPRINT1("[USBSTOR] Expected sizeof(CSW) == 0x0d but got %x\n", sizeof(CSW)); + return FALSE; + } + if (Context->csw->Signature != CSW_SIGNATURE) { DPRINT1("[USBSTOR] Expected Signature %x but got %x\n", CSW_SIGNATURE, Context->csw->Signature); @@ -105,12 +111,6 @@ return FALSE; } - if (Context->csw->Status != 0x00) - { - DPRINT1("[USBSTOR] Expected Status 0x00 but got %x\n", Context->csw->Status); - return FALSE; - } - // // CSW is valid // @@ -164,7 +164,294 @@ return STATUS_MORE_PROCESSING_REQUIRED; } +// +// driver verifier +// +IO_COMPLETION_ROUTINE USBSTOR_SenseCSWCompletionRoutine; +NTSTATUS +NTAPI +USBSTOR_SenseCSWCompletionRoutine( + PDEVICE_OBJECT DeviceObject, + PIRP Irp, + PVOID Ctx) +{ + PIRP_CONTEXT Context = (PIRP_CONTEXT)Ctx; + PIRP_CONTEXT OriginalContext = Context->OriginalContext; + PIO_STACK_LOCATION IoStack; + PSCSI_REQUEST_BLOCK Srb; + PDEVICE_OBJECT FdoDevice = Context->PDODeviceExtension->LowerDeviceObject; + PFDO_DEVICE_EXTENSION FdoDeviceExtension = Context->PDODeviceExtension->LowerDeviceObject->DeviceExtension; + + + DPRINT("USBSTOR_SenseCSWCompletionRoutine: Irp %p Ctx %p Status %x\n", Irp, Ctx, Irp->IoStatus.Status); + + // 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); + } + } + + if (!NT_SUCCESS(Irp->IoStatus.Status)) + { + // if STALL + DPRINT1("USBSTOR_SenseCSWCompletionRoutine Status %x\n", Irp->IoStatus.Status); + } + + if (!USBSTOR_IsCSWValid(Context)) + { + // 6.3.1 Valid CSW + DPRINT1("CSW not Valid. Index %x Status %x\n", Context->ErrorIndex, Irp->IoStatus.Status); + } + + // 6.3.2 Meaningful CSW + if (Context->csw->Status <= 0x02) + { + if (Context->csw->Status == 0x01) + { + DPRINT1("CSWStatus 0x01. Command failed\n"); + } + + if (Context->csw->Status == 0x02) + { + DPRINT1("CSWStatus 0x02. Reset recovery\n"); + } + } + else + { + DPRINT1("FIXME: CSW not Meaningful. CSWStatus %x\n", Irp->IoStatus.Status); + ASSERT(FALSE); + } + + // FIXME: check status + //Context->Irp->IoStatus.Status = Irp->IoStatus.Status; + //Context->Irp->IoStatus.Information = Context->TransferDataLength; + + // free our allocated Sense IRP + IoFreeIrp(Irp); + + // free Sense CBW + FreeItem(Context->cbw); + + // free our allocated CDB + ExFreePool(Context->SenseCDB); + + // free our allocated IRP + IoFreeIrp(Context->Irp); + + // free Sense Context + FreeItem(Context); + + // get SRB pointer + IoStack = IoGetCurrentIrpStackLocation(OriginalContext->Irp); + Srb = (PSCSI_REQUEST_BLOCK)IoStack->Parameters.Others.Argument1; + ASSERT(Srb); + + // Sense data is OK + Srb->SrbStatus |= SRB_STATUS_AUTOSENSE_VALID; + + // free CBW + FreeItem(OriginalContext->cbw); + + // FIXME: check status -> if (SRB_STATUS(Srb->SrbStatus) != SRB_STATUS_SUCCESS ) Irp->IoStatus.Status = ConvertSrbStatus(Srb->SrbStatus); + OriginalContext->Irp->IoStatus.Status = STATUS_IO_DEVICE_ERROR; + OriginalContext->Irp->IoStatus.Information = 0; // OriginalContext->TransferDataLength; + + if (FdoDeviceExtension->IrpListFreeze) + { + // UnFreezing Queue (?spinlock) + FdoDeviceExtension->IrpListFreeze = FALSE; + } + + // terminate current IRP + USBSTOR_QueueTerminateRequest(FdoDevice, OriginalContext->Irp); + + // complete IRP + IoCompleteRequest(OriginalContext->Irp, IO_NO_INCREMENT); + + // start next IRP + USBSTOR_QueueNextRequest(FdoDevice); + + // free context + FreeItem(OriginalContext); + + // done + return STATUS_MORE_PROCESSING_REQUIRED; +} + +NTSTATUS +USBSTOR_SendRequestSense( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP OriginalIrp, + IN PIRP_CONTEXT OriginalContext) +{ + PPDO_DEVICE_EXTENSION PDODeviceExtension = OriginalContext->PDODeviceExtension; + PFDO_DEVICE_EXTENSION FDODeviceExtension = OriginalContext->FDODeviceExtension; + PIO_STACK_LOCATION IoStack = IoGetCurrentIrpStackLocation(OriginalContext->Irp); + PSCSI_REQUEST_BLOCK InitialSrb; + PCDB Cdb; + PIRP_CONTEXT Context; + PIRP Irp; + + + // + // allocate CDB for REQUEST SENSE + // + Cdb = ExAllocatePool(NonPagedPool, sizeof(Cdb->CDB6INQUIRY)); + + if ( Cdb == NULL ) + { + DPRINT1("USBSTOR_SendRequestSense Allocate CDB failed\n"); + return STATUS_INSUFFICIENT_RESOURCES; + } + + RtlZeroMemory(Cdb, sizeof(Cdb->CDB6INQUIRY)); + + // + // get original SRB + // + InitialSrb = (PSCSI_REQUEST_BLOCK)IoStack->Parameters.Others.Argument1; + ASSERT(InitialSrb); + + // + // Build CDB for REQUEST SENSE + // + Cdb->CDB6INQUIRY.OperationCode = SCSIOP_REQUEST_SENSE; + Cdb->CDB6INQUIRY.LogicalUnitNumber = (PDODeviceExtension->LUN & 15); //USB_MAX_LUN + Cdb->CDB6INQUIRY.Reserved1 = 0; + Cdb->CDB6INQUIRY.PageCode = 0; + Cdb->CDB6INQUIRY.IReserved = 0; + Cdb->CDB6INQUIRY.AllocationLength = (UCHAR)InitialSrb->SenseInfoBufferLength; + Cdb->CDB6INQUIRY.Control = 0; + + // + // allocate IRP-context for REQUEST SENSE + // + Context = USBSTOR_AllocateIrpContext(); + if (!Context) + { + // + // no memory + // + return STATUS_INSUFFICIENT_RESOURCES; + } + + // + // save old IRP-context + // + Context->OriginalContext = OriginalContext; + + // + // now build the CBW + // + USBSTOR_BuildCBW((ULONG)Context->cbw, + InitialSrb->SenseInfoBufferLength, + PDODeviceExtension->LUN, + sizeof(Cdb->CDB6INQUIRY), //6 + (PUCHAR)Cdb, + Context->cbw); + + DPRINT("USBSTOR_SendRequestSense: 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 context + // + Context->Irp = OriginalIrp; + Context->TransferData = InitialSrb->SenseInfoBuffer; + Context->TransferDataLength = InitialSrb->SenseInfoBufferLength; + Context->FDODeviceExtension = OriginalContext->FDODeviceExtension; + Context->PDODeviceExtension = OriginalContext->PDODeviceExtension; + Context->RetryCount = OriginalContext->RetryCount; + Context->ErrorIndex = 0; + + // + // save CDB + // + Context->SenseCDB = Cdb; + + // + // is there transfer data + // + if (Context->TransferDataLength) + { + // + // 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 IRP + // + Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE); + if (!Irp) + { + FreeItem(Context->cbw); + FreeItem(Context); + return STATUS_INSUFFICIENT_RESOURCES; + } + + if (OriginalIrp) + { + // + // mark orignal IRP as pending + // + IoMarkIrpPending(OriginalIrp); + } + + // + // send IRP + // + DPRINT("USBSTOR_SendRequestSense: USBSTOR_SendCBW(%p, %p), Irql %x\n", Context, Irp, KeGetCurrentIrql()); + USBSTOR_SendCBW(Context, Irp); + + // + // done + // + return STATUS_PENDING; +} + // // driver verifier // @@ -185,11 +472,15 @@ PREAD_CAPACITY_DATA CapacityData; PUFI_CAPACITY_RESPONSE Response; NTSTATUS Status; + PDEVICE_OBJECT FdoDevice; + PFDO_DEVICE_EXTENSION FdoDeviceExtension; // // access context // Context = (PIRP_CONTEXT)Ctx; + FdoDevice = Context->PDODeviceExtension->LowerDeviceObject; + FdoDeviceExtension = FdoDevice->DeviceExtension; // // is there a mdl @@ -223,7 +514,7 @@ DPRINT("USBSTOR_CSWCompletionRoutine Status %x\n", Irp->IoStatus.Status); - if (!NT_SUCCESS(Irp->IoStatus.Information)) + if (!NT_SUCCESS(Irp->IoStatus.Status)) { if (Context->ErrorIndex == 0) { @@ -233,7 +524,7 @@ Context->ErrorIndex = 1; // - // clear stall and resend cbw + // clear STALL and resend CSW // Status = USBSTOR_QueueWorkItem(Context, Irp); ASSERT(Status == STATUS_MORE_PROCESSING_REQUIRED); @@ -241,10 +532,18 @@ } // - // perform reset recovery + // increment error index // - Context->ErrorIndex = 2; + Context->ErrorIndex = 3; + + // + // free our allocated irp + // IoFreeIrp(Irp); + + // + // perform Reset Recovery and handle error + // Status = USBSTOR_QueueWorkItem(Context, NULL); ASSERT(Status == STATUS_MORE_PROCESSING_REQUIRED); return STATUS_MORE_PROCESSING_REQUIRED; @@ -253,16 +552,72 @@ if (!USBSTOR_IsCSWValid(Context)) { // - // perform reset recovery + // increment error index // - Context->ErrorIndex = 2; + Context->ErrorIndex = 3; + + // + // free our allocated irp + // IoFreeIrp(Irp); + + // + // perform Reset Recovery and handle error + // Status = USBSTOR_QueueWorkItem(Context, NULL); ASSERT(Status == STATUS_MORE_PROCESSING_REQUIRED); return STATUS_MORE_PROCESSING_REQUIRED; } + // + // 6.3.2 Meaningful CSW + // + if (Context->csw->Status <= 0x02) + { + if (Context->csw->Status == 0x01) // 6.6.4 Command Failure + { + DPRINT1("CSWStatus 0x01. Command failed\n"); + // + // Freezing Queue (?spinlock) + // + FdoDeviceExtension->IrpListFreeze = TRUE; + + // + // Send a SCSI REQUEST SENSE command + // + Status = USBSTOR_SendRequestSense(Context->PDODeviceExtension->Self, Irp, Context); + return STATUS_MORE_PROCESSING_REQUIRED; + } + + if (Context->csw->Status == 0x02) //6.6.2 Internal Device Error + { + DPRINT1("CSWStatus 0x02. Reset recovery\n"); + + // + // increment error index + // + Context->ErrorIndex = 3; + + // + // free our allocated irp + // + IoFreeIrp(Irp); + + // + // perform Reset Recovery and handle error + // + Status = USBSTOR_QueueWorkItem(Context, NULL); + ASSERT(Status == STATUS_MORE_PROCESSING_REQUIRED); + return STATUS_MORE_PROCESSING_REQUIRED; + } + } + else + { + DPRINT1("FIXME: CSW not Meaningful. CSWStatus %x\n", Irp->IoStatus.Status); + ASSERT(FALSE); + } + // // get current stack location // @@ -274,8 +629,6 @@ Request = (PSCSI_REQUEST_BLOCK)IoStack->Parameters.Others.Argument1; ASSERT(Request); - Status = Irp->IoStatus.Status; - // // get SCSI command data block // @@ -347,7 +700,7 @@ // // terminate current request // - USBSTOR_QueueTerminateRequest(Context->PDODeviceExtension->LowerDeviceObject, Context->Irp); + USBSTOR_QueueTerminateRequest(FdoDevice, Context->Irp); // // complete request @@ -357,7 +710,7 @@ // // start next request // - USBSTOR_QueueNextRequest(Context->PDODeviceExtension->LowerDeviceObject); + USBSTOR_QueueNextRequest(FdoDevice); // // free our allocated irp @@ -395,7 +748,7 @@ Context->FDODeviceExtension->InterfaceInformation->Pipes[Context->FDODeviceExtension->BulkInPipeIndex].PipeHandle, Context->csw, NULL, - 512, //FIXME + sizeof(CSW), USBD_TRANSFER_DIRECTION_IN | USBD_SHORT_TRANSFER_OK, NULL); @@ -410,9 +763,22 @@ // - // setup completion routine + // if error - IRP List (queue) Frozen // - IoSetCompletionRoutine(Irp, USBSTOR_CSWCompletionRoutine, Context, TRUE, TRUE, TRUE); + if (Context->FDODeviceExtension->IrpListFreeze) + { + // + // setup completion routine for Request Sense + // + IoSetCompletionRoutine(Irp, USBSTOR_SenseCSWCompletionRoutine, Context, TRUE, TRUE, TRUE); + } + else + { + // + // setup completion routine + // + IoSetCompletionRoutine(Irp, USBSTOR_CSWCompletionRoutine, Context, TRUE, TRUE, TRUE); + } // // call driver @@ -420,7 +786,6 @@ IoCallDriver(Context->FDODeviceExtension->LowerDeviceObject, Irp); } - // // driver verifier // @@ -447,7 +812,7 @@ if (!NT_SUCCESS(Irp->IoStatus.Status)) { // - // clear stall and resend cbw + // clear STALL and send CSW // Context->ErrorIndex = 1; Status = USBSTOR_QueueWorkItem(Context, Irp); @@ -482,6 +847,7 @@ PIO_STACK_LOCATION IoStack; UCHAR Code; USBD_PIPE_HANDLE PipeHandle; + NTSTATUS Status; DPRINT("USBSTOR_CBWCompletionRoutine Irp %p Ctx %p Status %x\n", Irp, Ctx, Irp->IoStatus.Status); @@ -495,6 +861,17 @@ // IoStack = IoGetNextIrpStackLocation(Irp); + if (!NT_SUCCESS(Irp->IoStatus.Status)) + { + // + // perform Reset Recovery and send the CSW + // + Context->ErrorIndex = 2; + Status = USBSTOR_QueueWorkItem(Context, Irp); + ASSERT(Status == STATUS_MORE_PROCESSING_REQUIRED); + return STATUS_MORE_PROCESSING_REQUIRED; + } + // // is there data to be submitted // @@ -548,7 +925,7 @@ Context->FDODeviceExtension->InterfaceInformation->Pipes[Context->FDODeviceExtension->BulkInPipeIndex].PipeHandle, Context->csw, NULL, - 512, //FIXME + sizeof(CSW), USBD_TRANSFER_DIRECTION_IN | USBD_SHORT_TRANSFER_OK, NULL); @@ -691,6 +1068,7 @@ Context->FDODeviceExtension = FDODeviceExtension; Context->PDODeviceExtension = PDODeviceExtension; Context->RetryCount = RetryCount; + Context->ErrorIndex = 0; // // is there transfer data Index: drivers/usb/usbstor/usbstor.h =================================================================== --- drivers/usb/usbstor/usbstor.h (revision 70555) +++ drivers/usb/usbstor/usbstor.h (working copy) @@ -312,7 +312,7 @@ UCHAR Bytes[16]; }UFI_UNKNOWN_CMD, *PUFI_UNKNOWN_CMD; -typedef struct +typedef struct _IRP_CONTEXT { union { @@ -328,6 +328,8 @@ PMDL TransferBufferMDL; ULONG ErrorIndex; ULONG RetryCount; + PCDB SenseCDB; + struct _IRP_CONTEXT *OriginalContext; }IRP_CONTEXT, *PIRP_CONTEXT; typedef struct _ERRORHANDLER_WORKITEM_DATA Index: drivers/usb/usbuhci/hardware.cpp =================================================================== --- drivers/usb/usbuhci/hardware.cpp (revision 70555) +++ drivers/usb/usbuhci/hardware.cpp (working copy) @@ -125,6 +125,9 @@ PUHCI_TRANSFER_DESCRIPTOR m_StrayDescriptor; // stray descriptor KTIMER m_SCETimer; // SCE timer KDPC m_SCETimerDpc; // timer dpc + + PVOID m_DoubleBuffer; + ULONG m_DoublePhysBuffer; }; //================================================================================================= @@ -370,7 +373,7 @@ // // Initialize the UsbQueue now that we have an AdapterObject. // - Status = m_UsbQueue->Initialize(PUSBHARDWAREDEVICE(this), m_Adapter, m_MemoryManager, NULL); + Status = m_UsbQueue->Initialize(PUSBHARDWAREDEVICE(this), m_Adapter, m_MemoryManager, m_DoubleBuffer, m_DoublePhysBuffer, NULL); if (!NT_SUCCESS(Status)) { DPRINT1("Failed to Initialize the UsbQueue\n"); Index: drivers/usb/usbuhci/usb_queue.cpp =================================================================== --- drivers/usb/usbuhci/usb_queue.cpp (revision 70555) +++ drivers/usb/usbuhci/usb_queue.cpp (working copy) @@ -56,6 +56,8 @@ KSPIN_LOCK m_Lock; // list lock PUHCIHARDWAREDEVICE m_Hardware; // hardware + PVOID m_DoubleBuffer; + ULONG m_DoublePhysBuffer; }; //================================================================================================= @@ -82,6 +84,8 @@ IN PUSBHARDWAREDEVICE Hardware, IN PDMA_ADAPTER AdapterObject, IN PDMAMEMORYMANAGER MemManager, + IN PVOID DoubleBuffer, + IN ULONG DoublePhysBuffer, IN OPTIONAL PKSPIN_LOCK Lock) { @@ -290,7 +294,7 @@ NTSTATUS Status; *OutRequest = NULL; - Status = InternalCreateUSBRequest(&UsbRequest); + Status = InternalCreateUSBRequest(&UsbRequest, m_DoubleBuffer, m_DoublePhysBuffer); if (NT_SUCCESS(Status)) { Index: drivers/usb/usbuhci/usb_request.cpp =================================================================== --- drivers/usb/usbuhci/usb_request.cpp (revision 70555) +++ drivers/usb/usbuhci/usb_request.cpp (working copy) @@ -133,6 +133,9 @@ // base PVOID m_Base; + PVOID m_DoubleBuffer; + ULONG m_DoublePhysBuffer; + }; //---------------------------------------------------------------------------------------- @@ -145,6 +148,13 @@ return STATUS_UNSUCCESSFUL; } +VOID +CUSBRequest::GetDoubleBuffer(PVOID DoubleBuffer, ULONG DoublePhysBuffer) +{ + m_DoubleBuffer = DoubleBuffer; + m_DoublePhysBuffer = DoublePhysBuffer; +} + //---------------------------------------------------------------------------------------- NTSTATUS CUSBRequest::InitializeWithSetupPacket( @@ -1399,7 +1409,7 @@ NTSTATUS NTAPI InternalCreateUSBRequest( - PUSBREQUEST *OutRequest) + PUSBREQUEST *OutRequest, PVOID DoubleBuffer, ULONG DoublePhysBuffer) { PUSBREQUEST This; @@ -1420,6 +1430,8 @@ // This->AddRef(); + This->GetDoubleBuffer(DoubleBuffer, DoublePhysBuffer); + // // return result // Index: drivers/usb/usbuhci/usbuhci.h =================================================================== --- drivers/usb/usbuhci/usbuhci.h (revision 70555) +++ drivers/usb/usbuhci/usbuhci.h (working copy) @@ -45,6 +45,6 @@ // // usb_request.cpp // -NTSTATUS NTAPI InternalCreateUSBRequest(PUSBREQUEST *OutRequest); +NTSTATUS NTAPI InternalCreateUSBRequest(PUSBREQUEST *OutRequest, PVOID m_DoubleBuffer, ULONG m_DoublePhysBuffer); #endif /* USBUHCI_H__ */ Index: lib/drivers/libusb/common_interfaces.h =================================================================== --- lib/drivers/libusb/common_interfaces.h (revision 70555) +++ lib/drivers/libusb/common_interfaces.h (working copy) @@ -326,6 +326,10 @@ \ STDMETHOD_(ULONG, GetTransferType)( THIS) PURE; \ \ + STDMETHOD_(VOID, GetDoubleBuffer)( THIS_ \ + IN PVOID DoubleBuffer, \ + IN ULONG DoublePhysBuffer) PURE; \ + \ STDMETHOD_(VOID, GetResultStatus)( THIS_ \ OUT OPTIONAL NTSTATUS * NtStatusCode, \ OUT OPTIONAL PULONG UrbStatusCode) PURE; @@ -348,6 +352,10 @@ \ STDMETHODIMP_(ULONG) GetTransferType(VOID); \ \ + STDMETHODIMP_(VOID) GetDoubleBuffer( \ + IN PVOID DoubleBuffer, \ + IN ULONG DoublePhysBuffer); \ + \ STDMETHODIMP_(VOID) GetResultStatus( \ OUT OPTIONAL NTSTATUS * NtStatusCode, \ OUT OPTIONAL PULONG UrbStatusCode); @@ -373,6 +381,8 @@ IN PUSBHARDWAREDEVICE Hardware, \ IN PDMA_ADAPTER AdapterObject, \ IN PDMAMEMORYMANAGER MemManager, \ + IN PVOID DoubleBuffer, \ + IN ULONG DoublePhysBuffer, \ IN OPTIONAL PKSPIN_LOCK Lock) PURE; \ \ STDMETHOD_(NTSTATUS, AddUSBRequest)( THIS_ \ @@ -390,6 +400,8 @@ IN PUSBHARDWAREDEVICE Hardware, \ IN PDMA_ADAPTER AdapterObject, \ IN PDMAMEMORYMANAGER MemManager, \ + IN PVOID DoubleBuffer, \ + IN ULONG DoublePhysBuffer, \ IN OPTIONAL PKSPIN_LOCK Lock); \ \ STDMETHODIMP_(NTSTATUS) AddUSBRequest( \ Index: lib/drivers/libusb/hcd_controller.cpp =================================================================== --- lib/drivers/libusb/hcd_controller.cpp (revision 70555) +++ lib/drivers/libusb/hcd_controller.cpp (working copy) @@ -10,7 +10,7 @@ #include "libusb.h" -#define NDEBUG +//#define NDEBUG #include class CHCDController : public IHCDController, @@ -415,12 +415,19 @@ // start the hardware // Status = m_Hardware->PnpStart(RawResourceList, TranslatedResourceList); + + if (NT_SUCCESS(Status)) + { + // + // enable symbolic link + // + Status = SetSymbolicLink(TRUE); + } } - - // - // enable symbolic link - // - Status = SetSymbolicLink(TRUE); + else + { + Status = STATUS_UNSUCCESSFUL; + } } DPRINT("[%s] HandlePnp IRP_MN_START FDO: Status %x\n", m_USBType ,Status); Index: lib/drivers/libusb/hub_controller.cpp =================================================================== --- lib/drivers/libusb/hub_controller.cpp (revision 70555) +++ lib/drivers/libusb/hub_controller.cpp (working copy) @@ -10,7 +10,7 @@ #include "libusb.h" -#define NDEBUG +//#define NDEBUG #include VOID NTAPI StatusChangeEndpointCallBack( Index: lib/drivers/libusb/usb_device.cpp =================================================================== --- lib/drivers/libusb/usb_device.cpp (revision 70555) +++ lib/drivers/libusb/usb_device.cpp (working copy) @@ -10,7 +10,7 @@ #include "libusb.h" -#define NDEBUG +//#define NDEBUG #include class CUSBDevice : public IUSBDevice