• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
UhciMapUserRequest(IN USB_HC_DEV * Uhc,IN OUT VOID * Request,OUT UINT8 ** MappedAddr,OUT VOID ** Map)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
UhciMapUserData(IN USB_HC_DEV * Uhc,IN EFI_USB_DATA_DIRECTION Direction,IN VOID * Data,IN OUT UINTN * Len,OUT UINT8 * PktId,OUT UINT8 ** MappedAddr,OUT VOID ** Map)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
UhciLinkTdToQh(IN USB_HC_DEV * Uhc,IN UHCI_QH_SW * Qh,IN UHCI_TD_SW * Td)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
UhciUnlinkTdFromQh(IN UHCI_QH_SW * Qh,IN UHCI_TD_SW * Td)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
UhciAppendTd(IN USB_HC_DEV * Uhc,IN UHCI_TD_SW * PrevTd,IN UHCI_TD_SW * ThisTd)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
UhciDestoryTds(IN USB_HC_DEV * Uhc,IN UHCI_TD_SW * FirstTd)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 *
UhciCreateQh(IN USB_HC_DEV * Uhc,IN UINTN Interval)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 *
UhciCreateTd(IN USB_HC_DEV * Uhc)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 *
UhciCreateSetupTd(IN USB_HC_DEV * Uhc,IN UINT8 DevAddr,IN UINT8 * Request,IN UINT8 * RequestPhy,IN BOOLEAN IsLow)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 *
UhciCreateDataTd(IN USB_HC_DEV * Uhc,IN UINT8 DevAddr,IN UINT8 Endpoint,IN UINT8 * DataPtr,IN UINT8 * DataPhyPtr,IN UINTN Len,IN UINT8 PktId,IN UINT8 Toggle,IN BOOLEAN IsLow)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 *
UhciCreateStatusTd(IN USB_HC_DEV * Uhc,IN UINT8 DevAddr,IN UINT8 PktId,IN BOOLEAN IsLow)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 *
UhciCreateCtrlTds(IN USB_HC_DEV * Uhc,IN UINT8 DeviceAddr,IN UINT8 DataPktId,IN UINT8 * Request,IN UINT8 * RequestPhy,IN UINT8 * Data,IN UINT8 * DataPhy,IN UINTN DataLen,IN UINT8 MaxPacket,IN BOOLEAN IsLow)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 *
UhciCreateBulkOrIntTds(IN USB_HC_DEV * Uhc,IN UINT8 DevAddr,IN UINT8 EndPoint,IN UINT8 PktId,IN UINT8 * Data,IN UINT8 * DataPhy,IN UINTN DataLen,IN OUT UINT8 * DataToggle,IN UINT8 MaxPacket,IN BOOLEAN IsLow)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