]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Bus/Pci/EhciDxe/EhciUrb.c
MdeModulePkg: Apply uncrustify changes
[mirror_edk2.git] / MdeModulePkg / Bus / Pci / EhciDxe / EhciUrb.c
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 Copyright (c) Microsoft Corporation.<BR>
8 SPDX-License-Identifier: BSD-2-Clause-Patent
9
10 **/
11
12 #include "Ehci.h"
13
14 /**
15 Create a single QTD to hold the data.
16
17 @param Ehc The EHCI device.
18 @param Data The cpu memory address of current data not associated with a QTD.
19 @param DataPhy The pci bus address of current data not associated with a QTD.
20 @param DataLen The length of the data.
21 @param PktId Packet ID to use in the QTD.
22 @param Toggle Data toggle to use in the QTD.
23 @param MaxPacket Maximu packet length of the endpoint.
24
25 @return Created QTD or NULL if failed to create one.
26
27 **/
28 EHC_QTD *
29 EhcCreateQtd (
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
113 /**
114 Initialize the queue head for interrupt transfer,
115 that is, initialize the following three fields:
116 1. SplitXState in the Status field
117 2. Microframe S-mask
118 3. Microframe C-mask
119
120 @param Ep The queue head's related endpoint.
121 @param QhHw The queue head to initialize.
122
123 **/
124 VOID
125 EhcInitIntQh (
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
157 /**
158 Allocate and initialize a EHCI queue head.
159
160 @param Ehci The EHCI device.
161 @param Ep The endpoint to create queue head for.
162
163 @return Created queue head or NULL if failed to create one.
164
165 **/
166 EHC_QH *
167 EhcCreateQh (
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
243 /**
244 Convert the poll interval from application to that
245 be used by EHCI interface data structure. Only need
246 to get the max 2^n that is less than interval. UEFI
247 can't support high speed endpoint with a interval less
248 than 8 microframe because interval is specified in
249 the unit of ms (millisecond).
250
251 @param Interval The interval to convert.
252
253 @return The converted interval.
254
255 **/
256 UINTN
257 EhcConvertPollRate (
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
280 /**
281 Free a list of QTDs.
282
283 @param Ehc The EHCI device.
284 @param Qtds The list head of the QTD.
285
286 **/
287 VOID
288 EhcFreeQtds (
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
305 /**
306 Free an allocated URB. It is possible for it to be partially inited.
307
308 @param Ehc The EHCI device.
309 @param Urb The URB to free.
310
311 **/
312 VOID
313 EhcFreeUrb (
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
342 /**
343 Create a list of QTDs for the URB.
344
345 @param Ehc The EHCI device.
346 @param Urb The URB to create QTDs for.
347
348 @retval EFI_OUT_OF_RESOURCES Failed to allocate resource for QTD.
349 @retval EFI_SUCCESS The QTDs are allocated for the URB.
350
351 **/
352 EFI_STATUS
353 EhcCreateQtds (
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
501 ON_ERROR:
502 EhcFreeQtds (Ehc, &Qh->Qtds);
503 return EFI_OUT_OF_RESOURCES;
504 }
505
506 /**
507 Create a new URB and its associated QTD.
508
509 @param Ehc The EHCI device.
510 @param DevAddr The device address.
511 @param EpAddr Endpoint addrress & its direction.
512 @param DevSpeed The device speed.
513 @param Toggle Initial data toggle to use.
514 @param MaxPacket The max packet length of the endpoint.
515 @param Hub The transaction translator to use.
516 @param Type The transaction type.
517 @param Request The standard USB request for control transfer.
518 @param Data The user data to transfer.
519 @param DataLen The length of data buffer.
520 @param Callback The function to call when data is transferred.
521 @param Context The context to the callback.
522 @param Interval The interval for interrupt transfer.
523
524 @return Created URB or NULL.
525
526 **/
527 URB *
528 EhcCreateUrb (
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,
535 IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Hub,
536 IN UINTN Type,
537 IN EFI_USB_DEVICE_REQUEST *Request,
538 IN VOID *Data,
539 IN UINTN DataLen,
540 IN EFI_ASYNC_USB_TRANSFER_CALLBACK Callback,
541 IN VOID *Context,
542 IN UINTN Interval
543 )
544 {
545 USB_ENDPOINT *Ep;
546 EFI_PHYSICAL_ADDRESS PhyAddr;
547 EFI_PCI_IO_PROTOCOL_OPERATION MapOp;
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);
602 MapOp = EfiPciIoOperationBusMasterRead;
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) {
617 MapOp = EfiPciIoOperationBusMasterWrite;
618 } else {
619 MapOp = EfiPciIoOperationBusMasterRead;
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
640 ON_ERROR:
641 EhcFreeUrb (Ehc, Urb);
642 return NULL;
643 }