2 * PROJECT: ReactOS Universal Serial Bus Host Controller Interface
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: drivers/usb/usbuhci/usb_request.cpp
5 * PURPOSE: USB UHCI device driver.
7 * Michael Martin (michael.martin@reactos.org)
8 * Johannes Anderwald (johannes.anderwald@reactos.org)
16 class CUSBRequest
: public IUHCIRequest
19 STDMETHODIMP
QueryInterface( REFIID InterfaceId
, PVOID
* Interface
);
21 STDMETHODIMP_(ULONG
) AddRef()
23 InterlockedIncrement(&m_Ref
);
26 STDMETHODIMP_(ULONG
) Release()
28 InterlockedDecrement(&m_Ref
);
43 ULONG
InternalGetTransferType();
44 UCHAR
InternalGetPidDirection();
45 UCHAR
GetDeviceAddress();
46 NTSTATUS
BuildSetupPacket();
47 NTSTATUS
BuildSetupPacketFromURB();
48 UCHAR
GetEndpointAddress();
49 USHORT
GetMaxPacketSize();
50 NTSTATUS
CreateDescriptor(PUHCI_TRANSFER_DESCRIPTOR
*OutDescriptor
, IN UCHAR PidCode
, ULONG BufferLength
);
51 NTSTATUS
BuildControlTransferDescriptor(IN PUHCI_QUEUE_HEAD
* OutQueueHead
);
52 NTSTATUS
BuildBulkInterruptTransferDescriptor(IN PUHCI_QUEUE_HEAD
* OutQueueHead
);
53 NTSTATUS
BuildQueueHead(OUT PUHCI_QUEUE_HEAD
*OutQueueHead
);
54 VOID
FreeDescriptor(IN PUHCI_TRANSFER_DESCRIPTOR Descriptor
);
55 NTSTATUS
BuildTransferDescriptorChain(IN PVOID TransferBuffer
, IN ULONG TransferBufferLength
, IN UCHAR PidCode
, IN UCHAR InitialDataToggle
, OUT PUHCI_TRANSFER_DESCRIPTOR
* OutFirstDescriptor
, OUT PUHCI_TRANSFER_DESCRIPTOR
* OutLastDescriptor
, OUT PULONG OutTransferBufferOffset
, OUT PUCHAR OutDataToggle
);
57 // constructor / destructor
58 CUSBRequest(IUnknown
*OuterUnknown
);
59 virtual ~CUSBRequest();
65 // memory manager for allocating setup packet / queue head / transfer descriptors
67 PDMAMEMORYMANAGER m_DmaManager
;
70 // caller provided irp packet containing URB request
75 // transfer buffer length
77 ULONG m_TransferBufferLength
;
80 // current transfer length
82 ULONG m_TransferBufferLengthCompleted
;
85 // Total Transfer Length
87 ULONG m_TotalBytesTransferred
;
90 // transfer buffer MDL
92 PMDL m_TransferBufferMDL
;
95 // caller provided setup packet
97 PUSB_DEFAULT_PIPE_SETUP_PACKET m_SetupPacket
;
100 // completion event for callers who initialized request with setup packet
102 PKEVENT m_CompletionEvent
;
105 // device address for callers who initialized it with device address
107 UCHAR m_DeviceAddress
;
110 // store end point address
112 PUSB_ENDPOINT m_EndpointDescriptor
;
115 // allocated setup packet from the DMA pool
117 PUSB_DEFAULT_PIPE_SETUP_PACKET m_DescriptorPacket
;
118 PHYSICAL_ADDRESS m_DescriptorSetupPacket
;
121 // stores the result of the operation
123 NTSTATUS m_NtStatusCode
;
124 ULONG m_UrbStatusCode
;
127 // store device speed
129 USB_DEVICE_SPEED m_DeviceSpeed
;
136 //----------------------------------------------------------------------------------------
137 CUSBRequest::CUSBRequest(IUnknown
*OuterUnknown
) :
138 m_CompletionEvent(NULL
)
140 UNREFERENCED_PARAMETER(OuterUnknown
);
143 //----------------------------------------------------------------------------------------
144 CUSBRequest::~CUSBRequest()
146 if (m_CompletionEvent
!= NULL
)
148 ExFreePoolWithTag(m_CompletionEvent
, TAG_USBUHCI
);
152 //----------------------------------------------------------------------------------------
155 CUSBRequest::QueryInterface(
159 return STATUS_UNSUCCESSFUL
;
162 //----------------------------------------------------------------------------------------
164 CUSBRequest::InitializeWithSetupPacket(
165 IN PDMAMEMORYMANAGER DmaManager
,
166 IN PUSB_DEFAULT_PIPE_SETUP_PACKET SetupPacket
,
167 IN PUSBDEVICE Device
,
168 IN OPTIONAL
struct _USB_ENDPOINT
* EndpointDescriptor
,
169 IN OUT ULONG TransferBufferLength
,
170 IN OUT PMDL TransferBuffer
)
175 PC_ASSERT(DmaManager
);
176 PC_ASSERT(SetupPacket
);
181 m_DmaManager
= DmaManager
;
182 m_SetupPacket
= SetupPacket
;
183 m_TransferBufferLength
= TransferBufferLength
;
184 m_TransferBufferMDL
= TransferBuffer
;
185 m_DeviceAddress
= Device
->GetDeviceAddress();
186 m_EndpointDescriptor
= EndpointDescriptor
;
187 m_TotalBytesTransferred
= 0;
188 m_DeviceSpeed
= Device
->GetSpeed();
191 // Set Length Completed to 0
193 m_TransferBufferLengthCompleted
= 0;
196 // allocate completion event
198 m_CompletionEvent
= (PKEVENT
)ExAllocatePoolWithTag(NonPagedPool
, sizeof(KEVENT
), TAG_USBUHCI
);
199 if (!m_CompletionEvent
)
202 // failed to allocate completion event
204 return STATUS_INSUFFICIENT_RESOURCES
;
208 // initialize completion event
210 KeInitializeEvent(m_CompletionEvent
, NotificationEvent
, FALSE
);
215 return STATUS_SUCCESS
;
217 //----------------------------------------------------------------------------------------
219 CUSBRequest::InitializeWithIrp(
220 IN PDMAMEMORYMANAGER DmaManager
,
221 IN PUSBDEVICE Device
,
224 PIO_STACK_LOCATION IoStack
;
230 PC_ASSERT(DmaManager
);
233 m_DmaManager
= DmaManager
;
234 m_TotalBytesTransferred
= 0;
235 m_DeviceSpeed
= Device
->GetSpeed();
238 // get current irp stack location
240 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
245 PC_ASSERT(IoStack
->MajorFunction
== IRP_MJ_INTERNAL_DEVICE_CONTROL
);
246 PC_ASSERT(IoStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_INTERNAL_USB_SUBMIT_URB
);
247 PC_ASSERT(IoStack
->Parameters
.Others
.Argument1
!= 0);
252 Urb
= (PURB
)IoStack
->Parameters
.Others
.Argument1
;
260 // check function type
262 switch (Urb
->UrbHeader
.Function
)
264 case URB_FUNCTION_ISOCH_TRANSFER
:
267 // there must be at least one packet
269 ASSERT(Urb
->UrbIsochronousTransfer
.NumberOfPackets
);
272 // is there data to be transferred
274 if (Urb
->UrbIsochronousTransfer
.TransferBufferLength
)
277 // Check if there is a MDL
279 if (!Urb
->UrbBulkOrInterruptTransfer
.TransferBufferMDL
)
284 PC_ASSERT(Urb
->UrbBulkOrInterruptTransfer
.TransferBuffer
);
287 // Create one using TransferBuffer
289 DPRINT("Creating Mdl from Urb Buffer %p Length %lu\n", Urb
->UrbBulkOrInterruptTransfer
.TransferBuffer
, Urb
->UrbBulkOrInterruptTransfer
.TransferBufferLength
);
290 m_TransferBufferMDL
= IoAllocateMdl(Urb
->UrbBulkOrInterruptTransfer
.TransferBuffer
,
291 Urb
->UrbBulkOrInterruptTransfer
.TransferBufferLength
,
296 if (!m_TransferBufferMDL
)
299 // failed to allocate mdl
301 return STATUS_INSUFFICIENT_RESOURCES
;
305 // build mdl for non paged pool
306 // FIXME: Does hub driver already do this when passing MDL?
308 MmBuildMdlForNonPagedPool(m_TransferBufferMDL
);
315 m_TransferBufferMDL
= Urb
->UrbIsochronousTransfer
.TransferBufferMDL
;
320 // save buffer length
322 m_TransferBufferLength
= Urb
->UrbIsochronousTransfer
.TransferBufferLength
;
325 // Set Length Completed to 0
327 m_TransferBufferLengthCompleted
= 0;
330 // get endpoint descriptor
332 m_EndpointDescriptor
= (PUSB_ENDPOINT
)Urb
->UrbIsochronousTransfer
.PipeHandle
;
335 // completed initialization
340 // luckily those request have the same structure layout
342 case URB_FUNCTION_CLASS_INTERFACE
:
343 case URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE
:
344 case URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER
:
347 // bulk interrupt transfer
349 if (Urb
->UrbBulkOrInterruptTransfer
.TransferBufferLength
)
352 // Check if there is a MDL
354 if (!Urb
->UrbBulkOrInterruptTransfer
.TransferBufferMDL
)
359 PC_ASSERT(Urb
->UrbBulkOrInterruptTransfer
.TransferBuffer
);
362 // Create one using TransferBuffer
364 DPRINT("Creating Mdl from Urb Buffer %p Length %lu\n", Urb
->UrbBulkOrInterruptTransfer
.TransferBuffer
, Urb
->UrbBulkOrInterruptTransfer
.TransferBufferLength
);
365 m_TransferBufferMDL
= IoAllocateMdl(Urb
->UrbBulkOrInterruptTransfer
.TransferBuffer
,
366 Urb
->UrbBulkOrInterruptTransfer
.TransferBufferLength
,
371 if (!m_TransferBufferMDL
)
374 // failed to allocate mdl
376 return STATUS_INSUFFICIENT_RESOURCES
;
380 // build mdl for non paged pool
381 // FIXME: Does hub driver already do this when passing MDL?
383 MmBuildMdlForNonPagedPool(m_TransferBufferMDL
);
386 // Keep that ehci created the MDL and needs to free it.
391 m_TransferBufferMDL
= Urb
->UrbBulkOrInterruptTransfer
.TransferBufferMDL
;
395 // save buffer length
397 m_TransferBufferLength
= Urb
->UrbBulkOrInterruptTransfer
.TransferBufferLength
;
400 // Set Length Completed to 0
402 m_TransferBufferLengthCompleted
= 0;
405 // get endpoint descriptor
407 m_EndpointDescriptor
= (PUSB_ENDPOINT
)Urb
->UrbBulkOrInterruptTransfer
.PipeHandle
;
413 DPRINT1("URB Function: not supported %x\n", Urb
->UrbHeader
.Function
);
420 return STATUS_SUCCESS
;
424 //----------------------------------------------------------------------------------------
426 CUSBRequest::IsRequestComplete()
429 // FIXME: check if request was split
433 // Check if the transfer was completed, only valid for Bulk Transfers
435 if ((m_TransferBufferLengthCompleted
< m_TransferBufferLength
)
436 && (GetTransferType() == USB_ENDPOINT_TYPE_BULK
))
439 // Transfer not completed
445 //----------------------------------------------------------------------------------------
447 CUSBRequest::GetTransferType()
450 // call internal implementation
452 return InternalGetTransferType();
456 CUSBRequest::GetMaxPacketSize()
458 if (!m_EndpointDescriptor
)
467 ASSERT(m_EndpointDescriptor
);
470 // return max packet size
472 return m_EndpointDescriptor
->EndPointDescriptor
.wMaxPacketSize
;
476 CUSBRequest::GetInterval()
478 ASSERT(m_EndpointDescriptor
);
479 ASSERT((m_EndpointDescriptor
->EndPointDescriptor
.bmAttributes
& USB_ENDPOINT_TYPE_MASK
) == USB_ENDPOINT_TYPE_INTERRUPT
);
482 // return interrupt interval
484 return m_EndpointDescriptor
->EndPointDescriptor
.bInterval
;
488 CUSBRequest::GetEndpointAddress()
490 if (!m_EndpointDescriptor
)
499 ASSERT(m_EndpointDescriptor
);
502 // endpoint number is between 1-15
504 return (m_EndpointDescriptor
->EndPointDescriptor
.bEndpointAddress
& 0xF);
507 //----------------------------------------------------------------------------------------
509 CUSBRequest::InternalGetTransferType()
514 // check if an irp is provided
518 ASSERT(m_EndpointDescriptor
);
521 // end point is defined in the low byte of bmAttributes
523 TransferType
= (m_EndpointDescriptor
->EndPointDescriptor
.bmAttributes
& USB_ENDPOINT_TYPE_MASK
);
528 // initialized with setup packet, must be a control transfer
530 TransferType
= USB_ENDPOINT_TYPE_CONTROL
;
540 CUSBRequest::InternalGetPidDirection()
542 if (m_EndpointDescriptor
)
545 // end point direction is highest bit in bEndpointAddress
547 return (m_EndpointDescriptor
->EndPointDescriptor
.bEndpointAddress
& USB_ENDPOINT_DIRECTION_MASK
) >> 7;
552 // request arrives on the control pipe, extract direction from setup packet
554 ASSERT(m_SetupPacket
);
555 return (m_SetupPacket
->bmRequestType
.B
>> 7);
560 //----------------------------------------------------------------------------------------
562 CUSBRequest::GetDeviceAddress()
564 PIO_STACK_LOCATION IoStack
;
566 PUSBDEVICE UsbDevice
;
569 // check if there is an irp provided
574 // used provided address
576 return m_DeviceAddress
;
580 // get current stack location
582 IoStack
= IoGetCurrentIrpStackLocation(m_Irp
);
587 Urb
= (PURB
)IoStack
->Parameters
.Others
.Argument1
;
590 // check if there is a pipe handle provided
592 if (Urb
->UrbHeader
.UsbdDeviceHandle
)
595 // there is a device handle provided
597 UsbDevice
= (PUSBDEVICE
)Urb
->UrbHeader
.UsbdDeviceHandle
;
600 // return device address
602 return UsbDevice
->GetDeviceAddress();
606 // no device handle provided, it is the host root bus
611 //----------------------------------------------------------------------------------------
613 CUSBRequest::GetEndpointDescriptor(
614 struct _UHCI_QUEUE_HEAD
** OutQueueHead
)
616 NTSTATUS Status
= STATUS_UNSUCCESSFUL
;
620 TransferType
= InternalGetTransferType();
622 if (TransferType
== USB_ENDPOINT_TYPE_CONTROL
)
627 Status
= BuildControlTransferDescriptor(OutQueueHead
);
629 else if (TransferType
== USB_ENDPOINT_TYPE_INTERRUPT
|| TransferType
== USB_ENDPOINT_TYPE_BULK
)
634 Status
= BuildBulkInterruptTransferDescriptor(OutQueueHead
);
637 if (!NT_SUCCESS(Status
))
648 (*OutQueueHead
)->Request
= PVOID(this);
653 return STATUS_SUCCESS
;
656 //----------------------------------------------------------------------------------------
658 CUSBRequest::GetResultStatus(
659 OUT OPTIONAL NTSTATUS
* NtStatusCode
,
660 OUT OPTIONAL PULONG UrbStatusCode
)
665 PC_ASSERT(m_CompletionEvent
);
668 // wait for the operation to complete
670 KeWaitForSingleObject(m_CompletionEvent
, Executive
, KernelMode
, FALSE
, NULL
);
677 *NtStatusCode
= m_NtStatusCode
;
685 *UrbStatusCode
= m_UrbStatusCode
;
690 //-----------------------------------------------------------------------------------------
692 CUSBRequest::CreateDescriptor(
693 OUT PUHCI_TRANSFER_DESCRIPTOR
*OutDescriptor
,
697 PUHCI_TRANSFER_DESCRIPTOR Descriptor
;
698 PHYSICAL_ADDRESS Address
;
702 // allocate descriptor
704 Status
= m_DmaManager
->Allocate(sizeof(UHCI_TRANSFER_DESCRIPTOR
), (PVOID
*)&Descriptor
, &Address
);
705 if (!NT_SUCCESS(Status
))
707 DPRINT1("[USBUHCI] Failed to allocate descriptor\n");
714 Descriptor
->PhysicalAddress
= Address
.LowPart
;
715 Descriptor
->Status
= TD_STATUS_ACTIVE
;
717 if (InternalGetTransferType() == USB_ENDPOINT_TYPE_ISOCHRONOUS
)
720 // isochronous transfer descriptor
722 Descriptor
->Status
|= TD_CONTROL_ISOCHRONOUS
;
729 Descriptor
->Status
|= TD_CONTROL_3_ERRORS
;
731 if (PidCode
== TD_TOKEN_IN
&& (InternalGetTransferType() != USB_ENDPOINT_TYPE_CONTROL
))
734 // enable short packet detect for bulk & interrupt
736 Descriptor
->Status
|= TD_CONTROL_SPD
;
741 // is it low speed device
743 if (m_DeviceSpeed
== UsbLowSpeed
)
748 Descriptor
->Status
|= TD_CONTROL_LOWSPEED
;
754 Descriptor
->BufferSize
= BufferLength
;
762 // store buffer length
764 Descriptor
->Token
= (BufferLength
- 1) << TD_TOKEN_MAXLEN_SHIFT
;
769 // no buffer magic constant
771 Descriptor
->Token
= TD_TOKEN_NULL_DATA
;
775 // store address & endpoint number
777 Descriptor
->Token
|= GetEndpointAddress() << TD_TOKEN_ENDPTADDR_SHIFT
;
778 Descriptor
->Token
|= GetDeviceAddress() << TD_TOKEN_DEVADDR_SHIFT
| PidCode
;
783 // allocate buffer for descriptor
785 Status
= m_DmaManager
->Allocate(BufferLength
, (PVOID
*)&Descriptor
->BufferLogical
, &Address
);
786 if (!NT_SUCCESS(Status
))
788 DPRINT1("[USBUHCI] Failed to allocate descriptor buffer length %lu\n", BufferLength
);
789 m_DmaManager
->Release(Descriptor
, sizeof(UHCI_TRANSFER_DESCRIPTOR
));
796 Descriptor
->BufferPhysical
= Address
.LowPart
;
802 *OutDescriptor
= Descriptor
;
803 return STATUS_SUCCESS
;
807 CUSBRequest::BuildTransferDescriptorChain(
808 IN PVOID TransferBuffer
,
809 IN ULONG TransferBufferLength
,
811 IN UCHAR InitialDataToggle
,
812 OUT PUHCI_TRANSFER_DESCRIPTOR
* OutFirstDescriptor
,
813 OUT PUHCI_TRANSFER_DESCRIPTOR
* OutLastDescriptor
,
814 OUT PULONG OutTransferBufferOffset
,
815 OUT PUCHAR OutDataToggle
)
817 PUHCI_TRANSFER_DESCRIPTOR FirstDescriptor
= NULL
, CurrentDescriptor
, LastDescriptor
= NULL
;
818 ULONG TransferBufferOffset
= 0;
820 ULONG MaxPacketSize
, CurrentBufferSize
;
823 // FIXME FIXME FIXME FIXME FIXME
825 if (GetDeviceSpeed() == UsbLowSpeed
)
828 // low speed use max 8 bytes
834 if (m_EndpointDescriptor
)
839 MaxPacketSize
= m_EndpointDescriptor
->EndPointDescriptor
.wMaxPacketSize
;
853 // determine current packet size
855 CurrentBufferSize
= min(MaxPacketSize
, TransferBufferLength
- TransferBufferOffset
);
858 // allocate descriptor
860 Status
= CreateDescriptor(&CurrentDescriptor
, PidCode
, CurrentBufferSize
);
861 if (!NT_SUCCESS(Status
))
864 // failed to allocate queue head
866 DPRINT1("[UHCI] Failed to create descriptor\n");
871 if (PidCode
== TD_TOKEN_OUT
)
876 RtlCopyMemory(CurrentDescriptor
->BufferLogical
, (PVOID
)((ULONG_PTR
)TransferBuffer
+ TransferBufferOffset
), CurrentBufferSize
);
883 CurrentDescriptor
->UserBuffer
= (PVOID
)((ULONG_PTR
)TransferBuffer
+ TransferBufferOffset
);
886 if (!FirstDescriptor
)
891 FirstDescriptor
= CurrentDescriptor
;
898 LastDescriptor
->LinkPhysical
= CurrentDescriptor
->PhysicalAddress
| TD_DEPTH_FIRST
;
899 LastDescriptor
->NextLogicalDescriptor
= (PVOID
)CurrentDescriptor
;
902 if (InitialDataToggle
)
907 CurrentDescriptor
->Token
|= TD_TOKEN_DATA1
;
913 LastDescriptor
= CurrentDescriptor
;
914 TransferBufferOffset
+= CurrentBufferSize
;
915 InitialDataToggle
= !InitialDataToggle
;
917 }while(TransferBufferOffset
< TransferBufferLength
);
919 if (OutTransferBufferOffset
)
922 // store transfer buffer length
924 *OutTransferBufferOffset
= TransferBufferOffset
;
927 if (OutFirstDescriptor
)
930 // store first descriptor
932 *OutFirstDescriptor
= FirstDescriptor
;
935 if (OutLastDescriptor
)
938 // store last descriptor
940 *OutLastDescriptor
= CurrentDescriptor
;
948 *OutDataToggle
= InitialDataToggle
;
954 return STATUS_SUCCESS
;
958 CUSBRequest::BuildQueueHead(
959 OUT PUHCI_QUEUE_HEAD
*OutQueueHead
)
961 PUHCI_QUEUE_HEAD QueueHead
;
963 PHYSICAL_ADDRESS Address
;
966 // allocate queue head
968 Status
= m_DmaManager
->Allocate(sizeof(UHCI_QUEUE_HEAD
), (PVOID
*)&QueueHead
, &Address
);
969 if (!NT_SUCCESS(Status
))
972 // failed to allocate queue head
974 DPRINT1("[UHCI] Failed to create queue head\n");
981 QueueHead
->PhysicalAddress
= Address
.LowPart
;
982 QueueHead
->ElementPhysical
= Address
.LowPart
;
987 *OutQueueHead
= QueueHead
;
988 return STATUS_SUCCESS
;
992 CUSBRequest::FreeDescriptor(
993 IN PUHCI_TRANSFER_DESCRIPTOR Descriptor
)
995 if (Descriptor
->BufferLogical
)
1000 m_DmaManager
->Release(Descriptor
->BufferLogical
, Descriptor
->BufferSize
);
1006 m_DmaManager
->Release(Descriptor
, sizeof(UHCI_TRANSFER_DESCRIPTOR
));
1010 CUSBRequest::BuildBulkInterruptTransferDescriptor(
1011 IN PUHCI_QUEUE_HEAD
* OutQueueHead
)
1014 PUHCI_QUEUE_HEAD QueueHead
;
1015 PUHCI_TRANSFER_DESCRIPTOR FirstDescriptor
, LastDescriptor
;
1016 ULONG ChainDescriptorLength
;
1021 // create queue head
1022 Status
= BuildQueueHead(&QueueHead
);
1023 if (!NT_SUCCESS(Status
))
1025 // failed to allocate queue head
1026 DPRINT1("[UHCI] Failed to create queue head\n");
1031 Direction
= InternalGetPidDirection();
1036 m_Base
= MmGetMdlVirtualAddress(m_TransferBufferMDL
);
1039 ASSERT(m_Base
!= NULL
);
1042 // get new buffer offset
1043 Buffer
= (PVOID
)((ULONG_PTR
)m_Base
+ m_TransferBufferLengthCompleted
);
1045 // FIXME determine buffer limit
1046 BufferSize
= min(m_TransferBufferLength
- m_TransferBufferLengthCompleted
, PAGE_SIZE
);
1048 // create descriptor chain
1049 Status
= BuildTransferDescriptorChain(Buffer
,
1051 Direction
? TD_TOKEN_IN
: TD_TOKEN_OUT
,
1052 m_EndpointDescriptor
->DataToggle
,
1055 &ChainDescriptorLength
,
1057 if (!NT_SUCCESS(Status
))
1060 // failed to allocate descriptor
1062 DPRINT1("[UHCI] Failed to create descriptor chain\n");
1063 m_DmaManager
->Release(QueueHead
, sizeof(UHCI_QUEUE_HEAD
));
1067 // adjust buffer offset
1068 m_TransferBufferLengthCompleted
+= ChainDescriptorLength
;
1070 // fire interrupt when the last descriptor is complete
1071 LastDescriptor
->Status
|= TD_CONTROL_IOC
;
1072 LastDescriptor
->LinkPhysical
= TD_TERMINATE
;
1073 LastDescriptor
->NextLogicalDescriptor
= NULL
;
1075 // link queue head with first data descriptor descriptor
1076 QueueHead
->NextElementDescriptor
= (PVOID
)FirstDescriptor
;
1077 QueueHead
->ElementPhysical
= FirstDescriptor
->PhysicalAddress
;
1080 *OutQueueHead
= QueueHead
;
1081 return STATUS_SUCCESS
;
1086 CUSBRequest::BuildControlTransferDescriptor(
1087 IN PUHCI_QUEUE_HEAD
* OutQueueHead
)
1089 PUHCI_TRANSFER_DESCRIPTOR SetupDescriptor
, StatusDescriptor
, FirstDescriptor
, LastDescriptor
;
1090 PUHCI_QUEUE_HEAD QueueHead
;
1093 ULONG ChainDescriptorLength
;
1096 // create queue head
1098 Status
= BuildQueueHead(&QueueHead
);
1099 if (!NT_SUCCESS(Status
))
1102 // failed to allocate queue head
1104 DPRINT1("[UHCI] Failed to create queue head\n");
1111 Direction
= InternalGetPidDirection();
1114 // build setup descriptor
1116 Status
= CreateDescriptor(&SetupDescriptor
,
1118 sizeof(USB_DEFAULT_PIPE_SETUP_PACKET
));
1119 if (!NT_SUCCESS(Status
))
1122 // failed to allocate descriptor
1124 DPRINT1("[UHCI] Failed to create setup descriptor\n");
1125 m_DmaManager
->Release(QueueHead
, sizeof(UHCI_QUEUE_HEAD
));
1130 // build status descriptor
1132 Status
= CreateDescriptor(&StatusDescriptor
,
1133 Direction
? TD_TOKEN_OUT
: TD_TOKEN_IN
,
1135 if (!NT_SUCCESS(Status
))
1138 // failed to allocate descriptor
1140 DPRINT1("[UHCI] Failed to create status descriptor\n");
1141 FreeDescriptor(SetupDescriptor
);
1142 m_DmaManager
->Release(QueueHead
, sizeof(UHCI_QUEUE_HEAD
));
1149 // copy setup packet
1151 RtlCopyMemory(SetupDescriptor
->BufferLogical
, m_SetupPacket
, sizeof(USB_DEFAULT_PIPE_SETUP_PACKET
));
1156 // generate setup packet from urb
1162 // init status descriptor
1164 StatusDescriptor
->Status
|= TD_CONTROL_IOC
;
1165 StatusDescriptor
->Token
|= TD_TOKEN_DATA1
;
1166 StatusDescriptor
->LinkPhysical
= TD_TERMINATE
;
1167 StatusDescriptor
->NextLogicalDescriptor
= NULL
;
1169 if (m_TransferBufferLength
)
1172 // create descriptor chain
1174 Status
= BuildTransferDescriptorChain(MmGetMdlVirtualAddress(m_TransferBufferMDL
),
1175 m_TransferBufferLength
,
1176 Direction
? TD_TOKEN_IN
: TD_TOKEN_OUT
,
1180 &ChainDescriptorLength
,
1182 if (!NT_SUCCESS(Status
))
1185 // failed to allocate descriptor
1187 DPRINT1("[UHCI] Failed to create descriptor chain\n");
1188 FreeDescriptor(SetupDescriptor
);
1189 FreeDescriptor(StatusDescriptor
);
1190 m_DmaManager
->Release(QueueHead
, sizeof(UHCI_QUEUE_HEAD
));
1195 // link setup descriptor to first data descriptor
1197 SetupDescriptor
->LinkPhysical
= FirstDescriptor
->PhysicalAddress
| TD_DEPTH_FIRST
;
1198 SetupDescriptor
->NextLogicalDescriptor
= (PVOID
)FirstDescriptor
;
1201 // link last data descriptor to status descriptor
1203 LastDescriptor
->LinkPhysical
= StatusDescriptor
->PhysicalAddress
| TD_DEPTH_FIRST
;
1204 LastDescriptor
->NextLogicalDescriptor
= (PVOID
)StatusDescriptor
;
1209 // directly link setup to status descriptor
1211 SetupDescriptor
->LinkPhysical
= StatusDescriptor
->PhysicalAddress
| TD_DEPTH_FIRST
;
1212 SetupDescriptor
->NextLogicalDescriptor
= (PVOID
)StatusDescriptor
;
1216 // link queue head with setup descriptor
1218 QueueHead
->NextElementDescriptor
= (PVOID
)SetupDescriptor
;
1219 QueueHead
->ElementPhysical
= SetupDescriptor
->PhysicalAddress
;
1224 *OutQueueHead
= QueueHead
;
1225 return STATUS_SUCCESS
;
1228 CUSBRequest::GetDeviceSpeed()
1230 return m_DeviceSpeed
;
1234 CUSBRequest::FreeEndpointDescriptor(
1235 struct _UHCI_QUEUE_HEAD
* OutDescriptor
)
1237 PUHCI_TRANSFER_DESCRIPTOR Descriptor
, NextDescriptor
;
1239 UCHAR DataToggle
= 0;
1243 // grab first transfer descriptor
1245 Descriptor
= (PUHCI_TRANSFER_DESCRIPTOR
)OutDescriptor
->NextElementDescriptor
;
1249 DataToggle
= (Descriptor
->Token
>> TD_TOKEN_DATA_TOGGLE_SHIFT
) & 0x01;
1251 if (Descriptor
->Status
& TD_ERROR_MASK
)
1256 DPRINT1("[USBUHCI] Error detected at descriptor %p Physical %x\n", Descriptor
, Descriptor
->PhysicalAddress
);
1261 ErrorCount
= (Descriptor
->Status
>> TD_ERROR_COUNT_SHIFT
) & TD_ERROR_COUNT_MASK
;
1262 if (ErrorCount
== 0)
1265 // error retry count elapsed
1267 m_NtStatusCode
= STATUS_UNSUCCESSFUL
;
1269 if (Descriptor
->Status
& TD_STATUS_ERROR_BUFFER
)
1271 DPRINT1("[USBUHCI] Buffer Error detected in descriptor %p Index %lu\n", Descriptor
, Index
);
1272 m_UrbStatusCode
= USBD_STATUS_DATA_BUFFER_ERROR
;
1274 else if (Descriptor
->Status
& TD_STATUS_ERROR_TIMEOUT
)
1276 DPRINT1("[USBUHCI] Timeout detected in descriptor %p Index %lu\n", Descriptor
, Index
);
1277 m_UrbStatusCode
= USBD_STATUS_TIMEOUT
;
1279 else if (Descriptor
->Status
& TD_STATUS_ERROR_NAK
)
1281 DPRINT1("[USBUHCI] Unexpected pid detected in descriptor %p Index %lu\n", Descriptor
, Index
);
1282 m_UrbStatusCode
= USBD_STATUS_UNEXPECTED_PID
;
1284 else if (Descriptor
->Status
& TD_STATUS_ERROR_BITSTUFF
)
1286 DPRINT1("[USBUHCI] BitStuff detected in descriptor %p Index %lu\n", Descriptor
, Index
);
1287 m_UrbStatusCode
= USBD_STATUS_BTSTUFF
;
1290 else if (Descriptor
->Status
& TD_STATUS_ERROR_BABBLE
)
1295 DPRINT1("[USBUHCI] Babble detected in descriptor %p Index %lu\n", Descriptor
, Index
);
1296 m_UrbStatusCode
= USBD_STATUS_BABBLE_DETECTED
;
1303 DPRINT1("[USBUHCI] Stall detected Descriptor %p Index %lu\n", Descriptor
, Index
);
1304 m_UrbStatusCode
= USBD_STATUS_STALL_PID
;
1310 // FIXME detect actual length
1312 if (Descriptor
->UserBuffer
)
1315 // copy contents back
1317 RtlCopyMemory(Descriptor
->UserBuffer
, Descriptor
->BufferLogical
, Descriptor
->BufferSize
);
1321 // move to next descriptor
1323 NextDescriptor
= (PUHCI_TRANSFER_DESCRIPTOR
)Descriptor
->NextLogicalDescriptor
;
1326 // free endpoint descriptor
1328 FreeDescriptor(Descriptor
);
1333 Descriptor
= NextDescriptor
;
1338 // now free queue head
1340 m_DmaManager
->Release(OutDescriptor
, sizeof(UHCI_QUEUE_HEAD
));
1342 // is there an endpoint descriptor
1343 if (m_EndpointDescriptor
)
1345 // invert last data toggle
1346 m_EndpointDescriptor
->DataToggle
= (DataToggle
== 0);
1351 CUSBRequest::CompletionCallback()
1353 PIO_STACK_LOCATION IoStack
;
1356 DPRINT("CUSBRequest::CompletionCallback\n");
1361 // set irp completion status
1363 m_Irp
->IoStatus
.Status
= m_NtStatusCode
;
1366 // get current irp stack location
1368 IoStack
= IoGetCurrentIrpStackLocation(m_Irp
);
1373 Urb
= (PURB
)IoStack
->Parameters
.Others
.Argument1
;
1378 Urb
->UrbHeader
.Status
= m_UrbStatusCode
;
1381 // Check if the MDL was created
1383 if (!Urb
->UrbBulkOrInterruptTransfer
.TransferBufferMDL
)
1388 IoFreeMdl(m_TransferBufferMDL
);
1392 // FIXME calculate length
1398 IoCompleteRequest(m_Irp
, IO_NO_INCREMENT
);
1403 // signal completion event
1405 PC_ASSERT(m_CompletionEvent
);
1406 KeSetEvent(m_CompletionEvent
, 0, FALSE
);
1412 //-----------------------------------------------------------------------------------------
1415 InternalCreateUSBRequest(
1416 PUSBREQUEST
*OutRequest
)
1421 // allocate requests
1423 This
= new(NonPagedPool
, TAG_USBUHCI
) CUSBRequest(0);
1427 // failed to allocate
1429 return STATUS_INSUFFICIENT_RESOURCES
;
1433 // add reference count
1440 *OutRequest
= (PUSBREQUEST
)This
;
1445 return STATUS_SUCCESS
;