Index: drivers/usb/usbohci/usb_request.cpp =================================================================== --- drivers/usb/usbohci/usb_request.cpp (revision 69875) +++ drivers/usb/usbohci/usb_request.cpp (working copy) @@ -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,11 @@ // base buffer // PVOID m_Base; + + // + // true if request have MDL + // + BOOLEAN m_RequestWithMdl; }; //---------------------------------------------------------------------------------------- @@ -362,6 +368,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,6 +398,7 @@ else { m_TransferBufferMDL = m_Urb->UrbBulkOrInterruptTransfer.TransferBufferMDL; + m_RequestWithMdl = TRUE; } // @@ -1338,6 +1347,167 @@ 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_PTR PfnArray; + ULONG PageNumber; + + + // 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 + + PfnArray = (ULONG_PTR)MmGetMdlPfnArray(m_TransferBufferMDL); + + // if transfer size >= 4096 (1 and more pages) + if (m_TransferBufferLength >= PAGE_SIZE) + { + PageNumber = (m_TransferBufferLengthCompleted >> PAGE_SHIFT) & 0x0000001F; // 0x3F for 0x40000 (0x1F for 0x10000) + + DPRINT("PageNumber - %x\n", PageNumber); + + if ( *(PULONG)((PULONG)PfnArray + PageNumber) > 1 ) + { + if ( (PageNumber == 0) && (m_TransferBufferMDL->ByteOffset > 0) ) + Address.LowPart = ((*(PULONG)PfnArray) << PAGE_SHIFT) + m_TransferBufferMDL->ByteOffset; + else + Address.LowPart = ((*(PULONG)((PULONG)PfnArray + PageNumber)) << PAGE_SHIFT); + } + else + { + DPRINT1("PhysAdr < 0x00001000\n"); //?? + } + } + else + { + // if transfer size < 4096 (< 1 page) + Address.LowPart = ((*(PULONG)PfnArray) << PAGE_SHIFT) + m_TransferBufferMDL->ByteOffset; + } + + if (Address.LowPart == 0) + { + // + return STATUS_UNSUCCESSFUL; + } + + CurrentDescriptor->BufferPhysical = Address.LowPart; + CurrentDescriptor->LastPhysicalByteAddress = CurrentDescriptor->BufferPhysical + TransferSize - 1; + + //DPRINT("CurrentDescriptor %p Addr %x TransferSize %lu\n", CurrentDescriptor, CurrentDescriptor->PhysicalAddress.LowPart, 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; + } + + //DPRINT("InitDescriptor: MaxTransferLength - %p, TransferBufferOffset - %x\n", MaxTransferLength, TransferBufferOffset); + + // 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) @@ -1582,18 +1752,38 @@ // // build request depending on type // - switch(TransferType) + switch (TransferType) { case USB_ENDPOINT_TYPE_CONTROL: Status = BuildControlTransferDescriptor((POHCI_ENDPOINT_DESCRIPTOR*)OutDescriptor); break; + case USB_ENDPOINT_TYPE_BULK: + if (m_RequestWithMdl) + { + Status = BuildBulkInterruptDataEndpoint(OutDescriptor); + } + else + { + Status = BuildBulkInterruptEndpoint(OutDescriptor); + } + break; + case USB_ENDPOINT_TYPE_INTERRUPT: - Status = BuildBulkInterruptEndpoint(OutDescriptor); + if (m_RequestWithMdl) + { + Status = BuildBulkInterruptDataEndpoint(OutDescriptor); + } + else + { + Status = BuildBulkInterruptEndpoint(OutDescriptor); + } break; + case USB_ENDPOINT_TYPE_ISOCHRONOUS: Status = BuildIsochronousEndpoint((POHCI_ENDPOINT_DESCRIPTOR*)OutDescriptor); break; + default: PC_ASSERT(FALSE); Status = STATUS_NOT_IMPLEMENTED;