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