]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Bus/Pci/EhciDxe/EhciUrb.c
Remove some useless EDK_RELEASE_VERSION, EFI_SPECIFICATION_VERSION ,and review VALID_...
[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
913cb9dc 6Copyright (c) 2007, Intel Corporation\r
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
78c2ffb5 128 @return None.\r
913cb9dc 129\r
130**/\r
913cb9dc 131VOID\r
132EhcInitIntQh (\r
133 IN USB_ENDPOINT *Ep,\r
134 IN QH_HW *QhHw\r
135 )\r
136{\r
137 //\r
138 // Because UEFI interface can't utilitize an endpoint with\r
139 // poll rate faster than 1ms, only need to set one bit in\r
140 // the queue head. simple. But it may be changed later. If\r
141 // sub-1ms interrupt is supported, need to update the S-Mask\r
142 // here\r
143 //\r
144 if (Ep->DevSpeed == EFI_USB_SPEED_HIGH) {\r
145 QhHw->SMask = QH_MICROFRAME_0;\r
146 return ;\r
147 }\r
148\r
149 //\r
150 // For low/full speed device, the transfer must go through\r
151 // the split transaction. Need to update three fields\r
152 // 1. SplitXState in the status\r
153 // 2. Microframe S-Mask\r
154 // 3. Microframe C-Mask\r
155 // UEFI USB doesn't exercise admission control. It simplely\r
156 // schedule the high speed transactions in microframe 0, and\r
157 // full/low speed transactions at microframe 1. This also\r
158 // avoid the use of FSTN.\r
159 //\r
160 QhHw->SMask = QH_MICROFRAME_1;\r
161 QhHw->CMask = QH_MICROFRAME_3 | QH_MICROFRAME_4 | QH_MICROFRAME_5;\r
162}\r
163\r
164\r
165\r
166/**\r
78c2ffb5 167 Allocate and initialize a EHCI queue head.\r
913cb9dc 168\r
78c2ffb5 169 @param Ehci The EHCI device.\r
170 @param Ep The endpoint to create queue head for.\r
913cb9dc 171\r
78c2ffb5 172 @return Created queue head or NULL if failed to create one.\r
913cb9dc 173\r
174**/\r
175EHC_QH *\r
176EhcCreateQh (\r
177 IN USB2_HC_DEV *Ehci,\r
178 IN USB_ENDPOINT *Ep\r
179 )\r
180{\r
181 EHC_QH *Qh;\r
182 QH_HW *QhHw;\r
183\r
184 Qh = UsbHcAllocateMem (Ehci->MemPool, sizeof (EHC_QH));\r
185\r
186 if (Qh == NULL) {\r
187 return NULL;\r
188 }\r
189\r
190 Qh->Signature = EHC_QH_SIG;\r
191 Qh->NextQh = NULL;\r
192 Qh->Interval = Ep->PollRate;\r
193\r
194 InitializeListHead (&Qh->Qtds);\r
195\r
196 QhHw = &Qh->QhHw;\r
197 QhHw->HorizonLink = QH_LINK (NULL, 0, TRUE);\r
198 QhHw->DeviceAddr = Ep->DevAddr;\r
199 QhHw->Inactive = 0;\r
200 QhHw->EpNum = Ep->EpAddr;\r
201 QhHw->EpSpeed = Ep->DevSpeed;\r
202 QhHw->DtCtrl = 0;\r
203 QhHw->ReclaimHead = 0;\r
204 QhHw->MaxPacketLen = (UINT32) Ep->MaxPacket;\r
205 QhHw->CtrlEp = 0;\r
206 QhHw->NakReload = QH_NAK_RELOAD;\r
207 QhHw->HubAddr = Ep->HubAddr;\r
208 QhHw->PortNum = Ep->HubPort;\r
209 QhHw->Multiplier = 1;\r
210 QhHw->DataToggle = Ep->Toggle;\r
211\r
212 if (Ep->DevSpeed != EFI_USB_SPEED_HIGH) {\r
213 QhHw->Status |= QTD_STAT_DO_SS;\r
214 }\r
215\r
216 switch (Ep->Type) {\r
217 case EHC_CTRL_TRANSFER:\r
218 //\r
219 // Special initialization for the control transfer:\r
220 // 1. Control transfer initialize data toggle from each QTD\r
221 // 2. Set the Control Endpoint Flag (C) for low/full speed endpoint.\r
222 //\r
223 QhHw->DtCtrl = 1;\r
224\r
225 if (Ep->DevSpeed != EFI_USB_SPEED_HIGH) {\r
226 QhHw->CtrlEp = 1;\r
227 }\r
228 break;\r
229\r
230 case EHC_INT_TRANSFER_ASYNC:\r
231 case EHC_INT_TRANSFER_SYNC:\r
232 //\r
233 // Special initialization for the interrupt transfer\r
234 // to set the S-Mask and C-Mask\r
235 //\r
236 QhHw->NakReload = 0;\r
237 EhcInitIntQh (Ep, QhHw);\r
238 break;\r
239\r
240 case EHC_BULK_TRANSFER:\r
241 if ((Ep->DevSpeed == EFI_USB_SPEED_HIGH) && (Ep->Direction == EfiUsbDataOut)) {\r
242 QhHw->Status |= QTD_STAT_DO_PING;\r
243 }\r
244\r
245 break;\r
246 }\r
247\r
248 return Qh;\r
249}\r
250\r
251\r
913cb9dc 252/**\r
253 Convert the poll interval from application to that\r
254 be used by EHCI interface data structure. Only need\r
255 to get the max 2^n that is less than interval. UEFI\r
256 can't support high speed endpoint with a interval less\r
257 than 8 microframe because interval is specified in\r
78c2ffb5 258 the unit of ms (millisecond).\r
913cb9dc 259\r
78c2ffb5 260 @param Interval The interval to convert.\r
913cb9dc 261\r
78c2ffb5 262 @return The converted interval.\r
913cb9dc 263\r
264**/\r
913cb9dc 265UINTN\r
266EhcConvertPollRate (\r
267 IN UINTN Interval\r
268 )\r
269{\r
270 UINTN BitCount;\r
271\r
272 if (Interval == 0) {\r
273 return 1;\r
274 }\r
275\r
276 //\r
277 // Find the index (1 based) of the highest non-zero bit\r
278 //\r
279 BitCount = 0;\r
280\r
281 while (Interval != 0) {\r
282 Interval >>= 1;\r
283 BitCount++;\r
284 }\r
285\r
db01f13e 286 return (UINTN)1 << (BitCount - 1);\r
913cb9dc 287}\r
288\r
289\r
913cb9dc 290/**\r
78c2ffb5 291 Free a list of QTDs.\r
913cb9dc 292\r
78c2ffb5 293 @param Ehc The EHCI device.\r
294 @param Qtds The list head of the QTD.\r
913cb9dc 295\r
78c2ffb5 296 @return None.\r
913cb9dc 297\r
298**/\r
913cb9dc 299VOID\r
300EhcFreeQtds (\r
301 IN USB2_HC_DEV *Ehc,\r
302 IN LIST_ENTRY *Qtds\r
303 )\r
304{\r
305 LIST_ENTRY *Entry;\r
306 LIST_ENTRY *Next;\r
307 EHC_QTD *Qtd;\r
308\r
309 EFI_LIST_FOR_EACH_SAFE (Entry, Next, Qtds) {\r
310 Qtd = EFI_LIST_CONTAINER (Entry, EHC_QTD, QtdList);\r
311\r
312 RemoveEntryList (&Qtd->QtdList);\r
313 UsbHcFreeMem (Ehc->MemPool, Qtd, sizeof (EHC_QTD));\r
314 }\r
315}\r
316\r
317\r
318/**\r
319 Free an allocated URB. It is possible for it to be partially inited.\r
320\r
78c2ffb5 321 @param Ehc The EHCI device.\r
322 @param Urb The URB to free.\r
913cb9dc 323\r
78c2ffb5 324 @return None.\r
913cb9dc 325\r
326**/\r
327VOID\r
328EhcFreeUrb (\r
329 IN USB2_HC_DEV *Ehc,\r
330 IN URB *Urb\r
331 )\r
332{\r
333 EFI_PCI_IO_PROTOCOL *PciIo;\r
334\r
335 PciIo = Ehc->PciIo;\r
336\r
337 if (Urb->RequestPhy != NULL) {\r
338 PciIo->Unmap (PciIo, Urb->RequestMap);\r
339 }\r
340\r
341 if (Urb->DataMap != NULL) {\r
342 PciIo->Unmap (PciIo, Urb->DataMap);\r
343 }\r
344\r
345 if (Urb->Qh != NULL) {\r
346 //\r
347 // Ensure that this queue head has been unlinked from the\r
348 // schedule data structures. Free all the associated QTDs\r
349 //\r
350 EhcFreeQtds (Ehc, &Urb->Qh->Qtds);\r
351 UsbHcFreeMem (Ehc->MemPool, Urb->Qh, sizeof (EHC_QH));\r
352 }\r
353\r
354 gBS->FreePool (Urb);\r
355}\r
356\r
357\r
913cb9dc 358/**\r
78c2ffb5 359 Create a list of QTDs for the URB.\r
913cb9dc 360\r
78c2ffb5 361 @param Ehc The EHCI device.\r
362 @param Urb The URB to create QTDs for.\r
913cb9dc 363\r
78c2ffb5 364 @retval EFI_OUT_OF_RESOURCES Failed to allocate resource for QTD.\r
365 @retval EFI_SUCCESS The QTDs are allocated for the URB.\r
913cb9dc 366\r
367**/\r
913cb9dc 368EFI_STATUS\r
369EhcCreateQtds (\r
370 IN USB2_HC_DEV *Ehc,\r
371 IN URB *Urb\r
372 )\r
373{\r
374 USB_ENDPOINT *Ep;\r
375 EHC_QH *Qh;\r
376 EHC_QTD *Qtd;\r
377 EHC_QTD *StatusQtd;\r
378 EHC_QTD *NextQtd;\r
379 LIST_ENTRY *Entry;\r
380 UINT32 AlterNext;\r
381 UINT8 Toggle;\r
382 UINTN Len;\r
383 UINT8 Pid;\r
384\r
385 ASSERT ((Urb != NULL) && (Urb->Qh != NULL));\r
386\r
387 //\r
388 // EHCI follows the alternet next QTD pointer if it meets\r
389 // a short read and the AlterNext pointer is valid. UEFI\r
390 // EHCI driver should terminate the transfer except the\r
391 // control transfer.\r
392 //\r
393 Toggle = 0;\r
394 Qh = Urb->Qh;\r
395 Ep = &Urb->Ep;\r
396 StatusQtd = NULL;\r
397 AlterNext = QTD_LINK (NULL, TRUE);\r
398\r
399 if (Ep->Direction == EfiUsbDataIn) {\r
400 AlterNext = QTD_LINK (Ehc->ShortReadStop, FALSE);\r
401 }\r
402\r
403 //\r
404 // Build the Setup and status packets for control transfer\r
405 //\r
406 if (Urb->Ep.Type == EHC_CTRL_TRANSFER) {\r
407 Len = sizeof (EFI_USB_DEVICE_REQUEST);\r
408 Qtd = EhcCreateQtd (Ehc, Urb->RequestPhy, Len, QTD_PID_SETUP, 0, Ep->MaxPacket);\r
409\r
410 if (Qtd == NULL) {\r
411 return EFI_OUT_OF_RESOURCES;\r
412 }\r
413\r
414 InsertTailList (&Qh->Qtds, &Qtd->QtdList);\r
415\r
416 //\r
417 // Create the status packet now. Set the AlterNext to it. So, when\r
418 // EHCI meets a short control read, it can resume at the status stage.\r
419 // Use the opposite direction of the data stage, or IN if there is\r
420 // no data stage.\r
421 //\r
422 if (Ep->Direction == EfiUsbDataIn) {\r
423 Pid = QTD_PID_OUTPUT;\r
424 } else {\r
425 Pid = QTD_PID_INPUT;\r
426 }\r
427\r
428 StatusQtd = EhcCreateQtd (Ehc, NULL, 0, Pid, 1, Ep->MaxPacket);\r
429\r
430 if (StatusQtd == NULL) {\r
431 goto ON_ERROR;\r
432 }\r
433\r
434 if (Ep->Direction == EfiUsbDataIn) {\r
435 AlterNext = QTD_LINK (StatusQtd, FALSE);\r
436 }\r
437\r
438 Toggle = 1;\r
439 }\r
440\r
441 //\r
442 // Build the data packets for all the transfers\r
443 //\r
444 if (Ep->Direction == EfiUsbDataIn) {\r
445 Pid = QTD_PID_INPUT;\r
446 } else {\r
447 Pid = QTD_PID_OUTPUT;\r
448 }\r
449\r
450 Qtd = NULL;\r
451 Len = 0;\r
452\r
453 while (Len < Urb->DataLen) {\r
454 Qtd = EhcCreateQtd (\r
455 Ehc,\r
456 (UINT8 *) Urb->DataPhy + Len,\r
457 Urb->DataLen - Len,\r
458 Pid,\r
459 Toggle,\r
460 Ep->MaxPacket\r
461 );\r
462\r
463 if (Qtd == NULL) {\r
464 goto ON_ERROR;\r
465 }\r
466\r
467 Qtd->QtdHw.AltNext = AlterNext;\r
468 InsertTailList (&Qh->Qtds, &Qtd->QtdList);\r
469\r
470 //\r
471 // Switch the Toggle bit if odd number of packets are included in the QTD.\r
472 //\r
473 if (((Qtd->DataLen + Ep->MaxPacket - 1) / Ep->MaxPacket) % 2) {\r
c52fa98c 474 Toggle = (UINT8) (1 - Toggle);\r
913cb9dc 475 }\r
476\r
477 Len += Qtd->DataLen;\r
478 }\r
479\r
480 //\r
481 // Insert the status packet for control transfer\r
482 //\r
483 if (Ep->Type == EHC_CTRL_TRANSFER) {\r
484 InsertTailList (&Qh->Qtds, &StatusQtd->QtdList);\r
485 }\r
486\r
487 //\r
488 // OK, all the QTDs needed are created. Now, fix the NextQtd point\r
489 //\r
490 EFI_LIST_FOR_EACH (Entry, &Qh->Qtds) {\r
491 Qtd = EFI_LIST_CONTAINER (Entry, EHC_QTD, QtdList);\r
492\r
493 //\r
494 // break if it is the last entry on the list\r
495 //\r
496 if (Entry->ForwardLink == &Qh->Qtds) {\r
497 break;\r
498 }\r
499\r
500 NextQtd = EFI_LIST_CONTAINER (Entry->ForwardLink, EHC_QTD, QtdList);\r
501 Qtd->QtdHw.NextQtd = QTD_LINK (NextQtd, FALSE);\r
502 }\r
503\r
504 //\r
505 // Link the QTDs to the queue head\r
506 //\r
507 NextQtd = EFI_LIST_CONTAINER (Qh->Qtds.ForwardLink, EHC_QTD, QtdList);\r
508 Qh->QhHw.NextQtd = QTD_LINK (NextQtd, FALSE);\r
509 return EFI_SUCCESS;\r
510\r
511ON_ERROR:\r
512 EhcFreeQtds (Ehc, &Qh->Qtds);\r
513 return EFI_OUT_OF_RESOURCES;\r
514}\r
515\r
516\r
517/**\r
78c2ffb5 518 Create a new URB and its associated QTD.\r
519\r
520 @param Ehc The EHCI device.\r
521 @param DevAddr The device address.\r
522 @param EpAddr Endpoint addrress & its direction.\r
523 @param DevSpeed The device speed.\r
524 @param Toggle Initial data toggle to use.\r
525 @param MaxPacket The max packet length of the endpoint.\r
526 @param Hub The transaction translator to use.\r
527 @param Type The transaction type.\r
528 @param Request The standard USB request for control transfer.\r
529 @param Data The user data to transfer.\r
530 @param DataLen The length of data buffer.\r
531 @param Callback The function to call when data is transferred.\r
532 @param Context The context to the callback.\r
533 @param Interval The interval for interrupt transfer.\r
534\r
535 @return Created URB or NULL.\r
913cb9dc 536\r
537**/\r
538URB *\r
539EhcCreateUrb (\r
540 IN USB2_HC_DEV *Ehc,\r
541 IN UINT8 DevAddr,\r
542 IN UINT8 EpAddr,\r
543 IN UINT8 DevSpeed,\r
544 IN UINT8 Toggle,\r
545 IN UINTN MaxPacket,\r
546 IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Hub,\r
547 IN UINTN Type,\r
548 IN EFI_USB_DEVICE_REQUEST *Request,\r
549 IN VOID *Data,\r
550 IN UINTN DataLen,\r
551 IN EFI_ASYNC_USB_TRANSFER_CALLBACK Callback,\r
552 IN VOID *Context,\r
553 IN UINTN Interval\r
554 )\r
555{\r
556 USB_ENDPOINT *Ep;\r
557 EFI_PHYSICAL_ADDRESS PhyAddr;\r
558 EFI_PCI_IO_PROTOCOL_OPERATION MapOp;\r
559 EFI_PCI_IO_PROTOCOL *PciIo;\r
560 EFI_STATUS Status;\r
561 UINTN Len;\r
562 URB *Urb;\r
563 VOID *Map;\r
564\r
565 Urb = AllocateZeroPool (sizeof (URB));\r
566\r
567 if (Urb == NULL) {\r
568 return NULL;\r
569 }\r
570\r
571 Urb->Signature = EHC_URB_SIG;\r
572 InitializeListHead (&Urb->UrbList);\r
573\r
574 Ep = &Urb->Ep;\r
575 Ep->DevAddr = DevAddr;\r
c52fa98c 576 Ep->EpAddr = (UINT8) (EpAddr & 0x0F);\r
78c2ffb5 577 Ep->Direction = (((EpAddr & 0x80) != 0) ? EfiUsbDataIn : EfiUsbDataOut);\r
913cb9dc 578 Ep->DevSpeed = DevSpeed;\r
579 Ep->MaxPacket = MaxPacket;\r
580\r
581 Ep->HubAddr = 0;\r
582 Ep->HubPort = 0;\r
583\r
584 if (DevSpeed != EFI_USB_SPEED_HIGH) {\r
585 ASSERT (Hub != NULL);\r
586\r
587 Ep->HubAddr = Hub->TranslatorHubAddress;\r
588 Ep->HubPort = Hub->TranslatorPortNumber;\r
589 }\r
590\r
591 Ep->Toggle = Toggle;\r
592 Ep->Type = Type;\r
593 Ep->PollRate = EhcConvertPollRate (Interval);\r
594\r
595 Urb->Request = Request;\r
596 Urb->Data = Data;\r
597 Urb->DataLen = DataLen;\r
598 Urb->Callback = Callback;\r
599 Urb->Context = Context;\r
600\r
601 PciIo = Ehc->PciIo;\r
602 Urb->Qh = EhcCreateQh (Ehc, &Urb->Ep);\r
603\r
604 if (Urb->Qh == NULL) {\r
605 goto ON_ERROR;\r
606 }\r
607\r
608 //\r
609 // Map the request and user data\r
610 //\r
611 if (Request != NULL) {\r
612 Len = sizeof (EFI_USB_DEVICE_REQUEST);\r
613 MapOp = EfiPciIoOperationBusMasterRead;\r
614 Status = PciIo->Map (PciIo, MapOp, Request, &Len, &PhyAddr, &Map);\r
615\r
616 if (EFI_ERROR (Status) || (Len != sizeof (EFI_USB_DEVICE_REQUEST))) {\r
617 goto ON_ERROR;\r
618 }\r
619\r
620 Urb->RequestPhy = (VOID *) ((UINTN) PhyAddr);\r
621 Urb->RequestMap = Map;\r
622 }\r
623\r
624 if (Data != NULL) {\r
625 Len = DataLen;\r
626\r
627 if (Ep->Direction == EfiUsbDataIn) {\r
628 MapOp = EfiPciIoOperationBusMasterWrite;\r
629 } else {\r
630 MapOp = EfiPciIoOperationBusMasterRead;\r
631 }\r
632\r
633 Status = PciIo->Map (PciIo, MapOp, Data, &Len, &PhyAddr, &Map);\r
634\r
635 if (EFI_ERROR (Status) || (Len != DataLen)) {\r
636 goto ON_ERROR;\r
637 }\r
638\r
639 Urb->DataPhy = (VOID *) ((UINTN) PhyAddr);\r
640 Urb->DataMap = Map;\r
641 }\r
642\r
643 Status = EhcCreateQtds (Ehc, Urb);\r
644\r
645 if (EFI_ERROR (Status)) {\r
646 goto ON_ERROR;\r
647 }\r
648\r
649 return Urb;\r
650\r
651ON_ERROR:\r
652 EhcFreeUrb (Ehc, Urb);\r
653 return NULL;\r
654}\r