TianoCore EDK2 master
Loading...
Searching...
No Matches
EhciUrb.c
Go to the documentation of this file.
1
12#include "Ehci.h"
13
28EHC_QTD *
30 IN USB2_HC_DEV *Ehc,
31 IN UINT8 *Data,
32 IN UINT8 *DataPhy,
33 IN UINTN DataLen,
34 IN UINT8 PktId,
35 IN UINT8 Toggle,
36 IN UINTN MaxPacket
37 )
38{
39 EHC_QTD *Qtd;
40 QTD_HW *QtdHw;
41 UINTN Index;
42 UINTN Len;
43 UINTN ThisBufLen;
44
45 ASSERT (Ehc != NULL);
46
47 Qtd = UsbHcAllocateMem (Ehc->MemPool, sizeof (EHC_QTD));
48
49 if (Qtd == NULL) {
50 return NULL;
51 }
52
53 Qtd->Signature = EHC_QTD_SIG;
54 Qtd->Data = Data;
55 Qtd->DataLen = 0;
56
57 InitializeListHead (&Qtd->QtdList);
58
59 QtdHw = &Qtd->QtdHw;
60 QtdHw->NextQtd = QTD_LINK (NULL, TRUE);
61 QtdHw->AltNext = QTD_LINK (NULL, TRUE);
62 QtdHw->Status = QTD_STAT_ACTIVE;
63 QtdHw->Pid = PktId;
64 QtdHw->ErrCnt = QTD_MAX_ERR;
65 QtdHw->Ioc = 0;
66 QtdHw->TotalBytes = 0;
67 QtdHw->DataToggle = Toggle;
68
69 //
70 // Fill in the buffer points
71 //
72 if (Data != NULL) {
73 Len = 0;
74
75 for (Index = 0; Index <= QTD_MAX_BUFFER; Index++) {
76 //
77 // Set the buffer point (Check page 41 EHCI Spec 1.0). No need to
78 // compute the offset and clear Reserved fields. This is already
79 // done in the data point.
80 //
81 QtdHw->Page[Index] = EHC_LOW_32BIT (DataPhy);
82 QtdHw->PageHigh[Index] = EHC_HIGH_32BIT (DataPhy);
83
84 ThisBufLen = QTD_BUF_LEN - (EHC_LOW_32BIT (DataPhy) & QTD_BUF_MASK);
85
86 if (Len + ThisBufLen >= DataLen) {
87 Len = DataLen;
88 break;
89 }
90
91 Len += ThisBufLen;
92 Data += ThisBufLen;
93 DataPhy += ThisBufLen;
94 }
95
96 //
97 // Need to fix the last pointer if the Qtd can't hold all the
98 // user's data to make sure that the length is in the unit of
99 // max packets. If it can hold all the data, there is no such
100 // need.
101 //
102 if (Len < DataLen) {
103 Len = Len - Len % MaxPacket;
104 }
105
106 QtdHw->TotalBytes = (UINT32)Len;
107 Qtd->DataLen = Len;
108 }
109
110 return Qtd;
111}
112
124VOID
126 IN USB_ENDPOINT *Ep,
127 IN QH_HW *QhHw
128 )
129{
130 //
131 // Because UEFI interface can't utilitize an endpoint with
132 // poll rate faster than 1ms, only need to set one bit in
133 // the queue head. simple. But it may be changed later. If
134 // sub-1ms interrupt is supported, need to update the S-Mask
135 // here
136 //
137 if (Ep->DevSpeed == EFI_USB_SPEED_HIGH) {
138 QhHw->SMask = QH_MICROFRAME_0;
139 return;
140 }
141
142 //
143 // For low/full speed device, the transfer must go through
144 // the split transaction. Need to update three fields
145 // 1. SplitXState in the status
146 // 2. Microframe S-Mask
147 // 3. Microframe C-Mask
148 // UEFI USB doesn't exercise admission control. It simplely
149 // schedule the high speed transactions in microframe 0, and
150 // full/low speed transactions at microframe 1. This also
151 // avoid the use of FSTN.
152 //
153 QhHw->SMask = QH_MICROFRAME_1;
154 QhHw->CMask = QH_MICROFRAME_3 | QH_MICROFRAME_4 | QH_MICROFRAME_5;
155}
156
166EHC_QH *
168 IN USB2_HC_DEV *Ehci,
169 IN USB_ENDPOINT *Ep
170 )
171{
172 EHC_QH *Qh;
173 QH_HW *QhHw;
174
175 Qh = UsbHcAllocateMem (Ehci->MemPool, sizeof (EHC_QH));
176
177 if (Qh == NULL) {
178 return NULL;
179 }
180
181 Qh->Signature = EHC_QH_SIG;
182 Qh->NextQh = NULL;
183 Qh->Interval = Ep->PollRate;
184
185 InitializeListHead (&Qh->Qtds);
186
187 QhHw = &Qh->QhHw;
188 QhHw->HorizonLink = QH_LINK (NULL, 0, TRUE);
189 QhHw->DeviceAddr = Ep->DevAddr;
190 QhHw->Inactive = 0;
191 QhHw->EpNum = Ep->EpAddr;
192 QhHw->EpSpeed = Ep->DevSpeed;
193 QhHw->DtCtrl = 0;
194 QhHw->ReclaimHead = 0;
195 QhHw->MaxPacketLen = (UINT32)Ep->MaxPacket;
196 QhHw->CtrlEp = 0;
197 QhHw->NakReload = QH_NAK_RELOAD;
198 QhHw->HubAddr = Ep->HubAddr;
199 QhHw->PortNum = Ep->HubPort;
200 QhHw->Multiplier = 1;
201 QhHw->DataToggle = Ep->Toggle;
202
203 if (Ep->DevSpeed != EFI_USB_SPEED_HIGH) {
204 QhHw->Status |= QTD_STAT_DO_SS;
205 }
206
207 switch (Ep->Type) {
208 case EHC_CTRL_TRANSFER:
209 //
210 // Special initialization for the control transfer:
211 // 1. Control transfer initialize data toggle from each QTD
212 // 2. Set the Control Endpoint Flag (C) for low/full speed endpoint.
213 //
214 QhHw->DtCtrl = 1;
215
216 if (Ep->DevSpeed != EFI_USB_SPEED_HIGH) {
217 QhHw->CtrlEp = 1;
218 }
219
220 break;
221
222 case EHC_INT_TRANSFER_ASYNC:
223 case EHC_INT_TRANSFER_SYNC:
224 //
225 // Special initialization for the interrupt transfer
226 // to set the S-Mask and C-Mask
227 //
228 QhHw->NakReload = 0;
229 EhcInitIntQh (Ep, QhHw);
230 break;
231
232 case EHC_BULK_TRANSFER:
233 if ((Ep->DevSpeed == EFI_USB_SPEED_HIGH) && (Ep->Direction == EfiUsbDataOut)) {
234 QhHw->Status |= QTD_STAT_DO_PING;
235 }
236
237 break;
238 }
239
240 return Qh;
241}
242
256UINTN
258 IN UINTN Interval
259 )
260{
261 UINTN BitCount;
262
263 if (Interval == 0) {
264 return 1;
265 }
266
267 //
268 // Find the index (1 based) of the highest non-zero bit
269 //
270 BitCount = 0;
271
272 while (Interval != 0) {
273 Interval >>= 1;
274 BitCount++;
275 }
276
277 return (UINTN)1 << (BitCount - 1);
278}
279
287VOID
289 IN USB2_HC_DEV *Ehc,
290 IN LIST_ENTRY *Qtds
291 )
292{
293 LIST_ENTRY *Entry;
294 LIST_ENTRY *Next;
295 EHC_QTD *Qtd;
296
297 BASE_LIST_FOR_EACH_SAFE (Entry, Next, Qtds) {
298 Qtd = EFI_LIST_CONTAINER (Entry, EHC_QTD, QtdList);
299
300 RemoveEntryList (&Qtd->QtdList);
301 UsbHcFreeMem (Ehc->MemPool, Qtd, sizeof (EHC_QTD));
302 }
303}
304
312VOID
314 IN USB2_HC_DEV *Ehc,
315 IN URB *Urb
316 )
317{
318 EFI_PCI_IO_PROTOCOL *PciIo;
319
320 PciIo = Ehc->PciIo;
321
322 if (Urb->RequestPhy != NULL) {
323 PciIo->Unmap (PciIo, Urb->RequestMap);
324 }
325
326 if (Urb->DataMap != NULL) {
327 PciIo->Unmap (PciIo, Urb->DataMap);
328 }
329
330 if (Urb->Qh != NULL) {
331 //
332 // Ensure that this queue head has been unlinked from the
333 // schedule data structures. Free all the associated QTDs
334 //
335 EhcFreeQtds (Ehc, &Urb->Qh->Qtds);
336 UsbHcFreeMem (Ehc->MemPool, Urb->Qh, sizeof (EHC_QH));
337 }
338
339 gBS->FreePool (Urb);
340}
341
354 IN USB2_HC_DEV *Ehc,
355 IN URB *Urb
356 )
357{
358 USB_ENDPOINT *Ep;
359 EHC_QH *Qh;
360 EHC_QTD *Qtd;
361 EHC_QTD *StatusQtd;
362 EHC_QTD *NextQtd;
363 LIST_ENTRY *Entry;
364 UINT32 AlterNext;
365 UINT8 Toggle;
366 UINTN Len;
367 UINT8 Pid;
368 EFI_PHYSICAL_ADDRESS PhyAddr;
369
370 ASSERT ((Urb != NULL) && (Urb->Qh != NULL));
371
372 //
373 // EHCI follows the alternet next QTD pointer if it meets
374 // a short read and the AlterNext pointer is valid. UEFI
375 // EHCI driver should terminate the transfer except the
376 // control transfer.
377 //
378 Toggle = 0;
379 Qh = Urb->Qh;
380 Ep = &Urb->Ep;
381 StatusQtd = NULL;
382 AlterNext = QTD_LINK (NULL, TRUE);
383
384 PhyAddr = UsbHcGetPciAddressForHostMem (Ehc->MemPool, Ehc->ShortReadStop, sizeof (EHC_QTD));
385 if (Ep->Direction == EfiUsbDataIn) {
386 AlterNext = QTD_LINK (PhyAddr, FALSE);
387 }
388
389 //
390 // Build the Setup and status packets for control transfer
391 //
392 if (Urb->Ep.Type == EHC_CTRL_TRANSFER) {
393 Len = sizeof (EFI_USB_DEVICE_REQUEST);
394 Qtd = EhcCreateQtd (Ehc, (UINT8 *)Urb->Request, (UINT8 *)Urb->RequestPhy, Len, QTD_PID_SETUP, 0, Ep->MaxPacket);
395
396 if (Qtd == NULL) {
397 return EFI_OUT_OF_RESOURCES;
398 }
399
400 InsertTailList (&Qh->Qtds, &Qtd->QtdList);
401
402 //
403 // Create the status packet now. Set the AlterNext to it. So, when
404 // EHCI meets a short control read, it can resume at the status stage.
405 // Use the opposite direction of the data stage, or IN if there is
406 // no data stage.
407 //
408 if (Ep->Direction == EfiUsbDataIn) {
409 Pid = QTD_PID_OUTPUT;
410 } else {
411 Pid = QTD_PID_INPUT;
412 }
413
414 StatusQtd = EhcCreateQtd (Ehc, NULL, NULL, 0, Pid, 1, Ep->MaxPacket);
415
416 if (StatusQtd == NULL) {
417 goto ON_ERROR;
418 }
419
420 if (Ep->Direction == EfiUsbDataIn) {
421 PhyAddr = UsbHcGetPciAddressForHostMem (Ehc->MemPool, StatusQtd, sizeof (EHC_QTD));
422 AlterNext = QTD_LINK (PhyAddr, FALSE);
423 }
424
425 Toggle = 1;
426 }
427
428 //
429 // Build the data packets for all the transfers
430 //
431 if (Ep->Direction == EfiUsbDataIn) {
432 Pid = QTD_PID_INPUT;
433 } else {
434 Pid = QTD_PID_OUTPUT;
435 }
436
437 Qtd = NULL;
438 Len = 0;
439
440 while (Len < Urb->DataLen) {
441 Qtd = EhcCreateQtd (
442 Ehc,
443 (UINT8 *)Urb->Data + Len,
444 (UINT8 *)Urb->DataPhy + Len,
445 Urb->DataLen - Len,
446 Pid,
447 Toggle,
448 Ep->MaxPacket
449 );
450
451 if (Qtd == NULL) {
452 goto ON_ERROR;
453 }
454
455 Qtd->QtdHw.AltNext = AlterNext;
456 InsertTailList (&Qh->Qtds, &Qtd->QtdList);
457
458 //
459 // Switch the Toggle bit if odd number of packets are included in the QTD.
460 //
461 if (((Qtd->DataLen + Ep->MaxPacket - 1) / Ep->MaxPacket) % 2) {
462 Toggle = (UINT8)(1 - Toggle);
463 }
464
465 Len += Qtd->DataLen;
466 }
467
468 //
469 // Insert the status packet for control transfer
470 //
471 if (Ep->Type == EHC_CTRL_TRANSFER) {
472 InsertTailList (&Qh->Qtds, &StatusQtd->QtdList);
473 }
474
475 //
476 // OK, all the QTDs needed are created. Now, fix the NextQtd point
477 //
478 BASE_LIST_FOR_EACH (Entry, &Qh->Qtds) {
479 Qtd = EFI_LIST_CONTAINER (Entry, EHC_QTD, QtdList);
480
481 //
482 // break if it is the last entry on the list
483 //
484 if (Entry->ForwardLink == &Qh->Qtds) {
485 break;
486 }
487
488 NextQtd = EFI_LIST_CONTAINER (Entry->ForwardLink, EHC_QTD, QtdList);
489 PhyAddr = UsbHcGetPciAddressForHostMem (Ehc->MemPool, NextQtd, sizeof (EHC_QTD));
490 Qtd->QtdHw.NextQtd = QTD_LINK (PhyAddr, FALSE);
491 }
492
493 //
494 // Link the QTDs to the queue head
495 //
496 NextQtd = EFI_LIST_CONTAINER (Qh->Qtds.ForwardLink, EHC_QTD, QtdList);
497 PhyAddr = UsbHcGetPciAddressForHostMem (Ehc->MemPool, NextQtd, sizeof (EHC_QTD));
498 Qh->QhHw.NextQtd = QTD_LINK (PhyAddr, FALSE);
499 return EFI_SUCCESS;
500
501ON_ERROR:
502 EhcFreeQtds (Ehc, &Qh->Qtds);
503 return EFI_OUT_OF_RESOURCES;
504}
505
527URB *
529 IN USB2_HC_DEV *Ehc,
530 IN UINT8 DevAddr,
531 IN UINT8 EpAddr,
532 IN UINT8 DevSpeed,
533 IN UINT8 Toggle,
534 IN UINTN MaxPacket,
536 IN UINTN Type,
537 IN EFI_USB_DEVICE_REQUEST *Request,
538 IN VOID *Data,
539 IN UINTN DataLen,
541 IN VOID *Context,
542 IN UINTN Interval
543 )
544{
545 USB_ENDPOINT *Ep;
546 EFI_PHYSICAL_ADDRESS PhyAddr;
548 EFI_PCI_IO_PROTOCOL *PciIo;
549 EFI_STATUS Status;
550 UINTN Len;
551 URB *Urb;
552 VOID *Map;
553
554 Urb = AllocateZeroPool (sizeof (URB));
555
556 if (Urb == NULL) {
557 return NULL;
558 }
559
560 Urb->Signature = EHC_URB_SIG;
561 InitializeListHead (&Urb->UrbList);
562
563 Ep = &Urb->Ep;
564 Ep->DevAddr = DevAddr;
565 Ep->EpAddr = (UINT8)(EpAddr & 0x0F);
566 Ep->Direction = (((EpAddr & 0x80) != 0) ? EfiUsbDataIn : EfiUsbDataOut);
567 Ep->DevSpeed = DevSpeed;
568 Ep->MaxPacket = MaxPacket;
569
570 Ep->HubAddr = 0;
571 Ep->HubPort = 0;
572
573 if (DevSpeed != EFI_USB_SPEED_HIGH) {
574 ASSERT (Hub != NULL);
575
576 Ep->HubAddr = Hub->TranslatorHubAddress;
577 Ep->HubPort = Hub->TranslatorPortNumber;
578 }
579
580 Ep->Toggle = Toggle;
581 Ep->Type = Type;
582 Ep->PollRate = EhcConvertPollRate (Interval);
583
584 Urb->Request = Request;
585 Urb->Data = Data;
586 Urb->DataLen = DataLen;
587 Urb->Callback = Callback;
588 Urb->Context = Context;
589
590 PciIo = Ehc->PciIo;
591 Urb->Qh = EhcCreateQh (Ehc, &Urb->Ep);
592
593 if (Urb->Qh == NULL) {
594 goto ON_ERROR;
595 }
596
597 //
598 // Map the request and user data
599 //
600 if (Request != NULL) {
601 Len = sizeof (EFI_USB_DEVICE_REQUEST);
603 Status = PciIo->Map (PciIo, MapOp, Request, &Len, &PhyAddr, &Map);
604
605 if (EFI_ERROR (Status) || (Len != sizeof (EFI_USB_DEVICE_REQUEST))) {
606 goto ON_ERROR;
607 }
608
609 Urb->RequestPhy = (VOID *)((UINTN)PhyAddr);
610 Urb->RequestMap = Map;
611 }
612
613 if (Data != NULL) {
614 Len = DataLen;
615
616 if (Ep->Direction == EfiUsbDataIn) {
618 } else {
620 }
621
622 Status = PciIo->Map (PciIo, MapOp, Data, &Len, &PhyAddr, &Map);
623
624 if (EFI_ERROR (Status) || (Len != DataLen)) {
625 goto ON_ERROR;
626 }
627
628 Urb->DataPhy = (VOID *)((UINTN)PhyAddr);
629 Urb->DataMap = Map;
630 }
631
632 Status = EhcCreateQtds (Ehc, Urb);
633
634 if (EFI_ERROR (Status)) {
635 goto ON_ERROR;
636 }
637
638 return Urb;
639
640ON_ERROR:
641 EhcFreeUrb (Ehc, Urb);
642 return NULL;
643}
UINT64 UINTN
#define BASE_LIST_FOR_EACH_SAFE(Entry, NextEntry, ListHead)
Definition: BaseLib.h:2929
#define BASE_LIST_FOR_EACH(Entry, ListHead)
Definition: BaseLib.h:2913
LIST_ENTRY *EFIAPI RemoveEntryList(IN CONST LIST_ENTRY *Entry)
Definition: LinkedList.c:590
LIST_ENTRY *EFIAPI InitializeListHead(IN OUT LIST_ENTRY *ListHead)
Definition: LinkedList.c:182
LIST_ENTRY *EFIAPI InsertTailList(IN OUT LIST_ENTRY *ListHead, IN OUT LIST_ENTRY *Entry)
Definition: LinkedList.c:259
VOID EhcFreeQtds(IN USB2_HC_DEV *Ehc, IN LIST_ENTRY *Qtds)
Definition: EhciUrb.c:288
VOID EhcInitIntQh(IN USB_ENDPOINT *Ep, IN QH_HW *QhHw)
Definition: EhciUrb.c:125
EFI_STATUS EhcCreateQtds(IN USB2_HC_DEV *Ehc, IN URB *Urb)
Definition: EhciUrb.c:353
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)
Definition: EhciUrb.c:29
EHC_QH * EhcCreateQh(IN USB2_HC_DEV *Ehci, IN USB_ENDPOINT *Ep)
Definition: EhciUrb.c:167
UINTN EhcConvertPollRate(IN UINTN Interval)
Definition: EhciUrb.c:257
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)
Definition: EhciUrb.c:528
VOID EhcFreeUrb(IN USB2_HC_DEV *Ehc, IN URB *Urb)
Definition: EhciUrb.c:313
EFI_PHYSICAL_ADDRESS UsbHcGetPciAddressForHostMem(IN USBHC_MEM_POOL *Pool, IN VOID *Mem, IN UINTN Size)
Definition: UsbHcMem.c:223
VOID UsbHcFreeMem(IN USBHC_MEM_POOL *Pool, IN VOID *Mem, IN UINTN Size)
Definition: UsbHcMem.c:493
VOID * UsbHcAllocateMem(IN USBHC_MEM_POOL *Pool, IN UINTN Size)
Definition: UsbHcMem.c:419
VOID *EFIAPI AllocateZeroPool(IN UINTN AllocationSize)
#define NULL
Definition: Base.h:319
#define TRUE
Definition: Base.h:301
#define FALSE
Definition: Base.h:307
#define IN
Definition: Base.h:279
EFI_PCI_IO_PROTOCOL_OPERATION
Definition: PciIo.h:77
@ EfiPciIoOperationBusMasterWrite
Definition: PciIo.h:85
@ EfiPciIoOperationBusMasterRead
Definition: PciIo.h:81
EFI_STATUS(EFIAPI * EFI_ASYNC_USB_TRANSFER_CALLBACK)(IN VOID *Data, IN UINTN DataLength, IN VOID *Context, IN UINT32 Status)
Definition: UsbIo.h:80
UINT64 EFI_PHYSICAL_ADDRESS
Definition: UefiBaseType.h:50
RETURN_STATUS EFI_STATUS
Definition: UefiBaseType.h:29
#define EFI_SUCCESS
Definition: UefiBaseType.h:112
EFI_BOOT_SERVICES * gBS
Definition: EhciUrb.h:200
Definition: EhciUrb.h:104
Definition: EhciUrb.h:88