3 Copyright (c) 2007, Intel Corporation
4 All rights reserved. This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution. The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
18 This file contains URB request, each request is warpped in a
19 URB (Usb Request Block)
29 Create a single QTD to hold the data
31 @param Ehc The EHCI device
32 @param Data Current data not associated with a QTD
33 @param DataLen The length of the data
34 @param PktId Packet ID to use in the QTD
35 @param Toggle Data toggle to use in the QTD
36 @param MaxPacket Maximu packet length of the endpoint
38 @return Created QTD or NULL if failed to create one
59 Qtd
= UsbHcAllocateMem (Ehc
->MemPool
, sizeof (EHC_QTD
));
65 Qtd
->Signature
= EHC_QTD_SIG
;
69 InitializeListHead (&Qtd
->QtdList
);
72 QtdHw
->NextQtd
= QTD_LINK (NULL
, TRUE
);
73 QtdHw
->AltNext
= QTD_LINK (NULL
, TRUE
);
74 QtdHw
->Status
= QTD_STAT_ACTIVE
;
76 QtdHw
->ErrCnt
= QTD_MAX_ERR
;
78 QtdHw
->TotalBytes
= 0;
79 QtdHw
->DataToggle
= Toggle
;
82 // Fill in the buffer points
87 for (Index
= 0; Index
<= QTD_MAX_BUFFER
; Index
++) {
89 // Set the buffer point (Check page 41 EHCI Spec 1.0). No need to
90 // compute the offset and clear Reserved fields. This is already
91 // done in the data point.
93 QtdHw
->Page
[Index
] = EHC_LOW_32BIT (Data
);
94 QtdHw
->PageHigh
[Index
] = EHC_HIGH_32BIT (Data
);
96 ThisBufLen
= QTD_BUF_LEN
- (EHC_LOW_32BIT (Data
) & QTD_BUF_MASK
);
98 if (Len
+ ThisBufLen
>= DataLen
) {
108 // Need to fix the last pointer if the Qtd can't hold all the
109 // user's data to make sure that the length is in the unit of
110 // max packets. If it can hold all the data, there is no such
114 Len
= Len
- Len
% MaxPacket
;
117 QtdHw
->TotalBytes
= (UINT32
) Len
;
127 Initialize the queue head for interrupt transfer,
128 that is, initialize the following three fields:
129 1. SplitXState in the Status field
133 @param Ep The queue head's related endpoint
134 @param QhHw The queue head to initialize
147 // Because UEFI interface can't utilitize an endpoint with
148 // poll rate faster than 1ms, only need to set one bit in
149 // the queue head. simple. But it may be changed later. If
150 // sub-1ms interrupt is supported, need to update the S-Mask
153 if (Ep
->DevSpeed
== EFI_USB_SPEED_HIGH
) {
154 QhHw
->SMask
= QH_MICROFRAME_0
;
159 // For low/full speed device, the transfer must go through
160 // the split transaction. Need to update three fields
161 // 1. SplitXState in the status
162 // 2. Microframe S-Mask
163 // 3. Microframe C-Mask
164 // UEFI USB doesn't exercise admission control. It simplely
165 // schedule the high speed transactions in microframe 0, and
166 // full/low speed transactions at microframe 1. This also
167 // avoid the use of FSTN.
169 QhHw
->SMask
= QH_MICROFRAME_1
;
170 QhHw
->CMask
= QH_MICROFRAME_3
| QH_MICROFRAME_4
| QH_MICROFRAME_5
;
176 Allocate and initialize a EHCI queue head
178 @param Ehci The EHCI device
179 @param Ep The endpoint to create queue head for
181 @return Created queue head or NULL if failed to create one
186 IN USB2_HC_DEV
*Ehci
,
193 Qh
= UsbHcAllocateMem (Ehci
->MemPool
, sizeof (EHC_QH
));
199 Qh
->Signature
= EHC_QH_SIG
;
201 Qh
->Interval
= Ep
->PollRate
;
203 InitializeListHead (&Qh
->Qtds
);
206 QhHw
->HorizonLink
= QH_LINK (NULL
, 0, TRUE
);
207 QhHw
->DeviceAddr
= Ep
->DevAddr
;
209 QhHw
->EpNum
= Ep
->EpAddr
;
210 QhHw
->EpSpeed
= Ep
->DevSpeed
;
212 QhHw
->ReclaimHead
= 0;
213 QhHw
->MaxPacketLen
= (UINT32
) Ep
->MaxPacket
;
215 QhHw
->NakReload
= QH_NAK_RELOAD
;
216 QhHw
->HubAddr
= Ep
->HubAddr
;
217 QhHw
->PortNum
= Ep
->HubPort
;
218 QhHw
->Multiplier
= 1;
219 QhHw
->DataToggle
= Ep
->Toggle
;
221 if (Ep
->DevSpeed
!= EFI_USB_SPEED_HIGH
) {
222 QhHw
->Status
|= QTD_STAT_DO_SS
;
226 case EHC_CTRL_TRANSFER
:
228 // Special initialization for the control transfer:
229 // 1. Control transfer initialize data toggle from each QTD
230 // 2. Set the Control Endpoint Flag (C) for low/full speed endpoint.
234 if (Ep
->DevSpeed
!= EFI_USB_SPEED_HIGH
) {
239 case EHC_INT_TRANSFER_ASYNC
:
240 case EHC_INT_TRANSFER_SYNC
:
242 // Special initialization for the interrupt transfer
243 // to set the S-Mask and C-Mask
246 EhcInitIntQh (Ep
, QhHw
);
249 case EHC_BULK_TRANSFER
:
250 if ((Ep
->DevSpeed
== EFI_USB_SPEED_HIGH
) && (Ep
->Direction
== EfiUsbDataOut
)) {
251 QhHw
->Status
|= QTD_STAT_DO_PING
;
263 Convert the poll interval from application to that
264 be used by EHCI interface data structure. Only need
265 to get the max 2^n that is less than interval. UEFI
266 can't support high speed endpoint with a interval less
267 than 8 microframe because interval is specified in
268 the unit of ms (millisecond)
270 @param Interval The interval to convert
272 @return The converted interval
288 // Find the index (1 based) of the highest non-zero bit
292 while (Interval
!= 0) {
297 return (UINTN
)1 << (BitCount
- 1);
305 @param Ehc The EHCI device
306 @param Qtds The list head of the QTD
322 EFI_LIST_FOR_EACH_SAFE (Entry
, Next
, Qtds
) {
323 Qtd
= EFI_LIST_CONTAINER (Entry
, EHC_QTD
, QtdList
);
325 RemoveEntryList (&Qtd
->QtdList
);
326 UsbHcFreeMem (Ehc
->MemPool
, Qtd
, sizeof (EHC_QTD
));
332 Free an allocated URB. It is possible for it to be partially inited.
334 @param Ehc The EHCI device
335 @param Urb The URB to free
346 EFI_PCI_IO_PROTOCOL
*PciIo
;
350 if (Urb
->RequestPhy
!= NULL
) {
351 PciIo
->Unmap (PciIo
, Urb
->RequestMap
);
354 if (Urb
->DataMap
!= NULL
) {
355 PciIo
->Unmap (PciIo
, Urb
->DataMap
);
358 if (Urb
->Qh
!= NULL
) {
360 // Ensure that this queue head has been unlinked from the
361 // schedule data structures. Free all the associated QTDs
363 EhcFreeQtds (Ehc
, &Urb
->Qh
->Qtds
);
364 UsbHcFreeMem (Ehc
->MemPool
, Urb
->Qh
, sizeof (EHC_QH
));
373 Create a list of QTDs for the URB
375 @param Ehc The EHCI device
376 @param Urb The URB to create QTDs for
378 @retval EFI_OUT_OF_RESOURCES Failed to allocate resource for QTD
379 @retval EFI_SUCCESS The QTDs are allocated for the URB
400 ASSERT ((Urb
!= NULL
) && (Urb
->Qh
!= NULL
));
403 // EHCI follows the alternet next QTD pointer if it meets
404 // a short read and the AlterNext pointer is valid. UEFI
405 // EHCI driver should terminate the transfer except the
412 AlterNext
= QTD_LINK (NULL
, TRUE
);
414 if (Ep
->Direction
== EfiUsbDataIn
) {
415 AlterNext
= QTD_LINK (Ehc
->ShortReadStop
, FALSE
);
419 // Build the Setup and status packets for control transfer
421 if (Urb
->Ep
.Type
== EHC_CTRL_TRANSFER
) {
422 Len
= sizeof (EFI_USB_DEVICE_REQUEST
);
423 Qtd
= EhcCreateQtd (Ehc
, Urb
->RequestPhy
, Len
, QTD_PID_SETUP
, 0, Ep
->MaxPacket
);
426 return EFI_OUT_OF_RESOURCES
;
429 InsertTailList (&Qh
->Qtds
, &Qtd
->QtdList
);
432 // Create the status packet now. Set the AlterNext to it. So, when
433 // EHCI meets a short control read, it can resume at the status stage.
434 // Use the opposite direction of the data stage, or IN if there is
437 if (Ep
->Direction
== EfiUsbDataIn
) {
438 Pid
= QTD_PID_OUTPUT
;
443 StatusQtd
= EhcCreateQtd (Ehc
, NULL
, 0, Pid
, 1, Ep
->MaxPacket
);
445 if (StatusQtd
== NULL
) {
449 if (Ep
->Direction
== EfiUsbDataIn
) {
450 AlterNext
= QTD_LINK (StatusQtd
, FALSE
);
457 // Build the data packets for all the transfers
459 if (Ep
->Direction
== EfiUsbDataIn
) {
462 Pid
= QTD_PID_OUTPUT
;
468 while (Len
< Urb
->DataLen
) {
471 (UINT8
*) Urb
->DataPhy
+ Len
,
482 Qtd
->QtdHw
.AltNext
= AlterNext
;
483 InsertTailList (&Qh
->Qtds
, &Qtd
->QtdList
);
486 // Switch the Toggle bit if odd number of packets are included in the QTD.
488 if (((Qtd
->DataLen
+ Ep
->MaxPacket
- 1) / Ep
->MaxPacket
) % 2) {
489 Toggle
= (UINT8
) (1 - Toggle
);
496 // Insert the status packet for control transfer
498 if (Ep
->Type
== EHC_CTRL_TRANSFER
) {
499 InsertTailList (&Qh
->Qtds
, &StatusQtd
->QtdList
);
503 // OK, all the QTDs needed are created. Now, fix the NextQtd point
505 EFI_LIST_FOR_EACH (Entry
, &Qh
->Qtds
) {
506 Qtd
= EFI_LIST_CONTAINER (Entry
, EHC_QTD
, QtdList
);
509 // break if it is the last entry on the list
511 if (Entry
->ForwardLink
== &Qh
->Qtds
) {
515 NextQtd
= EFI_LIST_CONTAINER (Entry
->ForwardLink
, EHC_QTD
, QtdList
);
516 Qtd
->QtdHw
.NextQtd
= QTD_LINK (NextQtd
, FALSE
);
520 // Link the QTDs to the queue head
522 NextQtd
= EFI_LIST_CONTAINER (Qh
->Qtds
.ForwardLink
, EHC_QTD
, QtdList
);
523 Qh
->QhHw
.NextQtd
= QTD_LINK (NextQtd
, FALSE
);
527 EhcFreeQtds (Ehc
, &Qh
->Qtds
);
528 return EFI_OUT_OF_RESOURCES
;
533 Create a new URB and its associated QTD
535 @param Ehc The EHCI device
536 @param DevAddr The device address
537 @param EpAddr Endpoint addrress & its direction
538 @param DevSpeed The device speed
539 @param Toggle Initial data toggle to use
540 @param MaxPacket The max packet length of the endpoint
541 @param Hub The transaction translator to use
542 @param Type The transaction type
543 @param Request The standard USB request for control transfer
544 @param Data The user data to transfer
545 @param DataLen The length of data buffer
546 @param Callback The function to call when data is transferred
547 @param Context The context to the callback
548 @param Interval The interval for interrupt transfer
550 @return Created URB or NULL
561 IN EFI_USB2_HC_TRANSACTION_TRANSLATOR
*Hub
,
563 IN EFI_USB_DEVICE_REQUEST
*Request
,
566 IN EFI_ASYNC_USB_TRANSFER_CALLBACK Callback
,
572 EFI_PHYSICAL_ADDRESS PhyAddr
;
573 EFI_PCI_IO_PROTOCOL_OPERATION MapOp
;
574 EFI_PCI_IO_PROTOCOL
*PciIo
;
580 Urb
= AllocateZeroPool (sizeof (URB
));
586 Urb
->Signature
= EHC_URB_SIG
;
587 InitializeListHead (&Urb
->UrbList
);
590 Ep
->DevAddr
= DevAddr
;
591 Ep
->EpAddr
= (UINT8
) (EpAddr
& 0x0F);
592 Ep
->Direction
= ((EpAddr
& 0x80) ? EfiUsbDataIn
: EfiUsbDataOut
);
593 Ep
->DevSpeed
= DevSpeed
;
594 Ep
->MaxPacket
= MaxPacket
;
599 if (DevSpeed
!= EFI_USB_SPEED_HIGH
) {
600 ASSERT (Hub
!= NULL
);
602 Ep
->HubAddr
= Hub
->TranslatorHubAddress
;
603 Ep
->HubPort
= Hub
->TranslatorPortNumber
;
608 Ep
->PollRate
= EhcConvertPollRate (Interval
);
610 Urb
->Request
= Request
;
612 Urb
->DataLen
= DataLen
;
613 Urb
->Callback
= Callback
;
614 Urb
->Context
= Context
;
617 Urb
->Qh
= EhcCreateQh (Ehc
, &Urb
->Ep
);
619 if (Urb
->Qh
== NULL
) {
624 // Map the request and user data
626 if (Request
!= NULL
) {
627 Len
= sizeof (EFI_USB_DEVICE_REQUEST
);
628 MapOp
= EfiPciIoOperationBusMasterRead
;
629 Status
= PciIo
->Map (PciIo
, MapOp
, Request
, &Len
, &PhyAddr
, &Map
);
631 if (EFI_ERROR (Status
) || (Len
!= sizeof (EFI_USB_DEVICE_REQUEST
))) {
635 Urb
->RequestPhy
= (VOID
*) ((UINTN
) PhyAddr
);
636 Urb
->RequestMap
= Map
;
642 if (Ep
->Direction
== EfiUsbDataIn
) {
643 MapOp
= EfiPciIoOperationBusMasterWrite
;
645 MapOp
= EfiPciIoOperationBusMasterRead
;
648 Status
= PciIo
->Map (PciIo
, MapOp
, Data
, &Len
, &PhyAddr
, &Map
);
650 if (EFI_ERROR (Status
) || (Len
!= DataLen
)) {
654 Urb
->DataPhy
= (VOID
*) ((UINTN
) PhyAddr
);
658 Status
= EhcCreateQtds (Ehc
, Urb
);
660 if (EFI_ERROR (Status
)) {
667 EhcFreeUrb (Ehc
, Urb
);