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