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