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
);
59 // constructor / destructor
60 CUSBRequest(IUnknown
*OuterUnknown
){}
61 virtual ~CUSBRequest(){}
67 // memory manager for allocating setup packet / queue head / transfer descriptors
69 PDMAMEMORYMANAGER m_DmaManager
;
72 // caller provided irp packet containing URB request
77 // transfer buffer length
79 ULONG m_TransferBufferLength
;
82 // current transfer length
84 ULONG m_TransferBufferLengthCompleted
;
87 // Total Transfer Length
89 ULONG m_TotalBytesTransferred
;
92 // transfer buffer MDL
94 PMDL m_TransferBufferMDL
;
97 // caller provided setup packet
99 PUSB_DEFAULT_PIPE_SETUP_PACKET m_SetupPacket
;
102 // completion event for callers who initialized request with setup packet
104 PKEVENT m_CompletionEvent
;
107 // device address for callers who initialized it with device address
109 UCHAR m_DeviceAddress
;
112 // store end point address
114 PUSB_ENDPOINT m_EndpointDescriptor
;
117 // allocated setup packet from the DMA pool
119 PUSB_DEFAULT_PIPE_SETUP_PACKET m_DescriptorPacket
;
120 PHYSICAL_ADDRESS m_DescriptorSetupPacket
;
123 // stores the result of the operation
125 NTSTATUS m_NtStatusCode
;
126 ULONG m_UrbStatusCode
;
129 // store device speed
131 USB_DEVICE_SPEED m_DeviceSpeed
;
138 //----------------------------------------------------------------------------------------
141 CUSBRequest::QueryInterface(
145 return STATUS_UNSUCCESSFUL
;
148 //----------------------------------------------------------------------------------------
150 CUSBRequest::InitializeWithSetupPacket(
151 IN PDMAMEMORYMANAGER DmaManager
,
152 IN PUSB_DEFAULT_PIPE_SETUP_PACKET SetupPacket
,
153 IN PUSBDEVICE Device
,
154 IN OPTIONAL
struct _USB_ENDPOINT
* EndpointDescriptor
,
155 IN OUT ULONG TransferBufferLength
,
156 IN OUT PMDL TransferBuffer
)
161 PC_ASSERT(DmaManager
);
162 PC_ASSERT(SetupPacket
);
167 m_DmaManager
= DmaManager
;
168 m_SetupPacket
= SetupPacket
;
169 m_TransferBufferLength
= TransferBufferLength
;
170 m_TransferBufferMDL
= TransferBuffer
;
171 m_DeviceAddress
= Device
->GetDeviceAddress();
172 m_EndpointDescriptor
= EndpointDescriptor
;
173 m_TotalBytesTransferred
= 0;
174 m_DeviceSpeed
= Device
->GetSpeed();
177 // Set Length Completed to 0
179 m_TransferBufferLengthCompleted
= 0;
182 // allocate completion event
184 m_CompletionEvent
= (PKEVENT
)ExAllocatePoolWithTag(NonPagedPool
, sizeof(KEVENT
), TAG_USBUHCI
);
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
,
207 IN PUSBDEVICE Device
,
210 PIO_STACK_LOCATION IoStack
;
216 PC_ASSERT(DmaManager
);
219 m_DmaManager
= DmaManager
;
220 m_TotalBytesTransferred
= 0;
221 m_DeviceSpeed
= Device
->GetSpeed();
224 // get current irp stack location
226 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
231 PC_ASSERT(IoStack
->MajorFunction
== IRP_MJ_INTERNAL_DEVICE_CONTROL
);
232 PC_ASSERT(IoStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_INTERNAL_USB_SUBMIT_URB
);
233 PC_ASSERT(IoStack
->Parameters
.Others
.Argument1
!= 0);
238 Urb
= (PURB
)IoStack
->Parameters
.Others
.Argument1
;
246 // check function type
248 switch (Urb
->UrbHeader
.Function
)
250 case URB_FUNCTION_ISOCH_TRANSFER
:
253 // there must be at least one packet
255 ASSERT(Urb
->UrbIsochronousTransfer
.NumberOfPackets
);
258 // is there data to be transferred
260 if (Urb
->UrbIsochronousTransfer
.TransferBufferLength
)
263 // Check if there is a MDL
265 if (!Urb
->UrbBulkOrInterruptTransfer
.TransferBufferMDL
)
270 PC_ASSERT(Urb
->UrbBulkOrInterruptTransfer
.TransferBuffer
);
273 // Create one using TransferBuffer
275 DPRINT("Creating Mdl from Urb Buffer %p Length %lu\n", Urb
->UrbBulkOrInterruptTransfer
.TransferBuffer
, Urb
->UrbBulkOrInterruptTransfer
.TransferBufferLength
);
276 m_TransferBufferMDL
= IoAllocateMdl(Urb
->UrbBulkOrInterruptTransfer
.TransferBuffer
,
277 Urb
->UrbBulkOrInterruptTransfer
.TransferBufferLength
,
282 if (!m_TransferBufferMDL
)
285 // failed to allocate mdl
287 return STATUS_INSUFFICIENT_RESOURCES
;
291 // build mdl for non paged pool
292 // FIXME: Does hub driver already do this when passing MDL?
294 MmBuildMdlForNonPagedPool(m_TransferBufferMDL
);
301 m_TransferBufferMDL
= Urb
->UrbIsochronousTransfer
.TransferBufferMDL
;
306 // save buffer length
308 m_TransferBufferLength
= Urb
->UrbIsochronousTransfer
.TransferBufferLength
;
311 // Set Length Completed to 0
313 m_TransferBufferLengthCompleted
= 0;
316 // get endpoint descriptor
318 m_EndpointDescriptor
= (PUSB_ENDPOINT
)Urb
->UrbIsochronousTransfer
.PipeHandle
;
321 // completed initialization
326 // luckily those request have the same structure layout
328 case URB_FUNCTION_CLASS_INTERFACE
:
329 case URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE
:
330 case URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER
:
333 // bulk interrupt transfer
335 if (Urb
->UrbBulkOrInterruptTransfer
.TransferBufferLength
)
338 // Check if there is a MDL
340 if (!Urb
->UrbBulkOrInterruptTransfer
.TransferBufferMDL
)
345 PC_ASSERT(Urb
->UrbBulkOrInterruptTransfer
.TransferBuffer
);
348 // Create one using TransferBuffer
350 DPRINT("Creating Mdl from Urb Buffer %p Length %lu\n", Urb
->UrbBulkOrInterruptTransfer
.TransferBuffer
, Urb
->UrbBulkOrInterruptTransfer
.TransferBufferLength
);
351 m_TransferBufferMDL
= IoAllocateMdl(Urb
->UrbBulkOrInterruptTransfer
.TransferBuffer
,
352 Urb
->UrbBulkOrInterruptTransfer
.TransferBufferLength
,
357 if (!m_TransferBufferMDL
)
360 // failed to allocate mdl
362 return STATUS_INSUFFICIENT_RESOURCES
;
366 // build mdl for non paged pool
367 // FIXME: Does hub driver already do this when passing MDL?
369 MmBuildMdlForNonPagedPool(m_TransferBufferMDL
);
372 // Keep that ehci created the MDL and needs to free it.
377 m_TransferBufferMDL
= Urb
->UrbBulkOrInterruptTransfer
.TransferBufferMDL
;
381 // save buffer length
383 m_TransferBufferLength
= Urb
->UrbBulkOrInterruptTransfer
.TransferBufferLength
;
386 // Set Length Completed to 0
388 m_TransferBufferLengthCompleted
= 0;
391 // get endpoint descriptor
393 m_EndpointDescriptor
= (PUSB_ENDPOINT
)Urb
->UrbBulkOrInterruptTransfer
.PipeHandle
;
399 DPRINT1("URB Function: not supported %x\n", Urb
->UrbHeader
.Function
);
406 return STATUS_SUCCESS
;
410 //----------------------------------------------------------------------------------------
412 CUSBRequest::IsRequestComplete()
415 // FIXME: check if request was split
419 // Check if the transfer was completed, only valid for Bulk Transfers
421 if ((m_TransferBufferLengthCompleted
< m_TransferBufferLength
)
422 && (GetTransferType() == USB_ENDPOINT_TYPE_BULK
))
425 // Transfer not completed
431 //----------------------------------------------------------------------------------------
433 CUSBRequest::GetTransferType()
436 // call internal implementation
438 return InternalGetTransferType();
442 CUSBRequest::GetMaxPacketSize()
444 if (!m_EndpointDescriptor
)
453 ASSERT(m_EndpointDescriptor
);
456 // return max packet size
458 return m_EndpointDescriptor
->EndPointDescriptor
.wMaxPacketSize
;
462 CUSBRequest::GetInterval()
464 ASSERT(m_EndpointDescriptor
);
465 ASSERT((m_EndpointDescriptor
->EndPointDescriptor
.bmAttributes
& USB_ENDPOINT_TYPE_MASK
) == USB_ENDPOINT_TYPE_INTERRUPT
);
468 // return interrupt interval
470 return m_EndpointDescriptor
->EndPointDescriptor
.bInterval
;
474 CUSBRequest::GetEndpointAddress()
476 if (!m_EndpointDescriptor
)
485 ASSERT(m_EndpointDescriptor
);
488 // endpoint number is between 1-15
490 return (m_EndpointDescriptor
->EndPointDescriptor
.bEndpointAddress
& 0xF);
493 //----------------------------------------------------------------------------------------
495 CUSBRequest::InternalGetTransferType()
500 // check if an irp is provided
504 ASSERT(m_EndpointDescriptor
);
507 // end point is defined in the low byte of bmAttributes
509 TransferType
= (m_EndpointDescriptor
->EndPointDescriptor
.bmAttributes
& USB_ENDPOINT_TYPE_MASK
);
514 // initialized with setup packet, must be a control transfer
516 TransferType
= USB_ENDPOINT_TYPE_CONTROL
;
526 CUSBRequest::InternalGetPidDirection()
528 if (m_EndpointDescriptor
)
531 // end point direction is highest bit in bEndpointAddress
533 return (m_EndpointDescriptor
->EndPointDescriptor
.bEndpointAddress
& USB_ENDPOINT_DIRECTION_MASK
) >> 7;
538 // request arrives on the control pipe, extract direction from setup packet
540 ASSERT(m_SetupPacket
);
541 return (m_SetupPacket
->bmRequestType
.B
>> 7);
546 //----------------------------------------------------------------------------------------
548 CUSBRequest::GetDeviceAddress()
550 PIO_STACK_LOCATION IoStack
;
552 PUSBDEVICE UsbDevice
;
555 // check if there is an irp provided
560 // used provided address
562 return m_DeviceAddress
;
566 // get current stack location
568 IoStack
= IoGetCurrentIrpStackLocation(m_Irp
);
573 Urb
= (PURB
)IoStack
->Parameters
.Others
.Argument1
;
576 // check if there is a pipe handle provided
578 if (Urb
->UrbHeader
.UsbdDeviceHandle
)
581 // there is a device handle provided
583 UsbDevice
= (PUSBDEVICE
)Urb
->UrbHeader
.UsbdDeviceHandle
;
586 // return device address
588 return UsbDevice
->GetDeviceAddress();
592 // no device handle provided, it is the host root bus
597 //----------------------------------------------------------------------------------------
599 CUSBRequest::GetEndpointDescriptor(
600 struct _UHCI_QUEUE_HEAD
** OutQueueHead
)
602 NTSTATUS Status
= STATUS_UNSUCCESSFUL
;
606 TransferType
= InternalGetTransferType();
608 if (TransferType
== USB_ENDPOINT_TYPE_CONTROL
)
613 Status
= BuildControlTransferDescriptor(OutQueueHead
);
615 else if (TransferType
== USB_ENDPOINT_TYPE_INTERRUPT
|| TransferType
== USB_ENDPOINT_TYPE_BULK
)
620 Status
= BuildBulkInterruptTransferDescriptor(OutQueueHead
);
623 if (!NT_SUCCESS(Status
))
634 (*OutQueueHead
)->Request
= PVOID(this);
639 return STATUS_SUCCESS
;
642 //----------------------------------------------------------------------------------------
644 CUSBRequest::GetResultStatus(
645 OUT OPTIONAL NTSTATUS
* NtStatusCode
,
646 OUT OPTIONAL PULONG UrbStatusCode
)
651 PC_ASSERT(m_CompletionEvent
);
654 // wait for the operation to complete
656 KeWaitForSingleObject(m_CompletionEvent
, Executive
, KernelMode
, FALSE
, NULL
);
663 *NtStatusCode
= m_NtStatusCode
;
671 *UrbStatusCode
= m_UrbStatusCode
;
676 //-----------------------------------------------------------------------------------------
678 CUSBRequest::CreateDescriptor(
679 OUT PUHCI_TRANSFER_DESCRIPTOR
*OutDescriptor
,
683 PUHCI_TRANSFER_DESCRIPTOR Descriptor
;
684 PHYSICAL_ADDRESS Address
;
688 // allocate descriptor
690 Status
= m_DmaManager
->Allocate(sizeof(UHCI_TRANSFER_DESCRIPTOR
), (PVOID
*)&Descriptor
, &Address
);
691 if (!NT_SUCCESS(Status
))
693 DPRINT1("[USBUHCI] Failed to allocate descriptor\n");
700 Descriptor
->PhysicalAddress
= Address
.LowPart
;
701 Descriptor
->Status
= TD_STATUS_ACTIVE
;
703 if (InternalGetTransferType() == USB_ENDPOINT_TYPE_ISOCHRONOUS
)
706 // isochronous transfer descriptor
708 Descriptor
->Status
|= TD_CONTROL_ISOCHRONOUS
;
715 Descriptor
->Status
|= TD_CONTROL_3_ERRORS
;
717 if (PidCode
== TD_TOKEN_IN
&& (InternalGetTransferType() != USB_ENDPOINT_TYPE_CONTROL
))
720 // enable short packet detect for bulk & interrupt
722 Descriptor
->Status
|= TD_CONTROL_SPD
;
727 // is it low speed device
729 if (m_DeviceSpeed
== UsbLowSpeed
)
734 Descriptor
->Status
|= TD_CONTROL_LOWSPEED
;
740 Descriptor
->BufferSize
= BufferLength
;
748 // store buffer length
750 Descriptor
->Token
= (BufferLength
- 1) << TD_TOKEN_MAXLEN_SHIFT
;
755 // no buffer magic constant
757 Descriptor
->Token
= TD_TOKEN_NULL_DATA
;
761 // store address & endpoint number
763 Descriptor
->Token
|= GetEndpointAddress() << TD_TOKEN_ENDPTADDR_SHIFT
;
764 Descriptor
->Token
|= GetDeviceAddress() << TD_TOKEN_DEVADDR_SHIFT
| PidCode
;
769 // allocate buffer for descriptor
771 Status
= m_DmaManager
->Allocate(BufferLength
, (PVOID
*)&Descriptor
->BufferLogical
, &Address
);
772 if (!NT_SUCCESS(Status
))
774 DPRINT1("[USBUHCI] Failed to allocate descriptor buffer length %lu\n", BufferLength
);
775 m_DmaManager
->Release(Descriptor
, sizeof(UHCI_TRANSFER_DESCRIPTOR
));
782 Descriptor
->BufferPhysical
= Address
.LowPart
;
788 *OutDescriptor
= Descriptor
;
789 return STATUS_SUCCESS
;
793 CUSBRequest::BuildTransferDescriptorChain(
794 IN PVOID TransferBuffer
,
795 IN ULONG TransferBufferLength
,
797 IN UCHAR InitialDataToggle
,
798 OUT PUHCI_TRANSFER_DESCRIPTOR
* OutFirstDescriptor
,
799 OUT PUHCI_TRANSFER_DESCRIPTOR
* OutLastDescriptor
,
800 OUT PULONG OutTransferBufferOffset
,
801 OUT PUCHAR OutDataToggle
)
803 PUHCI_TRANSFER_DESCRIPTOR FirstDescriptor
= NULL
, CurrentDescriptor
, LastDescriptor
= NULL
;
804 ULONG TransferBufferOffset
= 0;
806 ULONG MaxPacketSize
, CurrentBufferSize
;
809 // FIXME FIXME FIXME FIXME FIXME
811 if (GetDeviceSpeed() == UsbLowSpeed
)
814 // low speed use max 8 bytes
820 if (m_EndpointDescriptor
)
825 MaxPacketSize
= m_EndpointDescriptor
->EndPointDescriptor
.wMaxPacketSize
;
839 // determine current packet size
841 CurrentBufferSize
= min(MaxPacketSize
, TransferBufferLength
- TransferBufferOffset
);
844 // allocate descriptor
846 Status
= CreateDescriptor(&CurrentDescriptor
, PidCode
, CurrentBufferSize
);
847 if (!NT_SUCCESS(Status
))
850 // failed to allocate queue head
852 DPRINT1("[UHCI] Failed to create descriptor\n");
857 if (PidCode
== TD_TOKEN_OUT
)
862 RtlCopyMemory(CurrentDescriptor
->BufferLogical
, (PVOID
)((ULONG_PTR
)TransferBuffer
+ TransferBufferOffset
), CurrentBufferSize
);
869 CurrentDescriptor
->UserBuffer
= (PVOID
)((ULONG_PTR
)TransferBuffer
+ TransferBufferOffset
);
872 if (!FirstDescriptor
)
877 FirstDescriptor
= CurrentDescriptor
;
884 LastDescriptor
->LinkPhysical
= CurrentDescriptor
->PhysicalAddress
| TD_DEPTH_FIRST
;
885 LastDescriptor
->NextLogicalDescriptor
= (PVOID
)CurrentDescriptor
;
888 if (InitialDataToggle
)
893 CurrentDescriptor
->Token
|= TD_TOKEN_DATA1
;
899 LastDescriptor
= CurrentDescriptor
;
900 TransferBufferOffset
+= CurrentBufferSize
;
901 InitialDataToggle
= !InitialDataToggle
;
903 }while(TransferBufferOffset
< TransferBufferLength
);
905 if (OutTransferBufferOffset
)
908 // store transfer buffer length
910 *OutTransferBufferOffset
= TransferBufferOffset
;
913 if (OutFirstDescriptor
)
916 // store first descriptor
918 *OutFirstDescriptor
= FirstDescriptor
;
921 if (OutLastDescriptor
)
924 // store last descriptor
926 *OutLastDescriptor
= CurrentDescriptor
;
934 *OutDataToggle
= InitialDataToggle
;
940 return STATUS_SUCCESS
;
944 CUSBRequest::BuildQueueHead(
945 OUT PUHCI_QUEUE_HEAD
*OutQueueHead
)
947 PUHCI_QUEUE_HEAD QueueHead
;
949 PHYSICAL_ADDRESS Address
;
952 // allocate queue head
954 Status
= m_DmaManager
->Allocate(sizeof(UHCI_QUEUE_HEAD
), (PVOID
*)&QueueHead
, &Address
);
955 if (!NT_SUCCESS(Status
))
958 // failed to allocate queue head
960 DPRINT1("[UHCI] Failed to create queue head\n");
967 QueueHead
->PhysicalAddress
= Address
.LowPart
;
968 QueueHead
->ElementPhysical
= Address
.LowPart
;
973 *OutQueueHead
= QueueHead
;
974 return STATUS_SUCCESS
;
978 CUSBRequest::FreeDescriptor(
979 IN PUHCI_TRANSFER_DESCRIPTOR Descriptor
)
981 if (Descriptor
->BufferLogical
)
986 m_DmaManager
->Release(Descriptor
->BufferLogical
, Descriptor
->BufferSize
);
992 m_DmaManager
->Release(Descriptor
, sizeof(UHCI_TRANSFER_DESCRIPTOR
));
996 CUSBRequest::BuildBulkInterruptTransferDescriptor(
997 IN PUHCI_QUEUE_HEAD
* OutQueueHead
)
1000 PUHCI_QUEUE_HEAD QueueHead
;
1001 PUHCI_TRANSFER_DESCRIPTOR FirstDescriptor
, LastDescriptor
;
1002 ULONG ChainDescriptorLength
;
1007 // create queue head
1008 Status
= BuildQueueHead(&QueueHead
);
1009 if (!NT_SUCCESS(Status
))
1011 // failed to allocate descriptor
1012 DPRINT1("[UHCI] Failed to create queue head\n");
1017 Direction
= InternalGetPidDirection();
1022 m_Base
= MmGetMdlVirtualAddress(m_TransferBufferMDL
);
1025 ASSERT(m_Base
!= NULL
);
1028 // get new buffer offset
1029 Buffer
= (PVOID
)((ULONG_PTR
)m_Base
+ m_TransferBufferLengthCompleted
);
1031 // FIXME determine buffer limit
1032 BufferSize
= min(m_TransferBufferLength
- m_TransferBufferLengthCompleted
, PAGE_SIZE
);
1034 // create descriptor chain
1035 Status
= BuildTransferDescriptorChain(Buffer
,
1037 Direction
? TD_TOKEN_IN
: TD_TOKEN_OUT
,
1038 m_EndpointDescriptor
->DataToggle
,
1041 &ChainDescriptorLength
,
1044 // adjust buffer offset
1045 m_TransferBufferLengthCompleted
+= ChainDescriptorLength
;
1047 // fire interrupt when the last descriptor is complete
1048 LastDescriptor
->Status
|= TD_CONTROL_IOC
;
1049 LastDescriptor
->LinkPhysical
= TD_TERMINATE
;
1050 LastDescriptor
->NextLogicalDescriptor
= NULL
;
1052 // link queue head with first data descriptor descriptor
1053 QueueHead
->NextElementDescriptor
= (PVOID
)FirstDescriptor
;
1054 QueueHead
->ElementPhysical
= FirstDescriptor
->PhysicalAddress
;
1057 *OutQueueHead
= QueueHead
;
1058 return STATUS_SUCCESS
;
1063 CUSBRequest::BuildControlTransferDescriptor(
1064 IN PUHCI_QUEUE_HEAD
* OutQueueHead
)
1066 PUHCI_TRANSFER_DESCRIPTOR SetupDescriptor
, StatusDescriptor
, FirstDescriptor
, LastDescriptor
;
1067 PUHCI_QUEUE_HEAD QueueHead
;
1070 ULONG ChainDescriptorLength
;
1073 // create queue head
1075 Status
= BuildQueueHead(&QueueHead
);
1076 if (!NT_SUCCESS(Status
))
1079 // failed to allocate descriptor
1081 DPRINT1("[UHCI] Failed to create queue head\n");
1088 Direction
= InternalGetPidDirection();
1091 // build setup descriptor
1093 Status
= CreateDescriptor(&SetupDescriptor
,
1095 sizeof(USB_DEFAULT_PIPE_SETUP_PACKET
));
1096 if (!NT_SUCCESS(Status
))
1099 // failed to allocate descriptor
1101 DPRINT1("[UHCI] Failed to create setup descriptor\n");
1102 m_DmaManager
->Release(QueueHead
, sizeof(UHCI_QUEUE_HEAD
));
1107 // build status descriptor
1109 Status
= CreateDescriptor(&StatusDescriptor
,
1110 Direction
? TD_TOKEN_OUT
: TD_TOKEN_IN
,
1112 if (!NT_SUCCESS(Status
))
1115 // failed to allocate descriptor
1117 DPRINT1("[UHCI] Failed to create status descriptor\n");
1118 FreeDescriptor(SetupDescriptor
);
1119 m_DmaManager
->Release(QueueHead
, sizeof(UHCI_QUEUE_HEAD
));
1126 // copy setup packet
1128 RtlCopyMemory(SetupDescriptor
->BufferLogical
, m_SetupPacket
, sizeof(USB_DEFAULT_PIPE_SETUP_PACKET
));
1133 // generate setup packet from urb
1139 // init status descriptor
1141 StatusDescriptor
->Status
|= TD_CONTROL_IOC
;
1142 StatusDescriptor
->Token
|= TD_TOKEN_DATA1
;
1143 StatusDescriptor
->LinkPhysical
= TD_TERMINATE
;
1144 StatusDescriptor
->NextLogicalDescriptor
= NULL
;
1146 if (m_TransferBufferLength
)
1149 // create descriptor chain
1151 Status
= BuildTransferDescriptorChain(MmGetMdlVirtualAddress(m_TransferBufferMDL
),
1152 m_TransferBufferLength
,
1153 Direction
? TD_TOKEN_IN
: TD_TOKEN_OUT
,
1157 &ChainDescriptorLength
,
1159 if (!NT_SUCCESS(Status
))
1162 // failed to allocate descriptor
1164 DPRINT1("[UHCI] Failed to create descriptor chain\n");
1165 FreeDescriptor(SetupDescriptor
);
1166 FreeDescriptor(StatusDescriptor
);
1167 m_DmaManager
->Release(QueueHead
, sizeof(UHCI_QUEUE_HEAD
));
1172 // link setup descriptor to first data descriptor
1174 SetupDescriptor
->LinkPhysical
= FirstDescriptor
->PhysicalAddress
| TD_DEPTH_FIRST
;
1175 SetupDescriptor
->NextLogicalDescriptor
= (PVOID
)FirstDescriptor
;
1178 // link last data descriptor to status descriptor
1180 LastDescriptor
->LinkPhysical
= StatusDescriptor
->PhysicalAddress
| TD_DEPTH_FIRST
;
1181 LastDescriptor
->NextLogicalDescriptor
= (PVOID
)StatusDescriptor
;
1186 // directly link setup to status descriptor
1188 SetupDescriptor
->LinkPhysical
= StatusDescriptor
->PhysicalAddress
| TD_DEPTH_FIRST
;
1189 SetupDescriptor
->NextLogicalDescriptor
= (PVOID
)StatusDescriptor
;
1193 // link queue head with setup descriptor
1195 QueueHead
->NextElementDescriptor
= (PVOID
)SetupDescriptor
;
1196 QueueHead
->ElementPhysical
= SetupDescriptor
->PhysicalAddress
;
1201 *OutQueueHead
= QueueHead
;
1202 return STATUS_SUCCESS
;
1205 CUSBRequest::GetDeviceSpeed()
1207 return m_DeviceSpeed
;
1211 CUSBRequest::FreeEndpointDescriptor(
1212 struct _UHCI_QUEUE_HEAD
* OutDescriptor
)
1214 PUHCI_TRANSFER_DESCRIPTOR Descriptor
, NextDescriptor
;
1216 UCHAR DataToggle
= 0;
1220 // grab first transfer descriptor
1222 Descriptor
= (PUHCI_TRANSFER_DESCRIPTOR
)OutDescriptor
->NextElementDescriptor
;
1226 DataToggle
= (Descriptor
->Token
>> TD_TOKEN_DATA_TOGGLE_SHIFT
) & 0x01;
1228 if (Descriptor
->Status
& TD_ERROR_MASK
)
1233 DPRINT1("[USBUHCI] Error detected at descriptor %p Physical %x\n", Descriptor
, Descriptor
->PhysicalAddress
);
1238 ErrorCount
= (Descriptor
->Status
>> TD_ERROR_COUNT_SHIFT
) & TD_ERROR_COUNT_MASK
;
1239 if (ErrorCount
== 0)
1242 // error retry count elapsed
1244 m_NtStatusCode
= STATUS_UNSUCCESSFUL
;
1246 if (Descriptor
->Status
& TD_STATUS_ERROR_BUFFER
)
1248 DPRINT1("[USBUHCI] Buffer Error detected in descriptor %p Index %lu\n", Descriptor
, Index
);
1249 m_UrbStatusCode
= USBD_STATUS_DATA_BUFFER_ERROR
;
1251 else if (Descriptor
->Status
& TD_STATUS_ERROR_TIMEOUT
)
1253 DPRINT1("[USBUHCI] Timeout detected in descriptor %p Index %lu\n", Descriptor
, Index
);
1254 m_UrbStatusCode
= USBD_STATUS_TIMEOUT
;
1256 else if (Descriptor
->Status
& TD_STATUS_ERROR_NAK
)
1258 DPRINT1("[USBUHCI] Unexpected pid detected in descriptor %p Index %lu\n", Descriptor
, Index
);
1259 m_UrbStatusCode
= USBD_STATUS_UNEXPECTED_PID
;
1261 else if (Descriptor
->Status
& TD_STATUS_ERROR_BITSTUFF
)
1263 DPRINT1("[USBUHCI] BitStuff detected in descriptor %p Index %lu\n", Descriptor
, Index
);
1264 m_UrbStatusCode
= USBD_STATUS_BTSTUFF
;
1267 else if (Descriptor
->Status
& TD_STATUS_ERROR_BABBLE
)
1272 DPRINT1("[USBUHCI] Babble detected in descriptor %p Index %lu\n", Descriptor
, Index
);
1273 m_UrbStatusCode
= USBD_STATUS_BABBLE_DETECTED
;
1280 DPRINT1("[USBUHCI] Stall detected Descriptor %p Index %lu\n", Descriptor
, Index
);
1281 m_UrbStatusCode
= USBD_STATUS_STALL_PID
;
1287 // FIXME detect actual length
1289 if (Descriptor
->UserBuffer
)
1292 // copy contents back
1294 RtlCopyMemory(Descriptor
->UserBuffer
, Descriptor
->BufferLogical
, Descriptor
->BufferSize
);
1298 // move to next descriptor
1300 NextDescriptor
= (PUHCI_TRANSFER_DESCRIPTOR
)Descriptor
->NextLogicalDescriptor
;
1303 // free endpoint descriptor
1305 FreeDescriptor(Descriptor
);
1310 Descriptor
= NextDescriptor
;
1315 // now free queue head
1317 m_DmaManager
->Release(OutDescriptor
, sizeof(UHCI_QUEUE_HEAD
));
1319 // is there an endpoint descriptor
1320 if (m_EndpointDescriptor
)
1322 // invert last data toggle
1323 m_EndpointDescriptor
->DataToggle
= (DataToggle
== 0);
1328 CUSBRequest::CompletionCallback()
1330 PIO_STACK_LOCATION IoStack
;
1333 DPRINT("CUSBRequest::CompletionCallback\n");
1338 // set irp completion status
1340 m_Irp
->IoStatus
.Status
= m_NtStatusCode
;
1343 // get current irp stack location
1345 IoStack
= IoGetCurrentIrpStackLocation(m_Irp
);
1350 Urb
= (PURB
)IoStack
->Parameters
.Others
.Argument1
;
1355 Urb
->UrbHeader
.Status
= m_UrbStatusCode
;
1358 // Check if the MDL was created
1360 if (!Urb
->UrbBulkOrInterruptTransfer
.TransferBufferMDL
)
1365 IoFreeMdl(m_TransferBufferMDL
);
1369 // FIXME calculate length
1375 IoCompleteRequest(m_Irp
, IO_NO_INCREMENT
);
1380 // signal completion event
1382 PC_ASSERT(m_CompletionEvent
);
1383 KeSetEvent(m_CompletionEvent
, 0, FALSE
);
1389 //-----------------------------------------------------------------------------------------
1392 InternalCreateUSBRequest(
1393 PUSBREQUEST
*OutRequest
)
1398 // allocate requests
1400 This
= new(NonPagedPool
, TAG_USBUHCI
) CUSBRequest(0);
1404 // failed to allocate
1406 return STATUS_INSUFFICIENT_RESOURCES
;
1410 // add reference count
1417 *OutRequest
= (PUSBREQUEST
)This
;
1422 return STATUS_SUCCESS
;