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
;
145 Status
= EFI_INVALID_PARAMETER
;
156 @param Qh The queue head for the TD to link to.
157 @param Td The TD to link.
168 ASSERT ((Qh
!= NULL
) && (Td
!= NULL
));
170 Qh
->QhHw
.VerticalLink
= QH_VLINK (Td
, FALSE
);
171 Qh
->TDs
= (VOID
*) Td
;
176 Unlink TD from the QH.
178 @param Qh The queue head to unlink from.
179 @param Td The TD to unlink.
190 ASSERT ((Qh
!= NULL
) && (Td
!= NULL
));
192 Qh
->QhHw
.VerticalLink
= QH_VLINK (NULL
, TRUE
);
198 Append a new TD To the previous TD.
200 @param PrevTd Previous UHCI_TD_SW to be linked to.
201 @param ThisTd TD to link.
208 IN UHCI_TD_SW
*PrevTd
,
209 IN UHCI_TD_SW
*ThisTd
212 ASSERT ((PrevTd
!= NULL
) && (ThisTd
!= NULL
));
214 PrevTd
->TdHw
.NextLink
= TD_LINK (ThisTd
, TRUE
, FALSE
);
215 PrevTd
->NextTd
= (VOID
*) ThisTd
;
220 Delete a list of TDs.
222 @param Uhc The UHCI device.
223 @param FirstTd TD link list head.
231 IN UHCI_TD_SW
*FirstTd
239 while (NextTd
!= NULL
) {
241 NextTd
= ThisTd
->NextTd
;
242 UsbHcFreeMem (Uhc
->MemPool
, ThisTd
, sizeof (UHCI_TD_SW
));
248 Create an initialize a new queue head.
250 @param Uhc The UHCI device.
251 @param Interval The polling interval for the queue.
253 @return The newly created queue header.
264 Qh
= UsbHcAllocateMem (Uhc
->MemPool
, sizeof (UHCI_QH_SW
));
270 Qh
->QhHw
.HorizonLink
= QH_HLINK (NULL
, TRUE
);
271 Qh
->QhHw
.VerticalLink
= QH_VLINK (NULL
, TRUE
);
272 Qh
->Interval
= UhciConvertPollRate(Interval
);
281 Create and intialize a TD.
283 @param Uhc The UHCI device.
285 @return The newly allocated and initialized TD.
295 Td
= UsbHcAllocateMem (Uhc
->MemPool
, sizeof (UHCI_TD_SW
));
300 Td
->TdHw
.NextLink
= TD_LINK (NULL
, FALSE
, TRUE
);
310 Create and initialize a TD for Setup Stage of a control transfer.
312 @param Uhc The UHCI device.
313 @param DevAddr Device address.
314 @param Request Device request.
315 @param IsLow Full speed or low speed.
317 @return The created setup Td Pointer.
330 Td
= UhciCreateTd (Uhc
);
336 Td
->TdHw
.NextLink
= TD_LINK (NULL
, TRUE
, TRUE
);
337 Td
->TdHw
.ShortPacket
= FALSE
;
338 Td
->TdHw
.IsIsoch
= FALSE
;
339 Td
->TdHw
.IntOnCpl
= FALSE
;
340 Td
->TdHw
.ErrorCount
= 0x03;
341 Td
->TdHw
.Status
|= USBTD_ACTIVE
;
342 Td
->TdHw
.DataToggle
= 0;
343 Td
->TdHw
.EndPoint
= 0;
344 Td
->TdHw
.LowSpeed
= IsLow
? 1 : 0;
345 Td
->TdHw
.DeviceAddr
= DevAddr
& 0x7F;
346 Td
->TdHw
.MaxPacketLen
= (UINT32
) (sizeof (EFI_USB_DEVICE_REQUEST
) - 1);
347 Td
->TdHw
.PidCode
= SETUP_PACKET_ID
;
348 Td
->TdHw
.DataBuffer
= (UINT32
) (UINTN
) Request
;
351 Td
->DataLen
= sizeof (EFI_USB_DEVICE_REQUEST
);
358 Create a TD for data.
360 @param Uhc The UHCI device.
361 @param DevAddr Device address.
362 @param Endpoint Endpoint number.
363 @param DataPtr Data buffer.
364 @param Len Data length.
365 @param PktId Packet ID.
366 @param Toggle Data toggle value.
367 @param IsLow Full speed or low speed.
369 @return Data Td pointer if success, otherwise NULL.
387 // Code as length - 1, and the max valid length is 0x500
389 ASSERT (Len
<= 0x500);
391 Td
= UhciCreateTd (Uhc
);
397 Td
->TdHw
.NextLink
= TD_LINK (NULL
, TRUE
, TRUE
);
398 Td
->TdHw
.ShortPacket
= FALSE
;
399 Td
->TdHw
.IsIsoch
= FALSE
;
400 Td
->TdHw
.IntOnCpl
= FALSE
;
401 Td
->TdHw
.ErrorCount
= 0X03;
402 Td
->TdHw
.Status
= USBTD_ACTIVE
;
403 Td
->TdHw
.LowSpeed
= IsLow
? 1 : 0;
404 Td
->TdHw
.DataToggle
= Toggle
& 0x01;
405 Td
->TdHw
.EndPoint
= Endpoint
& 0x0F;
406 Td
->TdHw
.DeviceAddr
= DevAddr
& 0x7F;
407 Td
->TdHw
.MaxPacketLen
= (UINT32
) (Len
- 1);
408 Td
->TdHw
.PidCode
= (UINT8
) PktId
;
409 Td
->TdHw
.DataBuffer
= (UINT32
) (UINTN
) DataPtr
;
412 Td
->DataLen
= (UINT16
) Len
;
419 Create TD for the Status Stage of control transfer.
421 @param Uhc The UHCI device.
422 @param DevAddr Device address.
423 @param PktId Packet ID.
424 @param IsLow Full speed or low speed.
426 @return Status Td Pointer.
439 Td
= UhciCreateTd (Uhc
);
445 Td
->TdHw
.NextLink
= TD_LINK (NULL
, TRUE
, TRUE
);
446 Td
->TdHw
.ShortPacket
= FALSE
;
447 Td
->TdHw
.IsIsoch
= FALSE
;
448 Td
->TdHw
.IntOnCpl
= FALSE
;
449 Td
->TdHw
.ErrorCount
= 0x03;
450 Td
->TdHw
.Status
|= USBTD_ACTIVE
;
451 Td
->TdHw
.MaxPacketLen
= 0x7FF; //0x7FF: there is no data (refer to UHCI spec)
452 Td
->TdHw
.DataToggle
= 1;
453 Td
->TdHw
.EndPoint
= 0;
454 Td
->TdHw
.LowSpeed
= IsLow
? 1 : 0;
455 Td
->TdHw
.DeviceAddr
= DevAddr
& 0x7F;
456 Td
->TdHw
.PidCode
= (UINT8
) PktId
;
457 Td
->TdHw
.DataBuffer
= (UINT32
) (UINTN
) NULL
;
467 Create Tds list for Control Transfer.
469 @param Uhc The UHCI device.
470 @param DeviceAddr The device address.
471 @param DataPktId Packet Identification of Data Tds.
472 @param Request A pointer to request structure buffer to transfer.
473 @param Data A pointer to user data buffer to transfer.
474 @param DataLen Length of user data to transfer.
475 @param MaxPacket Maximum packet size for control transfer.
476 @param IsLow Full speed or low speed.
478 @return The Td list head for the control transfer.
494 UHCI_TD_SW
*FirstDataTd
;
496 UHCI_TD_SW
*PrevDataTd
;
497 UHCI_TD_SW
*StatusTd
;
510 // Create setup packets for the transfer
512 SetupTd
= UhciCreateSetupTd (Uhc
, DeviceAddr
, Request
, IsLow
);
514 if (SetupTd
== NULL
) {
519 // Create data packets for the transfer
523 while (DataLen
> 0) {
525 // PktSize is the data load size in each Td.
527 ThisTdLen
= (DataLen
> MaxPacket
? MaxPacket
: DataLen
);
529 DataTd
= UhciCreateDataTd (
540 if (DataTd
== NULL
) {
544 if (FirstDataTd
== NULL
) {
545 FirstDataTd
= DataTd
;
546 FirstDataTd
->NextTd
= NULL
;
548 UhciAppendTd (PrevDataTd
, DataTd
);
554 DataLen
-= ThisTdLen
;
558 // Status packet is on the opposite direction to data packets
560 if (OUTPUT_PACKET_ID
== DataPktId
) {
561 StatusPktId
= INPUT_PACKET_ID
;
563 StatusPktId
= OUTPUT_PACKET_ID
;
566 StatusTd
= UhciCreateStatusTd (Uhc
, DeviceAddr
, StatusPktId
, IsLow
);
568 if (StatusTd
== NULL
) {
573 // Link setup Td -> data Tds -> status Td together
575 if (FirstDataTd
!= NULL
) {
576 UhciAppendTd (SetupTd
, FirstDataTd
);
577 UhciAppendTd (PrevDataTd
, StatusTd
);
579 UhciAppendTd (SetupTd
, StatusTd
);
585 if (SetupTd
!= NULL
) {
586 UhciDestoryTds (Uhc
, SetupTd
);
589 if (FirstDataTd
!= NULL
) {
590 UhciDestoryTds (Uhc
, FirstDataTd
);
598 Create Tds list for Bulk/Interrupt Transfer.
600 @param Uhc USB_HC_DEV.
601 @param DevAddr Address of Device.
602 @param EndPoint Endpoint Number.
603 @param PktId Packet Identification of Data Tds.
604 @param Data A pointer to user data buffer to transfer.
605 @param DataLen Length of user data to transfer.
606 @param DataToggle Data Toggle Pointer.
607 @param MaxPacket Maximum packet size for Bulk/Interrupt transfer.
608 @param IsLow Is Low Speed Device.
610 @return The Tds list head for the bulk transfer.
614 UhciCreateBulkOrIntTds (
621 IN OUT UINT8
*DataToggle
,
627 UHCI_TD_SW
*FirstDataTd
;
628 UHCI_TD_SW
*PrevDataTd
;
636 // Create data packets for the transfer
638 while (DataLen
> 0) {
640 // PktSize is the data load size that each Td.
644 if (DataLen
> MaxPacket
) {
645 ThisTdLen
= MaxPacket
;
648 DataTd
= UhciCreateDataTd (
659 if (DataTd
== NULL
) {
663 if (PktId
== INPUT_PACKET_ID
) {
664 DataTd
->TdHw
.ShortPacket
= TRUE
;
667 if (FirstDataTd
== NULL
) {
668 FirstDataTd
= DataTd
;
669 FirstDataTd
->NextTd
= NULL
;
671 UhciAppendTd (PrevDataTd
, DataTd
);
677 DataLen
-= ThisTdLen
;
683 if (FirstDataTd
!= NULL
) {
684 UhciDestoryTds (Uhc
, FirstDataTd
);