[CMAKE]
[reactos.git] / drivers / usb / usbehci / urbreq.c
1 /*
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.
6 * PROGRAMMERS:
7 * Michael Martin (michael.martin@reactos.org)
8 */
9
10 #include "usbehci.h"
11
12 /* QueueHead must point to the base address in common buffer */
13 PVOID
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,
19 PVOID *CtrlData,
20 ULONG Size)
21 {
22 QueueHead->HorizontalLinkPointer = (ULONG)QueueHead | QH_TYPE_QH;
23
24 /* Set NakCountReload to max value possible */
25 QueueHead->EndPointCapabilities1.NakCountReload = 0xF;
26
27 /* 1 for non high speed, 0 for high speed device */
28 QueueHead->EndPointCapabilities1.ControlEndPointFlag = 0;
29
30 QueueHead->EndPointCapabilities1.HeadOfReclamation = TRUE;
31 QueueHead->EndPointCapabilities1.MaximumPacketLength = 64;
32
33 /* Get the Initial Data Toggle from the QEDT */
34 QueueHead->EndPointCapabilities1.QEDTDataToggleControl = TRUE;
35
36 /* HIGH SPEED DEVICE */
37 QueueHead->EndPointCapabilities1.EndPointSpeed = QH_ENDPOINT_HIGHSPEED;
38 QueueHead->EndPointCapabilities1.EndPointNumber = 0;
39
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;
43
44 QueueHead->EndPointCapabilities1.DeviceAddress = 0;
45 QueueHead->EndPointCapabilities2.HubAddr = 0;
46 QueueHead->EndPointCapabilities2.NumberOfTransactionPerFrame = 0x01;
47
48 /* 0 For Async, 1 for periodoc schedule */
49 QueueHead->EndPointCapabilities2.InterruptScheduleMask = 0;
50
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 */
63
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);
68
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);
72
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;
82
83 (*CtrlTD2)->NextPointer = TERMINATE_POINTER;
84 (*CtrlTD2)->AlternateNextPointer = TERMINATE_POINTER;
85 if (Size == 0)
86 (*CtrlTD2)->BufferPointer[0] = 0;
87 else
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;
95
96 (*CtrlTD1)->NextPointer = (ULONG)MmGetPhysicalAddress((PVOID)(*CtrlTD2)).LowPart;
97
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;
108 return NULL;
109 }
110
111 BOOLEAN
112 ExecuteControlRequest(PFDO_DEVICE_EXTENSION DeviceExtension, PUSB_DEFAULT_PIPE_SETUP_PACKET SetupPacket, UCHAR Address, ULONG Port, PVOID Buffer, ULONG BufferLength)
113 {
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;
119
120 PQUEUE_HEAD QueueHead;
121 PEHCI_USBCMD_CONTENT UsbCmd;
122 PEHCI_USBSTS_CONTEXT UsbSts;
123 LONG Base;
124 LONG tmp;
125
126 DPRINT1("ExecuteControlRequest: Buffer %x, Length %x\n", Buffer, BufferLength);
127
128 ExAcquireFastMutex(&DeviceExtension->AsyncListMutex);
129
130 Base = (ULONG) DeviceExtension->ResourceMemory;
131
132 /* Set up the QUEUE HEAD in memory */
133 QueueHead = (PQUEUE_HEAD) ((ULONG)DeviceExtension->AsyncListQueueHeadPtr);
134
135 /* Initialize the memory pointers */
136 IntializeHeadQueueForStandardRequest(QueueHead,
137 &CtrlTD1,
138 &CtrlTD2,
139 &CtrlTD3,
140 &CtrlSetup,
141 (PVOID)&CtrlData,
142 BufferLength);
143
144 QueueHead->EndPointCapabilities2.PortNumber = Port;
145 QueueHead->EndPointCapabilities1.DeviceAddress = Address;
146
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;
155
156 tmp = READ_REGISTER_ULONG((PULONG) (Base + EHCI_USBCMD));
157 UsbCmd = (PEHCI_USBCMD_CONTENT) &tmp;
158 UsbCmd->Run = FALSE;
159 WRITE_REGISTER_ULONG((PULONG) (Base + EHCI_USBCMD), tmp);
160
161 /* Wait for the controller to halt */
162 for (;;)
163 {
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)
169 {
170 break;
171 }
172 }
173
174 /* Set to TRUE on interrupt for async completion */
175 DeviceExtension->AsyncComplete = FALSE;
176 QueueHead->QETDPointer = (ULONG) MmGetPhysicalAddress((PVOID)(CtrlTD1)).LowPart;
177
178 tmp = READ_REGISTER_ULONG((PULONG) (Base + EHCI_USBCMD));
179 UsbCmd = (PEHCI_USBCMD_CONTENT) &tmp;
180 UsbCmd->AsyncEnable = TRUE;
181
182 WRITE_REGISTER_ULONG((PULONG)(Base + EHCI_USBCMD), tmp);
183
184 tmp = READ_REGISTER_ULONG((PULONG) (Base + EHCI_USBCMD));
185 UsbCmd = (PEHCI_USBCMD_CONTENT) &tmp;
186
187 /* Interrupt on Async completion */
188 UsbCmd->DoorBell = TRUE;
189 UsbCmd->Run = TRUE;
190 WRITE_REGISTER_ULONG((PULONG)(Base + EHCI_USBCMD), tmp);
191
192 for (;;)
193 {
194 KeStallExecutionProcessor(100);
195 DPRINT("Waiting for completion!\n");
196 if (DeviceExtension->AsyncComplete == TRUE)
197 break;
198 }
199
200 UsbCmd->Run = FALSE;
201 WRITE_REGISTER_ULONG((PULONG)(Base + EHCI_USBCMD), tmp);
202
203 if (SetupPacket->bmRequestType._BM.Dir == BMREQUEST_DEVICE_TO_HOST)
204 {
205 if ((Buffer) && (BufferLength))
206 {
207 RtlCopyMemory(Buffer, CtrlData, BufferLength);
208 }
209 else
210 DPRINT1("Unable to copy data to buffer\n");
211 }
212
213 ExReleaseFastMutex(&DeviceExtension->AsyncListMutex);
214
215 return TRUE;
216 }