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