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