2 * PROJECT: ReactOS Universal Serial Bus Bulk Enhanced Host Controller Interface
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: drivers/usb/usbehci/urbreq.c
5 * PURPOSE: URB Related Functions.
7 * Michael Martin (michael.martin@reactos.org)
12 /* QueueHead must point to the base address in common buffer */
14 IntializeHeadQueueForStandardRequest(PQUEUE_HEAD QueueHead
,
15 PQUEUE_TRANSFER_DESCRIPTOR
*CtrlTD1
,
16 PQUEUE_TRANSFER_DESCRIPTOR
*CtrlTD2
,
17 PQUEUE_TRANSFER_DESCRIPTOR
*CtrlTD3
,
18 PUSB_DEFAULT_PIPE_SETUP_PACKET
*CtrlSetup
,
22 QueueHead
->HorizontalLinkPointer
= (ULONG
)QueueHead
| QH_TYPE_QH
;
24 /* Set NakCountReload to max value possible */
25 QueueHead
->EndPointCapabilities1
.NakCountReload
= 0xF;
27 /* 1 for non high speed, 0 for high speed device */
28 QueueHead
->EndPointCapabilities1
.ControlEndPointFlag
= 0;
30 QueueHead
->EndPointCapabilities1
.HeadOfReclamation
= TRUE
;
31 QueueHead
->EndPointCapabilities1
.MaximumPacketLength
= 64;
33 /* Get the Initial Data Toggle from the QEDT */
34 QueueHead
->EndPointCapabilities1
.QEDTDataToggleControl
= TRUE
;
36 /* HIGH SPEED DEVICE */
37 QueueHead
->EndPointCapabilities1
.EndPointSpeed
= QH_ENDPOINT_HIGHSPEED
;
38 QueueHead
->EndPointCapabilities1
.EndPointNumber
= 0;
40 /* Only used for Periodic Schedule and Not High Speed devices.
41 Setting it to one result in undefined behavior for Async */
42 QueueHead
->EndPointCapabilities1
.InactiveOnNextTransaction
= 0;
44 QueueHead
->EndPointCapabilities1
.DeviceAddress
= 0;
45 QueueHead
->EndPointCapabilities2
.HubAddr
= 0;
46 QueueHead
->EndPointCapabilities2
.NumberOfTransactionPerFrame
= 0x01;
48 /* 0 For Async, 1 for periodoc schedule */
49 QueueHead
->EndPointCapabilities2
.InterruptScheduleMask
= 0;
51 QueueHead
->EndPointCapabilities2
.PortNumber
= 0;
52 QueueHead
->EndPointCapabilities2
.SplitCompletionMask
= 0;
53 QueueHead
->CurrentLinkPointer
= 0;
54 QueueHead
->QETDPointer
= TERMINATE_POINTER
;
55 QueueHead
->AlternateNextPointer
= TERMINATE_POINTER
;
56 QueueHead
->Token
.Bits
.InterruptOnComplete
= TRUE
;
57 QueueHead
->BufferPointer
[0] = 0;
58 QueueHead
->BufferPointer
[1] = 0;
59 QueueHead
->BufferPointer
[2] = 0;
60 QueueHead
->BufferPointer
[3] = 0;
61 QueueHead
->BufferPointer
[4] = 0;
62 /* Queue Head Initialized */
64 /* Queue Transfer Descriptors must be 32 byte aligned and reside in continous physical memory */
65 *CtrlTD1
= (PQUEUE_TRANSFER_DESCRIPTOR
) (((ULONG
)(QueueHead
) + sizeof(QUEUE_HEAD
) + 0x1F) & ~0x1F);
66 *CtrlTD2
= (PQUEUE_TRANSFER_DESCRIPTOR
) (((ULONG
)(*CtrlTD1
) + sizeof(QUEUE_TRANSFER_DESCRIPTOR
) + 0x1F) & ~0x1F);
67 *CtrlTD3
= (PQUEUE_TRANSFER_DESCRIPTOR
) (((ULONG
)(*CtrlTD2
) + sizeof(QUEUE_TRANSFER_DESCRIPTOR
) + 0x1F) & ~0x1F);
69 /* Must be Page aligned */
70 *CtrlSetup
= (PUSB_DEFAULT_PIPE_SETUP_PACKET
) (( (ULONG
)(*CtrlTD3
) + sizeof(QUEUE_TRANSFER_DESCRIPTOR
) + 0xFFF) & ~0xFFF);
71 *CtrlData
= (PVOID
) (( (ULONG
)(*CtrlSetup
) + sizeof(USB_DEFAULT_PIPE_SETUP_PACKET
) + 0xFFF) & ~0xFFF);
73 (*CtrlTD1
)->NextPointer
= TERMINATE_POINTER
;
74 (*CtrlTD1
)->AlternateNextPointer
= TERMINATE_POINTER
;
75 (*CtrlTD1
)->BufferPointer
[0] = (ULONG
)MmGetPhysicalAddress((PVOID
) (*CtrlSetup
)).LowPart
;
76 (*CtrlTD1
)->Token
.Bits
.DataToggle
= FALSE
;
77 (*CtrlTD1
)->Token
.Bits
.InterruptOnComplete
= FALSE
;
78 (*CtrlTD1
)->Token
.Bits
.TotalBytesToTransfer
= sizeof(USB_DEFAULT_PIPE_SETUP_PACKET
);
79 (*CtrlTD1
)->Token
.Bits
.ErrorCounter
= 0x03;
80 (*CtrlTD1
)->Token
.Bits
.PIDCode
= PID_CODE_SETUP_TOKEN
;
81 (*CtrlTD1
)->Token
.Bits
.Active
= TRUE
;
83 (*CtrlTD2
)->NextPointer
= TERMINATE_POINTER
;
84 (*CtrlTD2
)->AlternateNextPointer
= TERMINATE_POINTER
;
86 (*CtrlTD2
)->BufferPointer
[0] = 0;
88 (*CtrlTD2
)->BufferPointer
[0] = (ULONG
)MmGetPhysicalAddress((PVOID
) (*CtrlData
)).LowPart
;
89 (*CtrlTD2
)->Token
.Bits
.DataToggle
= TRUE
;
90 (*CtrlTD2
)->Token
.Bits
.InterruptOnComplete
= TRUE
;
91 (*CtrlTD2
)->Token
.Bits
.TotalBytesToTransfer
= Size
;
92 (*CtrlTD2
)->Token
.Bits
.ErrorCounter
= 0x03;
93 (*CtrlTD2
)->Token
.Bits
.PIDCode
= PID_CODE_IN_TOKEN
;
94 (*CtrlTD2
)->Token
.Bits
.Active
= TRUE
;
96 (*CtrlTD1
)->NextPointer
= (ULONG
)MmGetPhysicalAddress((PVOID
)(*CtrlTD2
)).LowPart
;
98 (*CtrlTD3
)->NextPointer
= TERMINATE_POINTER
;
99 (*CtrlTD3
)->AlternateNextPointer
= TERMINATE_POINTER
;
100 (*CtrlTD3
)->BufferPointer
[0] = 0;
101 (*CtrlTD3
)->Token
.Bits
.Active
= TRUE
;
102 (*CtrlTD3
)->Token
.Bits
.PIDCode
= PID_CODE_OUT_TOKEN
;
103 (*CtrlTD3
)->Token
.Bits
.InterruptOnComplete
= TRUE
;
104 (*CtrlTD3
)->Token
.Bits
.TotalBytesToTransfer
= 0;
105 (*CtrlTD3
)->Token
.Bits
.DataToggle
= TRUE
;
106 (*CtrlTD3
)->Token
.Bits
.ErrorCounter
= 0x03;
107 (*CtrlTD2
)->NextPointer
= (ULONG
) MmGetPhysicalAddress((PVOID
)(*CtrlTD3
)).LowPart
;
112 ExecuteControlRequest(PFDO_DEVICE_EXTENSION DeviceExtension
, PUSB_DEFAULT_PIPE_SETUP_PACKET SetupPacket
, UCHAR Address
, ULONG Port
, PVOID Buffer
, ULONG BufferLength
)
114 PUSB_DEFAULT_PIPE_SETUP_PACKET CtrlSetup
= NULL
;
115 PVOID CtrlData
= NULL
;
116 PQUEUE_TRANSFER_DESCRIPTOR CtrlTD1
= NULL
;
117 PQUEUE_TRANSFER_DESCRIPTOR CtrlTD2
= NULL
;
118 PQUEUE_TRANSFER_DESCRIPTOR CtrlTD3
= NULL
;
120 PQUEUE_HEAD QueueHead
;
121 PEHCI_USBCMD_CONTENT UsbCmd
;
122 PEHCI_USBSTS_CONTEXT UsbSts
;
126 DPRINT1("ExecuteControlRequest: Buffer %x, Length %x\n", Buffer
, BufferLength
);
128 ExAcquireFastMutex(&DeviceExtension
->AsyncListMutex
);
130 Base
= (ULONG
) DeviceExtension
->ResourceMemory
;
132 /* Set up the QUEUE HEAD in memory */
133 QueueHead
= (PQUEUE_HEAD
) ((ULONG
)DeviceExtension
->AsyncListQueueHeadPtr
);
135 /* Initialize the memory pointers */
136 IntializeHeadQueueForStandardRequest(QueueHead
,
144 QueueHead
->EndPointCapabilities2
.PortNumber
= Port
;
145 QueueHead
->EndPointCapabilities1
.DeviceAddress
= Address
;
147 CtrlSetup
->bmRequestType
._BM
.Recipient
= SetupPacket
->bmRequestType
._BM
.Recipient
;
148 CtrlSetup
->bmRequestType
._BM
.Type
= SetupPacket
->bmRequestType
._BM
.Type
;
149 CtrlSetup
->bmRequestType
._BM
.Dir
= SetupPacket
->bmRequestType
._BM
.Dir
;
150 CtrlSetup
->bRequest
= SetupPacket
->bRequest
;
151 CtrlSetup
->wValue
.LowByte
= SetupPacket
->wValue
.LowByte
;
152 CtrlSetup
->wValue
.HiByte
= SetupPacket
->wValue
.HiByte
;
153 CtrlSetup
->wIndex
.W
= SetupPacket
->wIndex
.W
;
154 CtrlSetup
->wLength
= SetupPacket
->wLength
;
156 tmp
= READ_REGISTER_ULONG((PULONG
) (Base
+ EHCI_USBCMD
));
157 UsbCmd
= (PEHCI_USBCMD_CONTENT
) &tmp
;
159 WRITE_REGISTER_ULONG((PULONG
) (Base
+ EHCI_USBCMD
), tmp
);
161 /* Wait for the controller to halt */
164 KeStallExecutionProcessor(10);
165 tmp
= READ_REGISTER_ULONG((PULONG
)(Base
+ EHCI_USBSTS
));
166 UsbSts
= (PEHCI_USBSTS_CONTEXT
)&tmp
;
167 DPRINT("Waiting for Halt, USBSTS: %x\n", READ_REGISTER_ULONG ((PULONG
)(Base
+ EHCI_USBSTS
)));
168 if (UsbSts
->HCHalted
)
174 /* Set to TRUE on interrupt for async completion */
175 DeviceExtension
->AsyncComplete
= FALSE
;
176 QueueHead
->QETDPointer
= (ULONG
) MmGetPhysicalAddress((PVOID
)(CtrlTD1
)).LowPart
;
178 tmp
= READ_REGISTER_ULONG((PULONG
) (Base
+ EHCI_USBCMD
));
179 UsbCmd
= (PEHCI_USBCMD_CONTENT
) &tmp
;
180 UsbCmd
->AsyncEnable
= TRUE
;
182 WRITE_REGISTER_ULONG((PULONG
)(Base
+ EHCI_USBCMD
), tmp
);
184 tmp
= READ_REGISTER_ULONG((PULONG
) (Base
+ EHCI_USBCMD
));
185 UsbCmd
= (PEHCI_USBCMD_CONTENT
) &tmp
;
187 /* Interrupt on Async completion */
188 UsbCmd
->DoorBell
= TRUE
;
190 WRITE_REGISTER_ULONG((PULONG
)(Base
+ EHCI_USBCMD
), tmp
);
194 KeStallExecutionProcessor(100);
195 DPRINT("Waiting for completion!\n");
196 if (DeviceExtension
->AsyncComplete
== TRUE
)
201 WRITE_REGISTER_ULONG((PULONG
)(Base
+ EHCI_USBCMD
), tmp
);
203 if (SetupPacket
->bmRequestType
._BM
.Dir
== BMREQUEST_DEVICE_TO_HOST
)
205 if ((Buffer
) && (BufferLength
))
207 RtlCopyMemory(Buffer
, CtrlData
, BufferLength
);
210 DPRINT1("Unable to copy data to buffer\n");
213 ExReleaseFastMutex(&DeviceExtension
->AsyncListMutex
);