• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /** @file
2 
3     This file contains URB request, each request is warpped in a
4     URB (Usb Request Block).
5 
6 Copyright (c) 2007 - 2010, Intel Corporation. All rights reserved.<BR>
7 This program and the accompanying materials
8 are licensed and made available under the terms and conditions of the BSD License
9 which accompanies this distribution.  The full text of the license may be found at
10 http://opensource.org/licenses/bsd-license.php
11 
12 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
13 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
14 
15 **/
16 
17 #include "Ehci.h"
18 
19 
20 /**
21   Create a single QTD to hold the data.
22 
23   @param  Ehc                   The EHCI device.
24   @param  Data                  The cpu memory address of current data not associated with a QTD.
25   @param  DataPhy               The pci bus address of current data not associated with a QTD.
26   @param  DataLen               The length of the data.
27   @param  PktId                 Packet ID to use in the QTD.
28   @param  Toggle                Data toggle to use in the QTD.
29   @param  MaxPacket             Maximu packet length of the endpoint.
30 
31   @return Created QTD or NULL if failed to create one.
32 
33 **/
34 EHC_QTD *
EhcCreateQtd(IN USB2_HC_DEV * Ehc,IN UINT8 * Data,IN UINT8 * DataPhy,IN UINTN DataLen,IN UINT8 PktId,IN UINT8 Toggle,IN UINTN MaxPacket)35 EhcCreateQtd (
36   IN USB2_HC_DEV          *Ehc,
37   IN UINT8                *Data,
38   IN UINT8                *DataPhy,
39   IN UINTN                DataLen,
40   IN UINT8                PktId,
41   IN UINT8                Toggle,
42   IN UINTN                MaxPacket
43   )
44 {
45   EHC_QTD                 *Qtd;
46   QTD_HW                  *QtdHw;
47   UINTN                   Index;
48   UINTN                   Len;
49   UINTN                   ThisBufLen;
50 
51   ASSERT (Ehc != NULL);
52 
53   Qtd = UsbHcAllocateMem (Ehc->MemPool, sizeof (EHC_QTD));
54 
55   if (Qtd == NULL) {
56     return NULL;
57   }
58 
59   Qtd->Signature    = EHC_QTD_SIG;
60   Qtd->Data         = Data;
61   Qtd->DataLen      = 0;
62 
63   InitializeListHead (&Qtd->QtdList);
64 
65   QtdHw             = &Qtd->QtdHw;
66   QtdHw->NextQtd    = QTD_LINK (NULL, TRUE);
67   QtdHw->AltNext    = QTD_LINK (NULL, TRUE);
68   QtdHw->Status     = QTD_STAT_ACTIVE;
69   QtdHw->Pid        = PktId;
70   QtdHw->ErrCnt     = QTD_MAX_ERR;
71   QtdHw->Ioc        = 0;
72   QtdHw->TotalBytes = 0;
73   QtdHw->DataToggle = Toggle;
74 
75   //
76   // Fill in the buffer points
77   //
78   if (Data != NULL) {
79     Len = 0;
80 
81     for (Index = 0; Index <= QTD_MAX_BUFFER; Index++) {
82       //
83       // Set the buffer point (Check page 41 EHCI Spec 1.0). No need to
84       // compute the offset and clear Reserved fields. This is already
85       // done in the data point.
86       //
87       QtdHw->Page[Index]      = EHC_LOW_32BIT (DataPhy);
88       QtdHw->PageHigh[Index]  = EHC_HIGH_32BIT (DataPhy);
89 
90       ThisBufLen              = QTD_BUF_LEN - (EHC_LOW_32BIT (DataPhy) & QTD_BUF_MASK);
91 
92       if (Len + ThisBufLen >= DataLen) {
93         Len = DataLen;
94         break;
95       }
96 
97       Len += ThisBufLen;
98       Data += ThisBufLen;
99       DataPhy += ThisBufLen;
100     }
101 
102     //
103     // Need to fix the last pointer if the Qtd can't hold all the
104     // user's data to make sure that the length is in the unit of
105     // max packets. If it can hold all the data, there is no such
106     // need.
107     //
108     if (Len < DataLen) {
109       Len = Len - Len % MaxPacket;
110     }
111 
112     QtdHw->TotalBytes = (UINT32) Len;
113     Qtd->DataLen      = Len;
114   }
115 
116   return Qtd;
117 }
118 
119 
120 
121 /**
122   Initialize the queue head for interrupt transfer,
123   that is, initialize the following three fields:
124   1. SplitXState in the Status field
125   2. Microframe S-mask
126   3. Microframe C-mask
127 
128   @param  Ep                    The queue head's related endpoint.
129   @param  QhHw                  The queue head to initialize.
130 
131 **/
132 VOID
EhcInitIntQh(IN USB_ENDPOINT * Ep,IN QH_HW * QhHw)133 EhcInitIntQh (
134   IN USB_ENDPOINT         *Ep,
135   IN QH_HW                *QhHw
136   )
137 {
138   //
139   // Because UEFI interface can't utilitize an endpoint with
140   // poll rate faster than 1ms, only need to set one bit in
141   // the queue head. simple. But it may be changed later. If
142   // sub-1ms interrupt is supported, need to update the S-Mask
143   // here
144   //
145   if (Ep->DevSpeed == EFI_USB_SPEED_HIGH) {
146     QhHw->SMask = QH_MICROFRAME_0;
147     return ;
148   }
149 
150   //
151   // For low/full speed device, the transfer must go through
152   // the split transaction. Need to update three fields
153   // 1. SplitXState in the status
154   // 2. Microframe S-Mask
155   // 3. Microframe C-Mask
156   // UEFI USB doesn't exercise admission control. It simplely
157   // schedule the high speed transactions in microframe 0, and
158   // full/low speed transactions at microframe 1. This also
159   // avoid the use of FSTN.
160   //
161   QhHw->SMask = QH_MICROFRAME_1;
162   QhHw->CMask = QH_MICROFRAME_3 | QH_MICROFRAME_4 | QH_MICROFRAME_5;
163 }
164 
165 
166 
167 /**
168   Allocate and initialize a EHCI queue head.
169 
170   @param  Ehci                  The EHCI device.
171   @param  Ep                    The endpoint to create queue head for.
172 
173   @return Created queue head or NULL if failed to create one.
174 
175 **/
176 EHC_QH *
EhcCreateQh(IN USB2_HC_DEV * Ehci,IN USB_ENDPOINT * Ep)177 EhcCreateQh (
178   IN USB2_HC_DEV          *Ehci,
179   IN USB_ENDPOINT         *Ep
180   )
181 {
182   EHC_QH                  *Qh;
183   QH_HW                   *QhHw;
184 
185   Qh = UsbHcAllocateMem (Ehci->MemPool, sizeof (EHC_QH));
186 
187   if (Qh == NULL) {
188     return NULL;
189   }
190 
191   Qh->Signature       = EHC_QH_SIG;
192   Qh->NextQh          = NULL;
193   Qh->Interval        = Ep->PollRate;
194 
195   InitializeListHead (&Qh->Qtds);
196 
197   QhHw                = &Qh->QhHw;
198   QhHw->HorizonLink   = QH_LINK (NULL, 0, TRUE);
199   QhHw->DeviceAddr    = Ep->DevAddr;
200   QhHw->Inactive      = 0;
201   QhHw->EpNum         = Ep->EpAddr;
202   QhHw->EpSpeed       = Ep->DevSpeed;
203   QhHw->DtCtrl        = 0;
204   QhHw->ReclaimHead   = 0;
205   QhHw->MaxPacketLen  = (UINT32) Ep->MaxPacket;
206   QhHw->CtrlEp        = 0;
207   QhHw->NakReload     = QH_NAK_RELOAD;
208   QhHw->HubAddr       = Ep->HubAddr;
209   QhHw->PortNum       = Ep->HubPort;
210   QhHw->Multiplier    = 1;
211   QhHw->DataToggle    = Ep->Toggle;
212 
213   if (Ep->DevSpeed != EFI_USB_SPEED_HIGH) {
214     QhHw->Status |= QTD_STAT_DO_SS;
215   }
216 
217   switch (Ep->Type) {
218   case EHC_CTRL_TRANSFER:
219     //
220     // Special initialization for the control transfer:
221     // 1. Control transfer initialize data toggle from each QTD
222     // 2. Set the Control Endpoint Flag (C) for low/full speed endpoint.
223     //
224     QhHw->DtCtrl = 1;
225 
226     if (Ep->DevSpeed != EFI_USB_SPEED_HIGH) {
227       QhHw->CtrlEp = 1;
228     }
229     break;
230 
231   case EHC_INT_TRANSFER_ASYNC:
232   case EHC_INT_TRANSFER_SYNC:
233     //
234     // Special initialization for the interrupt transfer
235     // to set the S-Mask and C-Mask
236     //
237     QhHw->NakReload = 0;
238     EhcInitIntQh (Ep, QhHw);
239     break;
240 
241   case EHC_BULK_TRANSFER:
242     if ((Ep->DevSpeed == EFI_USB_SPEED_HIGH) && (Ep->Direction == EfiUsbDataOut)) {
243       QhHw->Status |= QTD_STAT_DO_PING;
244     }
245 
246     break;
247   }
248 
249   return Qh;
250 }
251 
252 
253 /**
254   Convert the poll interval from application to that
255   be used by EHCI interface data structure. Only need
256   to get the max 2^n that is less than interval. UEFI
257   can't support high speed endpoint with a interval less
258   than 8 microframe because interval is specified in
259   the unit of ms (millisecond).
260 
261   @param  Interval              The interval to convert.
262 
263   @return The converted interval.
264 
265 **/
266 UINTN
EhcConvertPollRate(IN UINTN Interval)267 EhcConvertPollRate (
268   IN  UINTN               Interval
269   )
270 {
271   UINTN                   BitCount;
272 
273   if (Interval == 0) {
274     return 1;
275   }
276 
277   //
278   // Find the index (1 based) of the highest non-zero bit
279   //
280   BitCount = 0;
281 
282   while (Interval != 0) {
283     Interval >>= 1;
284     BitCount++;
285   }
286 
287   return (UINTN)1 << (BitCount - 1);
288 }
289 
290 
291 /**
292   Free a list of QTDs.
293 
294   @param  Ehc                   The EHCI device.
295   @param  Qtds                  The list head of the QTD.
296 
297 **/
298 VOID
EhcFreeQtds(IN USB2_HC_DEV * Ehc,IN LIST_ENTRY * Qtds)299 EhcFreeQtds (
300   IN USB2_HC_DEV          *Ehc,
301   IN LIST_ENTRY           *Qtds
302   )
303 {
304   LIST_ENTRY              *Entry;
305   LIST_ENTRY              *Next;
306   EHC_QTD                 *Qtd;
307 
308   EFI_LIST_FOR_EACH_SAFE (Entry, Next, Qtds) {
309     Qtd = EFI_LIST_CONTAINER (Entry, EHC_QTD, QtdList);
310 
311     RemoveEntryList (&Qtd->QtdList);
312     UsbHcFreeMem (Ehc->MemPool, Qtd, sizeof (EHC_QTD));
313   }
314 }
315 
316 
317 /**
318   Free an allocated URB. It is possible for it to be partially inited.
319 
320   @param  Ehc                   The EHCI device.
321   @param  Urb                   The URB to free.
322 
323 **/
324 VOID
EhcFreeUrb(IN USB2_HC_DEV * Ehc,IN URB * Urb)325 EhcFreeUrb (
326   IN USB2_HC_DEV          *Ehc,
327   IN URB                  *Urb
328   )
329 {
330   EFI_PCI_IO_PROTOCOL       *PciIo;
331 
332   PciIo = Ehc->PciIo;
333 
334   if (Urb->RequestPhy != NULL) {
335     PciIo->Unmap (PciIo, Urb->RequestMap);
336   }
337 
338   if (Urb->DataMap != NULL) {
339     PciIo->Unmap (PciIo, Urb->DataMap);
340   }
341 
342   if (Urb->Qh != NULL) {
343     //
344     // Ensure that this queue head has been unlinked from the
345     // schedule data structures. Free all the associated QTDs
346     //
347     EhcFreeQtds (Ehc, &Urb->Qh->Qtds);
348     UsbHcFreeMem (Ehc->MemPool, Urb->Qh, sizeof (EHC_QH));
349   }
350 
351   gBS->FreePool (Urb);
352 }
353 
354 
355 /**
356   Create a list of QTDs for the URB.
357 
358   @param  Ehc                   The EHCI device.
359   @param  Urb                   The URB to create QTDs for.
360 
361   @retval EFI_OUT_OF_RESOURCES  Failed to allocate resource for QTD.
362   @retval EFI_SUCCESS           The QTDs are allocated for the URB.
363 
364 **/
365 EFI_STATUS
EhcCreateQtds(IN USB2_HC_DEV * Ehc,IN URB * Urb)366 EhcCreateQtds (
367   IN USB2_HC_DEV          *Ehc,
368   IN URB                  *Urb
369   )
370 {
371   USB_ENDPOINT            *Ep;
372   EHC_QH                  *Qh;
373   EHC_QTD                 *Qtd;
374   EHC_QTD                 *StatusQtd;
375   EHC_QTD                 *NextQtd;
376   LIST_ENTRY              *Entry;
377   UINT32                  AlterNext;
378   UINT8                   Toggle;
379   UINTN                   Len;
380   UINT8                   Pid;
381   EFI_PHYSICAL_ADDRESS    PhyAddr;
382 
383   ASSERT ((Urb != NULL) && (Urb->Qh != NULL));
384 
385   //
386   // EHCI follows the alternet next QTD pointer if it meets
387   // a short read and the AlterNext pointer is valid. UEFI
388   // EHCI driver should terminate the transfer except the
389   // control transfer.
390   //
391   Toggle    = 0;
392   Qh        = Urb->Qh;
393   Ep        = &Urb->Ep;
394   StatusQtd = NULL;
395   AlterNext = QTD_LINK (NULL, TRUE);
396 
397   PhyAddr   = UsbHcGetPciAddressForHostMem (Ehc->MemPool, Ehc->ShortReadStop, sizeof (EHC_QTD));
398   if (Ep->Direction == EfiUsbDataIn) {
399     AlterNext = QTD_LINK (PhyAddr, FALSE);
400   }
401 
402   //
403   // Build the Setup and status packets for control transfer
404   //
405   if (Urb->Ep.Type == EHC_CTRL_TRANSFER) {
406     Len = sizeof (EFI_USB_DEVICE_REQUEST);
407     Qtd = EhcCreateQtd (Ehc, (UINT8 *)Urb->Request, (UINT8 *)Urb->RequestPhy, Len, QTD_PID_SETUP, 0, Ep->MaxPacket);
408 
409     if (Qtd == NULL) {
410       return EFI_OUT_OF_RESOURCES;
411     }
412 
413     InsertTailList (&Qh->Qtds, &Qtd->QtdList);
414 
415     //
416     // Create the status packet now. Set the AlterNext to it. So, when
417     // EHCI meets a short control read, it can resume at the status stage.
418     // Use the opposite direction of the data stage, or IN if there is
419     // no data stage.
420     //
421     if (Ep->Direction == EfiUsbDataIn) {
422       Pid = QTD_PID_OUTPUT;
423     } else {
424       Pid = QTD_PID_INPUT;
425     }
426 
427     StatusQtd = EhcCreateQtd (Ehc, NULL, NULL, 0, Pid, 1, Ep->MaxPacket);
428 
429     if (StatusQtd == NULL) {
430       goto ON_ERROR;
431     }
432 
433     if (Ep->Direction == EfiUsbDataIn) {
434       PhyAddr   = UsbHcGetPciAddressForHostMem (Ehc->MemPool, StatusQtd, sizeof (EHC_QTD));
435       AlterNext = QTD_LINK (PhyAddr, FALSE);
436     }
437 
438     Toggle = 1;
439   }
440 
441   //
442   // Build the data packets for all the transfers
443   //
444   if (Ep->Direction == EfiUsbDataIn) {
445     Pid = QTD_PID_INPUT;
446   } else {
447     Pid = QTD_PID_OUTPUT;
448   }
449 
450   Qtd = NULL;
451   Len = 0;
452 
453   while (Len < Urb->DataLen) {
454     Qtd = EhcCreateQtd (
455             Ehc,
456             (UINT8 *) Urb->Data + Len,
457             (UINT8 *) Urb->DataPhy + Len,
458             Urb->DataLen - Len,
459             Pid,
460             Toggle,
461             Ep->MaxPacket
462             );
463 
464     if (Qtd == NULL) {
465       goto ON_ERROR;
466     }
467 
468     Qtd->QtdHw.AltNext = AlterNext;
469     InsertTailList (&Qh->Qtds, &Qtd->QtdList);
470 
471     //
472     // Switch the Toggle bit if odd number of packets are included in the QTD.
473     //
474     if (((Qtd->DataLen + Ep->MaxPacket - 1) / Ep->MaxPacket) % 2) {
475       Toggle = (UINT8) (1 - Toggle);
476     }
477 
478     Len += Qtd->DataLen;
479   }
480 
481   //
482   // Insert the status packet for control transfer
483   //
484   if (Ep->Type == EHC_CTRL_TRANSFER) {
485     InsertTailList (&Qh->Qtds, &StatusQtd->QtdList);
486   }
487 
488   //
489   // OK, all the QTDs needed are created. Now, fix the NextQtd point
490   //
491   EFI_LIST_FOR_EACH (Entry, &Qh->Qtds) {
492     Qtd = EFI_LIST_CONTAINER (Entry, EHC_QTD, QtdList);
493 
494     //
495     // break if it is the last entry on the list
496     //
497     if (Entry->ForwardLink == &Qh->Qtds) {
498       break;
499     }
500 
501     NextQtd             = EFI_LIST_CONTAINER (Entry->ForwardLink, EHC_QTD, QtdList);
502     PhyAddr             = UsbHcGetPciAddressForHostMem (Ehc->MemPool, NextQtd, sizeof (EHC_QTD));
503     Qtd->QtdHw.NextQtd  = QTD_LINK (PhyAddr, FALSE);
504   }
505 
506   //
507   // Link the QTDs to the queue head
508   //
509   NextQtd           = EFI_LIST_CONTAINER (Qh->Qtds.ForwardLink, EHC_QTD, QtdList);
510   PhyAddr           = UsbHcGetPciAddressForHostMem (Ehc->MemPool, NextQtd, sizeof (EHC_QTD));
511   Qh->QhHw.NextQtd  = QTD_LINK (PhyAddr, FALSE);
512   return EFI_SUCCESS;
513 
514 ON_ERROR:
515   EhcFreeQtds (Ehc, &Qh->Qtds);
516   return EFI_OUT_OF_RESOURCES;
517 }
518 
519 
520 /**
521   Create a new URB and its associated QTD.
522 
523   @param  Ehc                   The EHCI device.
524   @param  DevAddr               The device address.
525   @param  EpAddr                Endpoint addrress & its direction.
526   @param  DevSpeed              The device speed.
527   @param  Toggle                Initial data toggle to use.
528   @param  MaxPacket             The max packet length of the endpoint.
529   @param  Hub                   The transaction translator to use.
530   @param  Type                  The transaction type.
531   @param  Request               The standard USB request for control transfer.
532   @param  Data                  The user data to transfer.
533   @param  DataLen               The length of data buffer.
534   @param  Callback              The function to call when data is transferred.
535   @param  Context               The context to the callback.
536   @param  Interval              The interval for interrupt transfer.
537 
538   @return Created URB or NULL.
539 
540 **/
541 URB *
EhcCreateUrb(IN USB2_HC_DEV * Ehc,IN UINT8 DevAddr,IN UINT8 EpAddr,IN UINT8 DevSpeed,IN UINT8 Toggle,IN UINTN MaxPacket,IN EFI_USB2_HC_TRANSACTION_TRANSLATOR * Hub,IN UINTN Type,IN EFI_USB_DEVICE_REQUEST * Request,IN VOID * Data,IN UINTN DataLen,IN EFI_ASYNC_USB_TRANSFER_CALLBACK Callback,IN VOID * Context,IN UINTN Interval)542 EhcCreateUrb (
543   IN USB2_HC_DEV                        *Ehc,
544   IN UINT8                              DevAddr,
545   IN UINT8                              EpAddr,
546   IN UINT8                              DevSpeed,
547   IN UINT8                              Toggle,
548   IN UINTN                              MaxPacket,
549   IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Hub,
550   IN UINTN                              Type,
551   IN EFI_USB_DEVICE_REQUEST             *Request,
552   IN VOID                               *Data,
553   IN UINTN                              DataLen,
554   IN EFI_ASYNC_USB_TRANSFER_CALLBACK    Callback,
555   IN VOID                               *Context,
556   IN UINTN                              Interval
557   )
558 {
559   USB_ENDPOINT                  *Ep;
560   EFI_PHYSICAL_ADDRESS          PhyAddr;
561   EFI_PCI_IO_PROTOCOL_OPERATION MapOp;
562   EFI_PCI_IO_PROTOCOL           *PciIo;
563   EFI_STATUS                    Status;
564   UINTN                         Len;
565   URB                           *Urb;
566   VOID                          *Map;
567 
568   Urb = AllocateZeroPool (sizeof (URB));
569 
570   if (Urb == NULL) {
571     return NULL;
572   }
573 
574   Urb->Signature  = EHC_URB_SIG;
575   InitializeListHead (&Urb->UrbList);
576 
577   Ep              = &Urb->Ep;
578   Ep->DevAddr     = DevAddr;
579   Ep->EpAddr      = (UINT8) (EpAddr & 0x0F);
580   Ep->Direction   = (((EpAddr & 0x80) != 0) ? EfiUsbDataIn : EfiUsbDataOut);
581   Ep->DevSpeed    = DevSpeed;
582   Ep->MaxPacket   = MaxPacket;
583 
584   Ep->HubAddr     = 0;
585   Ep->HubPort     = 0;
586 
587   if (DevSpeed != EFI_USB_SPEED_HIGH) {
588     ASSERT (Hub != NULL);
589 
590     Ep->HubAddr   = Hub->TranslatorHubAddress;
591     Ep->HubPort   = Hub->TranslatorPortNumber;
592   }
593 
594   Ep->Toggle      = Toggle;
595   Ep->Type        = Type;
596   Ep->PollRate    = EhcConvertPollRate (Interval);
597 
598   Urb->Request    = Request;
599   Urb->Data       = Data;
600   Urb->DataLen    = DataLen;
601   Urb->Callback   = Callback;
602   Urb->Context    = Context;
603 
604   PciIo           = Ehc->PciIo;
605   Urb->Qh         = EhcCreateQh (Ehc, &Urb->Ep);
606 
607   if (Urb->Qh == NULL) {
608     goto ON_ERROR;
609   }
610 
611   //
612   // Map the request and user data
613   //
614   if (Request != NULL) {
615     Len     = sizeof (EFI_USB_DEVICE_REQUEST);
616     MapOp   = EfiPciIoOperationBusMasterRead;
617     Status  = PciIo->Map (PciIo, MapOp, Request, &Len, &PhyAddr, &Map);
618 
619     if (EFI_ERROR (Status) || (Len != sizeof (EFI_USB_DEVICE_REQUEST))) {
620       goto ON_ERROR;
621     }
622 
623     Urb->RequestPhy = (VOID *) ((UINTN) PhyAddr);
624     Urb->RequestMap = Map;
625   }
626 
627   if (Data != NULL) {
628     Len     = DataLen;
629 
630     if (Ep->Direction == EfiUsbDataIn) {
631       MapOp = EfiPciIoOperationBusMasterWrite;
632     } else {
633       MapOp = EfiPciIoOperationBusMasterRead;
634     }
635 
636     Status  = PciIo->Map (PciIo, MapOp, Data, &Len, &PhyAddr, &Map);
637 
638     if (EFI_ERROR (Status) || (Len != DataLen)) {
639       goto ON_ERROR;
640     }
641 
642     Urb->DataPhy  = (VOID *) ((UINTN) PhyAddr);
643     Urb->DataMap  = Map;
644   }
645 
646   Status = EhcCreateQtds (Ehc, Urb);
647 
648   if (EFI_ERROR (Status)) {
649     goto ON_ERROR;
650   }
651 
652   return Urb;
653 
654 ON_ERROR:
655   EhcFreeUrb (Ehc, Urb);
656   return NULL;
657 }
658