]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Bus/Pci/UhciDxe/UhciQueue.c
MdeModulePkg: Replace BSD License with BSD+Patent License
[mirror_edk2.git] / MdeModulePkg / Bus / Pci / UhciDxe / UhciQueue.c
CommitLineData
913cb9dc 1/** @file\r
2\r
ab6495ea 3 The UHCI register operation routines.\r
4\r
cd5ebaa0 5Copyright (c) 2007 - 2010, Intel Corporation. All rights reserved.<BR>\r
9d510e61 6SPDX-License-Identifier: BSD-2-Clause-Patent\r
913cb9dc 7\r
913cb9dc 8**/\r
9\r
10#include "Uhci.h"\r
11\r
12\r
13/**\r
ab6495ea 14 Map address of request structure buffer.\r
913cb9dc 15\r
ab6495ea 16 @param Uhc The UHCI device.\r
17 @param Request The user request buffer.\r
18 @param MappedAddr Mapped address of request.\r
19 @param Map Identificaion of this mapping to return.\r
913cb9dc 20\r
ab6495ea 21 @return EFI_SUCCESS Success.\r
22 @return EFI_DEVICE_ERROR Fail to map the user request.\r
913cb9dc 23\r
24**/\r
25EFI_STATUS\r
26UhciMapUserRequest (\r
27 IN USB_HC_DEV *Uhc,\r
28 IN OUT VOID *Request,\r
29 OUT UINT8 **MappedAddr,\r
30 OUT VOID **Map\r
31 )\r
32{\r
33 EFI_STATUS Status;\r
34 UINTN Len;\r
35 EFI_PHYSICAL_ADDRESS PhyAddr;\r
36\r
37 Len = sizeof (EFI_USB_DEVICE_REQUEST);\r
38 Status = Uhc->PciIo->Map (\r
39 Uhc->PciIo,\r
40 EfiPciIoOperationBusMasterRead,\r
41 Request,\r
42 &Len,\r
43 &PhyAddr,\r
44 Map\r
45 );\r
46\r
47 if (!EFI_ERROR (Status)) {\r
48 *MappedAddr = (UINT8 *) (UINTN) PhyAddr;\r
49 }\r
50\r
51 return Status;\r
52}\r
53\r
54\r
55/**\r
ab6495ea 56 Map address of user data buffer.\r
913cb9dc 57\r
ab6495ea 58 @param Uhc The UHCI device.\r
59 @param Direction Direction of the data transfer.\r
60 @param Data The user data buffer.\r
61 @param Len Length of the user data.\r
62 @param PktId Packet identificaion.\r
63 @param MappedAddr Mapped address to return.\r
64 @param Map Identificaion of this mapping to return.\r
913cb9dc 65\r
ab6495ea 66 @return EFI_SUCCESS Success.\r
67 @return EFI_DEVICE_ERROR Fail to map the user data.\r
913cb9dc 68\r
69**/\r
70EFI_STATUS\r
71UhciMapUserData (\r
72 IN USB_HC_DEV *Uhc,\r
73 IN EFI_USB_DATA_DIRECTION Direction,\r
74 IN VOID *Data,\r
75 IN OUT UINTN *Len,\r
76 OUT UINT8 *PktId,\r
77 OUT UINT8 **MappedAddr,\r
78 OUT VOID **Map\r
79 )\r
80{\r
81 EFI_STATUS Status;\r
82 EFI_PHYSICAL_ADDRESS PhyAddr;\r
83\r
84 Status = EFI_SUCCESS;\r
85\r
86 switch (Direction) {\r
87 case EfiUsbDataIn:\r
88 //\r
89 // BusMasterWrite means cpu read\r
90 //\r
91 *PktId = INPUT_PACKET_ID;\r
92 Status = Uhc->PciIo->Map (\r
93 Uhc->PciIo,\r
94 EfiPciIoOperationBusMasterWrite,\r
95 Data,\r
96 Len,\r
97 &PhyAddr,\r
98 Map\r
99 );\r
100\r
101 if (EFI_ERROR (Status)) {\r
102 goto EXIT;\r
103 }\r
104\r
105 *MappedAddr = (UINT8 *) (UINTN) PhyAddr;\r
106 break;\r
107\r
108 case EfiUsbDataOut:\r
109 *PktId = OUTPUT_PACKET_ID;\r
110 Status = Uhc->PciIo->Map (\r
111 Uhc->PciIo,\r
112 EfiPciIoOperationBusMasterRead,\r
113 Data,\r
114 Len,\r
115 &PhyAddr,\r
116 Map\r
117 );\r
118\r
119 if (EFI_ERROR (Status)) {\r
120 goto EXIT;\r
121 }\r
122\r
123 *MappedAddr = (UINT8 *) (UINTN) PhyAddr;\r
124 break;\r
125\r
126 case EfiUsbNoData:\r
127 if ((Len != NULL) && (*Len != 0)) {\r
128 Status = EFI_INVALID_PARAMETER;\r
129 goto EXIT;\r
130 }\r
131\r
132 *PktId = OUTPUT_PACKET_ID;\r
913cb9dc 133 *MappedAddr = NULL;\r
134 *Map = NULL;\r
135 break;\r
136\r
137 default:\r
138 Status = EFI_INVALID_PARAMETER;\r
139 }\r
140\r
141EXIT:\r
142 return Status;\r
143}\r
144\r
145\r
913cb9dc 146/**\r
ab6495ea 147 Link the TD To QH.\r
913cb9dc 148\r
3af875e2 149 @param Uhc The UHCI device.\r
ab6495ea 150 @param Qh The queue head for the TD to link to.\r
151 @param Td The TD to link.\r
913cb9dc 152\r
913cb9dc 153**/\r
154VOID\r
155UhciLinkTdToQh (\r
3af875e2 156 IN USB_HC_DEV *Uhc,\r
913cb9dc 157 IN UHCI_QH_SW *Qh,\r
158 IN UHCI_TD_SW *Td\r
159 )\r
160{\r
3af875e2 161 EFI_PHYSICAL_ADDRESS PhyAddr;\r
3af875e2 162\r
aa91de05 163 PhyAddr = UsbHcGetPciAddressForHostMem (Uhc->MemPool, Td, sizeof (UHCI_TD_HW));\r
3af875e2 164\r
aa91de05 165 ASSERT ((Qh != NULL) && (Td != NULL));\r
913cb9dc 166\r
3af875e2 167 Qh->QhHw.VerticalLink = QH_VLINK (PhyAddr, FALSE);\r
913cb9dc 168 Qh->TDs = (VOID *) Td;\r
169}\r
170\r
171\r
172/**\r
ab6495ea 173 Unlink TD from the QH.\r
913cb9dc 174\r
ab6495ea 175 @param Qh The queue head to unlink from.\r
176 @param Td The TD to unlink.\r
913cb9dc 177\r
913cb9dc 178**/\r
179VOID\r
180UhciUnlinkTdFromQh (\r
181 IN UHCI_QH_SW *Qh,\r
182 IN UHCI_TD_SW *Td\r
183 )\r
184{\r
185 ASSERT ((Qh != NULL) && (Td != NULL));\r
186\r
187 Qh->QhHw.VerticalLink = QH_VLINK (NULL, TRUE);\r
188 Qh->TDs = NULL;\r
189}\r
190\r
191\r
192/**\r
ab6495ea 193 Append a new TD To the previous TD.\r
913cb9dc 194\r
3af875e2 195 @param Uhc The UHCI device.\r
ab6495ea 196 @param PrevTd Previous UHCI_TD_SW to be linked to.\r
197 @param ThisTd TD to link.\r
913cb9dc 198\r
913cb9dc 199**/\r
913cb9dc 200VOID\r
201UhciAppendTd (\r
3af875e2 202 IN USB_HC_DEV *Uhc,\r
913cb9dc 203 IN UHCI_TD_SW *PrevTd,\r
204 IN UHCI_TD_SW *ThisTd\r
205 )\r
206{\r
3af875e2 207 EFI_PHYSICAL_ADDRESS PhyAddr;\r
913cb9dc 208\r
aa91de05 209 PhyAddr = UsbHcGetPciAddressForHostMem (Uhc->MemPool, ThisTd, sizeof (UHCI_TD_HW));\r
3af875e2 210\r
aa91de05 211 ASSERT ((PrevTd != NULL) && (ThisTd != NULL));\r
3af875e2 212\r
213 PrevTd->TdHw.NextLink = TD_LINK (PhyAddr, TRUE, FALSE);\r
913cb9dc 214 PrevTd->NextTd = (VOID *) ThisTd;\r
215}\r
216\r
217\r
218/**\r
ab6495ea 219 Delete a list of TDs.\r
913cb9dc 220\r
ab6495ea 221 @param Uhc The UHCI device.\r
222 @param FirstTd TD link list head.\r
913cb9dc 223\r
ab6495ea 224 @return None.\r
913cb9dc 225\r
226**/\r
227VOID\r
228UhciDestoryTds (\r
229 IN USB_HC_DEV *Uhc,\r
230 IN UHCI_TD_SW *FirstTd\r
231 )\r
232{\r
233 UHCI_TD_SW *NextTd;\r
234 UHCI_TD_SW *ThisTd;\r
235\r
236 NextTd = FirstTd;\r
237\r
238 while (NextTd != NULL) {\r
239 ThisTd = NextTd;\r
240 NextTd = ThisTd->NextTd;\r
241 UsbHcFreeMem (Uhc->MemPool, ThisTd, sizeof (UHCI_TD_SW));\r
242 }\r
243}\r
244\r
245\r
246/**\r
ab6495ea 247 Create an initialize a new queue head.\r
913cb9dc 248\r
ab6495ea 249 @param Uhc The UHCI device.\r
250 @param Interval The polling interval for the queue.\r
913cb9dc 251\r
ab6495ea 252 @return The newly created queue header.\r
913cb9dc 253\r
254**/\r
255UHCI_QH_SW *\r
256UhciCreateQh (\r
257 IN USB_HC_DEV *Uhc,\r
258 IN UINTN Interval\r
259 )\r
260{\r
261 UHCI_QH_SW *Qh;\r
262\r
263 Qh = UsbHcAllocateMem (Uhc->MemPool, sizeof (UHCI_QH_SW));\r
264\r
265 if (Qh == NULL) {\r
266 return NULL;\r
267 }\r
268\r
269 Qh->QhHw.HorizonLink = QH_HLINK (NULL, TRUE);\r
270 Qh->QhHw.VerticalLink = QH_VLINK (NULL, TRUE);\r
b4c24e2d 271 Qh->Interval = UhciConvertPollRate(Interval);\r
913cb9dc 272 Qh->TDs = NULL;\r
273 Qh->NextQh = NULL;\r
274\r
275 return Qh;\r
276}\r
277\r
278\r
279/**\r
ab6495ea 280 Create and intialize a TD.\r
913cb9dc 281\r
ab6495ea 282 @param Uhc The UHCI device.\r
913cb9dc 283\r
ab6495ea 284 @return The newly allocated and initialized TD.\r
913cb9dc 285\r
286**/\r
913cb9dc 287UHCI_TD_SW *\r
288UhciCreateTd (\r
289 IN USB_HC_DEV *Uhc\r
290 )\r
291{\r
292 UHCI_TD_SW *Td;\r
293\r
294 Td = UsbHcAllocateMem (Uhc->MemPool, sizeof (UHCI_TD_SW));\r
295 if (Td == NULL) {\r
296 return NULL;\r
297 }\r
298\r
aa91de05 299 Td->TdHw.NextLink = TD_LINK (NULL, FALSE, TRUE);\r
913cb9dc 300 Td->NextTd = NULL;\r
301 Td->Data = NULL;\r
302 Td->DataLen = 0;\r
303\r
304 return Td;\r
305}\r
306\r
307\r
308/**\r
ab6495ea 309 Create and initialize a TD for Setup Stage of a control transfer.\r
913cb9dc 310\r
ab6495ea 311 @param Uhc The UHCI device.\r
312 @param DevAddr Device address.\r
3af875e2 313 @param Request A pointer to cpu memory address of Device request.\r
314 @param RequestPhy A pointer to pci memory address of Device request.\r
ab6495ea 315 @param IsLow Full speed or low speed.\r
913cb9dc 316\r
ab6495ea 317 @return The created setup Td Pointer.\r
913cb9dc 318\r
319**/\r
913cb9dc 320UHCI_TD_SW *\r
321UhciCreateSetupTd (\r
322 IN USB_HC_DEV *Uhc,\r
323 IN UINT8 DevAddr,\r
324 IN UINT8 *Request,\r
3af875e2 325 IN UINT8 *RequestPhy,\r
913cb9dc 326 IN BOOLEAN IsLow\r
327 )\r
328{\r
329 UHCI_TD_SW *Td;\r
330\r
331 Td = UhciCreateTd (Uhc);\r
332\r
333 if (Td == NULL) {\r
334 return NULL;\r
335 }\r
336\r
337 Td->TdHw.NextLink = TD_LINK (NULL, TRUE, TRUE);\r
338 Td->TdHw.ShortPacket = FALSE;\r
339 Td->TdHw.IsIsoch = FALSE;\r
340 Td->TdHw.IntOnCpl = FALSE;\r
341 Td->TdHw.ErrorCount = 0x03;\r
342 Td->TdHw.Status |= USBTD_ACTIVE;\r
343 Td->TdHw.DataToggle = 0;\r
344 Td->TdHw.EndPoint = 0;\r
345 Td->TdHw.LowSpeed = IsLow ? 1 : 0;\r
346 Td->TdHw.DeviceAddr = DevAddr & 0x7F;\r
347 Td->TdHw.MaxPacketLen = (UINT32) (sizeof (EFI_USB_DEVICE_REQUEST) - 1);\r
348 Td->TdHw.PidCode = SETUP_PACKET_ID;\r
3af875e2 349 Td->TdHw.DataBuffer = (UINT32) (UINTN) RequestPhy;\r
913cb9dc 350\r
351 Td->Data = Request;\r
c9325700 352 Td->DataLen = (UINT16) sizeof (EFI_USB_DEVICE_REQUEST);\r
913cb9dc 353\r
354 return Td;\r
355}\r
356\r
357\r
358/**\r
ab6495ea 359 Create a TD for data.\r
913cb9dc 360\r
ab6495ea 361 @param Uhc The UHCI device.\r
362 @param DevAddr Device address.\r
363 @param Endpoint Endpoint number.\r
3af875e2 364 @param DataPtr A pointer to cpu memory address of Data buffer.\r
365 @param DataPhyPtr A pointer to pci memory address of Data buffer.\r
ab6495ea 366 @param Len Data length.\r
367 @param PktId Packet ID.\r
368 @param Toggle Data toggle value.\r
369 @param IsLow Full speed or low speed.\r
913cb9dc 370\r
ab6495ea 371 @return Data Td pointer if success, otherwise NULL.\r
913cb9dc 372\r
373**/\r
913cb9dc 374UHCI_TD_SW *\r
375UhciCreateDataTd (\r
376 IN USB_HC_DEV *Uhc,\r
377 IN UINT8 DevAddr,\r
378 IN UINT8 Endpoint,\r
379 IN UINT8 *DataPtr,\r
3af875e2 380 IN UINT8 *DataPhyPtr,\r
913cb9dc 381 IN UINTN Len,\r
382 IN UINT8 PktId,\r
383 IN UINT8 Toggle,\r
384 IN BOOLEAN IsLow\r
385 )\r
386{\r
387 UHCI_TD_SW *Td;\r
388\r
389 //\r
390 // Code as length - 1, and the max valid length is 0x500\r
391 //\r
392 ASSERT (Len <= 0x500);\r
393\r
394 Td = UhciCreateTd (Uhc);\r
395\r
396 if (Td == NULL) {\r
397 return NULL;\r
398 }\r
399\r
400 Td->TdHw.NextLink = TD_LINK (NULL, TRUE, TRUE);\r
401 Td->TdHw.ShortPacket = FALSE;\r
402 Td->TdHw.IsIsoch = FALSE;\r
403 Td->TdHw.IntOnCpl = FALSE;\r
aa91de05 404 Td->TdHw.ErrorCount = 0x03;\r
913cb9dc 405 Td->TdHw.Status = USBTD_ACTIVE;\r
406 Td->TdHw.LowSpeed = IsLow ? 1 : 0;\r
407 Td->TdHw.DataToggle = Toggle & 0x01;\r
408 Td->TdHw.EndPoint = Endpoint & 0x0F;\r
409 Td->TdHw.DeviceAddr = DevAddr & 0x7F;\r
410 Td->TdHw.MaxPacketLen = (UINT32) (Len - 1);\r
411 Td->TdHw.PidCode = (UINT8) PktId;\r
3af875e2 412 Td->TdHw.DataBuffer = (UINT32) (UINTN) DataPhyPtr;\r
913cb9dc 413\r
414 Td->Data = DataPtr;\r
415 Td->DataLen = (UINT16) Len;\r
416\r
417 return Td;\r
418}\r
419\r
420\r
421/**\r
ab6495ea 422 Create TD for the Status Stage of control transfer.\r
913cb9dc 423\r
ab6495ea 424 @param Uhc The UHCI device.\r
425 @param DevAddr Device address.\r
426 @param PktId Packet ID.\r
427 @param IsLow Full speed or low speed.\r
913cb9dc 428\r
ab6495ea 429 @return Status Td Pointer.\r
913cb9dc 430\r
431**/\r
913cb9dc 432UHCI_TD_SW *\r
433UhciCreateStatusTd (\r
434 IN USB_HC_DEV *Uhc,\r
435 IN UINT8 DevAddr,\r
436 IN UINT8 PktId,\r
437 IN BOOLEAN IsLow\r
438 )\r
439{\r
440 UHCI_TD_SW *Td;\r
441\r
442 Td = UhciCreateTd (Uhc);\r
443\r
444 if (Td == NULL) {\r
445 return NULL;\r
446 }\r
447\r
448 Td->TdHw.NextLink = TD_LINK (NULL, TRUE, TRUE);\r
449 Td->TdHw.ShortPacket = FALSE;\r
450 Td->TdHw.IsIsoch = FALSE;\r
451 Td->TdHw.IntOnCpl = FALSE;\r
452 Td->TdHw.ErrorCount = 0x03;\r
453 Td->TdHw.Status |= USBTD_ACTIVE;\r
454 Td->TdHw.MaxPacketLen = 0x7FF; //0x7FF: there is no data (refer to UHCI spec)\r
455 Td->TdHw.DataToggle = 1;\r
456 Td->TdHw.EndPoint = 0;\r
457 Td->TdHw.LowSpeed = IsLow ? 1 : 0;\r
458 Td->TdHw.DeviceAddr = DevAddr & 0x7F;\r
459 Td->TdHw.PidCode = (UINT8) PktId;\r
460 Td->TdHw.DataBuffer = (UINT32) (UINTN) NULL;\r
461\r
462 Td->Data = NULL;\r
463 Td->DataLen = 0;\r
464\r
465 return Td;\r
466}\r
467\r
468\r
469/**\r
ab6495ea 470 Create Tds list for Control Transfer.\r
913cb9dc 471\r
ab6495ea 472 @param Uhc The UHCI device.\r
473 @param DeviceAddr The device address.\r
474 @param DataPktId Packet Identification of Data Tds.\r
3af875e2 475 @param Request A pointer to cpu memory address of request structure buffer to transfer.\r
476 @param RequestPhy A pointer to pci memory address of request structure buffer to transfer.\r
477 @param Data A pointer to cpu memory address of user data buffer to transfer.\r
478 @param DataPhy A pointer to pci memory address of user data buffer to transfer.\r
ab6495ea 479 @param DataLen Length of user data to transfer.\r
480 @param MaxPacket Maximum packet size for control transfer.\r
481 @param IsLow Full speed or low speed.\r
913cb9dc 482\r
ab6495ea 483 @return The Td list head for the control transfer.\r
913cb9dc 484\r
485**/\r
486UHCI_TD_SW *\r
487UhciCreateCtrlTds (\r
488 IN USB_HC_DEV *Uhc,\r
489 IN UINT8 DeviceAddr,\r
490 IN UINT8 DataPktId,\r
491 IN UINT8 *Request,\r
3af875e2 492 IN UINT8 *RequestPhy,\r
913cb9dc 493 IN UINT8 *Data,\r
3af875e2 494 IN UINT8 *DataPhy,\r
913cb9dc 495 IN UINTN DataLen,\r
496 IN UINT8 MaxPacket,\r
497 IN BOOLEAN IsLow\r
498 )\r
499{\r
500 UHCI_TD_SW *SetupTd;\r
501 UHCI_TD_SW *FirstDataTd;\r
502 UHCI_TD_SW *DataTd;\r
503 UHCI_TD_SW *PrevDataTd;\r
504 UHCI_TD_SW *StatusTd;\r
505 UINT8 DataToggle;\r
506 UINT8 StatusPktId;\r
507 UINTN ThisTdLen;\r
508\r
509\r
510 DataTd = NULL;\r
511 SetupTd = NULL;\r
512 FirstDataTd = NULL;\r
513 PrevDataTd = NULL;\r
514 StatusTd = NULL;\r
515\r
516 //\r
517 // Create setup packets for the transfer\r
518 //\r
3af875e2 519 SetupTd = UhciCreateSetupTd (Uhc, DeviceAddr, Request, RequestPhy, IsLow);\r
913cb9dc 520\r
521 if (SetupTd == NULL) {\r
522 return NULL;\r
523 }\r
524\r
525 //\r
526 // Create data packets for the transfer\r
527 //\r
528 DataToggle = 1;\r
529\r
530 while (DataLen > 0) {\r
531 //\r
532 // PktSize is the data load size in each Td.\r
533 //\r
534 ThisTdLen = (DataLen > MaxPacket ? MaxPacket : DataLen);\r
535\r
536 DataTd = UhciCreateDataTd (\r
537 Uhc,\r
538 DeviceAddr,\r
539 0,\r
3af875e2 540 Data, //cpu memory address\r
541 DataPhy, //Pci memory address\r
913cb9dc 542 ThisTdLen,\r
543 DataPktId,\r
544 DataToggle,\r
545 IsLow\r
546 );\r
547\r
548 if (DataTd == NULL) {\r
549 goto FREE_TD;\r
550 }\r
551\r
552 if (FirstDataTd == NULL) {\r
553 FirstDataTd = DataTd;\r
554 FirstDataTd->NextTd = NULL;\r
555 } else {\r
3af875e2 556 UhciAppendTd (Uhc, PrevDataTd, DataTd);\r
913cb9dc 557 }\r
558\r
559 DataToggle ^= 1;\r
560 PrevDataTd = DataTd;\r
561 Data += ThisTdLen;\r
3af875e2 562 DataPhy += ThisTdLen;\r
913cb9dc 563 DataLen -= ThisTdLen;\r
564 }\r
565\r
566 //\r
567 // Status packet is on the opposite direction to data packets\r
568 //\r
569 if (OUTPUT_PACKET_ID == DataPktId) {\r
570 StatusPktId = INPUT_PACKET_ID;\r
571 } else {\r
572 StatusPktId = OUTPUT_PACKET_ID;\r
573 }\r
574\r
575 StatusTd = UhciCreateStatusTd (Uhc, DeviceAddr, StatusPktId, IsLow);\r
576\r
577 if (StatusTd == NULL) {\r
578 goto FREE_TD;\r
579 }\r
580\r
581 //\r
582 // Link setup Td -> data Tds -> status Td together\r
583 //\r
584 if (FirstDataTd != NULL) {\r
3af875e2 585 UhciAppendTd (Uhc, SetupTd, FirstDataTd);\r
586 UhciAppendTd (Uhc, PrevDataTd, StatusTd);\r
913cb9dc 587 } else {\r
3af875e2 588 UhciAppendTd (Uhc, SetupTd, StatusTd);\r
913cb9dc 589 }\r
590\r
591 return SetupTd;\r
592\r
593FREE_TD:\r
594 if (SetupTd != NULL) {\r
595 UhciDestoryTds (Uhc, SetupTd);\r
596 }\r
597\r
598 if (FirstDataTd != NULL) {\r
599 UhciDestoryTds (Uhc, FirstDataTd);\r
600 }\r
601\r
602 return NULL;\r
603}\r
604\r
605\r
606/**\r
ab6495ea 607 Create Tds list for Bulk/Interrupt Transfer.\r
608\r
609 @param Uhc USB_HC_DEV.\r
610 @param DevAddr Address of Device.\r
611 @param EndPoint Endpoint Number.\r
612 @param PktId Packet Identification of Data Tds.\r
3af875e2 613 @param Data A pointer to cpu memory address of user data buffer to transfer.\r
614 @param DataPhy A pointer to pci memory address of user data buffer to transfer.\r
ab6495ea 615 @param DataLen Length of user data to transfer.\r
616 @param DataToggle Data Toggle Pointer.\r
617 @param MaxPacket Maximum packet size for Bulk/Interrupt transfer.\r
618 @param IsLow Is Low Speed Device.\r
619\r
620 @return The Tds list head for the bulk transfer.\r
913cb9dc 621\r
622**/\r
623UHCI_TD_SW *\r
624UhciCreateBulkOrIntTds (\r
625 IN USB_HC_DEV *Uhc,\r
626 IN UINT8 DevAddr,\r
627 IN UINT8 EndPoint,\r
628 IN UINT8 PktId,\r
629 IN UINT8 *Data,\r
3af875e2 630 IN UINT8 *DataPhy,\r
913cb9dc 631 IN UINTN DataLen,\r
632 IN OUT UINT8 *DataToggle,\r
633 IN UINT8 MaxPacket,\r
634 IN BOOLEAN IsLow\r
635 )\r
636{\r
637 UHCI_TD_SW *DataTd;\r
638 UHCI_TD_SW *FirstDataTd;\r
639 UHCI_TD_SW *PrevDataTd;\r
640 UINTN ThisTdLen;\r
641\r
642 DataTd = NULL;\r
643 FirstDataTd = NULL;\r
644 PrevDataTd = NULL;\r
645\r
646 //\r
647 // Create data packets for the transfer\r
648 //\r
649 while (DataLen > 0) {\r
650 //\r
651 // PktSize is the data load size that each Td.\r
652 //\r
653 ThisTdLen = DataLen;\r
654\r
655 if (DataLen > MaxPacket) {\r
656 ThisTdLen = MaxPacket;\r
657 }\r
658\r
659 DataTd = UhciCreateDataTd (\r
660 Uhc,\r
661 DevAddr,\r
662 EndPoint,\r
663 Data,\r
3af875e2 664 DataPhy,\r
913cb9dc 665 ThisTdLen,\r
666 PktId,\r
667 *DataToggle,\r
668 IsLow\r
669 );\r
670\r
671 if (DataTd == NULL) {\r
672 goto FREE_TD;\r
673 }\r
674\r
675 if (PktId == INPUT_PACKET_ID) {\r
676 DataTd->TdHw.ShortPacket = TRUE;\r
677 }\r
678\r
679 if (FirstDataTd == NULL) {\r
680 FirstDataTd = DataTd;\r
681 FirstDataTd->NextTd = NULL;\r
682 } else {\r
3af875e2 683 UhciAppendTd (Uhc, PrevDataTd, DataTd);\r
913cb9dc 684 }\r
685\r
686 *DataToggle ^= 1;\r
687 PrevDataTd = DataTd;\r
688 Data += ThisTdLen;\r
3af875e2 689 DataPhy += ThisTdLen;\r
913cb9dc 690 DataLen -= ThisTdLen;\r
691 }\r
692\r
693 return FirstDataTd;\r
694\r
695FREE_TD:\r
696 if (FirstDataTd != NULL) {\r
697 UhciDestoryTds (Uhc, FirstDataTd);\r
698 }\r
699\r
700 return NULL;\r
701}\r