]>
Commit | Line | Data |
---|---|---|
913cb9dc | 1 | /** @file\r |
2 | \r | |
78c2ffb5 | 3 | This file contains URB request, each request is warpped in a\r |
4 | URB (Usb Request Block).\r | |
5 | \r | |
cd5ebaa0 | 6 | Copyright (c) 2007 - 2010, Intel Corporation. All rights reserved.<BR>\r |
e33d3e7f | 7 | Copyright (c) Microsoft Corporation.<BR>\r |
9d510e61 | 8 | SPDX-License-Identifier: BSD-2-Clause-Patent\r |
913cb9dc | 9 | \r |
913cb9dc | 10 | **/\r |
11 | \r | |
12 | #include "Ehci.h"\r | |
13 | \r | |
913cb9dc | 14 | /**\r |
78c2ffb5 | 15 | Create a single QTD to hold the data.\r |
913cb9dc | 16 | \r |
78c2ffb5 | 17 | @param Ehc The EHCI device.\r |
739802e4 | 18 | @param Data The cpu memory address of current data not associated with a QTD.\r |
19 | @param DataPhy The pci bus address of current data not associated with a QTD.\r | |
78c2ffb5 | 20 | @param DataLen The length of the data.\r |
21 | @param PktId Packet ID to use in the QTD.\r | |
22 | @param Toggle Data toggle to use in the QTD.\r | |
23 | @param MaxPacket Maximu packet length of the endpoint.\r | |
913cb9dc | 24 | \r |
78c2ffb5 | 25 | @return Created QTD or NULL if failed to create one.\r |
913cb9dc | 26 | \r |
27 | **/\r | |
28 | EHC_QTD *\r | |
29 | EhcCreateQtd (\r | |
1436aea4 MK |
30 | IN USB2_HC_DEV *Ehc,\r |
31 | IN UINT8 *Data,\r | |
32 | IN UINT8 *DataPhy,\r | |
33 | IN UINTN DataLen,\r | |
34 | IN UINT8 PktId,\r | |
35 | IN UINT8 Toggle,\r | |
36 | IN UINTN MaxPacket\r | |
913cb9dc | 37 | )\r |
38 | {\r | |
1436aea4 MK |
39 | EHC_QTD *Qtd;\r |
40 | QTD_HW *QtdHw;\r | |
41 | UINTN Index;\r | |
42 | UINTN Len;\r | |
43 | UINTN ThisBufLen;\r | |
913cb9dc | 44 | \r |
45 | ASSERT (Ehc != NULL);\r | |
46 | \r | |
47 | Qtd = UsbHcAllocateMem (Ehc->MemPool, sizeof (EHC_QTD));\r | |
48 | \r | |
49 | if (Qtd == NULL) {\r | |
50 | return NULL;\r | |
51 | }\r | |
52 | \r | |
1436aea4 MK |
53 | Qtd->Signature = EHC_QTD_SIG;\r |
54 | Qtd->Data = Data;\r | |
55 | Qtd->DataLen = 0;\r | |
913cb9dc | 56 | \r |
57 | InitializeListHead (&Qtd->QtdList);\r | |
58 | \r | |
59 | QtdHw = &Qtd->QtdHw;\r | |
60 | QtdHw->NextQtd = QTD_LINK (NULL, TRUE);\r | |
61 | QtdHw->AltNext = QTD_LINK (NULL, TRUE);\r | |
62 | QtdHw->Status = QTD_STAT_ACTIVE;\r | |
63 | QtdHw->Pid = PktId;\r | |
64 | QtdHw->ErrCnt = QTD_MAX_ERR;\r | |
1ccdbf2a | 65 | QtdHw->Ioc = 0;\r |
913cb9dc | 66 | QtdHw->TotalBytes = 0;\r |
67 | QtdHw->DataToggle = Toggle;\r | |
68 | \r | |
69 | //\r | |
70 | // Fill in the buffer points\r | |
71 | //\r | |
72 | if (Data != NULL) {\r | |
73 | Len = 0;\r | |
74 | \r | |
75 | for (Index = 0; Index <= QTD_MAX_BUFFER; Index++) {\r | |
76 | //\r | |
77 | // Set the buffer point (Check page 41 EHCI Spec 1.0). No need to\r | |
78 | // compute the offset and clear Reserved fields. This is already\r | |
79 | // done in the data point.\r | |
80 | //\r | |
1436aea4 MK |
81 | QtdHw->Page[Index] = EHC_LOW_32BIT (DataPhy);\r |
82 | QtdHw->PageHigh[Index] = EHC_HIGH_32BIT (DataPhy);\r | |
913cb9dc | 83 | \r |
1436aea4 | 84 | ThisBufLen = QTD_BUF_LEN - (EHC_LOW_32BIT (DataPhy) & QTD_BUF_MASK);\r |
913cb9dc | 85 | \r |
86 | if (Len + ThisBufLen >= DataLen) {\r | |
87 | Len = DataLen;\r | |
88 | break;\r | |
89 | }\r | |
90 | \r | |
1436aea4 MK |
91 | Len += ThisBufLen;\r |
92 | Data += ThisBufLen;\r | |
739802e4 | 93 | DataPhy += ThisBufLen;\r |
913cb9dc | 94 | }\r |
95 | \r | |
96 | //\r | |
97 | // Need to fix the last pointer if the Qtd can't hold all the\r | |
98 | // user's data to make sure that the length is in the unit of\r | |
99 | // max packets. If it can hold all the data, there is no such\r | |
100 | // need.\r | |
101 | //\r | |
102 | if (Len < DataLen) {\r | |
103 | Len = Len - Len % MaxPacket;\r | |
104 | }\r | |
105 | \r | |
1436aea4 | 106 | QtdHw->TotalBytes = (UINT32)Len;\r |
913cb9dc | 107 | Qtd->DataLen = Len;\r |
108 | }\r | |
109 | \r | |
110 | return Qtd;\r | |
111 | }\r | |
112 | \r | |
913cb9dc | 113 | /**\r |
114 | Initialize the queue head for interrupt transfer,\r | |
115 | that is, initialize the following three fields:\r | |
116 | 1. SplitXState in the Status field\r | |
117 | 2. Microframe S-mask\r | |
118 | 3. Microframe C-mask\r | |
119 | \r | |
78c2ffb5 | 120 | @param Ep The queue head's related endpoint.\r |
121 | @param QhHw The queue head to initialize.\r | |
913cb9dc | 122 | \r |
913cb9dc | 123 | **/\r |
913cb9dc | 124 | VOID\r |
125 | EhcInitIntQh (\r | |
1436aea4 MK |
126 | IN USB_ENDPOINT *Ep,\r |
127 | IN QH_HW *QhHw\r | |
913cb9dc | 128 | )\r |
129 | {\r | |
130 | //\r | |
131 | // Because UEFI interface can't utilitize an endpoint with\r | |
132 | // poll rate faster than 1ms, only need to set one bit in\r | |
133 | // the queue head. simple. But it may be changed later. If\r | |
134 | // sub-1ms interrupt is supported, need to update the S-Mask\r | |
135 | // here\r | |
136 | //\r | |
137 | if (Ep->DevSpeed == EFI_USB_SPEED_HIGH) {\r | |
138 | QhHw->SMask = QH_MICROFRAME_0;\r | |
1436aea4 | 139 | return;\r |
913cb9dc | 140 | }\r |
141 | \r | |
142 | //\r | |
143 | // For low/full speed device, the transfer must go through\r | |
144 | // the split transaction. Need to update three fields\r | |
145 | // 1. SplitXState in the status\r | |
146 | // 2. Microframe S-Mask\r | |
147 | // 3. Microframe C-Mask\r | |
148 | // UEFI USB doesn't exercise admission control. It simplely\r | |
149 | // schedule the high speed transactions in microframe 0, and\r | |
150 | // full/low speed transactions at microframe 1. This also\r | |
151 | // avoid the use of FSTN.\r | |
152 | //\r | |
153 | QhHw->SMask = QH_MICROFRAME_1;\r | |
154 | QhHw->CMask = QH_MICROFRAME_3 | QH_MICROFRAME_4 | QH_MICROFRAME_5;\r | |
155 | }\r | |
156 | \r | |
913cb9dc | 157 | /**\r |
78c2ffb5 | 158 | Allocate and initialize a EHCI queue head.\r |
913cb9dc | 159 | \r |
78c2ffb5 | 160 | @param Ehci The EHCI device.\r |
161 | @param Ep The endpoint to create queue head for.\r | |
913cb9dc | 162 | \r |
78c2ffb5 | 163 | @return Created queue head or NULL if failed to create one.\r |
913cb9dc | 164 | \r |
165 | **/\r | |
166 | EHC_QH *\r | |
167 | EhcCreateQh (\r | |
1436aea4 MK |
168 | IN USB2_HC_DEV *Ehci,\r |
169 | IN USB_ENDPOINT *Ep\r | |
913cb9dc | 170 | )\r |
171 | {\r | |
1436aea4 MK |
172 | EHC_QH *Qh;\r |
173 | QH_HW *QhHw;\r | |
913cb9dc | 174 | \r |
175 | Qh = UsbHcAllocateMem (Ehci->MemPool, sizeof (EHC_QH));\r | |
176 | \r | |
177 | if (Qh == NULL) {\r | |
178 | return NULL;\r | |
179 | }\r | |
180 | \r | |
1436aea4 MK |
181 | Qh->Signature = EHC_QH_SIG;\r |
182 | Qh->NextQh = NULL;\r | |
183 | Qh->Interval = Ep->PollRate;\r | |
913cb9dc | 184 | \r |
185 | InitializeListHead (&Qh->Qtds);\r | |
186 | \r | |
1436aea4 MK |
187 | QhHw = &Qh->QhHw;\r |
188 | QhHw->HorizonLink = QH_LINK (NULL, 0, TRUE);\r | |
189 | QhHw->DeviceAddr = Ep->DevAddr;\r | |
190 | QhHw->Inactive = 0;\r | |
191 | QhHw->EpNum = Ep->EpAddr;\r | |
192 | QhHw->EpSpeed = Ep->DevSpeed;\r | |
193 | QhHw->DtCtrl = 0;\r | |
194 | QhHw->ReclaimHead = 0;\r | |
195 | QhHw->MaxPacketLen = (UINT32)Ep->MaxPacket;\r | |
196 | QhHw->CtrlEp = 0;\r | |
197 | QhHw->NakReload = QH_NAK_RELOAD;\r | |
198 | QhHw->HubAddr = Ep->HubAddr;\r | |
199 | QhHw->PortNum = Ep->HubPort;\r | |
200 | QhHw->Multiplier = 1;\r | |
201 | QhHw->DataToggle = Ep->Toggle;\r | |
913cb9dc | 202 | \r |
203 | if (Ep->DevSpeed != EFI_USB_SPEED_HIGH) {\r | |
204 | QhHw->Status |= QTD_STAT_DO_SS;\r | |
205 | }\r | |
206 | \r | |
207 | switch (Ep->Type) {\r | |
1436aea4 MK |
208 | case EHC_CTRL_TRANSFER:\r |
209 | //\r | |
210 | // Special initialization for the control transfer:\r | |
211 | // 1. Control transfer initialize data toggle from each QTD\r | |
212 | // 2. Set the Control Endpoint Flag (C) for low/full speed endpoint.\r | |
213 | //\r | |
214 | QhHw->DtCtrl = 1;\r | |
913cb9dc | 215 | \r |
1436aea4 MK |
216 | if (Ep->DevSpeed != EFI_USB_SPEED_HIGH) {\r |
217 | QhHw->CtrlEp = 1;\r | |
218 | }\r | |
913cb9dc | 219 | \r |
1436aea4 | 220 | break;\r |
913cb9dc | 221 | \r |
1436aea4 MK |
222 | case EHC_INT_TRANSFER_ASYNC:\r |
223 | case EHC_INT_TRANSFER_SYNC:\r | |
224 | //\r | |
225 | // Special initialization for the interrupt transfer\r | |
226 | // to set the S-Mask and C-Mask\r | |
227 | //\r | |
228 | QhHw->NakReload = 0;\r | |
229 | EhcInitIntQh (Ep, QhHw);\r | |
230 | break;\r | |
231 | \r | |
232 | case EHC_BULK_TRANSFER:\r | |
233 | if ((Ep->DevSpeed == EFI_USB_SPEED_HIGH) && (Ep->Direction == EfiUsbDataOut)) {\r | |
234 | QhHw->Status |= QTD_STAT_DO_PING;\r | |
235 | }\r | |
913cb9dc | 236 | \r |
1436aea4 | 237 | break;\r |
913cb9dc | 238 | }\r |
239 | \r | |
240 | return Qh;\r | |
241 | }\r | |
242 | \r | |
913cb9dc | 243 | /**\r |
244 | Convert the poll interval from application to that\r | |
245 | be used by EHCI interface data structure. Only need\r | |
246 | to get the max 2^n that is less than interval. UEFI\r | |
247 | can't support high speed endpoint with a interval less\r | |
248 | than 8 microframe because interval is specified in\r | |
78c2ffb5 | 249 | the unit of ms (millisecond).\r |
913cb9dc | 250 | \r |
78c2ffb5 | 251 | @param Interval The interval to convert.\r |
913cb9dc | 252 | \r |
78c2ffb5 | 253 | @return The converted interval.\r |
913cb9dc | 254 | \r |
255 | **/\r | |
913cb9dc | 256 | UINTN\r |
257 | EhcConvertPollRate (\r | |
1436aea4 | 258 | IN UINTN Interval\r |
913cb9dc | 259 | )\r |
260 | {\r | |
1436aea4 | 261 | UINTN BitCount;\r |
913cb9dc | 262 | \r |
263 | if (Interval == 0) {\r | |
264 | return 1;\r | |
265 | }\r | |
266 | \r | |
267 | //\r | |
268 | // Find the index (1 based) of the highest non-zero bit\r | |
269 | //\r | |
270 | BitCount = 0;\r | |
271 | \r | |
272 | while (Interval != 0) {\r | |
273 | Interval >>= 1;\r | |
274 | BitCount++;\r | |
275 | }\r | |
276 | \r | |
db01f13e | 277 | return (UINTN)1 << (BitCount - 1);\r |
913cb9dc | 278 | }\r |
279 | \r | |
913cb9dc | 280 | /**\r |
78c2ffb5 | 281 | Free a list of QTDs.\r |
913cb9dc | 282 | \r |
78c2ffb5 | 283 | @param Ehc The EHCI device.\r |
284 | @param Qtds The list head of the QTD.\r | |
913cb9dc | 285 | \r |
913cb9dc | 286 | **/\r |
913cb9dc | 287 | VOID\r |
288 | EhcFreeQtds (\r | |
1436aea4 MK |
289 | IN USB2_HC_DEV *Ehc,\r |
290 | IN LIST_ENTRY *Qtds\r | |
913cb9dc | 291 | )\r |
292 | {\r | |
1436aea4 MK |
293 | LIST_ENTRY *Entry;\r |
294 | LIST_ENTRY *Next;\r | |
295 | EHC_QTD *Qtd;\r | |
913cb9dc | 296 | \r |
e33d3e7f | 297 | BASE_LIST_FOR_EACH_SAFE (Entry, Next, Qtds) {\r |
913cb9dc | 298 | Qtd = EFI_LIST_CONTAINER (Entry, EHC_QTD, QtdList);\r |
299 | \r | |
300 | RemoveEntryList (&Qtd->QtdList);\r | |
301 | UsbHcFreeMem (Ehc->MemPool, Qtd, sizeof (EHC_QTD));\r | |
302 | }\r | |
303 | }\r | |
304 | \r | |
913cb9dc | 305 | /**\r |
306 | Free an allocated URB. It is possible for it to be partially inited.\r | |
307 | \r | |
78c2ffb5 | 308 | @param Ehc The EHCI device.\r |
309 | @param Urb The URB to free.\r | |
913cb9dc | 310 | \r |
913cb9dc | 311 | **/\r |
312 | VOID\r | |
313 | EhcFreeUrb (\r | |
1436aea4 MK |
314 | IN USB2_HC_DEV *Ehc,\r |
315 | IN URB *Urb\r | |
913cb9dc | 316 | )\r |
317 | {\r | |
1436aea4 | 318 | EFI_PCI_IO_PROTOCOL *PciIo;\r |
913cb9dc | 319 | \r |
320 | PciIo = Ehc->PciIo;\r | |
321 | \r | |
322 | if (Urb->RequestPhy != NULL) {\r | |
323 | PciIo->Unmap (PciIo, Urb->RequestMap);\r | |
324 | }\r | |
325 | \r | |
326 | if (Urb->DataMap != NULL) {\r | |
327 | PciIo->Unmap (PciIo, Urb->DataMap);\r | |
328 | }\r | |
329 | \r | |
330 | if (Urb->Qh != NULL) {\r | |
331 | //\r | |
332 | // Ensure that this queue head has been unlinked from the\r | |
333 | // schedule data structures. Free all the associated QTDs\r | |
334 | //\r | |
335 | EhcFreeQtds (Ehc, &Urb->Qh->Qtds);\r | |
336 | UsbHcFreeMem (Ehc->MemPool, Urb->Qh, sizeof (EHC_QH));\r | |
337 | }\r | |
338 | \r | |
339 | gBS->FreePool (Urb);\r | |
340 | }\r | |
341 | \r | |
913cb9dc | 342 | /**\r |
78c2ffb5 | 343 | Create a list of QTDs for the URB.\r |
913cb9dc | 344 | \r |
78c2ffb5 | 345 | @param Ehc The EHCI device.\r |
346 | @param Urb The URB to create QTDs for.\r | |
913cb9dc | 347 | \r |
78c2ffb5 | 348 | @retval EFI_OUT_OF_RESOURCES Failed to allocate resource for QTD.\r |
349 | @retval EFI_SUCCESS The QTDs are allocated for the URB.\r | |
913cb9dc | 350 | \r |
351 | **/\r | |
913cb9dc | 352 | EFI_STATUS\r |
353 | EhcCreateQtds (\r | |
1436aea4 MK |
354 | IN USB2_HC_DEV *Ehc,\r |
355 | IN URB *Urb\r | |
913cb9dc | 356 | )\r |
357 | {\r | |
1436aea4 MK |
358 | USB_ENDPOINT *Ep;\r |
359 | EHC_QH *Qh;\r | |
360 | EHC_QTD *Qtd;\r | |
361 | EHC_QTD *StatusQtd;\r | |
362 | EHC_QTD *NextQtd;\r | |
363 | LIST_ENTRY *Entry;\r | |
364 | UINT32 AlterNext;\r | |
365 | UINT8 Toggle;\r | |
366 | UINTN Len;\r | |
367 | UINT8 Pid;\r | |
368 | EFI_PHYSICAL_ADDRESS PhyAddr;\r | |
913cb9dc | 369 | \r |
370 | ASSERT ((Urb != NULL) && (Urb->Qh != NULL));\r | |
371 | \r | |
372 | //\r | |
373 | // EHCI follows the alternet next QTD pointer if it meets\r | |
374 | // a short read and the AlterNext pointer is valid. UEFI\r | |
375 | // EHCI driver should terminate the transfer except the\r | |
376 | // control transfer.\r | |
377 | //\r | |
378 | Toggle = 0;\r | |
379 | Qh = Urb->Qh;\r | |
380 | Ep = &Urb->Ep;\r | |
381 | StatusQtd = NULL;\r | |
382 | AlterNext = QTD_LINK (NULL, TRUE);\r | |
383 | \r | |
1436aea4 | 384 | PhyAddr = UsbHcGetPciAddressForHostMem (Ehc->MemPool, Ehc->ShortReadStop, sizeof (EHC_QTD));\r |
913cb9dc | 385 | if (Ep->Direction == EfiUsbDataIn) {\r |
739802e4 | 386 | AlterNext = QTD_LINK (PhyAddr, FALSE);\r |
913cb9dc | 387 | }\r |
388 | \r | |
389 | //\r | |
390 | // Build the Setup and status packets for control transfer\r | |
391 | //\r | |
392 | if (Urb->Ep.Type == EHC_CTRL_TRANSFER) {\r | |
393 | Len = sizeof (EFI_USB_DEVICE_REQUEST);\r | |
739802e4 | 394 | Qtd = EhcCreateQtd (Ehc, (UINT8 *)Urb->Request, (UINT8 *)Urb->RequestPhy, Len, QTD_PID_SETUP, 0, Ep->MaxPacket);\r |
913cb9dc | 395 | \r |
396 | if (Qtd == NULL) {\r | |
397 | return EFI_OUT_OF_RESOURCES;\r | |
398 | }\r | |
399 | \r | |
400 | InsertTailList (&Qh->Qtds, &Qtd->QtdList);\r | |
401 | \r | |
402 | //\r | |
403 | // Create the status packet now. Set the AlterNext to it. So, when\r | |
404 | // EHCI meets a short control read, it can resume at the status stage.\r | |
405 | // Use the opposite direction of the data stage, or IN if there is\r | |
406 | // no data stage.\r | |
407 | //\r | |
408 | if (Ep->Direction == EfiUsbDataIn) {\r | |
409 | Pid = QTD_PID_OUTPUT;\r | |
410 | } else {\r | |
411 | Pid = QTD_PID_INPUT;\r | |
412 | }\r | |
413 | \r | |
739802e4 | 414 | StatusQtd = EhcCreateQtd (Ehc, NULL, NULL, 0, Pid, 1, Ep->MaxPacket);\r |
913cb9dc | 415 | \r |
416 | if (StatusQtd == NULL) {\r | |
417 | goto ON_ERROR;\r | |
418 | }\r | |
419 | \r | |
420 | if (Ep->Direction == EfiUsbDataIn) {\r | |
739802e4 | 421 | PhyAddr = UsbHcGetPciAddressForHostMem (Ehc->MemPool, StatusQtd, sizeof (EHC_QTD));\r |
422 | AlterNext = QTD_LINK (PhyAddr, FALSE);\r | |
913cb9dc | 423 | }\r |
424 | \r | |
425 | Toggle = 1;\r | |
426 | }\r | |
427 | \r | |
428 | //\r | |
429 | // Build the data packets for all the transfers\r | |
430 | //\r | |
431 | if (Ep->Direction == EfiUsbDataIn) {\r | |
432 | Pid = QTD_PID_INPUT;\r | |
433 | } else {\r | |
434 | Pid = QTD_PID_OUTPUT;\r | |
435 | }\r | |
436 | \r | |
437 | Qtd = NULL;\r | |
438 | Len = 0;\r | |
439 | \r | |
440 | while (Len < Urb->DataLen) {\r | |
441 | Qtd = EhcCreateQtd (\r | |
442 | Ehc,\r | |
1436aea4 MK |
443 | (UINT8 *)Urb->Data + Len,\r |
444 | (UINT8 *)Urb->DataPhy + Len,\r | |
913cb9dc | 445 | Urb->DataLen - Len,\r |
446 | Pid,\r | |
447 | Toggle,\r | |
448 | Ep->MaxPacket\r | |
449 | );\r | |
450 | \r | |
451 | if (Qtd == NULL) {\r | |
452 | goto ON_ERROR;\r | |
453 | }\r | |
454 | \r | |
455 | Qtd->QtdHw.AltNext = AlterNext;\r | |
456 | InsertTailList (&Qh->Qtds, &Qtd->QtdList);\r | |
457 | \r | |
458 | //\r | |
459 | // Switch the Toggle bit if odd number of packets are included in the QTD.\r | |
460 | //\r | |
461 | if (((Qtd->DataLen + Ep->MaxPacket - 1) / Ep->MaxPacket) % 2) {\r | |
1436aea4 | 462 | Toggle = (UINT8)(1 - Toggle);\r |
913cb9dc | 463 | }\r |
464 | \r | |
465 | Len += Qtd->DataLen;\r | |
466 | }\r | |
467 | \r | |
468 | //\r | |
469 | // Insert the status packet for control transfer\r | |
470 | //\r | |
471 | if (Ep->Type == EHC_CTRL_TRANSFER) {\r | |
472 | InsertTailList (&Qh->Qtds, &StatusQtd->QtdList);\r | |
473 | }\r | |
474 | \r | |
475 | //\r | |
476 | // OK, all the QTDs needed are created. Now, fix the NextQtd point\r | |
477 | //\r | |
e33d3e7f | 478 | BASE_LIST_FOR_EACH (Entry, &Qh->Qtds) {\r |
913cb9dc | 479 | Qtd = EFI_LIST_CONTAINER (Entry, EHC_QTD, QtdList);\r |
480 | \r | |
481 | //\r | |
482 | // break if it is the last entry on the list\r | |
483 | //\r | |
484 | if (Entry->ForwardLink == &Qh->Qtds) {\r | |
485 | break;\r | |
486 | }\r | |
487 | \r | |
1436aea4 MK |
488 | NextQtd = EFI_LIST_CONTAINER (Entry->ForwardLink, EHC_QTD, QtdList);\r |
489 | PhyAddr = UsbHcGetPciAddressForHostMem (Ehc->MemPool, NextQtd, sizeof (EHC_QTD));\r | |
490 | Qtd->QtdHw.NextQtd = QTD_LINK (PhyAddr, FALSE);\r | |
913cb9dc | 491 | }\r |
492 | \r | |
493 | //\r | |
494 | // Link the QTDs to the queue head\r | |
495 | //\r | |
1436aea4 MK |
496 | NextQtd = EFI_LIST_CONTAINER (Qh->Qtds.ForwardLink, EHC_QTD, QtdList);\r |
497 | PhyAddr = UsbHcGetPciAddressForHostMem (Ehc->MemPool, NextQtd, sizeof (EHC_QTD));\r | |
498 | Qh->QhHw.NextQtd = QTD_LINK (PhyAddr, FALSE);\r | |
913cb9dc | 499 | return EFI_SUCCESS;\r |
500 | \r | |
501 | ON_ERROR:\r | |
502 | EhcFreeQtds (Ehc, &Qh->Qtds);\r | |
503 | return EFI_OUT_OF_RESOURCES;\r | |
504 | }\r | |
505 | \r | |
913cb9dc | 506 | /**\r |
78c2ffb5 | 507 | Create a new URB and its associated QTD.\r |
508 | \r | |
509 | @param Ehc The EHCI device.\r | |
510 | @param DevAddr The device address.\r | |
511 | @param EpAddr Endpoint addrress & its direction.\r | |
512 | @param DevSpeed The device speed.\r | |
513 | @param Toggle Initial data toggle to use.\r | |
514 | @param MaxPacket The max packet length of the endpoint.\r | |
515 | @param Hub The transaction translator to use.\r | |
516 | @param Type The transaction type.\r | |
517 | @param Request The standard USB request for control transfer.\r | |
f87db256 | 518 | @param Data The user data to transfer.\r |
78c2ffb5 | 519 | @param DataLen The length of data buffer.\r |
520 | @param Callback The function to call when data is transferred.\r | |
521 | @param Context The context to the callback.\r | |
522 | @param Interval The interval for interrupt transfer.\r | |
523 | \r | |
524 | @return Created URB or NULL.\r | |
913cb9dc | 525 | \r |
526 | **/\r | |
527 | URB *\r | |
528 | EhcCreateUrb (\r | |
1436aea4 MK |
529 | IN USB2_HC_DEV *Ehc,\r |
530 | IN UINT8 DevAddr,\r | |
531 | IN UINT8 EpAddr,\r | |
532 | IN UINT8 DevSpeed,\r | |
533 | IN UINT8 Toggle,\r | |
534 | IN UINTN MaxPacket,\r | |
535 | IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Hub,\r | |
536 | IN UINTN Type,\r | |
537 | IN EFI_USB_DEVICE_REQUEST *Request,\r | |
538 | IN VOID *Data,\r | |
539 | IN UINTN DataLen,\r | |
540 | IN EFI_ASYNC_USB_TRANSFER_CALLBACK Callback,\r | |
541 | IN VOID *Context,\r | |
542 | IN UINTN Interval\r | |
913cb9dc | 543 | )\r |
544 | {\r | |
1436aea4 MK |
545 | USB_ENDPOINT *Ep;\r |
546 | EFI_PHYSICAL_ADDRESS PhyAddr;\r | |
547 | EFI_PCI_IO_PROTOCOL_OPERATION MapOp;\r | |
548 | EFI_PCI_IO_PROTOCOL *PciIo;\r | |
549 | EFI_STATUS Status;\r | |
550 | UINTN Len;\r | |
551 | URB *Urb;\r | |
552 | VOID *Map;\r | |
913cb9dc | 553 | \r |
554 | Urb = AllocateZeroPool (sizeof (URB));\r | |
555 | \r | |
556 | if (Urb == NULL) {\r | |
557 | return NULL;\r | |
558 | }\r | |
559 | \r | |
1436aea4 | 560 | Urb->Signature = EHC_URB_SIG;\r |
913cb9dc | 561 | InitializeListHead (&Urb->UrbList);\r |
562 | \r | |
1436aea4 MK |
563 | Ep = &Urb->Ep;\r |
564 | Ep->DevAddr = DevAddr;\r | |
565 | Ep->EpAddr = (UINT8)(EpAddr & 0x0F);\r | |
566 | Ep->Direction = (((EpAddr & 0x80) != 0) ? EfiUsbDataIn : EfiUsbDataOut);\r | |
567 | Ep->DevSpeed = DevSpeed;\r | |
568 | Ep->MaxPacket = MaxPacket;\r | |
913cb9dc | 569 | \r |
1436aea4 MK |
570 | Ep->HubAddr = 0;\r |
571 | Ep->HubPort = 0;\r | |
913cb9dc | 572 | \r |
573 | if (DevSpeed != EFI_USB_SPEED_HIGH) {\r | |
574 | ASSERT (Hub != NULL);\r | |
575 | \r | |
1436aea4 MK |
576 | Ep->HubAddr = Hub->TranslatorHubAddress;\r |
577 | Ep->HubPort = Hub->TranslatorPortNumber;\r | |
913cb9dc | 578 | }\r |
579 | \r | |
1436aea4 MK |
580 | Ep->Toggle = Toggle;\r |
581 | Ep->Type = Type;\r | |
582 | Ep->PollRate = EhcConvertPollRate (Interval);\r | |
913cb9dc | 583 | \r |
1436aea4 MK |
584 | Urb->Request = Request;\r |
585 | Urb->Data = Data;\r | |
586 | Urb->DataLen = DataLen;\r | |
587 | Urb->Callback = Callback;\r | |
588 | Urb->Context = Context;\r | |
913cb9dc | 589 | \r |
1436aea4 MK |
590 | PciIo = Ehc->PciIo;\r |
591 | Urb->Qh = EhcCreateQh (Ehc, &Urb->Ep);\r | |
913cb9dc | 592 | \r |
593 | if (Urb->Qh == NULL) {\r | |
594 | goto ON_ERROR;\r | |
595 | }\r | |
596 | \r | |
597 | //\r | |
598 | // Map the request and user data\r | |
599 | //\r | |
600 | if (Request != NULL) {\r | |
1436aea4 MK |
601 | Len = sizeof (EFI_USB_DEVICE_REQUEST);\r |
602 | MapOp = EfiPciIoOperationBusMasterRead;\r | |
603 | Status = PciIo->Map (PciIo, MapOp, Request, &Len, &PhyAddr, &Map);\r | |
913cb9dc | 604 | \r |
605 | if (EFI_ERROR (Status) || (Len != sizeof (EFI_USB_DEVICE_REQUEST))) {\r | |
606 | goto ON_ERROR;\r | |
607 | }\r | |
608 | \r | |
1436aea4 | 609 | Urb->RequestPhy = (VOID *)((UINTN)PhyAddr);\r |
913cb9dc | 610 | Urb->RequestMap = Map;\r |
611 | }\r | |
612 | \r | |
613 | if (Data != NULL) {\r | |
1436aea4 | 614 | Len = DataLen;\r |
913cb9dc | 615 | \r |
f87db256 SZ |
616 | if (Ep->Direction == EfiUsbDataIn) {\r |
617 | MapOp = EfiPciIoOperationBusMasterWrite;\r | |
913cb9dc | 618 | } else {\r |
f87db256 | 619 | MapOp = EfiPciIoOperationBusMasterRead;\r |
913cb9dc | 620 | }\r |
621 | \r | |
1436aea4 | 622 | Status = PciIo->Map (PciIo, MapOp, Data, &Len, &PhyAddr, &Map);\r |
913cb9dc | 623 | \r |
624 | if (EFI_ERROR (Status) || (Len != DataLen)) {\r | |
625 | goto ON_ERROR;\r | |
626 | }\r | |
627 | \r | |
1436aea4 MK |
628 | Urb->DataPhy = (VOID *)((UINTN)PhyAddr);\r |
629 | Urb->DataMap = Map;\r | |
913cb9dc | 630 | }\r |
631 | \r | |
632 | Status = EhcCreateQtds (Ehc, Urb);\r | |
633 | \r | |
634 | if (EFI_ERROR (Status)) {\r | |
635 | goto ON_ERROR;\r | |
636 | }\r | |
637 | \r | |
638 | return Urb;\r | |
639 | \r | |
640 | ON_ERROR:\r | |
641 | EhcFreeUrb (Ehc, Urb);\r | |
642 | return NULL;\r | |
643 | }\r |