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