2 * PROJECT: ReactOS Universal Serial Bus Bulk Enhanced Host Controller Interface
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: drivers/usb/usbehci/usb_request.cpp
5 * PURPOSE: USB EHCI device driver.
7 * Michael Martin (michael.martin@reactos.org)
8 * Johannes Anderwald (johannes.anderwald@reactos.org)
16 class CUSBRequest
: public IUSBRequest
19 STDMETHODIMP
QueryInterface( REFIID InterfaceId
, PVOID
* Interface
);
21 STDMETHODIMP_(ULONG
) AddRef()
23 InterlockedIncrement(&m_Ref
);
26 STDMETHODIMP_(ULONG
) Release()
28 InterlockedDecrement(&m_Ref
);
38 // IUSBRequest interface functions
39 virtual NTSTATUS
InitializeWithSetupPacket(IN PDMAMEMORYMANAGER DmaManager
, IN PUSB_DEFAULT_PIPE_SETUP_PACKET SetupPacket
, IN UCHAR DeviceAddress
, IN OPTIONAL PUSB_ENDPOINT_DESCRIPTOR EndpointDescriptor
, IN OUT ULONG TransferBufferLength
, IN OUT PMDL TransferBuffer
);
40 virtual NTSTATUS
InitializeWithIrp(IN PDMAMEMORYMANAGER DmaManager
, IN OUT PIRP Irp
);
41 virtual VOID
CompletionCallback(IN NTSTATUS NtStatusCode
, IN ULONG UrbStatusCode
, IN
struct _QUEUE_HEAD
*QueueHead
);
42 virtual VOID
CancelCallback(IN NTSTATUS NtStatusCode
, IN
struct _QUEUE_HEAD
*QueueHead
);
43 virtual NTSTATUS
GetQueueHead(struct _QUEUE_HEAD
** OutHead
);
44 virtual BOOLEAN
IsRequestComplete();
45 virtual ULONG
GetTransferType();
46 virtual VOID
GetResultStatus(OUT OPTIONAL NTSTATUS
*NtStatusCode
, OUT OPTIONAL PULONG UrbStatusCode
);
47 virtual BOOLEAN
IsRequestInitialized();
48 virtual BOOLEAN
ShouldReleaseRequestAfterCompletion();
49 virtual VOID
FreeQueueHead(struct _QUEUE_HEAD
* QueueHead
);
50 virtual VOID
GetTransferBuffer(OUT PMDL
* OutMDL
, OUT PULONG TransferLength
);
51 virtual BOOLEAN
IsQueueHeadComplete(struct _QUEUE_HEAD
* QueueHead
);
55 ULONG
InternalGetTransferType();
56 UCHAR
InternalGetPidDirection();
57 NTSTATUS
BuildControlTransferQueueHead(PQUEUE_HEAD
* OutHead
);
58 NTSTATUS
BuildBulkTransferQueueHead(PQUEUE_HEAD
* OutHead
);
59 NTSTATUS
CreateDescriptor(PQUEUE_TRANSFER_DESCRIPTOR
*OutDescriptor
);
60 NTSTATUS
CreateQueueHead(PQUEUE_HEAD
*OutQueueHead
);
61 UCHAR
GetDeviceAddress();
62 NTSTATUS
BuildSetupPacket();
63 NTSTATUS
BuildSetupPacketFromURB();
64 ULONG
InternalCalculateTransferLength();
66 // constructor / destructor
67 CUSBRequest(IUnknown
*OuterUnknown
){}
68 virtual ~CUSBRequest(){}
74 // memory manager for allocating setup packet / queue head / transfer descriptors
76 PDMAMEMORYMANAGER m_DmaManager
;
79 // caller provided irp packet containing URB request
84 // transfer buffer length
86 ULONG m_TransferBufferLength
;
89 // current transfer length
91 ULONG m_TransferBufferLengthCompleted
;
94 // Total Transfer Length
96 ULONG m_TotalBytesTransferred
;
99 // transfer buffer MDL
101 PMDL m_TransferBufferMDL
;
104 // caller provided setup packet
106 PUSB_DEFAULT_PIPE_SETUP_PACKET m_SetupPacket
;
109 // completion event for callers who initialized request with setup packet
111 PKEVENT m_CompletionEvent
;
114 // device address for callers who initialized it with device address
116 UCHAR m_DeviceAddress
;
119 // store end point address
121 PUSB_ENDPOINT_DESCRIPTOR m_EndpointDescriptor
;
126 PQUEUE_HEAD m_QueueHead
;
129 // DMA transfer descriptors linked to the queue head
131 PQUEUE_TRANSFER_DESCRIPTOR m_TransferDescriptors
[3];
134 // allocated setup packet from the DMA pool
136 PUSB_DEFAULT_PIPE_SETUP_PACKET m_DescriptorPacket
;
137 PHYSICAL_ADDRESS m_DescriptorSetupPacket
;
140 // stores the result of the operation
142 NTSTATUS m_NtStatusCode
;
143 ULONG m_UrbStatusCode
;
147 //----------------------------------------------------------------------------------------
150 CUSBRequest::QueryInterface(
154 return STATUS_UNSUCCESSFUL
;
157 //----------------------------------------------------------------------------------------
159 CUSBRequest::InitializeWithSetupPacket(
160 IN PDMAMEMORYMANAGER DmaManager
,
161 IN PUSB_DEFAULT_PIPE_SETUP_PACKET SetupPacket
,
162 IN UCHAR DeviceAddress
,
163 IN OPTIONAL PUSB_ENDPOINT_DESCRIPTOR EndpointDescriptor
,
164 IN OUT ULONG TransferBufferLength
,
165 IN OUT PMDL TransferBuffer
)
170 PC_ASSERT(DmaManager
);
171 PC_ASSERT(SetupPacket
);
176 m_DmaManager
= DmaManager
;
177 m_SetupPacket
= SetupPacket
;
178 m_TransferBufferLength
= TransferBufferLength
;
179 m_TransferBufferMDL
= TransferBuffer
;
180 m_DeviceAddress
= DeviceAddress
;
181 m_EndpointDescriptor
= EndpointDescriptor
;
182 m_TotalBytesTransferred
= 0;
185 // Set Length Completed to 0
187 m_TransferBufferLengthCompleted
= 0;
190 // allocate completion event
192 m_CompletionEvent
= (PKEVENT
)ExAllocatePoolWithTag(NonPagedPool
, sizeof(KEVENT
), TAG_USBEHCI
);
193 if (!m_CompletionEvent
)
196 // failed to allocate completion event
198 return STATUS_INSUFFICIENT_RESOURCES
;
202 // initialize completion event
204 KeInitializeEvent(m_CompletionEvent
, NotificationEvent
, FALSE
);
209 return STATUS_SUCCESS
;
211 //----------------------------------------------------------------------------------------
213 CUSBRequest::InitializeWithIrp(
214 IN PDMAMEMORYMANAGER DmaManager
,
217 PIO_STACK_LOCATION IoStack
;
223 PC_ASSERT(DmaManager
);
226 m_DmaManager
= DmaManager
;
227 m_TotalBytesTransferred
= 0;
230 // get current irp stack location
232 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
237 PC_ASSERT(IoStack
->MajorFunction
== IRP_MJ_INTERNAL_DEVICE_CONTROL
);
238 PC_ASSERT(IoStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_INTERNAL_USB_SUBMIT_URB
);
239 PC_ASSERT(IoStack
->Parameters
.Others
.Argument1
!= 0);
244 Urb
= (PURB
)IoStack
->Parameters
.Others
.Argument1
;
252 // check function type
254 switch (Urb
->UrbHeader
.Function
)
257 // luckily those request have the same structure layout
259 case URB_FUNCTION_CLASS_INTERFACE
:
260 case URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE
:
261 case URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER
:
264 // bulk interrupt transfer
266 if (Urb
->UrbBulkOrInterruptTransfer
.TransferBufferLength
)
269 // Check if there is a MDL
271 if (!Urb
->UrbBulkOrInterruptTransfer
.TransferBufferMDL
)
276 PC_ASSERT(Urb
->UrbBulkOrInterruptTransfer
.TransferBuffer
);
279 // Create one using TransferBuffer
281 DPRINT("Creating Mdl from Urb Buffer %p Length %lu\n", Urb
->UrbBulkOrInterruptTransfer
.TransferBuffer
, Urb
->UrbBulkOrInterruptTransfer
.TransferBufferLength
);
282 m_TransferBufferMDL
= IoAllocateMdl(Urb
->UrbBulkOrInterruptTransfer
.TransferBuffer
,
283 Urb
->UrbBulkOrInterruptTransfer
.TransferBufferLength
,
288 if (!m_TransferBufferMDL
)
291 // failed to allocate mdl
293 return STATUS_INSUFFICIENT_RESOURCES
;
297 // build mdl for non paged pool
298 // FIXME: Does hub driver already do this when passing MDL?
300 MmBuildMdlForNonPagedPool(m_TransferBufferMDL
);
303 // Keep that ehci created the MDL and needs to free it.
308 m_TransferBufferMDL
= Urb
->UrbBulkOrInterruptTransfer
.TransferBufferMDL
;
312 // save buffer length
314 m_TransferBufferLength
= Urb
->UrbBulkOrInterruptTransfer
.TransferBufferLength
;
317 // Set Length Completed to 0
319 m_TransferBufferLengthCompleted
= 0;
322 // get endpoint descriptor
324 m_EndpointDescriptor
= (PUSB_ENDPOINT_DESCRIPTOR
)Urb
->UrbBulkOrInterruptTransfer
.PipeHandle
;
330 DPRINT1("URB Function: not supported %x\n", Urb
->UrbHeader
.Function
);
337 return STATUS_SUCCESS
;
341 //----------------------------------------------------------------------------------------
343 CUSBRequest::CompletionCallback(
344 IN NTSTATUS NtStatusCode
,
345 IN ULONG UrbStatusCode
,
346 IN
struct _QUEUE_HEAD
*QueueHead
)
348 PIO_STACK_LOCATION IoStack
;
352 // FIXME: support linked queue heads
356 // store completion code
358 m_NtStatusCode
= NtStatusCode
;
359 m_UrbStatusCode
= UrbStatusCode
;
364 // set irp completion status
366 m_Irp
->IoStatus
.Status
= NtStatusCode
;
369 // get current irp stack location
371 IoStack
= IoGetCurrentIrpStackLocation(m_Irp
);
376 Urb
= (PURB
)IoStack
->Parameters
.Others
.Argument1
;
381 Urb
->UrbHeader
.Status
= UrbStatusCode
;
384 // Check if the MDL was created
386 if (!Urb
->UrbBulkOrInterruptTransfer
.TransferBufferMDL
)
391 IoFreeMdl(m_TransferBufferMDL
);
395 // check if the request was successfull
397 if (!NT_SUCCESS(NtStatusCode
))
400 // set returned length to zero in case of error
402 Urb
->UrbHeader
.Length
= 0;
407 // calculate transfer length
409 Urb
->UrbBulkOrInterruptTransfer
.TransferBufferLength
= InternalCalculateTransferLength();
412 DPRINT("Request %p Completing Irp %p NtStatusCode %x UrbStatusCode %x Transferred Length %lu\n", this, m_Irp
, NtStatusCode
, UrbStatusCode
, Urb
->UrbBulkOrInterruptTransfer
.TransferBufferLength
);
415 // FIXME: check if the transfer was split
416 // if yes dont complete irp yet
418 IoCompleteRequest(m_Irp
, IO_NO_INCREMENT
);
423 // signal completion event
425 PC_ASSERT(m_CompletionEvent
);
426 KeSetEvent(m_CompletionEvent
, 0, FALSE
);
429 //----------------------------------------------------------------------------------------
431 CUSBRequest::CancelCallback(
432 IN NTSTATUS NtStatusCode
,
433 IN
struct _QUEUE_HEAD
*QueueHead
)
435 PIO_STACK_LOCATION IoStack
;
439 // FIXME: support linked queue heads
443 // store cancelleation code
445 m_NtStatusCode
= NtStatusCode
;
450 // set irp completion status
452 m_Irp
->IoStatus
.Status
= NtStatusCode
;
455 // get current irp stack location
457 IoStack
= IoGetCurrentIrpStackLocation(m_Irp
);
462 Urb
= (PURB
)IoStack
->Parameters
.Others
.Argument1
;
467 DPRINT1("Request Cancelled\n");
468 Urb
->UrbHeader
.Status
= USBD_STATUS_CANCELED
;
469 Urb
->UrbHeader
.Length
= 0;
472 // FIXME: check if the transfer was split
473 // if yes dont complete irp yet
475 IoCompleteRequest(m_Irp
, IO_NO_INCREMENT
);
480 // signal completion event
482 PC_ASSERT(m_CompletionEvent
);
483 KeSetEvent(m_CompletionEvent
, 0, FALSE
);
486 //----------------------------------------------------------------------------------------
488 CUSBRequest::GetQueueHead(
489 struct _QUEUE_HEAD
** OutHead
)
495 // first get transfer type
497 TransferType
= InternalGetTransferType();
500 // build request depending on type
504 case USB_ENDPOINT_TYPE_CONTROL
:
505 Status
= BuildControlTransferQueueHead(OutHead
);
507 case USB_ENDPOINT_TYPE_BULK
:
508 Status
= BuildBulkTransferQueueHead(OutHead
);
510 case USB_ENDPOINT_TYPE_INTERRUPT
:
511 DPRINT1("USB_ENDPOINT_TYPE_INTERRUPT not implemented\n");
512 Status
= STATUS_NOT_IMPLEMENTED
;
514 case USB_ENDPOINT_TYPE_ISOCHRONOUS
:
515 DPRINT1("USB_ENDPOINT_TYPE_ISOCHRONOUS not implemented\n");
516 Status
= STATUS_NOT_IMPLEMENTED
;
520 Status
= STATUS_NOT_IMPLEMENTED
;
524 if (NT_SUCCESS(Status
))
529 m_QueueHead
= *OutHead
;
532 // store request object
534 (*OutHead
)->Request
= PVOID(this);
543 //----------------------------------------------------------------------------------------
545 CUSBRequest::IsRequestComplete()
548 // FIXME: check if request was split
552 // Check if the transfer was completed, only valid for Bulk Transfers
554 if ((m_TransferBufferLengthCompleted
< m_TransferBufferLength
)
555 && (GetTransferType() == USB_ENDPOINT_TYPE_BULK
))
558 // Transfer not completed
564 //----------------------------------------------------------------------------------------
566 CUSBRequest::GetTransferType()
569 // call internal implementation
571 return InternalGetTransferType();
574 //----------------------------------------------------------------------------------------
576 CUSBRequest::InternalGetTransferType()
581 // check if an irp is provided
585 ASSERT(m_EndpointDescriptor
);
588 // end point is defined in the low byte of bmAttributes
590 TransferType
= (m_EndpointDescriptor
->bmAttributes
& USB_ENDPOINT_TYPE_MASK
);
595 // initialized with setup packet, must be a control transfer
597 TransferType
= USB_ENDPOINT_TYPE_CONTROL
;
607 CUSBRequest::InternalGetPidDirection()
610 ASSERT(m_EndpointDescriptor
);
613 // end point is defined in the low byte of bEndpointAddress
615 return (m_EndpointDescriptor
->bEndpointAddress
& USB_ENDPOINT_DIRECTION_MASK
) >> 7;
618 //----------------------------------------------------------------------------------------
620 CUSBRequest::BuildControlTransferQueueHead(
621 PQUEUE_HEAD
* OutHead
)
624 ULONG NumTransferDescriptors
, Index
;
625 PQUEUE_HEAD QueueHead
;
628 // first allocate the queue head
630 Status
= CreateQueueHead(&QueueHead
);
631 if (!NT_SUCCESS(Status
))
634 // failed to allocate queue head
636 return STATUS_INSUFFICIENT_RESOURCES
;
642 PC_ASSERT(QueueHead
);
645 // create setup packet
647 Status
= BuildSetupPacket();
648 if (!NT_SUCCESS(Status
))
651 // failed to allocate setup packet
653 return STATUS_INSUFFICIENT_RESOURCES
;
657 // calculate num of transfer descriptors
659 NumTransferDescriptors
= m_TransferBufferMDL
!= 0 ? 3 : 2;
662 // allocate transfer descriptors
664 for(Index
= 0; Index
< NumTransferDescriptors
; Index
++)
667 // allocate transfer descriptor
669 Status
= CreateDescriptor(&m_TransferDescriptors
[Index
]);
670 if (!NT_SUCCESS(Status
))
673 // failed to allocate transfer descriptor
680 // now initialize the queue head
682 QueueHead
->EndPointCharacteristics
.DeviceAddress
= GetDeviceAddress();
684 if (m_EndpointDescriptor
)
687 // set endpoint address and max packet length
689 QueueHead
->EndPointCharacteristics
.EndPointNumber
= m_EndpointDescriptor
->bEndpointAddress
& 0x0F;
690 QueueHead
->EndPointCharacteristics
.MaximumPacketLength
= m_EndpointDescriptor
->wMaxPacketSize
;
693 QueueHead
->Token
.Bits
.DataToggle
= TRUE
;
698 m_TransferDescriptors
[0]->Token
.Bits
.PIDCode
= PID_CODE_SETUP_TOKEN
;
699 m_TransferDescriptors
[0]->Token
.Bits
.TotalBytesToTransfer
= sizeof(USB_DEFAULT_PIPE_SETUP_PACKET
);
700 m_TransferDescriptors
[0]->Token
.Bits
.DataToggle
= FALSE
;
702 if (m_TransferBufferMDL
)
705 // setup in descriptor
707 m_TransferDescriptors
[1]->Token
.Bits
.PIDCode
= PID_CODE_IN_TOKEN
;
708 m_TransferDescriptors
[1]->Token
.Bits
.TotalBytesToTransfer
= m_TransferBufferLength
;
711 // FIXME: check if the request spawns over a page -> fill other members
713 PC_ASSERT(m_TransferBufferLength
<= PAGE_SIZE
);
714 m_TransferDescriptors
[1]->BufferPointer
[0] = MmGetPhysicalAddress(MmGetMdlVirtualAddress(m_TransferBufferMDL
)).LowPart
;
717 // setup out descriptor
719 m_TransferDescriptors
[2]->Token
.Bits
.PIDCode
= PID_CODE_OUT_TOKEN
;
720 m_TransferDescriptors
[2]->Token
.Bits
.TotalBytesToTransfer
= 0;
725 m_TransferDescriptors
[0]->NextPointer
= m_TransferDescriptors
[1]->PhysicalAddr
;
728 // special case, setup alternative next descriptor in case of error
729 // HAIKU links to dead descriptor
731 m_TransferDescriptors
[0]->AlternateNextPointer
= m_TransferDescriptors
[2]->PhysicalAddr
;
732 m_TransferDescriptors
[1]->NextPointer
= m_TransferDescriptors
[2]->PhysicalAddr
;
733 m_TransferDescriptors
[1]->AlternateNextPointer
= m_TransferDescriptors
[2]->PhysicalAddr
;
736 // interrupt on completion
738 m_TransferDescriptors
[2]->Token
.Bits
.InterruptOnComplete
= TRUE
;
744 // no buffer, setup in descriptor
746 m_TransferDescriptors
[1]->Token
.Bits
.PIDCode
= PID_CODE_IN_TOKEN
;
747 m_TransferDescriptors
[1]->Token
.Bits
.TotalBytesToTransfer
= 0;
752 m_TransferDescriptors
[0]->NextPointer
= m_TransferDescriptors
[1]->PhysicalAddr
;
753 m_TransferDescriptors
[0]->AlternateNextPointer
= m_TransferDescriptors
[1]->PhysicalAddr
;
756 // interrupt on completion
758 m_TransferDescriptors
[1]->Token
.Bits
.InterruptOnComplete
= TRUE
;
762 // link setup packet into buffer - Physical Address!!!
764 m_TransferDescriptors
[0]->BufferPointer
[0] = (ULONG
)PtrToUlong(m_DescriptorSetupPacket
.LowPart
);
767 // link transfer descriptors to queue head
769 QueueHead
->NextPointer
= m_TransferDescriptors
[0]->PhysicalAddr
;
774 *OutHead
= QueueHead
;
779 return STATUS_SUCCESS
;
782 //----------------------------------------------------------------------------------------
784 CUSBRequest::BuildBulkTransferQueueHead(
785 PQUEUE_HEAD
* OutHead
)
788 PQUEUE_HEAD QueueHead
;
789 ULONG TransferDescriptorCount
, Index
;
790 ULONG BytesAvailable
, BufferIndex
;
792 ULONG PageOffset
, CurrentTransferBufferLength
;
795 // Allocate the queue head
797 Status
= CreateQueueHead(&QueueHead
);
799 if (!NT_SUCCESS(Status
))
802 // failed to allocate queue heads
804 return STATUS_INSUFFICIENT_RESOURCES
;
810 PC_ASSERT(QueueHead
);
811 PC_ASSERT(m_TransferBufferLength
);
814 // Max default of 3 descriptors
816 TransferDescriptorCount
= 3;
819 // get virtual base of mdl
821 Base
= MmGetSystemAddressForMdlSafe(m_TransferBufferMDL
, NormalPagePriority
);
824 // Increase the size of last transfer, 0 in case this is the first
826 Base
= (PVOID
)((ULONG_PTR
)Base
+ m_TransferBufferLengthCompleted
);
828 PC_ASSERT(m_EndpointDescriptor
);
832 // Get the offset from page size
834 PageOffset
= BYTE_OFFSET(Base
);
837 // PageOffset should only be > 0 if this is the first transfer for this requests
839 if ((PageOffset
!= 0) && (m_TransferBufferLengthCompleted
!= 0))
845 // Calculate the size of this transfer
847 if ((PageOffset
!= 0) && ((m_TransferBufferLength
- m_TransferBufferLengthCompleted
) >= (PAGE_SIZE
* 4) + PageOffset
))
849 CurrentTransferBufferLength
= (PAGE_SIZE
* 4) + PageOffset
;
851 else if ((m_TransferBufferLength
- m_TransferBufferLengthCompleted
) >= PAGE_SIZE
* 5)
853 CurrentTransferBufferLength
= PAGE_SIZE
* 5;
856 CurrentTransferBufferLength
= (m_TransferBufferLength
- m_TransferBufferLengthCompleted
);
859 // Add current transfer length to transfer length completed
861 m_TransferBufferLengthCompleted
+= CurrentTransferBufferLength
;
862 BytesAvailable
= CurrentTransferBufferLength
;
863 DPRINT("CurrentTransferBufferLength %x, m_TransferBufferLengthCompleted %x\n", CurrentTransferBufferLength
, m_TransferBufferLengthCompleted
);
865 DPRINT("EndPointAddress %x\n", m_EndpointDescriptor
->bEndpointAddress
);
866 DPRINT("EndPointDirection %x\n", USB_ENDPOINT_DIRECTION_IN(m_EndpointDescriptor
->bEndpointAddress
));
868 DPRINT("Request %p Base Address %p TransferBytesLength %lu MDL %p\n", this, Base
, BytesAvailable
, m_TransferBufferMDL
);
869 DPRINT("InternalGetPidDirection() %d EndPointAddress %x\n", InternalGetPidDirection(), m_EndpointDescriptor
->bEndpointAddress
& 0x0F);
870 DPRINT("Irp %p QueueHead %p\n", m_Irp
, QueueHead
);
872 //PC_ASSERT(InternalGetPidDirection() == USB_ENDPOINT_DIRECTION_IN(m_EndpointDescriptor->bEndpointAddress));
875 // Allocated transfer descriptors
877 for (Index
= 0; Index
< TransferDescriptorCount
; Index
++)
879 Status
= CreateDescriptor(&m_TransferDescriptors
[Index
]);
880 if (!NT_SUCCESS(Status
))
883 // Failed to allocate transfer descriptors
889 FreeQueueHead(QueueHead
);
893 // FIXME: Implement FreeDescriptors
901 PC_ASSERT(BytesAvailable
);
904 // now setup transfer buffers
906 for(BufferIndex
= 0; BufferIndex
< 5; BufferIndex
++)
909 // If this is the first buffer of the first descriptor and there is a PageOffset
911 if ((BufferIndex
== 0) && (PageOffset
!= 0) && (Index
== 0))
914 // use physical address
916 m_TransferDescriptors
[Index
]->BufferPointer
[0] = MmGetPhysicalAddress(Base
).LowPart
;
921 Base
= (PVOID
)ROUND_TO_PAGES(Base
);
924 // increment transfer bytes
926 if (CurrentTransferBufferLength
> PAGE_SIZE
- PageOffset
)
927 m_TransferDescriptors
[Index
]->Token
.Bits
.TotalBytesToTransfer
= PAGE_SIZE
- PageOffset
;
929 m_TransferDescriptors
[Index
]->Token
.Bits
.TotalBytesToTransfer
= CurrentTransferBufferLength
;
932 // decrement available byte count
934 BytesAvailable
-= m_TransferDescriptors
[Index
]->Token
.Bits
.TotalBytesToTransfer
;
936 DPRINT("TransferDescriptor %p BufferPointer %p BufferIndex %lu TotalBytes %lu Remaining %lu\n", m_TransferDescriptors
[Index
], m_TransferDescriptors
[Index
]->BufferPointer
[BufferIndex
],
937 BufferIndex
, m_TransferDescriptors
[Index
]->Token
.Bits
.TotalBytesToTransfer
, BytesAvailable
);
942 // the following pages always start on byte zero of each page
944 PC_ASSERT(((ULONG_PTR
)Base
& (PAGE_SIZE
-1)) == 0);
946 if (BytesAvailable
>= PAGE_SIZE
)
951 m_TransferDescriptors
[Index
]->BufferPointer
[BufferIndex
] = MmGetPhysicalAddress(Base
).LowPart
;
956 Base
= (PVOID
)((ULONG_PTR
)Base
+ PAGE_SIZE
);
959 // increment transfer descriptor bytes
961 m_TransferDescriptors
[Index
]->Token
.Bits
.TotalBytesToTransfer
+= PAGE_SIZE
;
964 // decrement available byte count
966 BytesAvailable
-= PAGE_SIZE
;
968 DPRINT("TransferDescriptor %p BufferPointer %p BufferIndex %lu TotalBytes %lu Remaining %lu\n", m_TransferDescriptors
[Index
], m_TransferDescriptors
[Index
]->BufferPointer
[BufferIndex
],
969 BufferIndex
, m_TransferDescriptors
[Index
]->Token
.Bits
.TotalBytesToTransfer
, BytesAvailable
);
973 PC_ASSERT(BytesAvailable
);
978 m_TransferDescriptors
[Index
]->BufferPointer
[BufferIndex
] = MmGetPhysicalAddress(Base
).LowPart
;
981 // increment transfer descriptor bytes
983 m_TransferDescriptors
[Index
]->Token
.Bits
.TotalBytesToTransfer
+= BytesAvailable
;
986 // decrement available byte count
988 BytesAvailable
-= BytesAvailable
;
991 // done as this is the last partial or full page
993 DPRINT("TransferDescriptor %p BufferPointer %p BufferIndex %lu TotalBytes %lu Remaining %lu\n", m_TransferDescriptors
[Index
], m_TransferDescriptors
[Index
]->BufferPointer
[BufferIndex
],
994 BufferIndex
, m_TransferDescriptors
[Index
]->Token
.Bits
.TotalBytesToTransfer
, BytesAvailable
);
1001 // Check if all bytes have been consumed
1003 if (BytesAvailable
== 0)
1008 // store transfer bytes of descriptor
1010 m_TransferDescriptors
[Index
]->TotalBytesToTransfer
= m_TransferDescriptors
[Index
]->Token
.Bits
.TotalBytesToTransfer
;
1013 // Go ahead and link descriptors
1017 m_TransferDescriptors
[Index
- 1]->NextPointer
= m_TransferDescriptors
[Index
]->PhysicalAddr
;
1023 m_TransferDescriptors
[Index
]->Token
.Bits
.PIDCode
= InternalGetPidDirection();
1026 // FIXME: performance penality?
1028 m_TransferDescriptors
[Index
]->Token
.Bits
.InterruptOnComplete
= TRUE
;
1031 // FIXME need dead queue transfer descriptor?
1035 // Check if all bytes have been consumed
1037 if (BytesAvailable
== 0)
1042 // all bytes should have been consumed
1044 PC_ASSERT(BytesAvailable
== 0);
1047 // Initialize the QueueHead
1049 QueueHead
->EndPointCharacteristics
.DeviceAddress
= GetDeviceAddress();
1051 if (m_EndpointDescriptor
)
1054 // Set endpoint address and max packet length
1056 QueueHead
->EndPointCharacteristics
.EndPointNumber
= m_EndpointDescriptor
->bEndpointAddress
& 0x0F;
1057 QueueHead
->EndPointCharacteristics
.MaximumPacketLength
= m_EndpointDescriptor
->wMaxPacketSize
;
1060 QueueHead
->Token
.Bits
.DataToggle
= TRUE
;
1063 // link descriptor with queue head
1065 QueueHead
->NextPointer
= m_TransferDescriptors
[0]->PhysicalAddr
;
1070 *OutHead
= QueueHead
;
1075 return STATUS_SUCCESS
;
1078 //----------------------------------------------------------------------------------------
1080 CUSBRequest::CreateDescriptor(
1081 PQUEUE_TRANSFER_DESCRIPTOR
*OutDescriptor
)
1083 PQUEUE_TRANSFER_DESCRIPTOR Descriptor
;
1085 PHYSICAL_ADDRESS TransferDescriptorPhysicalAddress
;
1088 // allocate descriptor
1090 Status
= m_DmaManager
->Allocate(sizeof(QUEUE_TRANSFER_DESCRIPTOR
), (PVOID
*)&Descriptor
, &TransferDescriptorPhysicalAddress
);
1091 if (!NT_SUCCESS(Status
))
1094 // failed to allocate transfer descriptor
1096 return STATUS_INSUFFICIENT_RESOURCES
;
1100 // initialize transfer descriptor
1102 Descriptor
->NextPointer
= TERMINATE_POINTER
;
1103 Descriptor
->AlternateNextPointer
= TERMINATE_POINTER
;
1104 Descriptor
->Token
.Bits
.DataToggle
= TRUE
;
1105 Descriptor
->Token
.Bits
.ErrorCounter
= 0x03;
1106 Descriptor
->Token
.Bits
.Active
= TRUE
;
1107 Descriptor
->PhysicalAddr
= TransferDescriptorPhysicalAddress
.LowPart
;
1112 *OutDescriptor
= Descriptor
;
1120 //----------------------------------------------------------------------------------------
1122 CUSBRequest::CreateQueueHead(
1123 PQUEUE_HEAD
*OutQueueHead
)
1125 PQUEUE_HEAD QueueHead
;
1126 PHYSICAL_ADDRESS QueueHeadPhysicalAddress
;
1130 // allocate queue head
1132 Status
= m_DmaManager
->Allocate(sizeof(QUEUE_HEAD
), (PVOID
*)&QueueHead
, &QueueHeadPhysicalAddress
);
1134 if (!NT_SUCCESS(Status
))
1137 // failed to allocate queue head
1139 return STATUS_INSUFFICIENT_RESOURCES
;
1143 // initialize queue head
1145 QueueHead
->HorizontalLinkPointer
= TERMINATE_POINTER
;
1146 QueueHead
->AlternateNextPointer
= TERMINATE_POINTER
;
1147 QueueHead
->NextPointer
= TERMINATE_POINTER
;
1150 // 1 for non high speed, 0 for high speed device
1152 QueueHead
->EndPointCharacteristics
.ControlEndPointFlag
= 0;
1153 QueueHead
->EndPointCharacteristics
.HeadOfReclamation
= FALSE
;
1154 QueueHead
->EndPointCharacteristics
.MaximumPacketLength
= 64;
1157 // Set NakCountReload to max value possible
1159 QueueHead
->EndPointCharacteristics
.NakCountReload
= 0xF;
1162 // Get the Initial Data Toggle from the QEDT
1164 QueueHead
->EndPointCharacteristics
.QEDTDataToggleControl
= FALSE
;
1167 // FIXME: check if High Speed Device
1169 QueueHead
->EndPointCharacteristics
.EndPointSpeed
= QH_ENDPOINT_HIGHSPEED
;
1170 QueueHead
->EndPointCapabilities
.NumberOfTransactionPerFrame
= 0x03;
1171 QueueHead
->Token
.DWord
= 0;
1172 QueueHead
->Token
.Bits
.InterruptOnComplete
= FALSE
;
1175 // FIXME check if that is really needed
1177 QueueHead
->PhysicalAddr
= QueueHeadPhysicalAddress
.LowPart
;
1180 // output queue head
1182 *OutQueueHead
= QueueHead
;
1187 return STATUS_SUCCESS
;
1190 //----------------------------------------------------------------------------------------
1192 CUSBRequest::GetDeviceAddress()
1194 PIO_STACK_LOCATION IoStack
;
1196 PUSBDEVICE UsbDevice
;
1199 // check if there is an irp provided
1204 // used provided address
1206 return m_DeviceAddress
;
1210 // get current stack location
1212 IoStack
= IoGetCurrentIrpStackLocation(m_Irp
);
1215 // get contained urb
1217 Urb
= (PURB
)IoStack
->Parameters
.Others
.Argument1
;
1220 // check if there is a pipe handle provided
1222 if (Urb
->UrbHeader
.UsbdDeviceHandle
)
1225 // there is a device handle provided
1227 UsbDevice
= (PUSBDEVICE
)Urb
->UrbHeader
.UsbdDeviceHandle
;
1230 // return device address
1232 return UsbDevice
->GetDeviceAddress();
1236 // no device handle provided, it is the host root bus
1241 //----------------------------------------------------------------------------------------
1243 CUSBRequest::BuildSetupPacket()
1248 // allocate common buffer setup packet
1250 Status
= m_DmaManager
->Allocate(sizeof(USB_DEFAULT_PIPE_SETUP_PACKET
), (PVOID
*)&m_DescriptorPacket
, &m_DescriptorSetupPacket
);
1251 if (!NT_SUCCESS(Status
))
1262 // copy setup packet
1264 RtlCopyMemory(m_DescriptorPacket
, m_SetupPacket
, sizeof(USB_DEFAULT_PIPE_SETUP_PACKET
));
1269 // build setup packet from urb
1271 Status
= BuildSetupPacketFromURB();
1282 CUSBRequest::BuildSetupPacketFromURB()
1284 PIO_STACK_LOCATION IoStack
;
1286 NTSTATUS Status
= STATUS_NOT_IMPLEMENTED
;
1292 PC_ASSERT(m_DescriptorPacket
);
1295 // get stack location
1297 IoStack
= IoGetCurrentIrpStackLocation(m_Irp
);
1302 Urb
= (PURB
)IoStack
->Parameters
.Others
.Argument1
;
1305 // zero descriptor packet
1307 RtlZeroMemory(m_DescriptorPacket
, sizeof(USB_DEFAULT_PIPE_SETUP_PACKET
));
1310 switch (Urb
->UrbHeader
.Function
)
1313 case URB_FUNCTION_CLEAR_FEATURE_TO_DEVICE
:
1314 case URB_FUNCTION_CLEAR_FEATURE_TO_INTERFACE
:
1315 case URB_FUNCTION_CLEAR_FEATURE_TO_ENDPOINT
:
1320 case URB_FUNCTION_GET_CONFIGURATION
:
1321 m_DescriptorPacket
->bRequest
= USB_REQUEST_GET_CONFIGURATION
;
1322 m_DescriptorPacket
->bmRequestType
.B
= 0x80;
1323 m_DescriptorPacket
->wLength
= 1;
1326 /* GET DESCRIPTOR */
1327 case URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE
:
1328 m_DescriptorPacket
->bRequest
= USB_REQUEST_GET_DESCRIPTOR
;
1329 m_DescriptorPacket
->wValue
.LowByte
= Urb
->UrbControlDescriptorRequest
.Index
;
1330 m_DescriptorPacket
->wValue
.HiByte
= Urb
->UrbControlDescriptorRequest
.DescriptorType
;
1331 m_DescriptorPacket
->wIndex
.W
= Urb
->UrbControlDescriptorRequest
.LanguageId
;
1332 m_DescriptorPacket
->wLength
= Urb
->UrbControlDescriptorRequest
.TransferBufferLength
;
1333 m_DescriptorPacket
->bmRequestType
.B
= 0x80;
1337 case URB_FUNCTION_GET_INTERFACE
:
1338 m_DescriptorPacket
->bRequest
= USB_REQUEST_GET_CONFIGURATION
;
1339 m_DescriptorPacket
->wIndex
.W
= Urb
->UrbControlGetStatusRequest
.Index
;
1340 m_DescriptorPacket
->bmRequestType
.B
= 0x80;
1341 m_DescriptorPacket
->wLength
= 1;
1345 case URB_FUNCTION_GET_STATUS_FROM_DEVICE
:
1346 m_DescriptorPacket
->bRequest
= USB_REQUEST_GET_STATUS
;
1347 ASSERT(Urb
->UrbControlGetStatusRequest
.Index
== 0);
1348 m_DescriptorPacket
->wIndex
.W
= Urb
->UrbControlGetStatusRequest
.Index
;
1349 m_DescriptorPacket
->bmRequestType
.B
= 0x80;
1350 m_DescriptorPacket
->wLength
= 2;
1353 case URB_FUNCTION_GET_STATUS_FROM_INTERFACE
:
1354 m_DescriptorPacket
->bRequest
= USB_REQUEST_GET_STATUS
;
1355 ASSERT(Urb
->UrbControlGetStatusRequest
.Index
!= 0);
1356 m_DescriptorPacket
->wIndex
.W
= Urb
->UrbControlGetStatusRequest
.Index
;
1357 m_DescriptorPacket
->bmRequestType
.B
= 0x81;
1358 m_DescriptorPacket
->wLength
= 2;
1361 case URB_FUNCTION_GET_STATUS_FROM_ENDPOINT
:
1362 m_DescriptorPacket
->bRequest
= USB_REQUEST_GET_STATUS
;
1363 ASSERT(Urb
->UrbControlGetStatusRequest
.Index
!= 0);
1364 m_DescriptorPacket
->wIndex
.W
= Urb
->UrbControlGetStatusRequest
.Index
;
1365 m_DescriptorPacket
->bmRequestType
.B
= 0x82;
1366 m_DescriptorPacket
->wLength
= 2;
1372 case URB_FUNCTION_SELECT_CONFIGURATION
:
1373 m_DescriptorPacket
->bRequest
= USB_REQUEST_SET_CONFIGURATION
;
1374 m_DescriptorPacket
->wValue
.W
= Urb
->UrbSelectConfiguration
.ConfigurationDescriptor
->bConfigurationValue
;
1375 m_DescriptorPacket
->wIndex
.W
= 0;
1376 m_DescriptorPacket
->wLength
= 0;
1377 m_DescriptorPacket
->bmRequestType
.B
= 0x00;
1380 /* SET DESCRIPTOR */
1381 case URB_FUNCTION_SET_DESCRIPTOR_TO_DEVICE
:
1382 case URB_FUNCTION_SET_DESCRIPTOR_TO_INTERFACE
:
1383 case URB_FUNCTION_SET_DESCRIPTOR_TO_ENDPOINT
:
1388 case URB_FUNCTION_SET_FEATURE_TO_DEVICE
:
1389 m_DescriptorPacket
->bRequest
= USB_REQUEST_SET_FEATURE
;
1390 ASSERT(Urb
->UrbControlGetStatusRequest
.Index
== 0);
1391 m_DescriptorPacket
->wIndex
.W
= Urb
->UrbControlGetStatusRequest
.Index
;
1392 m_DescriptorPacket
->bmRequestType
.B
= 0x80;
1395 case URB_FUNCTION_SET_FEATURE_TO_INTERFACE
:
1396 m_DescriptorPacket
->bRequest
= USB_REQUEST_SET_FEATURE
;
1397 ASSERT(Urb
->UrbControlGetStatusRequest
.Index
== 0);
1398 m_DescriptorPacket
->wIndex
.W
= Urb
->UrbControlGetStatusRequest
.Index
;
1399 m_DescriptorPacket
->bmRequestType
.B
= 0x81;
1402 case URB_FUNCTION_SET_FEATURE_TO_ENDPOINT
:
1403 m_DescriptorPacket
->bRequest
= USB_REQUEST_SET_FEATURE
;
1404 ASSERT(Urb
->UrbControlGetStatusRequest
.Index
== 0);
1405 m_DescriptorPacket
->wIndex
.W
= Urb
->UrbControlGetStatusRequest
.Index
;
1406 m_DescriptorPacket
->bmRequestType
.B
= 0x82;
1410 case URB_FUNCTION_SELECT_INTERFACE
:
1411 m_DescriptorPacket
->bRequest
= USB_REQUEST_SET_INTERFACE
;
1412 m_DescriptorPacket
->wValue
.W
= Urb
->UrbSelectInterface
.Interface
.AlternateSetting
;
1413 m_DescriptorPacket
->wIndex
.W
= Urb
->UrbSelectInterface
.Interface
.InterfaceNumber
;
1414 m_DescriptorPacket
->wLength
= 0;
1415 m_DescriptorPacket
->bmRequestType
.B
= 0x01;
1419 case URB_FUNCTION_SYNC_RESET_PIPE_AND_CLEAR_STALL
:
1430 //----------------------------------------------------------------------------------------
1432 CUSBRequest::GetResultStatus(
1433 OUT OPTIONAL NTSTATUS
* NtStatusCode
,
1434 OUT OPTIONAL PULONG UrbStatusCode
)
1439 PC_ASSERT(m_CompletionEvent
);
1442 // wait for the operation to complete
1444 KeWaitForSingleObject(m_CompletionEvent
, Executive
, KernelMode
, FALSE
, NULL
);
1451 *NtStatusCode
= m_NtStatusCode
;
1459 *UrbStatusCode
= m_UrbStatusCode
;
1465 //-----------------------------------------------------------------------------------------
1467 CUSBRequest::IsRequestInitialized()
1469 if (m_Irp
|| m_SetupPacket
)
1472 // request is initialized
1478 // request is not initialized
1483 //-----------------------------------------------------------------------------------------
1485 CUSBRequest::ShouldReleaseRequestAfterCompletion()
1490 // the request is completed, release it
1497 // created with an setup packet, don't release
1503 //-----------------------------------------------------------------------------------------
1505 CUSBRequest::FreeQueueHead(
1506 IN
struct _QUEUE_HEAD
* QueueHead
)
1508 LONG DescriptorCount
;
1511 // FIXME: support chained queue heads
1513 //PC_ASSERT(QueueHead == m_QueueHead);
1516 // release queue head
1518 m_DmaManager
->Release(QueueHead
, sizeof(QUEUE_HEAD
));
1526 // release transfer descriptors
1528 for (DescriptorCount
= 0; DescriptorCount
< 3; DescriptorCount
++)
1530 if (m_TransferDescriptors
[DescriptorCount
])
1533 // Calculate Total Bytes Transferred
1534 // FIXME: Is this the correct method of determine bytes transferred?
1536 if (USB_ENDPOINT_TYPE_BULK
== GetTransferType())
1541 ASSERT(m_EndpointDescriptor
);
1543 if (USB_ENDPOINT_DIRECTION_IN(m_EndpointDescriptor
->bEndpointAddress
))
1545 DPRINT1("m_TotalBytesTransferred %x, %x - %x\n",
1546 m_TotalBytesTransferred
,
1547 m_TransferDescriptors
[DescriptorCount
]->TotalBytesToTransfer
,
1548 m_TransferDescriptors
[DescriptorCount
]->Token
.Bits
.TotalBytesToTransfer
);
1550 m_TotalBytesTransferred
+=
1551 m_TransferDescriptors
[DescriptorCount
]->TotalBytesToTransfer
-
1552 m_TransferDescriptors
[DescriptorCount
]->Token
.Bits
.TotalBytesToTransfer
;
1557 // release transfer descriptors
1559 m_DmaManager
->Release(m_TransferDescriptors
[DescriptorCount
], sizeof(QUEUE_TRANSFER_DESCRIPTOR
));
1560 m_TransferDescriptors
[DescriptorCount
] = 0;
1564 if (m_DescriptorPacket
)
1567 // release packet descriptor
1569 m_DmaManager
->Release(m_DescriptorPacket
, sizeof(USB_DEFAULT_PIPE_SETUP_PACKET
));
1570 m_DescriptorPacket
= 0;
1574 //-----------------------------------------------------------------------------------------
1576 CUSBRequest::IsQueueHeadComplete(
1577 struct _QUEUE_HEAD
* QueueHead
)
1582 // first check - is the queue head currently active
1584 if (QueueHead
->Token
.Bits
.Active
)
1587 // queue head is active (currently processed)
1593 // FIXME: support chained queue heads
1595 for(Index
= 0; Index
< 3; Index
++)
1598 // check transfer descriptors for completion
1600 if (m_TransferDescriptors
[Index
])
1603 // check for serious error
1605 //PC_ASSERT(m_TransferDescriptors[Index]->Token.Bits.Halted == 0);
1608 // the transfer descriptor should be in the same state as the queue head
1610 //PC_ASSERT(m_TransferDescriptors[Index]->Token.Bits.Active == 0);
1617 //-----------------------------------------------------------------------------------------
1619 CUSBRequest::GetTransferBuffer(
1621 OUT PULONG TransferLength
)
1625 PC_ASSERT(TransferLength
);
1627 *OutMDL
= m_TransferBufferMDL
;
1628 *TransferLength
= m_TransferBufferLength
;
1630 //-----------------------------------------------------------------------------------------
1632 CUSBRequest::InternalCalculateTransferLength()
1637 // FIXME: get length for control request
1639 return m_TransferBufferLength
;
1645 ASSERT(m_EndpointDescriptor
);
1647 if (USB_ENDPOINT_DIRECTION_IN(m_EndpointDescriptor
->bEndpointAddress
))
1651 // HACK: Properly determine transfer length
1653 return m_TransferBufferLength
;//m_TotalBytesTransferred;
1657 // bulk out transfer
1659 return m_TransferBufferLength
;
1662 //-----------------------------------------------------------------------------------------
1664 InternalCreateUSBRequest(
1665 PUSBREQUEST
*OutRequest
)
1670 // allocate requests
1672 This
= new(NonPagedPool
, TAG_USBEHCI
) CUSBRequest(0);
1676 // failed to allocate
1678 return STATUS_INSUFFICIENT_RESOURCES
;
1682 // add reference count
1689 *OutRequest
= (PUSBREQUEST
)This
;
1694 return STATUS_SUCCESS
;