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