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
);
47 virtual VOID
CompletionCallback(struct _OHCI_ENDPOINT_DESCRIPTOR
* OutDescriptor
);
48 virtual VOID
FreeEndpointDescriptor(struct _OHCI_ENDPOINT_DESCRIPTOR
* OutDescriptor
);
49 virtual UCHAR
GetInterval();
53 ULONG
InternalGetTransferType();
54 UCHAR
InternalGetPidDirection();
55 UCHAR
GetDeviceAddress();
56 NTSTATUS
BuildSetupPacket();
57 NTSTATUS
BuildSetupPacketFromURB();
58 NTSTATUS
BuildControlTransferDescriptor(POHCI_ENDPOINT_DESCRIPTOR
* OutEndpointDescriptor
);
59 NTSTATUS
BuildBulkInterruptEndpoint(POHCI_ENDPOINT_DESCRIPTOR
* OutEndpointDescriptor
);
60 NTSTATUS
BuildIsochronousEndpoint(POHCI_ENDPOINT_DESCRIPTOR
* OutEndpointDescriptor
);
61 NTSTATUS
CreateGeneralTransferDescriptor(POHCI_GENERAL_TD
* OutDescriptor
, ULONG BufferSize
);
62 VOID
FreeDescriptor(POHCI_GENERAL_TD Descriptor
);
63 NTSTATUS
AllocateEndpointDescriptor(OUT POHCI_ENDPOINT_DESCRIPTOR
*OutDescriptor
);
64 NTSTATUS
CreateIsochronousTransferDescriptor(OUT POHCI_ISO_TD
*OutDescriptor
, ULONG FrameCount
);
65 UCHAR
GetEndpointAddress();
66 USHORT
GetMaxPacketSize();
68 // constructor / destructor
69 CUSBRequest(IUnknown
*OuterUnknown
){}
70 virtual ~CUSBRequest(){}
76 // memory manager for allocating setup packet / queue head / transfer descriptors
78 PDMAMEMORYMANAGER m_DmaManager
;
81 // caller provided irp packet containing URB request
86 // transfer buffer length
88 ULONG m_TransferBufferLength
;
91 // current transfer length
93 ULONG m_TransferBufferLengthCompleted
;
96 // Total Transfer Length
98 ULONG m_TotalBytesTransferred
;
101 // transfer buffer MDL
103 PMDL m_TransferBufferMDL
;
106 // caller provided setup packet
108 PUSB_DEFAULT_PIPE_SETUP_PACKET m_SetupPacket
;
111 // completion event for callers who initialized request with setup packet
113 PKEVENT m_CompletionEvent
;
116 // device address for callers who initialized it with device address
118 UCHAR m_DeviceAddress
;
121 // store end point address
123 PUSB_ENDPOINT_DESCRIPTOR m_EndpointDescriptor
;
126 // allocated setup packet from the DMA pool
128 PUSB_DEFAULT_PIPE_SETUP_PACKET m_DescriptorPacket
;
129 PHYSICAL_ADDRESS m_DescriptorSetupPacket
;
132 // stores the result of the operation
134 NTSTATUS m_NtStatusCode
;
135 ULONG m_UrbStatusCode
;
139 //----------------------------------------------------------------------------------------
142 CUSBRequest::QueryInterface(
146 return STATUS_UNSUCCESSFUL
;
149 //----------------------------------------------------------------------------------------
151 CUSBRequest::InitializeWithSetupPacket(
152 IN PDMAMEMORYMANAGER DmaManager
,
153 IN PUSB_DEFAULT_PIPE_SETUP_PACKET SetupPacket
,
154 IN UCHAR DeviceAddress
,
155 IN OPTIONAL PUSB_ENDPOINT_DESCRIPTOR EndpointDescriptor
,
156 IN OUT ULONG TransferBufferLength
,
157 IN OUT PMDL TransferBuffer
)
162 PC_ASSERT(DmaManager
);
163 PC_ASSERT(SetupPacket
);
168 m_DmaManager
= DmaManager
;
169 m_SetupPacket
= SetupPacket
;
170 m_TransferBufferLength
= TransferBufferLength
;
171 m_TransferBufferMDL
= TransferBuffer
;
172 m_DeviceAddress
= DeviceAddress
;
173 m_EndpointDescriptor
= EndpointDescriptor
;
174 m_TotalBytesTransferred
= 0;
177 // Set Length Completed to 0
179 m_TransferBufferLengthCompleted
= 0;
182 // allocate completion event
184 m_CompletionEvent
= (PKEVENT
)ExAllocatePoolWithTag(NonPagedPool
, sizeof(KEVENT
), TAG_USBOHCI
);
185 if (!m_CompletionEvent
)
188 // failed to allocate completion event
190 return STATUS_INSUFFICIENT_RESOURCES
;
194 // initialize completion event
196 KeInitializeEvent(m_CompletionEvent
, NotificationEvent
, FALSE
);
201 return STATUS_SUCCESS
;
203 //----------------------------------------------------------------------------------------
205 CUSBRequest::InitializeWithIrp(
206 IN PDMAMEMORYMANAGER DmaManager
,
209 PIO_STACK_LOCATION IoStack
;
215 PC_ASSERT(DmaManager
);
218 m_DmaManager
= DmaManager
;
219 m_TotalBytesTransferred
= 0;
222 // get current irp stack location
224 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
229 PC_ASSERT(IoStack
->MajorFunction
== IRP_MJ_INTERNAL_DEVICE_CONTROL
);
230 PC_ASSERT(IoStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_INTERNAL_USB_SUBMIT_URB
);
231 PC_ASSERT(IoStack
->Parameters
.Others
.Argument1
!= 0);
236 Urb
= (PURB
)IoStack
->Parameters
.Others
.Argument1
;
244 // check function type
246 switch (Urb
->UrbHeader
.Function
)
248 case URB_FUNCTION_ISOCH_TRANSFER
:
251 // there must be at least one packet
253 ASSERT(Urb
->UrbIsochronousTransfer
.NumberOfPackets
);
256 // is there data to be transferred
258 if (Urb
->UrbIsochronousTransfer
.TransferBufferLength
)
261 // Check if there is a MDL
263 if (!Urb
->UrbBulkOrInterruptTransfer
.TransferBufferMDL
)
268 PC_ASSERT(Urb
->UrbBulkOrInterruptTransfer
.TransferBuffer
);
271 // Create one using TransferBuffer
273 DPRINT("Creating Mdl from Urb Buffer %p Length %lu\n", Urb
->UrbBulkOrInterruptTransfer
.TransferBuffer
, Urb
->UrbBulkOrInterruptTransfer
.TransferBufferLength
);
274 m_TransferBufferMDL
= IoAllocateMdl(Urb
->UrbBulkOrInterruptTransfer
.TransferBuffer
,
275 Urb
->UrbBulkOrInterruptTransfer
.TransferBufferLength
,
280 if (!m_TransferBufferMDL
)
283 // failed to allocate mdl
285 return STATUS_INSUFFICIENT_RESOURCES
;
289 // build mdl for non paged pool
290 // FIXME: Does hub driver already do this when passing MDL?
292 MmBuildMdlForNonPagedPool(m_TransferBufferMDL
);
299 m_TransferBufferMDL
= Urb
->UrbIsochronousTransfer
.TransferBufferMDL
;
304 // save buffer length
306 m_TransferBufferLength
= Urb
->UrbIsochronousTransfer
.TransferBufferLength
;
309 // Set Length Completed to 0
311 m_TransferBufferLengthCompleted
= 0;
314 // get endpoint descriptor
316 m_EndpointDescriptor
= (PUSB_ENDPOINT_DESCRIPTOR
)Urb
->UrbIsochronousTransfer
.PipeHandle
;
319 // completed initialization
324 // luckily those request have the same structure layout
326 case URB_FUNCTION_CLASS_INTERFACE
:
327 case URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE
:
328 case URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER
:
331 // bulk interrupt transfer
333 if (Urb
->UrbBulkOrInterruptTransfer
.TransferBufferLength
)
336 // Check if there is a MDL
338 if (!Urb
->UrbBulkOrInterruptTransfer
.TransferBufferMDL
)
343 PC_ASSERT(Urb
->UrbBulkOrInterruptTransfer
.TransferBuffer
);
346 // Create one using TransferBuffer
348 DPRINT("Creating Mdl from Urb Buffer %p Length %lu\n", Urb
->UrbBulkOrInterruptTransfer
.TransferBuffer
, Urb
->UrbBulkOrInterruptTransfer
.TransferBufferLength
);
349 m_TransferBufferMDL
= IoAllocateMdl(Urb
->UrbBulkOrInterruptTransfer
.TransferBuffer
,
350 Urb
->UrbBulkOrInterruptTransfer
.TransferBufferLength
,
355 if (!m_TransferBufferMDL
)
358 // failed to allocate mdl
360 return STATUS_INSUFFICIENT_RESOURCES
;
364 // build mdl for non paged pool
365 // FIXME: Does hub driver already do this when passing MDL?
367 MmBuildMdlForNonPagedPool(m_TransferBufferMDL
);
370 // Keep that ehci created the MDL and needs to free it.
375 m_TransferBufferMDL
= Urb
->UrbBulkOrInterruptTransfer
.TransferBufferMDL
;
379 // save buffer length
381 m_TransferBufferLength
= Urb
->UrbBulkOrInterruptTransfer
.TransferBufferLength
;
384 // Set Length Completed to 0
386 m_TransferBufferLengthCompleted
= 0;
389 // get endpoint descriptor
391 m_EndpointDescriptor
= (PUSB_ENDPOINT_DESCRIPTOR
)Urb
->UrbBulkOrInterruptTransfer
.PipeHandle
;
397 DPRINT1("URB Function: not supported %x\n", Urb
->UrbHeader
.Function
);
404 return STATUS_SUCCESS
;
408 //----------------------------------------------------------------------------------------
410 CUSBRequest::IsRequestComplete()
413 // FIXME: check if request was split
417 // Check if the transfer was completed, only valid for Bulk Transfers
419 if ((m_TransferBufferLengthCompleted
< m_TransferBufferLength
)
420 && (GetTransferType() == USB_ENDPOINT_TYPE_BULK
))
423 // Transfer not completed
429 //----------------------------------------------------------------------------------------
431 CUSBRequest::GetTransferType()
434 // call internal implementation
436 return InternalGetTransferType();
440 CUSBRequest::GetMaxPacketSize()
442 if (!m_EndpointDescriptor
)
451 ASSERT(m_EndpointDescriptor
);
454 // return max packet size
456 return m_EndpointDescriptor
->wMaxPacketSize
;
460 CUSBRequest::GetInterval()
462 ASSERT(m_EndpointDescriptor
);
463 ASSERT((m_EndpointDescriptor
->bmAttributes
& USB_ENDPOINT_TYPE_MASK
) == USB_ENDPOINT_TYPE_INTERRUPT
);
466 // return interrupt interval
468 return m_EndpointDescriptor
->bInterval
;
472 CUSBRequest::GetEndpointAddress()
474 if (!m_EndpointDescriptor
)
483 ASSERT(m_EndpointDescriptor
);
486 // endpoint number is between 1-15
488 return (m_EndpointDescriptor
->bEndpointAddress
& 0xF);
491 //----------------------------------------------------------------------------------------
493 CUSBRequest::InternalGetTransferType()
498 // check if an irp is provided
502 ASSERT(m_EndpointDescriptor
);
505 // end point is defined in the low byte of bmAttributes
507 TransferType
= (m_EndpointDescriptor
->bmAttributes
& USB_ENDPOINT_TYPE_MASK
);
512 // initialized with setup packet, must be a control transfer
514 TransferType
= USB_ENDPOINT_TYPE_CONTROL
;
524 CUSBRequest::InternalGetPidDirection()
527 ASSERT(m_EndpointDescriptor
);
530 // end point is defined in the low byte of bEndpointAddress
532 return (m_EndpointDescriptor
->bEndpointAddress
& USB_ENDPOINT_DIRECTION_MASK
) >> 7;
536 //----------------------------------------------------------------------------------------
538 CUSBRequest::GetDeviceAddress()
540 PIO_STACK_LOCATION IoStack
;
542 PUSBDEVICE UsbDevice
;
545 // check if there is an irp provided
550 // used provided address
552 return m_DeviceAddress
;
556 // get current stack location
558 IoStack
= IoGetCurrentIrpStackLocation(m_Irp
);
563 Urb
= (PURB
)IoStack
->Parameters
.Others
.Argument1
;
566 // check if there is a pipe handle provided
568 if (Urb
->UrbHeader
.UsbdDeviceHandle
)
571 // there is a device handle provided
573 UsbDevice
= (PUSBDEVICE
)Urb
->UrbHeader
.UsbdDeviceHandle
;
576 // return device address
578 return UsbDevice
->GetDeviceAddress();
582 // no device handle provided, it is the host root bus
588 CUSBRequest::FreeDescriptor(
589 POHCI_GENERAL_TD Descriptor
)
591 if (Descriptor
->BufferSize
)
596 m_DmaManager
->Release(Descriptor
->BufferLogical
, Descriptor
->BufferSize
);
600 // release descriptor
602 m_DmaManager
->Release(Descriptor
, sizeof(OHCI_GENERAL_TD
));
606 //----------------------------------------------------------------------------------------
608 CUSBRequest::CreateIsochronousTransferDescriptor(
609 POHCI_ISO_TD
* OutDescriptor
,
612 POHCI_ISO_TD Descriptor
;
613 PHYSICAL_ADDRESS DescriptorAddress
;
617 // allocate transfer descriptor
619 Status
= m_DmaManager
->Allocate(sizeof(OHCI_ISO_TD
), (PVOID
*)&Descriptor
, &DescriptorAddress
);
620 if (!NT_SUCCESS(Status
))
629 // initialize descriptor, hardware part
631 Descriptor
->Flags
= OHCI_ITD_SET_FRAME_COUNT(FrameCount
) | OHCI_ITD_SET_DELAY_INTERRUPT(OHCI_TD_INTERRUPT_NONE
);// | OHCI_TD_SET_CONDITION_CODE(OHCI_TD_CONDITION_NOT_ACCESSED);
632 Descriptor
->BufferPhysical
= 0;
633 Descriptor
->NextPhysicalDescriptor
= 0;
634 Descriptor
->LastPhysicalByteAddress
= 0;
639 Descriptor
->PhysicalAddress
.QuadPart
= DescriptorAddress
.QuadPart
;
640 Descriptor
->NextLogicalDescriptor
= 0;
645 *OutDescriptor
= Descriptor
;
650 return STATUS_SUCCESS
;
654 CUSBRequest::BuildIsochronousEndpoint(
655 POHCI_ENDPOINT_DESCRIPTOR
* OutEndpointDescriptor
)
657 POHCI_ISO_TD FirstDescriptor
, PreviousDescriptor
= NULL
, CurrentDescriptor
;
658 POHCI_ENDPOINT_DESCRIPTOR EndpointDescriptor
;
659 ULONG Index
= 0, SubIndex
, NumberOfPackets
, PageOffset
, Page
;
662 PIO_STACK_LOCATION IoStack
;
664 PHYSICAL_ADDRESS Address
;
667 // get current irp stack location
669 IoStack
= IoGetCurrentIrpStackLocation(m_Irp
);
674 PC_ASSERT(IoStack
->MajorFunction
== IRP_MJ_INTERNAL_DEVICE_CONTROL
);
675 PC_ASSERT(IoStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_INTERNAL_USB_SUBMIT_URB
);
676 PC_ASSERT(IoStack
->Parameters
.Others
.Argument1
!= 0);
681 Urb
= (PURB
)IoStack
->Parameters
.Others
.Argument1
;
685 // allocate endpoint descriptor
687 Status
= AllocateEndpointDescriptor(&EndpointDescriptor
);
688 if (!NT_SUCCESS(Status
))
691 // failed to create setup descriptor
700 Buffer
= MmGetSystemAddressForMdlSafe(m_TransferBufferMDL
, NormalPagePriority
);
704 // FIXME: support requests which spans serveral pages
706 ASSERT(ADDRESS_AND_SIZE_TO_SPAN_PAGES(MmGetMdlVirtualAddress(m_TransferBufferMDL
), MmGetMdlByteCount(m_TransferBufferMDL
)) <= 2);
708 Status
= m_DmaManager
->Allocate(m_TransferBufferLength
, &Buffer
, &Address
);
709 ASSERT(Status
== STATUS_SUCCESS
);
712 while(Index
< Urb
->UrbIsochronousTransfer
.NumberOfPackets
)
715 // get number of packets remaining
717 NumberOfPackets
= min(Urb
->UrbIsochronousTransfer
.NumberOfPackets
- Index
, OHCI_ITD_NOFFSET
);
719 // allocate iso descriptor
721 Status
= CreateIsochronousTransferDescriptor(&CurrentDescriptor
, NumberOfPackets
);
722 if (!NT_SUCCESS(Status
))
726 // failed to allocate descriptor
735 Page
= MmGetPhysicalAddress(Buffer
).LowPart
;
740 PageOffset
= BYTE_OFFSET(Page
);
743 // initialize descriptor
745 CurrentDescriptor
->BufferPhysical
= Page
- PageOffset
;
747 for(SubIndex
= 0; SubIndex
< NumberOfPackets
; SubIndex
++)
750 // store buffer offset
752 CurrentDescriptor
->Offset
[SubIndex
] = Urb
->UrbIsochronousTransfer
.IsoPacket
[Index
+SubIndex
].Offset
+ PageOffset
;
753 DPRINT1("Index %lu PacketOffset %lu FinalOffset %lu\n", SubIndex
+Index
, Urb
->UrbIsochronousTransfer
.IsoPacket
[Index
+SubIndex
].Offset
, CurrentDescriptor
->Offset
[SubIndex
]);
757 // increment packet offset
759 Index
+= NumberOfPackets
;
762 // check if this is the last descriptor
764 if (Index
== Urb
->UrbIsochronousTransfer
.NumberOfPackets
)
769 CurrentDescriptor
->LastPhysicalByteAddress
= CurrentDescriptor
->BufferPhysical
+ PageOffset
+ m_TransferBufferLength
- 1;
774 // use start address of next packet - 1
776 CurrentDescriptor
->LastPhysicalByteAddress
= CurrentDescriptor
->BufferPhysical
+ PageOffset
+ Urb
->UrbIsochronousTransfer
.IsoPacket
[Index
].Offset
- 1;
780 // is there a previous descriptor
782 if (PreviousDescriptor
)
787 PreviousDescriptor
->NextLogicalDescriptor
= CurrentDescriptor
;
788 PreviousDescriptor
->NextPhysicalDescriptor
= CurrentDescriptor
->PhysicalAddress
.LowPart
;
795 FirstDescriptor
= CurrentDescriptor
;
799 // store as previous descriptor
801 PreviousDescriptor
= CurrentDescriptor
;
802 DPRINT1("Current Descriptor %p Logical %lx StartAddress %x EndAddress %x\n", CurrentDescriptor
, CurrentDescriptor
->PhysicalAddress
.LowPart
, CurrentDescriptor
->BufferPhysical
, CurrentDescriptor
->LastPhysicalByteAddress
);
805 // fire interrupt as soon transfer is finished
807 CurrentDescriptor
->Flags
|= OHCI_TD_SET_DELAY_INTERRUPT(OHCI_TD_INTERRUPT_IMMEDIATE
);
811 // clear interrupt mask for last transfer descriptor
813 CurrentDescriptor
->Flags
&= ~OHCI_TD_INTERRUPT_MASK
;
816 // fire interrupt as soon transfer is finished
818 CurrentDescriptor
->Flags
|= OHCI_TD_SET_DELAY_INTERRUPT(OHCI_TD_INTERRUPT_IMMEDIATE
);
821 // set isochronous type
823 EndpointDescriptor
->Flags
|= OHCI_ENDPOINT_ISOCHRONOUS_FORMAT
;
826 // now link descriptor to endpoint
828 EndpointDescriptor
->HeadPhysicalDescriptor
= FirstDescriptor
->PhysicalAddress
.LowPart
;
829 EndpointDescriptor
->TailPhysicalDescriptor
= CurrentDescriptor
->PhysicalAddress
.LowPart
;
830 EndpointDescriptor
->HeadLogicalDescriptor
= FirstDescriptor
;
835 *OutEndpointDescriptor
= EndpointDescriptor
;
840 return STATUS_SUCCESS
;
843 //----------------------------------------------------------------------------------------
845 CUSBRequest::CreateGeneralTransferDescriptor(
846 POHCI_GENERAL_TD
* OutDescriptor
,
849 POHCI_GENERAL_TD Descriptor
;
850 PHYSICAL_ADDRESS DescriptorAddress
;
854 // allocate transfer descriptor
856 Status
= m_DmaManager
->Allocate(sizeof(OHCI_GENERAL_TD
), (PVOID
*)&Descriptor
, &DescriptorAddress
);
857 if (!NT_SUCCESS(Status
))
866 // initialize descriptor, hardware part
868 Descriptor
->Flags
= 0;
869 Descriptor
->BufferPhysical
= 0;
870 Descriptor
->NextPhysicalDescriptor
= 0;
871 Descriptor
->LastPhysicalByteAddress
= 0;
876 Descriptor
->PhysicalAddress
.QuadPart
= DescriptorAddress
.QuadPart
;
877 Descriptor
->BufferSize
= BufferSize
;
882 // allocate buffer from dma
884 Status
= m_DmaManager
->Allocate(BufferSize
, &Descriptor
->BufferLogical
, &DescriptorAddress
);
885 if (!NT_SUCCESS(Status
))
890 m_DmaManager
->Release(Descriptor
, sizeof(OHCI_GENERAL_TD
));
895 // set physical address of buffer
897 Descriptor
->BufferPhysical
= DescriptorAddress
.LowPart
;
898 Descriptor
->LastPhysicalByteAddress
= Descriptor
->BufferPhysical
+ BufferSize
- 1;
904 *OutDescriptor
= Descriptor
;
909 return STATUS_SUCCESS
;
913 CUSBRequest::AllocateEndpointDescriptor(
914 OUT POHCI_ENDPOINT_DESCRIPTOR
*OutDescriptor
)
916 POHCI_ENDPOINT_DESCRIPTOR Descriptor
;
917 PHYSICAL_ADDRESS DescriptorAddress
;
921 // allocate descriptor
923 Status
= m_DmaManager
->Allocate(sizeof(OHCI_ENDPOINT_DESCRIPTOR
), (PVOID
*)&Descriptor
, &DescriptorAddress
);
924 if (!NT_SUCCESS(Status
))
927 // failed to allocate descriptor
933 // intialize descriptor
935 Descriptor
->Flags
= OHCI_ENDPOINT_SKIP
;
938 // append device address and endpoint number
940 Descriptor
->Flags
|= OHCI_ENDPOINT_SET_DEVICE_ADDRESS(GetDeviceAddress());
941 Descriptor
->Flags
|= OHCI_ENDPOINT_SET_ENDPOINT_NUMBER(GetEndpointAddress());
942 Descriptor
->Flags
|= OHCI_ENDPOINT_SET_MAX_PACKET_SIZE(GetMaxPacketSize());
944 DPRINT("Flags %x DeviceAddress %x EndpointAddress %x PacketSize %x\n", Descriptor
->Flags
, GetDeviceAddress(), GetEndpointAddress(), GetMaxPacketSize());
947 // is there an endpoint descriptor
949 if (m_EndpointDescriptor
)
954 if (USB_ENDPOINT_DIRECTION_OUT(m_EndpointDescriptor
->bEndpointAddress
))
959 Descriptor
->Flags
|= OHCI_ENDPOINT_DIRECTION_OUT
;
966 Descriptor
->Flags
|= OHCI_ENDPOINT_DIRECTION_IN
;
973 // FIXME: detect type
975 Descriptor
->Flags
|= OHCI_ENDPOINT_FULL_SPEED
;
977 Descriptor
->HeadPhysicalDescriptor
= 0;
978 Descriptor
->NextPhysicalEndpoint
= 0;
979 Descriptor
->TailPhysicalDescriptor
= 0;
980 Descriptor
->PhysicalAddress
.QuadPart
= DescriptorAddress
.QuadPart
;
985 *OutDescriptor
= Descriptor
;
990 return STATUS_SUCCESS
;
994 CUSBRequest::BuildBulkInterruptEndpoint(
995 POHCI_ENDPOINT_DESCRIPTOR
* OutEndpointDescriptor
)
997 POHCI_GENERAL_TD FirstDescriptor
, PreviousDescriptor
= NULL
, CurrentDescriptor
, LastDescriptor
;
998 POHCI_ENDPOINT_DESCRIPTOR EndpointDescriptor
;
999 ULONG BufferSize
, CurrentSize
, Direction
, MaxLengthInPage
;
1004 // allocate endpoint descriptor
1006 Status
= AllocateEndpointDescriptor(&EndpointDescriptor
);
1007 if (!NT_SUCCESS(Status
))
1010 // failed to create setup descriptor
1016 // allocate transfer descriptor for last descriptor
1018 Status
= CreateGeneralTransferDescriptor(&LastDescriptor
, 0);
1019 if (!NT_SUCCESS(Status
))
1022 // failed to create transfer descriptor
1024 m_DmaManager
->Release(EndpointDescriptor
, sizeof(OHCI_ENDPOINT_DESCRIPTOR
));
1031 BufferSize
= m_TransferBufferLength
;
1033 ASSERT(m_TransferBufferMDL
);
1038 Buffer
= MmGetSystemAddressForMdlSafe(m_TransferBufferMDL
, NormalPagePriority
);
1041 if (InternalGetPidDirection())
1046 Direction
= OHCI_TD_DIRECTION_PID_IN
;
1053 Direction
= OHCI_TD_DIRECTION_PID_OUT
;
1059 // get current buffersize
1061 CurrentSize
= min(8192, BufferSize
);
1066 MaxLengthInPage
= PAGE_SIZE
- BYTE_OFFSET(Buffer
);
1069 // get minimum from current page size
1071 CurrentSize
= min(CurrentSize
, MaxLengthInPage
);
1072 ASSERT(CurrentSize
);
1075 // allocate transfer descriptor
1077 Status
= CreateGeneralTransferDescriptor(&CurrentDescriptor
, 0);
1078 if (!NT_SUCCESS(Status
))
1081 // failed to create transfer descriptor
1085 m_DmaManager
->Release(EndpointDescriptor
, sizeof(OHCI_ENDPOINT_DESCRIPTOR
));
1086 FreeDescriptor(LastDescriptor
);
1091 // initialize descriptor
1093 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
;
1096 // store physical address of buffer
1098 CurrentDescriptor
->BufferPhysical
= MmGetPhysicalAddress(Buffer
).LowPart
;
1099 CurrentDescriptor
->LastPhysicalByteAddress
= CurrentDescriptor
->BufferPhysical
+ CurrentSize
- 1;
1102 // is there a previous descriptor
1104 if (PreviousDescriptor
)
1109 PreviousDescriptor
->NextLogicalDescriptor
= (PVOID
)CurrentDescriptor
;
1110 PreviousDescriptor
->NextPhysicalDescriptor
= CurrentDescriptor
->PhysicalAddress
.LowPart
;
1115 // it is the first descriptor
1117 FirstDescriptor
= CurrentDescriptor
;
1120 DPRINT("PreviousDescriptor %p CurrentDescriptor %p Logical %x Buffer Logical %p Physical %x Last Physical %x CurrentSize %lu\n", PreviousDescriptor
, CurrentDescriptor
, CurrentDescriptor
->PhysicalAddress
.LowPart
, CurrentDescriptor
->BufferLogical
, CurrentDescriptor
->BufferPhysical
, CurrentDescriptor
->LastPhysicalByteAddress
, CurrentSize
);
1123 // set previous descriptor
1125 PreviousDescriptor
= CurrentDescriptor
;
1128 // subtract buffer size
1130 BufferSize
-= CurrentSize
;
1133 // increment buffer offset
1135 Buffer
= (PVOID
)((ULONG_PTR
)Buffer
+ CurrentSize
);
1140 // first descriptor has no carry bit
1142 FirstDescriptor
->Flags
&= ~OHCI_TD_TOGGLE_CARRY
;
1147 FirstDescriptor
->Flags
|= OHCI_TD_TOGGLE_0
;
1150 // clear interrupt mask for last transfer descriptor
1152 CurrentDescriptor
->Flags
&= ~OHCI_TD_INTERRUPT_MASK
;
1155 // fire interrupt as soon transfer is finished
1157 CurrentDescriptor
->Flags
|= OHCI_TD_SET_DELAY_INTERRUPT(OHCI_TD_INTERRUPT_IMMEDIATE
);
1160 // link last data descriptor to last descriptor
1162 CurrentDescriptor
->NextLogicalDescriptor
= LastDescriptor
;
1163 CurrentDescriptor
->NextPhysicalDescriptor
= LastDescriptor
->PhysicalAddress
.LowPart
;
1166 // now link descriptor to endpoint
1168 EndpointDescriptor
->HeadPhysicalDescriptor
= FirstDescriptor
->PhysicalAddress
.LowPart
;
1169 EndpointDescriptor
->TailPhysicalDescriptor
= LastDescriptor
->PhysicalAddress
.LowPart
;
1170 EndpointDescriptor
->HeadLogicalDescriptor
= FirstDescriptor
;
1175 *OutEndpointDescriptor
= EndpointDescriptor
;
1180 return STATUS_SUCCESS
;
1185 CUSBRequest::BuildControlTransferDescriptor(
1186 POHCI_ENDPOINT_DESCRIPTOR
* OutEndpointDescriptor
)
1188 POHCI_GENERAL_TD SetupDescriptor
, StatusDescriptor
, DataDescriptor
= NULL
, LastDescriptor
;
1189 POHCI_ENDPOINT_DESCRIPTOR EndpointDescriptor
;
1193 // allocate endpoint descriptor
1195 Status
= AllocateEndpointDescriptor(&EndpointDescriptor
);
1196 if (!NT_SUCCESS(Status
))
1199 // failed to create setup descriptor
1205 // first allocate setup descriptor
1207 Status
= CreateGeneralTransferDescriptor(&SetupDescriptor
, sizeof(USB_DEFAULT_PIPE_SETUP_PACKET
));
1208 if (!NT_SUCCESS(Status
))
1211 // failed to create setup descriptor
1213 m_DmaManager
->Release(EndpointDescriptor
, sizeof(OHCI_ENDPOINT_DESCRIPTOR
));
1218 // now create the status descriptor
1220 Status
= CreateGeneralTransferDescriptor(&StatusDescriptor
, 0);
1221 if (!NT_SUCCESS(Status
))
1224 // failed to create status descriptor
1226 FreeDescriptor(SetupDescriptor
);
1227 m_DmaManager
->Release(EndpointDescriptor
, sizeof(OHCI_ENDPOINT_DESCRIPTOR
));
1232 // finally create the last descriptor
1234 Status
= CreateGeneralTransferDescriptor(&LastDescriptor
, 0);
1235 if (!NT_SUCCESS(Status
))
1238 // failed to create status descriptor
1240 FreeDescriptor(SetupDescriptor
);
1241 FreeDescriptor(StatusDescriptor
);
1242 m_DmaManager
->Release(EndpointDescriptor
, sizeof(OHCI_ENDPOINT_DESCRIPTOR
));
1246 if (m_TransferBufferLength
)
1249 // FIXME: support more than one data descriptor
1251 ASSERT(m_TransferBufferLength
< 8192);
1254 // now create the data descriptor
1256 Status
= CreateGeneralTransferDescriptor(&DataDescriptor
, 0);
1257 if (!NT_SUCCESS(Status
))
1260 // failed to create status descriptor
1262 m_DmaManager
->Release(EndpointDescriptor
, sizeof(OHCI_ENDPOINT_DESCRIPTOR
));
1263 FreeDescriptor(SetupDescriptor
);
1264 FreeDescriptor(StatusDescriptor
);
1265 FreeDescriptor(LastDescriptor
);
1270 // initialize data descriptor
1272 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
;
1275 // store physical address of buffer
1277 DataDescriptor
->BufferPhysical
= MmGetPhysicalAddress(MmGetMdlVirtualAddress(m_TransferBufferMDL
)).LowPart
;
1278 DataDescriptor
->LastPhysicalByteAddress
= DataDescriptor
->BufferPhysical
+ m_TransferBufferLength
- 1;
1283 // initialize setup descriptor
1285 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
);
1290 // copy setup packet
1292 RtlCopyMemory(SetupDescriptor
->BufferLogical
, m_SetupPacket
, sizeof(USB_DEFAULT_PIPE_SETUP_PACKET
));
1297 // generate setup packet from urb
1303 // initialize status descriptor
1305 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
);
1306 if (m_TransferBufferLength
== 0)
1309 // input direction is flipped for the status descriptor
1311 StatusDescriptor
->Flags
|= OHCI_TD_DIRECTION_PID_IN
;
1316 // output direction is flipped for the status descriptor
1318 StatusDescriptor
->Flags
|= OHCI_TD_DIRECTION_PID_OUT
;
1322 // now link the descriptors
1324 if (m_TransferBufferLength
)
1327 // link setup descriptor to data descriptor
1329 SetupDescriptor
->NextPhysicalDescriptor
= DataDescriptor
->PhysicalAddress
.LowPart
;
1330 SetupDescriptor
->NextLogicalDescriptor
= DataDescriptor
;
1333 // link data descriptor to status descriptor
1334 // FIXME: check if there are more data descriptors
1336 DataDescriptor
->NextPhysicalDescriptor
= StatusDescriptor
->PhysicalAddress
.LowPart
;
1337 DataDescriptor
->NextLogicalDescriptor
= StatusDescriptor
;
1340 // link status descriptor to last descriptor
1342 StatusDescriptor
->NextPhysicalDescriptor
= LastDescriptor
->PhysicalAddress
.LowPart
;
1343 StatusDescriptor
->NextLogicalDescriptor
= LastDescriptor
;
1348 // link setup descriptor to status descriptor
1350 SetupDescriptor
->NextPhysicalDescriptor
= StatusDescriptor
->PhysicalAddress
.LowPart
;
1351 SetupDescriptor
->NextLogicalDescriptor
= StatusDescriptor
;
1354 // link status descriptor to last descriptor
1356 StatusDescriptor
->NextPhysicalDescriptor
= LastDescriptor
->PhysicalAddress
.LowPart
;
1357 StatusDescriptor
->NextLogicalDescriptor
= LastDescriptor
;
1361 // now link descriptor to endpoint
1363 EndpointDescriptor
->HeadPhysicalDescriptor
= SetupDescriptor
->PhysicalAddress
.LowPart
;
1364 EndpointDescriptor
->TailPhysicalDescriptor
= LastDescriptor
->PhysicalAddress
.LowPart
;
1365 EndpointDescriptor
->HeadLogicalDescriptor
= SetupDescriptor
;
1370 *OutEndpointDescriptor
= EndpointDescriptor
;
1375 return STATUS_SUCCESS
;
1378 //----------------------------------------------------------------------------------------
1380 CUSBRequest::GetEndpointDescriptor(
1381 struct _OHCI_ENDPOINT_DESCRIPTOR
** OutDescriptor
)
1387 // get transfer type
1389 TransferType
= InternalGetTransferType();
1392 // build request depending on type
1394 switch(TransferType
)
1396 case USB_ENDPOINT_TYPE_CONTROL
:
1397 Status
= BuildControlTransferDescriptor((POHCI_ENDPOINT_DESCRIPTOR
*)OutDescriptor
);
1399 case USB_ENDPOINT_TYPE_BULK
:
1400 case USB_ENDPOINT_TYPE_INTERRUPT
:
1401 Status
= BuildBulkInterruptEndpoint(OutDescriptor
);
1403 case USB_ENDPOINT_TYPE_ISOCHRONOUS
:
1404 Status
= BuildIsochronousEndpoint((POHCI_ENDPOINT_DESCRIPTOR
*)OutDescriptor
);
1408 Status
= STATUS_NOT_IMPLEMENTED
;
1412 if (NT_SUCCESS(Status
))
1417 //m_QueueHead = *OutDescriptor;
1420 // store request object
1422 (*OutDescriptor
)->Request
= PVOID(this);
1431 //----------------------------------------------------------------------------------------
1433 CUSBRequest::GetResultStatus(
1434 OUT OPTIONAL NTSTATUS
* NtStatusCode
,
1435 OUT OPTIONAL PULONG UrbStatusCode
)
1440 PC_ASSERT(m_CompletionEvent
);
1443 // wait for the operation to complete
1445 KeWaitForSingleObject(m_CompletionEvent
, Executive
, KernelMode
, FALSE
, NULL
);
1452 *NtStatusCode
= m_NtStatusCode
;
1460 *UrbStatusCode
= m_UrbStatusCode
;
1466 CUSBRequest::FreeEndpointDescriptor(
1467 struct _OHCI_ENDPOINT_DESCRIPTOR
* OutDescriptor
)
1469 POHCI_GENERAL_TD TransferDescriptor
, NextTransferDescriptor
;
1470 POHCI_ISO_TD IsoTransferDescriptor
, IsoNextTransferDescriptor
;
1471 ULONG Index
, PacketCount
;
1473 DPRINT("CUSBRequest::FreeEndpointDescriptor EndpointDescriptor %p Logical %x\n", OutDescriptor
, OutDescriptor
->PhysicalAddress
.LowPart
);
1475 if (OutDescriptor
->Flags
& OHCI_ENDPOINT_ISOCHRONOUS_FORMAT
)
1478 // get first iso transfer descriptor
1480 IsoTransferDescriptor
= (POHCI_ISO_TD
)OutDescriptor
->HeadLogicalDescriptor
;
1483 // release endpoint descriptor
1485 m_DmaManager
->Release(OutDescriptor
, sizeof(OHCI_ENDPOINT_DESCRIPTOR
));
1487 while(IsoTransferDescriptor
)
1492 IsoNextTransferDescriptor
= IsoTransferDescriptor
->NextLogicalDescriptor
;
1497 PacketCount
= OHCI_ITD_GET_FRAME_COUNT(IsoTransferDescriptor
->Flags
);
1499 DPRINT1("CUSBRequest::FreeEndpointDescriptor Descriptor %p Logical %x Buffer Physical %x EndAddress %x PacketCount %lu\n", IsoTransferDescriptor
, IsoTransferDescriptor
->PhysicalAddress
.LowPart
, IsoTransferDescriptor
->BufferPhysical
, IsoTransferDescriptor
->LastPhysicalByteAddress
, PacketCount
);
1501 for(Index
= 0; Index
< PacketCount
; Index
++)
1503 DPRINT1("PSW Index %lu Value %x\n", Index
, IsoTransferDescriptor
->Offset
[Index
]);
1507 // release descriptor
1509 m_DmaManager
->Release(IsoTransferDescriptor
, sizeof(OHCI_ISO_TD
));
1514 IsoTransferDescriptor
= IsoNextTransferDescriptor
;
1520 // get first general transfer descriptor
1522 TransferDescriptor
= (POHCI_GENERAL_TD
)OutDescriptor
->HeadLogicalDescriptor
;
1525 // release endpoint descriptor
1527 m_DmaManager
->Release(OutDescriptor
, sizeof(OHCI_ENDPOINT_DESCRIPTOR
));
1529 while(TransferDescriptor
)
1534 NextTransferDescriptor
= (POHCI_GENERAL_TD
)TransferDescriptor
->NextLogicalDescriptor
;
1537 // is there a buffer associated
1539 if (TransferDescriptor
->BufferSize
)
1544 m_DmaManager
->Release(TransferDescriptor
->BufferLogical
, TransferDescriptor
->BufferSize
);
1547 DPRINT("CUSBRequest::FreeEndpointDescriptor Descriptor %p Logical %x Buffer Physical %x EndAddress %x\n", TransferDescriptor
, TransferDescriptor
->PhysicalAddress
.LowPart
, TransferDescriptor
->BufferPhysical
, TransferDescriptor
->LastPhysicalByteAddress
);
1550 // release descriptor
1552 m_DmaManager
->Release(TransferDescriptor
, sizeof(OHCI_GENERAL_TD
));
1557 TransferDescriptor
= NextTransferDescriptor
;
1564 CUSBRequest::CompletionCallback(
1565 struct _OHCI_ENDPOINT_DESCRIPTOR
* OutDescriptor
)
1567 PIO_STACK_LOCATION IoStack
;
1570 DPRINT("CUSBRequest::CompletionCallback Descriptor %p PhysicalAddress %x\n", OutDescriptor
, OutDescriptor
->PhysicalAddress
.LowPart
);
1575 m_NtStatusCode
= STATUS_SUCCESS
;
1576 m_UrbStatusCode
= USBD_STATUS_SUCCESS
;
1581 // set irp completion status
1583 m_Irp
->IoStatus
.Status
= STATUS_SUCCESS
; //FIXME
1586 // get current irp stack location
1588 IoStack
= IoGetCurrentIrpStackLocation(m_Irp
);
1593 Urb
= (PURB
)IoStack
->Parameters
.Others
.Argument1
;
1598 Urb
->UrbHeader
.Status
= USBD_STATUS_SUCCESS
; //FIXME
1601 // Check if the MDL was created
1603 if (!Urb
->UrbBulkOrInterruptTransfer
.TransferBufferMDL
)
1608 IoFreeMdl(m_TransferBufferMDL
);
1612 // FIXME: support status and calculate length
1616 // FIXME: check if the transfer was split
1617 // if yes dont complete irp yet
1619 IoCompleteRequest(m_Irp
, IO_NO_INCREMENT
);
1624 // signal completion event
1626 PC_ASSERT(m_CompletionEvent
);
1627 KeSetEvent(m_CompletionEvent
, 0, FALSE
);
1632 //-----------------------------------------------------------------------------------------
1634 CUSBRequest::IsRequestInitialized()
1636 if (m_Irp
|| m_SetupPacket
)
1639 // request is initialized
1645 // request is not initialized
1650 //-----------------------------------------------------------------------------------------
1652 CUSBRequest::IsQueueHeadComplete(
1653 struct _QUEUE_HEAD
* QueueHead
)
1661 //-----------------------------------------------------------------------------------------
1663 InternalCreateUSBRequest(
1664 PUSBREQUEST
*OutRequest
)
1669 // allocate requests
1671 This
= new(NonPagedPool
, TAG_USBOHCI
) CUSBRequest(0);
1675 // failed to allocate
1677 return STATUS_INSUFFICIENT_RESOURCES
;
1681 // add reference count
1688 *OutRequest
= (PUSBREQUEST
)This
;
1693 return STATUS_SUCCESS
;