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