]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Bus/Pci/EhciDxe/EhciUrb.c
MdeModulePkg EhciDxe: Use common buffer for AsyncInterruptTransfer
[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
HT
6Copyright (c) 2007 - 2010, Intel Corporation. All rights reserved.<BR>\r
7This program and the accompanying materials\r
913cb9dc 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
739802e4 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
78c2ffb5 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
913cb9dc 30\r
78c2ffb5 31 @return Created QTD or NULL if failed to create one.\r
913cb9dc 32\r
33**/\r
34EHC_QTD *\r
35EhcCreateQtd (\r
36 IN USB2_HC_DEV *Ehc,\r
37 IN UINT8 *Data,\r
739802e4 38 IN UINT8 *DataPhy,\r
913cb9dc 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
1ccdbf2a 71 QtdHw->Ioc = 0;\r
913cb9dc 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
739802e4 87 QtdHw->Page[Index] = EHC_LOW_32BIT (DataPhy);\r
88 QtdHw->PageHigh[Index] = EHC_HIGH_32BIT (DataPhy);\r
913cb9dc 89\r
739802e4 90 ThisBufLen = QTD_BUF_LEN - (EHC_LOW_32BIT (DataPhy) & QTD_BUF_MASK);\r
913cb9dc 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
739802e4 99 DataPhy += ThisBufLen;\r
913cb9dc 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
78c2ffb5 128 @param Ep The queue head's related endpoint.\r
129 @param QhHw The queue head to initialize.\r
913cb9dc 130\r
913cb9dc 131**/\r
913cb9dc 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
78c2ffb5 168 Allocate and initialize a EHCI queue head.\r
913cb9dc 169\r
78c2ffb5 170 @param Ehci The EHCI device.\r
171 @param Ep The endpoint to create queue head for.\r
913cb9dc 172\r
78c2ffb5 173 @return Created queue head or NULL if failed to create one.\r
913cb9dc 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
913cb9dc 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
78c2ffb5 259 the unit of ms (millisecond).\r
913cb9dc 260\r
78c2ffb5 261 @param Interval The interval to convert.\r
913cb9dc 262\r
78c2ffb5 263 @return The converted interval.\r
913cb9dc 264\r
265**/\r
913cb9dc 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
db01f13e 287 return (UINTN)1 << (BitCount - 1);\r
913cb9dc 288}\r
289\r
290\r
913cb9dc 291/**\r
78c2ffb5 292 Free a list of QTDs.\r
913cb9dc 293\r
78c2ffb5 294 @param Ehc The EHCI device.\r
295 @param Qtds The list head of the QTD.\r
913cb9dc 296\r
913cb9dc 297**/\r
913cb9dc 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
78c2ffb5 320 @param Ehc The EHCI device.\r
321 @param Urb The URB to free.\r
913cb9dc 322\r
913cb9dc 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
0cd64525
SZ
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
913cb9dc 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
913cb9dc 363/**\r
78c2ffb5 364 Create a list of QTDs for the URB.\r
913cb9dc 365\r
78c2ffb5 366 @param Ehc The EHCI device.\r
367 @param Urb The URB to create QTDs for.\r
913cb9dc 368\r
78c2ffb5 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
913cb9dc 371\r
372**/\r
913cb9dc 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
739802e4 389 EFI_PHYSICAL_ADDRESS PhyAddr;\r
913cb9dc 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
739802e4 405 PhyAddr = UsbHcGetPciAddressForHostMem (Ehc->MemPool, Ehc->ShortReadStop, sizeof (EHC_QTD));\r
913cb9dc 406 if (Ep->Direction == EfiUsbDataIn) {\r
739802e4 407 AlterNext = QTD_LINK (PhyAddr, FALSE);\r
913cb9dc 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
739802e4 415 Qtd = EhcCreateQtd (Ehc, (UINT8 *)Urb->Request, (UINT8 *)Urb->RequestPhy, Len, QTD_PID_SETUP, 0, Ep->MaxPacket);\r
913cb9dc 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
739802e4 435 StatusQtd = EhcCreateQtd (Ehc, NULL, NULL, 0, Pid, 1, Ep->MaxPacket);\r
913cb9dc 436\r
437 if (StatusQtd == NULL) {\r
438 goto ON_ERROR;\r
439 }\r
440\r
441 if (Ep->Direction == EfiUsbDataIn) {\r
739802e4 442 PhyAddr = UsbHcGetPciAddressForHostMem (Ehc->MemPool, StatusQtd, sizeof (EHC_QTD));\r
443 AlterNext = QTD_LINK (PhyAddr, FALSE);\r
913cb9dc 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
739802e4 464 (UINT8 *) Urb->Data + Len,\r
913cb9dc 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
c52fa98c 483 Toggle = (UINT8) (1 - Toggle);\r
913cb9dc 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
739802e4 510 PhyAddr = UsbHcGetPciAddressForHostMem (Ehc->MemPool, NextQtd, sizeof (EHC_QTD));\r
511 Qtd->QtdHw.NextQtd = QTD_LINK (PhyAddr, FALSE);\r
913cb9dc 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
739802e4 518 PhyAddr = UsbHcGetPciAddressForHostMem (Ehc->MemPool, NextQtd, sizeof (EHC_QTD));\r
519 Qh->QhHw.NextQtd = QTD_LINK (PhyAddr, FALSE);\r
913cb9dc 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
78c2ffb5 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
0cd64525
SZ
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
78c2ffb5 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
913cb9dc 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
0cd64525 561 IN BOOLEAN AllocateCommonBuffer,\r
913cb9dc 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
c52fa98c 589 Ep->EpAddr = (UINT8) (EpAddr & 0x0F);\r
78c2ffb5 590 Ep->Direction = (((EpAddr & 0x80) != 0) ? EfiUsbDataIn : EfiUsbDataOut);\r
913cb9dc 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
0cd64525
SZ
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
913cb9dc 624 Urb->Data = Data;\r
625 Urb->DataLen = DataLen;\r
0cd64525 626 Urb->AllocateCommonBuffer = AllocateCommonBuffer;\r
913cb9dc 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
0cd64525
SZ
656 if (Urb->AllocateCommonBuffer) {\r
657 MapOp = EfiPciIoOperationBusMasterCommonBuffer;\r
913cb9dc 658 } else {\r
0cd64525
SZ
659 if (Ep->Direction == EfiUsbDataIn) {\r
660 MapOp = EfiPciIoOperationBusMasterWrite;\r
661 } else {\r
662 MapOp = EfiPciIoOperationBusMasterRead;\r
663 }\r
913cb9dc 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