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/usbohci/usb_request.cpp
5 * PURPOSE: USB OHCI 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 BOOLEAN
IsRequestComplete();
42 virtual ULONG
GetTransferType();
43 virtual NTSTATUS
GetEndpointDescriptor(struct _OHCI_ENDPOINT_DESCRIPTOR
** OutEndpointDescriptor
);
44 virtual VOID
GetResultStatus(OUT OPTIONAL NTSTATUS
*NtStatusCode
, OUT OPTIONAL PULONG UrbStatusCode
);
45 virtual BOOLEAN
IsRequestInitialized();
46 virtual BOOLEAN
IsQueueHeadComplete(struct _QUEUE_HEAD
* QueueHead
);
50 ULONG
InternalGetTransferType();
51 UCHAR
InternalGetPidDirection();
52 UCHAR
GetDeviceAddress();
53 NTSTATUS
BuildSetupPacket();
54 NTSTATUS
BuildSetupPacketFromURB();
55 NTSTATUS
BuildControlTransferDescriptor(POHCI_ENDPOINT_DESCRIPTOR
* OutEndpointDescriptor
);
56 NTSTATUS
CreateGeneralTransferDescriptor(POHCI_GENERAL_TD
* OutDescriptor
, ULONG BufferSize
);
57 VOID
FreeDescriptor(POHCI_GENERAL_TD Descriptor
);
58 NTSTATUS
AllocateEndpointDescriptor(OUT POHCI_ENDPOINT_DESCRIPTOR
*OutDescriptor
);
59 UCHAR
GetEndpointAddress();
60 USHORT
GetMaxPacketSize();
62 // constructor / destructor
63 CUSBRequest(IUnknown
*OuterUnknown
){}
64 virtual ~CUSBRequest(){}
70 // memory manager for allocating setup packet / queue head / transfer descriptors
72 PDMAMEMORYMANAGER m_DmaManager
;
75 // caller provided irp packet containing URB request
80 // transfer buffer length
82 ULONG m_TransferBufferLength
;
85 // current transfer length
87 ULONG m_TransferBufferLengthCompleted
;
90 // Total Transfer Length
92 ULONG m_TotalBytesTransferred
;
95 // transfer buffer MDL
97 PMDL m_TransferBufferMDL
;
100 // caller provided setup packet
102 PUSB_DEFAULT_PIPE_SETUP_PACKET m_SetupPacket
;
105 // completion event for callers who initialized request with setup packet
107 PKEVENT m_CompletionEvent
;
110 // device address for callers who initialized it with device address
112 UCHAR m_DeviceAddress
;
115 // store end point address
117 PUSB_ENDPOINT_DESCRIPTOR m_EndpointDescriptor
;
120 // allocated setup packet from the DMA pool
122 PUSB_DEFAULT_PIPE_SETUP_PACKET m_DescriptorPacket
;
123 PHYSICAL_ADDRESS m_DescriptorSetupPacket
;
126 // stores the result of the operation
128 NTSTATUS m_NtStatusCode
;
129 ULONG m_UrbStatusCode
;
133 //----------------------------------------------------------------------------------------
136 CUSBRequest::QueryInterface(
140 return STATUS_UNSUCCESSFUL
;
143 //----------------------------------------------------------------------------------------
145 CUSBRequest::InitializeWithSetupPacket(
146 IN PDMAMEMORYMANAGER DmaManager
,
147 IN PUSB_DEFAULT_PIPE_SETUP_PACKET SetupPacket
,
148 IN UCHAR DeviceAddress
,
149 IN OPTIONAL PUSB_ENDPOINT_DESCRIPTOR EndpointDescriptor
,
150 IN OUT ULONG TransferBufferLength
,
151 IN OUT PMDL TransferBuffer
)
156 PC_ASSERT(DmaManager
);
157 PC_ASSERT(SetupPacket
);
162 m_DmaManager
= DmaManager
;
163 m_SetupPacket
= SetupPacket
;
164 m_TransferBufferLength
= TransferBufferLength
;
165 m_TransferBufferMDL
= TransferBuffer
;
166 m_DeviceAddress
= DeviceAddress
;
167 m_EndpointDescriptor
= EndpointDescriptor
;
168 m_TotalBytesTransferred
= 0;
171 // Set Length Completed to 0
173 m_TransferBufferLengthCompleted
= 0;
176 // allocate completion event
178 m_CompletionEvent
= (PKEVENT
)ExAllocatePoolWithTag(NonPagedPool
, sizeof(KEVENT
), TAG_USBOHCI
);
179 if (!m_CompletionEvent
)
182 // failed to allocate completion event
184 return STATUS_INSUFFICIENT_RESOURCES
;
188 // initialize completion event
190 KeInitializeEvent(m_CompletionEvent
, NotificationEvent
, FALSE
);
195 return STATUS_SUCCESS
;
197 //----------------------------------------------------------------------------------------
199 CUSBRequest::InitializeWithIrp(
200 IN PDMAMEMORYMANAGER DmaManager
,
203 PIO_STACK_LOCATION IoStack
;
209 PC_ASSERT(DmaManager
);
212 m_DmaManager
= DmaManager
;
213 m_TotalBytesTransferred
= 0;
216 // get current irp stack location
218 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
223 PC_ASSERT(IoStack
->MajorFunction
== IRP_MJ_INTERNAL_DEVICE_CONTROL
);
224 PC_ASSERT(IoStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_INTERNAL_USB_SUBMIT_URB
);
225 PC_ASSERT(IoStack
->Parameters
.Others
.Argument1
!= 0);
230 Urb
= (PURB
)IoStack
->Parameters
.Others
.Argument1
;
238 // check function type
240 switch (Urb
->UrbHeader
.Function
)
243 // luckily those request have the same structure layout
245 case URB_FUNCTION_CLASS_INTERFACE
:
246 case URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE
:
247 case URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER
:
250 // bulk interrupt transfer
252 if (Urb
->UrbBulkOrInterruptTransfer
.TransferBufferLength
)
255 // Check if there is a MDL
257 if (!Urb
->UrbBulkOrInterruptTransfer
.TransferBufferMDL
)
262 PC_ASSERT(Urb
->UrbBulkOrInterruptTransfer
.TransferBuffer
);
265 // Create one using TransferBuffer
267 DPRINT("Creating Mdl from Urb Buffer %p Length %lu\n", Urb
->UrbBulkOrInterruptTransfer
.TransferBuffer
, Urb
->UrbBulkOrInterruptTransfer
.TransferBufferLength
);
268 m_TransferBufferMDL
= IoAllocateMdl(Urb
->UrbBulkOrInterruptTransfer
.TransferBuffer
,
269 Urb
->UrbBulkOrInterruptTransfer
.TransferBufferLength
,
274 if (!m_TransferBufferMDL
)
277 // failed to allocate mdl
279 return STATUS_INSUFFICIENT_RESOURCES
;
283 // build mdl for non paged pool
284 // FIXME: Does hub driver already do this when passing MDL?
286 MmBuildMdlForNonPagedPool(m_TransferBufferMDL
);
289 // Keep that ehci created the MDL and needs to free it.
294 m_TransferBufferMDL
= Urb
->UrbBulkOrInterruptTransfer
.TransferBufferMDL
;
298 // save buffer length
300 m_TransferBufferLength
= Urb
->UrbBulkOrInterruptTransfer
.TransferBufferLength
;
303 // Set Length Completed to 0
305 m_TransferBufferLengthCompleted
= 0;
308 // get endpoint descriptor
310 m_EndpointDescriptor
= (PUSB_ENDPOINT_DESCRIPTOR
)Urb
->UrbBulkOrInterruptTransfer
.PipeHandle
;
316 DPRINT1("URB Function: not supported %x\n", Urb
->UrbHeader
.Function
);
323 return STATUS_SUCCESS
;
327 //----------------------------------------------------------------------------------------
329 CUSBRequest::IsRequestComplete()
332 // FIXME: check if request was split
336 // Check if the transfer was completed, only valid for Bulk Transfers
338 if ((m_TransferBufferLengthCompleted
< m_TransferBufferLength
)
339 && (GetTransferType() == USB_ENDPOINT_TYPE_BULK
))
342 // Transfer not completed
348 //----------------------------------------------------------------------------------------
350 CUSBRequest::GetTransferType()
353 // call internal implementation
355 return InternalGetTransferType();
359 CUSBRequest::GetMaxPacketSize()
361 if (!m_EndpointDescriptor
)
370 ASSERT(m_EndpointDescriptor
);
373 // return max packet size
375 return m_EndpointDescriptor
->wMaxPacketSize
;
379 CUSBRequest::GetEndpointAddress()
381 if (!m_EndpointDescriptor
)
390 ASSERT(m_EndpointDescriptor
);
393 // endpoint number is between 1-15
395 return (m_EndpointDescriptor
->bEndpointAddress
& 0xF);
398 //----------------------------------------------------------------------------------------
400 CUSBRequest::InternalGetTransferType()
405 // check if an irp is provided
409 ASSERT(m_EndpointDescriptor
);
412 // end point is defined in the low byte of bmAttributes
414 TransferType
= (m_EndpointDescriptor
->bmAttributes
& USB_ENDPOINT_TYPE_MASK
);
419 // initialized with setup packet, must be a control transfer
421 TransferType
= USB_ENDPOINT_TYPE_CONTROL
;
431 CUSBRequest::InternalGetPidDirection()
434 ASSERT(m_EndpointDescriptor
);
437 // end point is defined in the low byte of bEndpointAddress
439 return (m_EndpointDescriptor
->bEndpointAddress
& USB_ENDPOINT_DIRECTION_MASK
) >> 7;
443 //----------------------------------------------------------------------------------------
445 CUSBRequest::GetDeviceAddress()
447 PIO_STACK_LOCATION IoStack
;
449 PUSBDEVICE UsbDevice
;
452 // check if there is an irp provided
457 // used provided address
459 return m_DeviceAddress
;
463 // get current stack location
465 IoStack
= IoGetCurrentIrpStackLocation(m_Irp
);
470 Urb
= (PURB
)IoStack
->Parameters
.Others
.Argument1
;
473 // check if there is a pipe handle provided
475 if (Urb
->UrbHeader
.UsbdDeviceHandle
)
478 // there is a device handle provided
480 UsbDevice
= (PUSBDEVICE
)Urb
->UrbHeader
.UsbdDeviceHandle
;
483 // return device address
485 return UsbDevice
->GetDeviceAddress();
489 // no device handle provided, it is the host root bus
495 CUSBRequest::FreeDescriptor(
496 POHCI_GENERAL_TD Descriptor
)
498 if (Descriptor
->BufferSize
)
503 m_DmaManager
->Release(Descriptor
->BufferLogical
, Descriptor
->BufferSize
);
507 // release descriptor
509 m_DmaManager
->Release(Descriptor
, sizeof(OHCI_GENERAL_TD
));
512 //----------------------------------------------------------------------------------------
514 CUSBRequest::CreateGeneralTransferDescriptor(
515 POHCI_GENERAL_TD
* OutDescriptor
,
518 POHCI_GENERAL_TD Descriptor
;
519 PHYSICAL_ADDRESS DescriptorAddress
;
523 // allocate transfer descriptor
525 Status
= m_DmaManager
->Allocate(sizeof(OHCI_GENERAL_TD
), (PVOID
*)&Descriptor
, &DescriptorAddress
);
526 if (!NT_SUCCESS(Status
))
535 // initialize descriptor, hardware part
537 Descriptor
->Flags
= 0;
538 Descriptor
->BufferPhysical
= 0;
539 Descriptor
->NextPhysicalDescriptor
= 0;
540 Descriptor
->LastPhysicalByteAddress
= 0;
545 Descriptor
->PhysicalAddress
.QuadPart
= DescriptorAddress
.QuadPart
;
546 Descriptor
->BufferSize
= BufferSize
;
551 // allocate buffer from dma
553 Status
= m_DmaManager
->Allocate(BufferSize
, &Descriptor
->BufferLogical
, &DescriptorAddress
);
554 if (!NT_SUCCESS(Status
))
559 m_DmaManager
->Release(Descriptor
, sizeof(OHCI_GENERAL_TD
));
564 // set physical address of buffer
566 Descriptor
->BufferPhysical
= DescriptorAddress
.LowPart
;
567 Descriptor
->LastPhysicalByteAddress
= Descriptor
->BufferPhysical
+ BufferSize
- 1;
573 *OutDescriptor
= Descriptor
;
578 return STATUS_SUCCESS
;
582 CUSBRequest::AllocateEndpointDescriptor(
583 OUT POHCI_ENDPOINT_DESCRIPTOR
*OutDescriptor
)
585 POHCI_ENDPOINT_DESCRIPTOR Descriptor
;
586 PHYSICAL_ADDRESS DescriptorAddress
;
590 // allocate descriptor
592 Status
= m_DmaManager
->Allocate(sizeof(OHCI_ENDPOINT_DESCRIPTOR
), (PVOID
*)&Descriptor
, &DescriptorAddress
);
593 if (!NT_SUCCESS(Status
))
596 // failed to allocate descriptor
602 // intialize descriptor
604 Descriptor
->Flags
= OHCI_ENDPOINT_SKIP
;
607 // append device address and endpoint number
609 Descriptor
->Flags
|= OHCI_ENDPOINT_SET_DEVICE_ADDRESS(m_DeviceAddress
);
610 Descriptor
->Flags
|= OHCI_ENDPOINT_SET_ENDPOINT_NUMBER(GetEndpointAddress());
611 Descriptor
->Flags
|= OHCI_ENDPOINT_SET_MAX_PACKET_SIZE(GetMaxPacketSize());
614 // FIXME: detect type
616 Descriptor
->Flags
|= OHCI_ENDPOINT_FULL_SPEED
;
618 Descriptor
->HeadPhysicalDescriptor
= 0;
619 Descriptor
->NextPhysicalEndpoint
= 0;
620 Descriptor
->TailPhysicalDescriptor
= 0;
621 Descriptor
->PhysicalAddress
.QuadPart
= DescriptorAddress
.QuadPart
;
626 *OutDescriptor
= Descriptor
;
631 return STATUS_SUCCESS
;
635 CUSBRequest::BuildControlTransferDescriptor(
636 POHCI_ENDPOINT_DESCRIPTOR
* OutEndpointDescriptor
)
638 POHCI_GENERAL_TD SetupDescriptor
, StatusDescriptor
, DataDescriptor
= NULL
;
639 POHCI_ENDPOINT_DESCRIPTOR EndpointDescriptor
;
642 DPRINT1("CUSBRequest::BuildControlTransferDescriptor\n");
645 // allocate endpoint descriptor
647 Status
= AllocateEndpointDescriptor(&EndpointDescriptor
);
648 if (!NT_SUCCESS(Status
))
651 // failed to create setup descriptor
657 // first allocate setup descriptor
659 Status
= CreateGeneralTransferDescriptor(&SetupDescriptor
, sizeof(USB_DEFAULT_PIPE_SETUP_PACKET
));
660 if (!NT_SUCCESS(Status
))
663 // failed to create setup descriptor
665 m_DmaManager
->Release(EndpointDescriptor
, sizeof(OHCI_ENDPOINT_DESCRIPTOR
));
670 // now create the status descriptor
672 Status
= CreateGeneralTransferDescriptor(&StatusDescriptor
, 0);
673 if (!NT_SUCCESS(Status
))
676 // failed to create status descriptor
678 FreeDescriptor(SetupDescriptor
);
679 m_DmaManager
->Release(EndpointDescriptor
, sizeof(OHCI_ENDPOINT_DESCRIPTOR
));
683 if (m_TransferBufferLength
)
686 // FIXME: support more than one data descriptor
688 ASSERT(m_TransferBufferLength
< 8192);
691 // now create the data descriptor
693 Status
= CreateGeneralTransferDescriptor(&DataDescriptor
, 0);
694 if (!NT_SUCCESS(Status
))
697 // failed to create status descriptor
699 m_DmaManager
->Release(EndpointDescriptor
, sizeof(OHCI_ENDPOINT_DESCRIPTOR
));
700 FreeDescriptor(SetupDescriptor
);
701 FreeDescriptor(StatusDescriptor
);
706 // initialize data descriptor
708 DataDescriptor
->Flags
= 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
| OHCI_TD_DIRECTION_PID_IN
;
711 // store physical address of buffer
713 DataDescriptor
->BufferPhysical
= MmGetPhysicalAddress(MmGetMdlVirtualAddress(m_TransferBufferMDL
)).LowPart
;
714 DataDescriptor
->LastPhysicalByteAddress
= DataDescriptor
->BufferPhysical
+ m_TransferBufferLength
- 1;
718 // initialize setup descriptor
720 SetupDescriptor
->Flags
= OHCI_TD_DIRECTION_PID_SETUP
| OHCI_TD_SET_CONDITION_CODE(OHCI_TD_CONDITION_NOT_ACCESSED
) | OHCI_TD_TOGGLE_0
| OHCI_TD_SET_DELAY_INTERRUPT(OHCI_TD_INTERRUPT_NONE
);
727 RtlCopyMemory(SetupDescriptor
->BufferLogical
, m_SetupPacket
, sizeof(USB_DEFAULT_PIPE_SETUP_PACKET
));
732 // generate setup packet from urb
738 // initialize status descriptor
740 StatusDescriptor
->Flags
= OHCI_TD_SET_CONDITION_CODE(OHCI_TD_CONDITION_NOT_ACCESSED
) | OHCI_TD_TOGGLE_1
| OHCI_TD_SET_DELAY_INTERRUPT(OHCI_TD_INTERRUPT_IMMEDIATE
);
741 if (m_TransferBufferLength
== 0)
744 // input direction is flipped for the status descriptor
746 StatusDescriptor
->Flags
|= OHCI_TD_DIRECTION_PID_IN
;
751 // output direction is flipped for the status descriptor
753 StatusDescriptor
->Flags
|= OHCI_TD_DIRECTION_PID_OUT
;
757 // now link the descriptors
759 if (m_TransferBufferLength
)
762 // link setup descriptor to data descriptor
764 SetupDescriptor
->NextPhysicalDescriptor
= DataDescriptor
->PhysicalAddress
.LowPart
;
767 // FIXME: should link to last data descriptor to status descriptor
769 DataDescriptor
->NextPhysicalDescriptor
= StatusDescriptor
->PhysicalAddress
.LowPart
;
774 // link setup descriptor to status descriptor
776 SetupDescriptor
->NextPhysicalDescriptor
= StatusDescriptor
->PhysicalAddress
.LowPart
;
780 // now link descriptor to endpoint
782 EndpointDescriptor
->HeadPhysicalDescriptor
= SetupDescriptor
->PhysicalAddress
.LowPart
;
783 EndpointDescriptor
->TailPhysicalDescriptor
= SetupDescriptor
->PhysicalAddress
.LowPart
;
784 DPRINT1("CUSBRequest::BuildControlTransferDescriptor done\n");
789 *OutEndpointDescriptor
= EndpointDescriptor
;
794 return STATUS_SUCCESS
;
797 //----------------------------------------------------------------------------------------
799 CUSBRequest::GetEndpointDescriptor(
800 struct _OHCI_ENDPOINT_DESCRIPTOR
** OutDescriptor
)
808 TransferType
= InternalGetTransferType();
811 // build request depending on type
815 case USB_ENDPOINT_TYPE_CONTROL
:
816 Status
= BuildControlTransferDescriptor((POHCI_ENDPOINT_DESCRIPTOR
*)OutDescriptor
);
818 case USB_ENDPOINT_TYPE_BULK
:
819 DPRINT1("USB_ENDPOINT_TYPE_BULK not implemented\n");
820 Status
= STATUS_NOT_IMPLEMENTED
; //BuildBulkTransferQueueHead(OutDescriptor);
822 case USB_ENDPOINT_TYPE_INTERRUPT
:
823 DPRINT1("USB_ENDPOINT_TYPE_INTERRUPT not implemented\n");
824 Status
= STATUS_NOT_IMPLEMENTED
;
826 case USB_ENDPOINT_TYPE_ISOCHRONOUS
:
827 DPRINT1("USB_ENDPOINT_TYPE_ISOCHRONOUS not implemented\n");
828 Status
= STATUS_NOT_IMPLEMENTED
;
832 Status
= STATUS_NOT_IMPLEMENTED
;
836 if (NT_SUCCESS(Status
))
841 //m_QueueHead = *OutDescriptor;
844 // store request object
846 (*OutDescriptor
)->Request
= PVOID(this);
855 //----------------------------------------------------------------------------------------
857 CUSBRequest::GetResultStatus(
858 OUT OPTIONAL NTSTATUS
* NtStatusCode
,
859 OUT OPTIONAL PULONG UrbStatusCode
)
864 PC_ASSERT(m_CompletionEvent
);
867 // wait for the operation to complete
869 KeWaitForSingleObject(m_CompletionEvent
, Executive
, KernelMode
, FALSE
, NULL
);
876 *NtStatusCode
= m_NtStatusCode
;
884 *UrbStatusCode
= m_UrbStatusCode
;
890 //-----------------------------------------------------------------------------------------
892 CUSBRequest::IsRequestInitialized()
894 if (m_Irp
|| m_SetupPacket
)
897 // request is initialized
903 // request is not initialized
908 //-----------------------------------------------------------------------------------------
910 CUSBRequest::IsQueueHeadComplete(
911 struct _QUEUE_HEAD
* QueueHead
)
919 //-----------------------------------------------------------------------------------------
921 InternalCreateUSBRequest(
922 PUSBREQUEST
*OutRequest
)
929 This
= new(NonPagedPool
, TAG_USBOHCI
) CUSBRequest(0);
933 // failed to allocate
935 return STATUS_INSUFFICIENT_RESOURCES
;
939 // add reference count
946 *OutRequest
= (PUSBREQUEST
)This
;
951 return STATUS_SUCCESS
;