]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Bus/Pci/EhciDxe/EhciUrb.c
Revert "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
342 if (Urb->Qh != NULL) {\r
343 //\r
344 // Ensure that this queue head has been unlinked from the\r
345 // schedule data structures. Free all the associated QTDs\r
346 //\r
347 EhcFreeQtds (Ehc, &Urb->Qh->Qtds);\r
348 UsbHcFreeMem (Ehc->MemPool, Urb->Qh, sizeof (EHC_QH));\r
349 }\r
350\r
351 gBS->FreePool (Urb);\r
352}\r
353\r
354\r
913cb9dc 355/**\r
78c2ffb5 356 Create a list of QTDs for the URB.\r
913cb9dc 357\r
78c2ffb5 358 @param Ehc The EHCI device.\r
359 @param Urb The URB to create QTDs for.\r
913cb9dc 360\r
78c2ffb5 361 @retval EFI_OUT_OF_RESOURCES Failed to allocate resource for QTD.\r
362 @retval EFI_SUCCESS The QTDs are allocated for the URB.\r
913cb9dc 363\r
364**/\r
913cb9dc 365EFI_STATUS\r
366EhcCreateQtds (\r
367 IN USB2_HC_DEV *Ehc,\r
368 IN URB *Urb\r
369 )\r
370{\r
371 USB_ENDPOINT *Ep;\r
372 EHC_QH *Qh;\r
373 EHC_QTD *Qtd;\r
374 EHC_QTD *StatusQtd;\r
375 EHC_QTD *NextQtd;\r
376 LIST_ENTRY *Entry;\r
377 UINT32 AlterNext;\r
378 UINT8 Toggle;\r
379 UINTN Len;\r
380 UINT8 Pid;\r
739802e4 381 EFI_PHYSICAL_ADDRESS PhyAddr;\r
913cb9dc 382\r
383 ASSERT ((Urb != NULL) && (Urb->Qh != NULL));\r
384\r
385 //\r
386 // EHCI follows the alternet next QTD pointer if it meets\r
387 // a short read and the AlterNext pointer is valid. UEFI\r
388 // EHCI driver should terminate the transfer except the\r
389 // control transfer.\r
390 //\r
391 Toggle = 0;\r
392 Qh = Urb->Qh;\r
393 Ep = &Urb->Ep;\r
394 StatusQtd = NULL;\r
395 AlterNext = QTD_LINK (NULL, TRUE);\r
396\r
739802e4 397 PhyAddr = UsbHcGetPciAddressForHostMem (Ehc->MemPool, Ehc->ShortReadStop, sizeof (EHC_QTD));\r
913cb9dc 398 if (Ep->Direction == EfiUsbDataIn) {\r
739802e4 399 AlterNext = QTD_LINK (PhyAddr, FALSE);\r
913cb9dc 400 }\r
401\r
402 //\r
403 // Build the Setup and status packets for control transfer\r
404 //\r
405 if (Urb->Ep.Type == EHC_CTRL_TRANSFER) {\r
406 Len = sizeof (EFI_USB_DEVICE_REQUEST);\r
739802e4 407 Qtd = EhcCreateQtd (Ehc, (UINT8 *)Urb->Request, (UINT8 *)Urb->RequestPhy, Len, QTD_PID_SETUP, 0, Ep->MaxPacket);\r
913cb9dc 408\r
409 if (Qtd == NULL) {\r
410 return EFI_OUT_OF_RESOURCES;\r
411 }\r
412\r
413 InsertTailList (&Qh->Qtds, &Qtd->QtdList);\r
414\r
415 //\r
416 // Create the status packet now. Set the AlterNext to it. So, when\r
417 // EHCI meets a short control read, it can resume at the status stage.\r
418 // Use the opposite direction of the data stage, or IN if there is\r
419 // no data stage.\r
420 //\r
421 if (Ep->Direction == EfiUsbDataIn) {\r
422 Pid = QTD_PID_OUTPUT;\r
423 } else {\r
424 Pid = QTD_PID_INPUT;\r
425 }\r
426\r
739802e4 427 StatusQtd = EhcCreateQtd (Ehc, NULL, NULL, 0, Pid, 1, Ep->MaxPacket);\r
913cb9dc 428\r
429 if (StatusQtd == NULL) {\r
430 goto ON_ERROR;\r
431 }\r
432\r
433 if (Ep->Direction == EfiUsbDataIn) {\r
739802e4 434 PhyAddr = UsbHcGetPciAddressForHostMem (Ehc->MemPool, StatusQtd, sizeof (EHC_QTD));\r
435 AlterNext = QTD_LINK (PhyAddr, FALSE);\r
913cb9dc 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
739802e4 456 (UINT8 *) Urb->Data + Len,\r
913cb9dc 457 (UINT8 *) Urb->DataPhy + Len,\r
458 Urb->DataLen - Len,\r
459 Pid,\r
460 Toggle,\r
461 Ep->MaxPacket\r
462 );\r
463\r
464 if (Qtd == NULL) {\r
465 goto ON_ERROR;\r
466 }\r
467\r
468 Qtd->QtdHw.AltNext = AlterNext;\r
469 InsertTailList (&Qh->Qtds, &Qtd->QtdList);\r
470\r
471 //\r
472 // Switch the Toggle bit if odd number of packets are included in the QTD.\r
473 //\r
474 if (((Qtd->DataLen + Ep->MaxPacket - 1) / Ep->MaxPacket) % 2) {\r
c52fa98c 475 Toggle = (UINT8) (1 - Toggle);\r
913cb9dc 476 }\r
477\r
478 Len += Qtd->DataLen;\r
479 }\r
480\r
481 //\r
482 // Insert the status packet for control transfer\r
483 //\r
484 if (Ep->Type == EHC_CTRL_TRANSFER) {\r
485 InsertTailList (&Qh->Qtds, &StatusQtd->QtdList);\r
486 }\r
487\r
488 //\r
489 // OK, all the QTDs needed are created. Now, fix the NextQtd point\r
490 //\r
491 EFI_LIST_FOR_EACH (Entry, &Qh->Qtds) {\r
492 Qtd = EFI_LIST_CONTAINER (Entry, EHC_QTD, QtdList);\r
493\r
494 //\r
495 // break if it is the last entry on the list\r
496 //\r
497 if (Entry->ForwardLink == &Qh->Qtds) {\r
498 break;\r
499 }\r
500\r
501 NextQtd = EFI_LIST_CONTAINER (Entry->ForwardLink, EHC_QTD, QtdList);\r
739802e4 502 PhyAddr = UsbHcGetPciAddressForHostMem (Ehc->MemPool, NextQtd, sizeof (EHC_QTD));\r
503 Qtd->QtdHw.NextQtd = QTD_LINK (PhyAddr, FALSE);\r
913cb9dc 504 }\r
505\r
506 //\r
507 // Link the QTDs to the queue head\r
508 //\r
509 NextQtd = EFI_LIST_CONTAINER (Qh->Qtds.ForwardLink, EHC_QTD, QtdList);\r
739802e4 510 PhyAddr = UsbHcGetPciAddressForHostMem (Ehc->MemPool, NextQtd, sizeof (EHC_QTD));\r
511 Qh->QhHw.NextQtd = QTD_LINK (PhyAddr, FALSE);\r
913cb9dc 512 return EFI_SUCCESS;\r
513\r
514ON_ERROR:\r
515 EhcFreeQtds (Ehc, &Qh->Qtds);\r
516 return EFI_OUT_OF_RESOURCES;\r
517}\r
518\r
519\r
520/**\r
78c2ffb5 521 Create a new URB and its associated QTD.\r
522\r
523 @param Ehc The EHCI device.\r
524 @param DevAddr The device address.\r
525 @param EpAddr Endpoint addrress & its direction.\r
526 @param DevSpeed The device speed.\r
527 @param Toggle Initial data toggle to use.\r
528 @param MaxPacket The max packet length of the endpoint.\r
529 @param Hub The transaction translator to use.\r
530 @param Type The transaction type.\r
531 @param Request The standard USB request for control transfer.\r
f87db256 532 @param Data The user data to transfer.\r
78c2ffb5 533 @param DataLen The length of data buffer.\r
534 @param Callback The function to call when data is transferred.\r
535 @param Context The context to the callback.\r
536 @param Interval The interval for interrupt transfer.\r
537\r
538 @return Created URB or NULL.\r
913cb9dc 539\r
540**/\r
541URB *\r
542EhcCreateUrb (\r
543 IN USB2_HC_DEV *Ehc,\r
544 IN UINT8 DevAddr,\r
545 IN UINT8 EpAddr,\r
546 IN UINT8 DevSpeed,\r
547 IN UINT8 Toggle,\r
548 IN UINTN MaxPacket,\r
549 IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Hub,\r
550 IN UINTN Type,\r
551 IN EFI_USB_DEVICE_REQUEST *Request,\r
552 IN VOID *Data,\r
553 IN UINTN DataLen,\r
554 IN EFI_ASYNC_USB_TRANSFER_CALLBACK Callback,\r
555 IN VOID *Context,\r
556 IN UINTN Interval\r
557 )\r
558{\r
559 USB_ENDPOINT *Ep;\r
560 EFI_PHYSICAL_ADDRESS PhyAddr;\r
561 EFI_PCI_IO_PROTOCOL_OPERATION MapOp;\r
562 EFI_PCI_IO_PROTOCOL *PciIo;\r
563 EFI_STATUS Status;\r
564 UINTN Len;\r
565 URB *Urb;\r
566 VOID *Map;\r
567\r
568 Urb = AllocateZeroPool (sizeof (URB));\r
569\r
570 if (Urb == NULL) {\r
571 return NULL;\r
572 }\r
573\r
574 Urb->Signature = EHC_URB_SIG;\r
575 InitializeListHead (&Urb->UrbList);\r
576\r
577 Ep = &Urb->Ep;\r
578 Ep->DevAddr = DevAddr;\r
c52fa98c 579 Ep->EpAddr = (UINT8) (EpAddr & 0x0F);\r
78c2ffb5 580 Ep->Direction = (((EpAddr & 0x80) != 0) ? EfiUsbDataIn : EfiUsbDataOut);\r
913cb9dc 581 Ep->DevSpeed = DevSpeed;\r
582 Ep->MaxPacket = MaxPacket;\r
583\r
584 Ep->HubAddr = 0;\r
585 Ep->HubPort = 0;\r
586\r
587 if (DevSpeed != EFI_USB_SPEED_HIGH) {\r
588 ASSERT (Hub != NULL);\r
589\r
590 Ep->HubAddr = Hub->TranslatorHubAddress;\r
591 Ep->HubPort = Hub->TranslatorPortNumber;\r
592 }\r
593\r
594 Ep->Toggle = Toggle;\r
595 Ep->Type = Type;\r
596 Ep->PollRate = EhcConvertPollRate (Interval);\r
597\r
598 Urb->Request = Request;\r
599 Urb->Data = Data;\r
600 Urb->DataLen = DataLen;\r
601 Urb->Callback = Callback;\r
602 Urb->Context = Context;\r
603\r
604 PciIo = Ehc->PciIo;\r
605 Urb->Qh = EhcCreateQh (Ehc, &Urb->Ep);\r
606\r
607 if (Urb->Qh == NULL) {\r
608 goto ON_ERROR;\r
609 }\r
610\r
611 //\r
612 // Map the request and user data\r
613 //\r
614 if (Request != NULL) {\r
615 Len = sizeof (EFI_USB_DEVICE_REQUEST);\r
616 MapOp = EfiPciIoOperationBusMasterRead;\r
617 Status = PciIo->Map (PciIo, MapOp, Request, &Len, &PhyAddr, &Map);\r
618\r
619 if (EFI_ERROR (Status) || (Len != sizeof (EFI_USB_DEVICE_REQUEST))) {\r
620 goto ON_ERROR;\r
621 }\r
622\r
623 Urb->RequestPhy = (VOID *) ((UINTN) PhyAddr);\r
624 Urb->RequestMap = Map;\r
625 }\r
626\r
627 if (Data != NULL) {\r
628 Len = DataLen;\r
629\r
f87db256
SZ
630 if (Ep->Direction == EfiUsbDataIn) {\r
631 MapOp = EfiPciIoOperationBusMasterWrite;\r
913cb9dc 632 } else {\r
f87db256 633 MapOp = EfiPciIoOperationBusMasterRead;\r
913cb9dc 634 }\r
635\r
636 Status = PciIo->Map (PciIo, MapOp, Data, &Len, &PhyAddr, &Map);\r
637\r
638 if (EFI_ERROR (Status) || (Len != DataLen)) {\r
639 goto ON_ERROR;\r
640 }\r
641\r
642 Urb->DataPhy = (VOID *) ((UINTN) PhyAddr);\r
643 Urb->DataMap = Map;\r
644 }\r
645\r
646 Status = EhcCreateQtds (Ehc, Urb);\r
647\r
648 if (EFI_ERROR (Status)) {\r
649 goto ON_ERROR;\r
650 }\r
651\r
652 return Urb;\r
653\r
654ON_ERROR:\r
655 EhcFreeUrb (Ehc, Urb);\r
656 return NULL;\r
657}\r