]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Bus/Pci/EhciDxe/EhciUrb.c
MdeModulePkg: Replace BSD License with BSD+Patent License
[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
cd5ebaa0 6Copyright (c) 2007 - 2010, Intel Corporation. All rights reserved.<BR>\r
9d510e61 7SPDX-License-Identifier: BSD-2-Clause-Patent\r
913cb9dc 8\r
913cb9dc 9**/\r
10\r
11#include "Ehci.h"\r
12\r
13\r
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
28EHC_QTD *\r
29EhcCreateQtd (\r
30 IN USB2_HC_DEV *Ehc,\r
31 IN UINT8 *Data,\r
739802e4 32 IN UINT8 *DataPhy,\r
913cb9dc 33 IN UINTN DataLen,\r
34 IN UINT8 PktId,\r
35 IN UINT8 Toggle,\r
36 IN UINTN MaxPacket\r
37 )\r
38{\r
39 EHC_QTD *Qtd;\r
40 QTD_HW *QtdHw;\r
41 UINTN Index;\r
42 UINTN Len;\r
43 UINTN ThisBufLen;\r
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
53 Qtd->Signature = EHC_QTD_SIG;\r
54 Qtd->Data = Data;\r
55 Qtd->DataLen = 0;\r
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
739802e4 81 QtdHw->Page[Index] = EHC_LOW_32BIT (DataPhy);\r
82 QtdHw->PageHigh[Index] = EHC_HIGH_32BIT (DataPhy);\r
913cb9dc 83\r
739802e4 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
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
106 QtdHw->TotalBytes = (UINT32) Len;\r
107 Qtd->DataLen = Len;\r
108 }\r
109\r
110 return Qtd;\r
111}\r
112\r
113\r
114\r
115/**\r
116 Initialize the queue head for interrupt transfer,\r
117 that is, initialize the following three fields:\r
118 1. SplitXState in the Status field\r
119 2. Microframe S-mask\r
120 3. Microframe C-mask\r
121\r
78c2ffb5 122 @param Ep The queue head's related endpoint.\r
123 @param QhHw The queue head to initialize.\r
913cb9dc 124\r
913cb9dc 125**/\r
913cb9dc 126VOID\r
127EhcInitIntQh (\r
128 IN USB_ENDPOINT *Ep,\r
129 IN QH_HW *QhHw\r
130 )\r
131{\r
132 //\r
133 // Because UEFI interface can't utilitize an endpoint with\r
134 // poll rate faster than 1ms, only need to set one bit in\r
135 // the queue head. simple. But it may be changed later. If\r
136 // sub-1ms interrupt is supported, need to update the S-Mask\r
137 // here\r
138 //\r
139 if (Ep->DevSpeed == EFI_USB_SPEED_HIGH) {\r
140 QhHw->SMask = QH_MICROFRAME_0;\r
141 return ;\r
142 }\r
143\r
144 //\r
145 // For low/full speed device, the transfer must go through\r
146 // the split transaction. Need to update three fields\r
147 // 1. SplitXState in the status\r
148 // 2. Microframe S-Mask\r
149 // 3. Microframe C-Mask\r
150 // UEFI USB doesn't exercise admission control. It simplely\r
151 // schedule the high speed transactions in microframe 0, and\r
152 // full/low speed transactions at microframe 1. This also\r
153 // avoid the use of FSTN.\r
154 //\r
155 QhHw->SMask = QH_MICROFRAME_1;\r
156 QhHw->CMask = QH_MICROFRAME_3 | QH_MICROFRAME_4 | QH_MICROFRAME_5;\r
157}\r
158\r
159\r
160\r
161/**\r
78c2ffb5 162 Allocate and initialize a EHCI queue head.\r
913cb9dc 163\r
78c2ffb5 164 @param Ehci The EHCI device.\r
165 @param Ep The endpoint to create queue head for.\r
913cb9dc 166\r
78c2ffb5 167 @return Created queue head or NULL if failed to create one.\r
913cb9dc 168\r
169**/\r
170EHC_QH *\r
171EhcCreateQh (\r
172 IN USB2_HC_DEV *Ehci,\r
173 IN USB_ENDPOINT *Ep\r
174 )\r
175{\r
176 EHC_QH *Qh;\r
177 QH_HW *QhHw;\r
178\r
179 Qh = UsbHcAllocateMem (Ehci->MemPool, sizeof (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
188\r
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
913cb9dc 247/**\r
248 Convert the poll interval from application to that\r
249 be used by EHCI interface data structure. Only need\r
250 to get the max 2^n that is less than interval. UEFI\r
251 can't support high speed endpoint with a interval less\r
252 than 8 microframe because interval is specified in\r
78c2ffb5 253 the unit of ms (millisecond).\r
913cb9dc 254\r
78c2ffb5 255 @param Interval The interval to convert.\r
913cb9dc 256\r
78c2ffb5 257 @return The converted interval.\r
913cb9dc 258\r
259**/\r
913cb9dc 260UINTN\r
261EhcConvertPollRate (\r
262 IN UINTN Interval\r
263 )\r
264{\r
265 UINTN BitCount;\r
266\r
267 if (Interval == 0) {\r
268 return 1;\r
269 }\r
270\r
271 //\r
272 // Find the index (1 based) of the highest non-zero bit\r
273 //\r
274 BitCount = 0;\r
275\r
276 while (Interval != 0) {\r
277 Interval >>= 1;\r
278 BitCount++;\r
279 }\r
280\r
db01f13e 281 return (UINTN)1 << (BitCount - 1);\r
913cb9dc 282}\r
283\r
284\r
913cb9dc 285/**\r
78c2ffb5 286 Free a list of QTDs.\r
913cb9dc 287\r
78c2ffb5 288 @param Ehc The EHCI device.\r
289 @param Qtds The list head of the QTD.\r
913cb9dc 290\r
913cb9dc 291**/\r
913cb9dc 292VOID\r
293EhcFreeQtds (\r
294 IN USB2_HC_DEV *Ehc,\r
295 IN LIST_ENTRY *Qtds\r
296 )\r
297{\r
298 LIST_ENTRY *Entry;\r
299 LIST_ENTRY *Next;\r
300 EHC_QTD *Qtd;\r
301\r
302 EFI_LIST_FOR_EACH_SAFE (Entry, Next, Qtds) {\r
303 Qtd = EFI_LIST_CONTAINER (Entry, EHC_QTD, QtdList);\r
304\r
305 RemoveEntryList (&Qtd->QtdList);\r
306 UsbHcFreeMem (Ehc->MemPool, Qtd, sizeof (EHC_QTD));\r
307 }\r
308}\r
309\r
310\r
311/**\r
312 Free an allocated URB. It is possible for it to be partially inited.\r
313\r
78c2ffb5 314 @param Ehc The EHCI device.\r
315 @param Urb The URB to free.\r
913cb9dc 316\r
913cb9dc 317**/\r
318VOID\r
319EhcFreeUrb (\r
320 IN USB2_HC_DEV *Ehc,\r
321 IN URB *Urb\r
322 )\r
323{\r
324 EFI_PCI_IO_PROTOCOL *PciIo;\r
325\r
326 PciIo = Ehc->PciIo;\r
327\r
328 if (Urb->RequestPhy != NULL) {\r
329 PciIo->Unmap (PciIo, Urb->RequestMap);\r
330 }\r
331\r
332 if (Urb->DataMap != NULL) {\r
333 PciIo->Unmap (PciIo, Urb->DataMap);\r
334 }\r
335\r
336 if (Urb->Qh != NULL) {\r
337 //\r
338 // Ensure that this queue head has been unlinked from the\r
339 // schedule data structures. Free all the associated QTDs\r
340 //\r
341 EhcFreeQtds (Ehc, &Urb->Qh->Qtds);\r
342 UsbHcFreeMem (Ehc->MemPool, Urb->Qh, sizeof (EHC_QH));\r
343 }\r
344\r
345 gBS->FreePool (Urb);\r
346}\r
347\r
348\r
913cb9dc 349/**\r
78c2ffb5 350 Create a list of QTDs for the URB.\r
913cb9dc 351\r
78c2ffb5 352 @param Ehc The EHCI device.\r
353 @param Urb The URB to create QTDs for.\r
913cb9dc 354\r
78c2ffb5 355 @retval EFI_OUT_OF_RESOURCES Failed to allocate resource for QTD.\r
356 @retval EFI_SUCCESS The QTDs are allocated for the URB.\r
913cb9dc 357\r
358**/\r
913cb9dc 359EFI_STATUS\r
360EhcCreateQtds (\r
361 IN USB2_HC_DEV *Ehc,\r
362 IN URB *Urb\r
363 )\r
364{\r
365 USB_ENDPOINT *Ep;\r
366 EHC_QH *Qh;\r
367 EHC_QTD *Qtd;\r
368 EHC_QTD *StatusQtd;\r
369 EHC_QTD *NextQtd;\r
370 LIST_ENTRY *Entry;\r
371 UINT32 AlterNext;\r
372 UINT8 Toggle;\r
373 UINTN Len;\r
374 UINT8 Pid;\r
739802e4 375 EFI_PHYSICAL_ADDRESS PhyAddr;\r
913cb9dc 376\r
377 ASSERT ((Urb != NULL) && (Urb->Qh != NULL));\r
378\r
379 //\r
380 // EHCI follows the alternet next QTD pointer if it meets\r
381 // a short read and the AlterNext pointer is valid. UEFI\r
382 // EHCI driver should terminate the transfer except the\r
383 // control transfer.\r
384 //\r
385 Toggle = 0;\r
386 Qh = Urb->Qh;\r
387 Ep = &Urb->Ep;\r
388 StatusQtd = NULL;\r
389 AlterNext = QTD_LINK (NULL, TRUE);\r
390\r
739802e4 391 PhyAddr = UsbHcGetPciAddressForHostMem (Ehc->MemPool, Ehc->ShortReadStop, sizeof (EHC_QTD));\r
913cb9dc 392 if (Ep->Direction == EfiUsbDataIn) {\r
739802e4 393 AlterNext = QTD_LINK (PhyAddr, FALSE);\r
913cb9dc 394 }\r
395\r
396 //\r
397 // Build the Setup and status packets for control transfer\r
398 //\r
399 if (Urb->Ep.Type == EHC_CTRL_TRANSFER) {\r
400 Len = sizeof (EFI_USB_DEVICE_REQUEST);\r
739802e4 401 Qtd = EhcCreateQtd (Ehc, (UINT8 *)Urb->Request, (UINT8 *)Urb->RequestPhy, Len, QTD_PID_SETUP, 0, Ep->MaxPacket);\r
913cb9dc 402\r
403 if (Qtd == NULL) {\r
404 return EFI_OUT_OF_RESOURCES;\r
405 }\r
406\r
407 InsertTailList (&Qh->Qtds, &Qtd->QtdList);\r
408\r
409 //\r
410 // Create the status packet now. Set the AlterNext to it. So, when\r
411 // EHCI meets a short control read, it can resume at the status stage.\r
412 // Use the opposite direction of the data stage, or IN if there is\r
413 // no data stage.\r
414 //\r
415 if (Ep->Direction == EfiUsbDataIn) {\r
416 Pid = QTD_PID_OUTPUT;\r
417 } else {\r
418 Pid = QTD_PID_INPUT;\r
419 }\r
420\r
739802e4 421 StatusQtd = EhcCreateQtd (Ehc, NULL, NULL, 0, Pid, 1, Ep->MaxPacket);\r
913cb9dc 422\r
423 if (StatusQtd == NULL) {\r
424 goto ON_ERROR;\r
425 }\r
426\r
427 if (Ep->Direction == EfiUsbDataIn) {\r
739802e4 428 PhyAddr = UsbHcGetPciAddressForHostMem (Ehc->MemPool, StatusQtd, sizeof (EHC_QTD));\r
429 AlterNext = QTD_LINK (PhyAddr, FALSE);\r
913cb9dc 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
739802e4 450 (UINT8 *) Urb->Data + Len,\r
913cb9dc 451 (UINT8 *) Urb->DataPhy + Len,\r
452 Urb->DataLen - Len,\r
453 Pid,\r
454 Toggle,\r
455 Ep->MaxPacket\r
456 );\r
457\r
458 if (Qtd == NULL) {\r
459 goto ON_ERROR;\r
460 }\r
461\r
462 Qtd->QtdHw.AltNext = AlterNext;\r
463 InsertTailList (&Qh->Qtds, &Qtd->QtdList);\r
464\r
465 //\r
466 // Switch the Toggle bit if odd number of packets are included in the QTD.\r
467 //\r
468 if (((Qtd->DataLen + Ep->MaxPacket - 1) / Ep->MaxPacket) % 2) {\r
c52fa98c 469 Toggle = (UINT8) (1 - Toggle);\r
913cb9dc 470 }\r
471\r
472 Len += Qtd->DataLen;\r
473 }\r
474\r
475 //\r
476 // Insert the status packet for control transfer\r
477 //\r
478 if (Ep->Type == EHC_CTRL_TRANSFER) {\r
479 InsertTailList (&Qh->Qtds, &StatusQtd->QtdList);\r
480 }\r
481\r
482 //\r
483 // OK, all the QTDs needed are created. Now, fix the NextQtd point\r
484 //\r
485 EFI_LIST_FOR_EACH (Entry, &Qh->Qtds) {\r
486 Qtd = EFI_LIST_CONTAINER (Entry, EHC_QTD, QtdList);\r
487\r
488 //\r
489 // break if it is the last entry on the list\r
490 //\r
491 if (Entry->ForwardLink == &Qh->Qtds) {\r
492 break;\r
493 }\r
494\r
495 NextQtd = EFI_LIST_CONTAINER (Entry->ForwardLink, EHC_QTD, QtdList);\r
739802e4 496 PhyAddr = UsbHcGetPciAddressForHostMem (Ehc->MemPool, NextQtd, sizeof (EHC_QTD));\r
497 Qtd->QtdHw.NextQtd = QTD_LINK (PhyAddr, FALSE);\r
913cb9dc 498 }\r
499\r
500 //\r
501 // Link the QTDs to the queue head\r
502 //\r
503 NextQtd = EFI_LIST_CONTAINER (Qh->Qtds.ForwardLink, EHC_QTD, QtdList);\r
739802e4 504 PhyAddr = UsbHcGetPciAddressForHostMem (Ehc->MemPool, NextQtd, sizeof (EHC_QTD));\r
505 Qh->QhHw.NextQtd = QTD_LINK (PhyAddr, FALSE);\r
913cb9dc 506 return EFI_SUCCESS;\r
507\r
508ON_ERROR:\r
509 EhcFreeQtds (Ehc, &Qh->Qtds);\r
510 return EFI_OUT_OF_RESOURCES;\r
511}\r
512\r
513\r
514/**\r
78c2ffb5 515 Create a new URB and its associated QTD.\r
516\r
517 @param Ehc The EHCI device.\r
518 @param DevAddr The device address.\r
519 @param EpAddr Endpoint addrress & its direction.\r
520 @param DevSpeed The device speed.\r
521 @param Toggle Initial data toggle to use.\r
522 @param MaxPacket The max packet length of the endpoint.\r
523 @param Hub The transaction translator to use.\r
524 @param Type The transaction type.\r
525 @param Request The standard USB request for control transfer.\r
f87db256 526 @param Data The user data to transfer.\r
78c2ffb5 527 @param DataLen The length of data buffer.\r
528 @param Callback The function to call when data is transferred.\r
529 @param Context The context to the callback.\r
530 @param Interval The interval for interrupt transfer.\r
531\r
532 @return Created URB or NULL.\r
913cb9dc 533\r
534**/\r
535URB *\r
536EhcCreateUrb (\r
537 IN USB2_HC_DEV *Ehc,\r
538 IN UINT8 DevAddr,\r
539 IN UINT8 EpAddr,\r
540 IN UINT8 DevSpeed,\r
541 IN UINT8 Toggle,\r
542 IN UINTN MaxPacket,\r
543 IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Hub,\r
544 IN UINTN Type,\r
545 IN EFI_USB_DEVICE_REQUEST *Request,\r
546 IN VOID *Data,\r
547 IN UINTN DataLen,\r
548 IN EFI_ASYNC_USB_TRANSFER_CALLBACK Callback,\r
549 IN VOID *Context,\r
550 IN UINTN Interval\r
551 )\r
552{\r
553 USB_ENDPOINT *Ep;\r
554 EFI_PHYSICAL_ADDRESS PhyAddr;\r
555 EFI_PCI_IO_PROTOCOL_OPERATION MapOp;\r
556 EFI_PCI_IO_PROTOCOL *PciIo;\r
557 EFI_STATUS Status;\r
558 UINTN Len;\r
559 URB *Urb;\r
560 VOID *Map;\r
561\r
562 Urb = AllocateZeroPool (sizeof (URB));\r
563\r
564 if (Urb == NULL) {\r
565 return NULL;\r
566 }\r
567\r
568 Urb->Signature = EHC_URB_SIG;\r
569 InitializeListHead (&Urb->UrbList);\r
570\r
571 Ep = &Urb->Ep;\r
572 Ep->DevAddr = DevAddr;\r
c52fa98c 573 Ep->EpAddr = (UINT8) (EpAddr & 0x0F);\r
78c2ffb5 574 Ep->Direction = (((EpAddr & 0x80) != 0) ? EfiUsbDataIn : EfiUsbDataOut);\r
913cb9dc 575 Ep->DevSpeed = DevSpeed;\r
576 Ep->MaxPacket = MaxPacket;\r
577\r
578 Ep->HubAddr = 0;\r
579 Ep->HubPort = 0;\r
580\r
581 if (DevSpeed != EFI_USB_SPEED_HIGH) {\r
582 ASSERT (Hub != NULL);\r
583\r
584 Ep->HubAddr = Hub->TranslatorHubAddress;\r
585 Ep->HubPort = Hub->TranslatorPortNumber;\r
586 }\r
587\r
588 Ep->Toggle = Toggle;\r
589 Ep->Type = Type;\r
590 Ep->PollRate = EhcConvertPollRate (Interval);\r
591\r
592 Urb->Request = Request;\r
593 Urb->Data = Data;\r
594 Urb->DataLen = DataLen;\r
595 Urb->Callback = Callback;\r
596 Urb->Context = Context;\r
597\r
598 PciIo = Ehc->PciIo;\r
599 Urb->Qh = EhcCreateQh (Ehc, &Urb->Ep);\r
600\r
601 if (Urb->Qh == NULL) {\r
602 goto ON_ERROR;\r
603 }\r
604\r
605 //\r
606 // Map the request and user data\r
607 //\r
608 if (Request != NULL) {\r
609 Len = sizeof (EFI_USB_DEVICE_REQUEST);\r
610 MapOp = EfiPciIoOperationBusMasterRead;\r
611 Status = PciIo->Map (PciIo, MapOp, Request, &Len, &PhyAddr, &Map);\r
612\r
613 if (EFI_ERROR (Status) || (Len != sizeof (EFI_USB_DEVICE_REQUEST))) {\r
614 goto ON_ERROR;\r
615 }\r
616\r
617 Urb->RequestPhy = (VOID *) ((UINTN) PhyAddr);\r
618 Urb->RequestMap = Map;\r
619 }\r
620\r
621 if (Data != NULL) {\r
622 Len = DataLen;\r
623\r
f87db256
SZ
624 if (Ep->Direction == EfiUsbDataIn) {\r
625 MapOp = EfiPciIoOperationBusMasterWrite;\r
913cb9dc 626 } else {\r
f87db256 627 MapOp = EfiPciIoOperationBusMasterRead;\r
913cb9dc 628 }\r
629\r
630 Status = PciIo->Map (PciIo, MapOp, Data, &Len, &PhyAddr, &Map);\r
631\r
632 if (EFI_ERROR (Status) || (Len != DataLen)) {\r
633 goto ON_ERROR;\r
634 }\r
635\r
636 Urb->DataPhy = (VOID *) ((UINTN) PhyAddr);\r
637 Urb->DataMap = Map;\r
638 }\r
639\r
640 Status = EhcCreateQtds (Ehc, Urb);\r
641\r
642 if (EFI_ERROR (Status)) {\r
643 goto ON_ERROR;\r
644 }\r
645\r
646 return Urb;\r
647\r
648ON_ERROR:\r
649 EhcFreeUrb (Ehc, Urb);\r
650 return NULL;\r
651}\r