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