3 The UHCI register operation routines.
5 Copyright (c) 2007 - 2008, Intel Corporation
6 All rights reserved. This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution. The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
20 Map address of request structure buffer.
22 @param Uhc The UHCI device.
23 @param Request The user request buffer.
24 @param MappedAddr Mapped address of request.
25 @param Map Identificaion of this mapping to return.
27 @return EFI_SUCCESS Success.
28 @return EFI_DEVICE_ERROR Fail to map the user request.
35 OUT UINT8
**MappedAddr
,
41 EFI_PHYSICAL_ADDRESS PhyAddr
;
43 Len
= sizeof (EFI_USB_DEVICE_REQUEST
);
44 Status
= Uhc
->PciIo
->Map (
46 EfiPciIoOperationBusMasterRead
,
53 if (!EFI_ERROR (Status
)) {
54 *MappedAddr
= (UINT8
*) (UINTN
) PhyAddr
;
62 Map address of user data buffer.
64 @param Uhc The UHCI device.
65 @param Direction Direction of the data transfer.
66 @param Data The user data buffer.
67 @param Len Length of the user data.
68 @param PktId Packet identificaion.
69 @param MappedAddr Mapped address to return.
70 @param Map Identificaion of this mapping to return.
72 @return EFI_SUCCESS Success.
73 @return EFI_DEVICE_ERROR Fail to map the user data.
79 IN EFI_USB_DATA_DIRECTION Direction
,
83 OUT UINT8
**MappedAddr
,
88 EFI_PHYSICAL_ADDRESS PhyAddr
;
95 // BusMasterWrite means cpu read
97 *PktId
= INPUT_PACKET_ID
;
98 Status
= Uhc
->PciIo
->Map (
100 EfiPciIoOperationBusMasterWrite
,
107 if (EFI_ERROR (Status
)) {
111 *MappedAddr
= (UINT8
*) (UINTN
) PhyAddr
;
115 *PktId
= OUTPUT_PACKET_ID
;
116 Status
= Uhc
->PciIo
->Map (
118 EfiPciIoOperationBusMasterRead
,
125 if (EFI_ERROR (Status
)) {
129 *MappedAddr
= (UINT8
*) (UINTN
) PhyAddr
;
133 if ((Len
!= NULL
) && (*Len
!= 0)) {
134 Status
= EFI_INVALID_PARAMETER
;
138 *PktId
= OUTPUT_PACKET_ID
;
144 Status
= EFI_INVALID_PARAMETER
;
155 @param Qh The queue head for the TD to link to.
156 @param Td The TD to link.
167 ASSERT ((Qh
!= NULL
) && (Td
!= NULL
));
169 Qh
->QhHw
.VerticalLink
= QH_VLINK (Td
, FALSE
);
170 Qh
->TDs
= (VOID
*) Td
;
175 Unlink TD from the QH.
177 @param Qh The queue head to unlink from.
178 @param Td The TD to unlink.
189 ASSERT ((Qh
!= NULL
) && (Td
!= NULL
));
191 Qh
->QhHw
.VerticalLink
= QH_VLINK (NULL
, TRUE
);
197 Append a new TD To the previous TD.
199 @param PrevTd Previous UHCI_TD_SW to be linked to.
200 @param ThisTd TD to link.
207 IN UHCI_TD_SW
*PrevTd
,
208 IN UHCI_TD_SW
*ThisTd
211 ASSERT ((PrevTd
!= NULL
) && (ThisTd
!= NULL
));
213 PrevTd
->TdHw
.NextLink
= TD_LINK (ThisTd
, TRUE
, FALSE
);
214 PrevTd
->NextTd
= (VOID
*) ThisTd
;
219 Delete a list of TDs.
221 @param Uhc The UHCI device.
222 @param FirstTd TD link list head.
230 IN UHCI_TD_SW
*FirstTd
238 while (NextTd
!= NULL
) {
240 NextTd
= ThisTd
->NextTd
;
241 UsbHcFreeMem (Uhc
->MemPool
, ThisTd
, sizeof (UHCI_TD_SW
));
247 Create an initialize a new queue head.
249 @param Uhc The UHCI device.
250 @param Interval The polling interval for the queue.
252 @return The newly created queue header.
263 Qh
= UsbHcAllocateMem (Uhc
->MemPool
, sizeof (UHCI_QH_SW
));
269 Qh
->QhHw
.HorizonLink
= QH_HLINK (NULL
, TRUE
);
270 Qh
->QhHw
.VerticalLink
= QH_VLINK (NULL
, TRUE
);
271 Qh
->Interval
= UhciConvertPollRate(Interval
);
280 Create and intialize a TD.
282 @param Uhc The UHCI device.
284 @return The newly allocated and initialized TD.
294 Td
= UsbHcAllocateMem (Uhc
->MemPool
, sizeof (UHCI_TD_SW
));
299 Td
->TdHw
.NextLink
= TD_LINK (NULL
, FALSE
, TRUE
);
309 Create and initialize a TD for Setup Stage of a control transfer.
311 @param Uhc The UHCI device.
312 @param DevAddr Device address.
313 @param Request Device request.
314 @param IsLow Full speed or low speed.
316 @return The created setup Td Pointer.
329 Td
= UhciCreateTd (Uhc
);
335 Td
->TdHw
.NextLink
= TD_LINK (NULL
, TRUE
, TRUE
);
336 Td
->TdHw
.ShortPacket
= FALSE
;
337 Td
->TdHw
.IsIsoch
= FALSE
;
338 Td
->TdHw
.IntOnCpl
= FALSE
;
339 Td
->TdHw
.ErrorCount
= 0x03;
340 Td
->TdHw
.Status
|= USBTD_ACTIVE
;
341 Td
->TdHw
.DataToggle
= 0;
342 Td
->TdHw
.EndPoint
= 0;
343 Td
->TdHw
.LowSpeed
= IsLow
? 1 : 0;
344 Td
->TdHw
.DeviceAddr
= DevAddr
& 0x7F;
345 Td
->TdHw
.MaxPacketLen
= (UINT32
) (sizeof (EFI_USB_DEVICE_REQUEST
) - 1);
346 Td
->TdHw
.PidCode
= SETUP_PACKET_ID
;
347 Td
->TdHw
.DataBuffer
= (UINT32
) (UINTN
) Request
;
350 Td
->DataLen
= sizeof (EFI_USB_DEVICE_REQUEST
);
357 Create a TD for data.
359 @param Uhc The UHCI device.
360 @param DevAddr Device address.
361 @param Endpoint Endpoint number.
362 @param DataPtr Data buffer.
363 @param Len Data length.
364 @param PktId Packet ID.
365 @param Toggle Data toggle value.
366 @param IsLow Full speed or low speed.
368 @return Data Td pointer if success, otherwise NULL.
386 // Code as length - 1, and the max valid length is 0x500
388 ASSERT (Len
<= 0x500);
390 Td
= UhciCreateTd (Uhc
);
396 Td
->TdHw
.NextLink
= TD_LINK (NULL
, TRUE
, TRUE
);
397 Td
->TdHw
.ShortPacket
= FALSE
;
398 Td
->TdHw
.IsIsoch
= FALSE
;
399 Td
->TdHw
.IntOnCpl
= FALSE
;
400 Td
->TdHw
.ErrorCount
= 0X03;
401 Td
->TdHw
.Status
= USBTD_ACTIVE
;
402 Td
->TdHw
.LowSpeed
= IsLow
? 1 : 0;
403 Td
->TdHw
.DataToggle
= Toggle
& 0x01;
404 Td
->TdHw
.EndPoint
= Endpoint
& 0x0F;
405 Td
->TdHw
.DeviceAddr
= DevAddr
& 0x7F;
406 Td
->TdHw
.MaxPacketLen
= (UINT32
) (Len
- 1);
407 Td
->TdHw
.PidCode
= (UINT8
) PktId
;
408 Td
->TdHw
.DataBuffer
= (UINT32
) (UINTN
) DataPtr
;
411 Td
->DataLen
= (UINT16
) Len
;
418 Create TD for the Status Stage of control transfer.
420 @param Uhc The UHCI device.
421 @param DevAddr Device address.
422 @param PktId Packet ID.
423 @param IsLow Full speed or low speed.
425 @return Status Td Pointer.
438 Td
= UhciCreateTd (Uhc
);
444 Td
->TdHw
.NextLink
= TD_LINK (NULL
, TRUE
, TRUE
);
445 Td
->TdHw
.ShortPacket
= FALSE
;
446 Td
->TdHw
.IsIsoch
= FALSE
;
447 Td
->TdHw
.IntOnCpl
= FALSE
;
448 Td
->TdHw
.ErrorCount
= 0x03;
449 Td
->TdHw
.Status
|= USBTD_ACTIVE
;
450 Td
->TdHw
.MaxPacketLen
= 0x7FF; //0x7FF: there is no data (refer to UHCI spec)
451 Td
->TdHw
.DataToggle
= 1;
452 Td
->TdHw
.EndPoint
= 0;
453 Td
->TdHw
.LowSpeed
= IsLow
? 1 : 0;
454 Td
->TdHw
.DeviceAddr
= DevAddr
& 0x7F;
455 Td
->TdHw
.PidCode
= (UINT8
) PktId
;
456 Td
->TdHw
.DataBuffer
= (UINT32
) (UINTN
) NULL
;
466 Create Tds list for Control Transfer.
468 @param Uhc The UHCI device.
469 @param DeviceAddr The device address.
470 @param DataPktId Packet Identification of Data Tds.
471 @param Request A pointer to request structure buffer to transfer.
472 @param Data A pointer to user data buffer to transfer.
473 @param DataLen Length of user data to transfer.
474 @param MaxPacket Maximum packet size for control transfer.
475 @param IsLow Full speed or low speed.
477 @return The Td list head for the control transfer.
493 UHCI_TD_SW
*FirstDataTd
;
495 UHCI_TD_SW
*PrevDataTd
;
496 UHCI_TD_SW
*StatusTd
;
509 // Create setup packets for the transfer
511 SetupTd
= UhciCreateSetupTd (Uhc
, DeviceAddr
, Request
, IsLow
);
513 if (SetupTd
== NULL
) {
518 // Create data packets for the transfer
522 while (DataLen
> 0) {
524 // PktSize is the data load size in each Td.
526 ThisTdLen
= (DataLen
> MaxPacket
? MaxPacket
: DataLen
);
528 DataTd
= UhciCreateDataTd (
539 if (DataTd
== NULL
) {
543 if (FirstDataTd
== NULL
) {
544 FirstDataTd
= DataTd
;
545 FirstDataTd
->NextTd
= NULL
;
547 UhciAppendTd (PrevDataTd
, DataTd
);
553 DataLen
-= ThisTdLen
;
557 // Status packet is on the opposite direction to data packets
559 if (OUTPUT_PACKET_ID
== DataPktId
) {
560 StatusPktId
= INPUT_PACKET_ID
;
562 StatusPktId
= OUTPUT_PACKET_ID
;
565 StatusTd
= UhciCreateStatusTd (Uhc
, DeviceAddr
, StatusPktId
, IsLow
);
567 if (StatusTd
== NULL
) {
572 // Link setup Td -> data Tds -> status Td together
574 if (FirstDataTd
!= NULL
) {
575 UhciAppendTd (SetupTd
, FirstDataTd
);
576 UhciAppendTd (PrevDataTd
, StatusTd
);
578 UhciAppendTd (SetupTd
, StatusTd
);
584 if (SetupTd
!= NULL
) {
585 UhciDestoryTds (Uhc
, SetupTd
);
588 if (FirstDataTd
!= NULL
) {
589 UhciDestoryTds (Uhc
, FirstDataTd
);
597 Create Tds list for Bulk/Interrupt Transfer.
599 @param Uhc USB_HC_DEV.
600 @param DevAddr Address of Device.
601 @param EndPoint Endpoint Number.
602 @param PktId Packet Identification of Data Tds.
603 @param Data A pointer to user data buffer to transfer.
604 @param DataLen Length of user data to transfer.
605 @param DataToggle Data Toggle Pointer.
606 @param MaxPacket Maximum packet size for Bulk/Interrupt transfer.
607 @param IsLow Is Low Speed Device.
609 @return The Tds list head for the bulk transfer.
613 UhciCreateBulkOrIntTds (
620 IN OUT UINT8
*DataToggle
,
626 UHCI_TD_SW
*FirstDataTd
;
627 UHCI_TD_SW
*PrevDataTd
;
635 // Create data packets for the transfer
637 while (DataLen
> 0) {
639 // PktSize is the data load size that each Td.
643 if (DataLen
> MaxPacket
) {
644 ThisTdLen
= MaxPacket
;
647 DataTd
= UhciCreateDataTd (
658 if (DataTd
== NULL
) {
662 if (PktId
== INPUT_PACKET_ID
) {
663 DataTd
->TdHw
.ShortPacket
= TRUE
;
666 if (FirstDataTd
== NULL
) {
667 FirstDataTd
= DataTd
;
668 FirstDataTd
->NextTd
= NULL
;
670 UhciAppendTd (PrevDataTd
, DataTd
);
676 DataLen
-= ThisTdLen
;
682 if (FirstDataTd
!= NULL
) {
683 UhciDestoryTds (Uhc
, FirstDataTd
);