]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Bus/Pci/EhciDxe/EhciUrb.c
MdeModulePkg: Replace BSD License with BSD+Patent License
[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 SPDX-License-Identifier: BSD-2-Clause-Patent
8
9 **/
10
11 #include "Ehci.h"
12
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
115 /**
116 Initialize the queue head for interrupt transfer,
117 that is, initialize the following three fields:
118 1. SplitXState in the Status field
119 2. Microframe S-mask
120 3. Microframe C-mask
121
122 @param Ep The queue head's related endpoint.
123 @param QhHw The queue head to initialize.
124
125 **/
126 VOID
127 EhcInitIntQh (
128 IN USB_ENDPOINT *Ep,
129 IN QH_HW *QhHw
130 )
131 {
132 //
133 // Because UEFI interface can't utilitize an endpoint with
134 // poll rate faster than 1ms, only need to set one bit in
135 // the queue head. simple. But it may be changed later. If
136 // sub-1ms interrupt is supported, need to update the S-Mask
137 // here
138 //
139 if (Ep->DevSpeed == EFI_USB_SPEED_HIGH) {
140 QhHw->SMask = QH_MICROFRAME_0;
141 return ;
142 }
143
144 //
145 // For low/full speed device, the transfer must go through
146 // the split transaction. Need to update three fields
147 // 1. SplitXState in the status
148 // 2. Microframe S-Mask
149 // 3. Microframe C-Mask
150 // UEFI USB doesn't exercise admission control. It simplely
151 // schedule the high speed transactions in microframe 0, and
152 // full/low speed transactions at microframe 1. This also
153 // avoid the use of FSTN.
154 //
155 QhHw->SMask = QH_MICROFRAME_1;
156 QhHw->CMask = QH_MICROFRAME_3 | QH_MICROFRAME_4 | QH_MICROFRAME_5;
157 }
158
159
160
161 /**
162 Allocate and initialize a EHCI queue head.
163
164 @param Ehci The EHCI device.
165 @param Ep The endpoint to create queue head for.
166
167 @return Created queue head or NULL if failed to create one.
168
169 **/
170 EHC_QH *
171 EhcCreateQh (
172 IN USB2_HC_DEV *Ehci,
173 IN USB_ENDPOINT *Ep
174 )
175 {
176 EHC_QH *Qh;
177 QH_HW *QhHw;
178
179 Qh = UsbHcAllocateMem (Ehci->MemPool, sizeof (EHC_QH));
180
181 if (Qh == NULL) {
182 return NULL;
183 }
184
185 Qh->Signature = EHC_QH_SIG;
186 Qh->NextQh = NULL;
187 Qh->Interval = Ep->PollRate;
188
189 InitializeListHead (&Qh->Qtds);
190
191 QhHw = &Qh->QhHw;
192 QhHw->HorizonLink = QH_LINK (NULL, 0, TRUE);
193 QhHw->DeviceAddr = Ep->DevAddr;
194 QhHw->Inactive = 0;
195 QhHw->EpNum = Ep->EpAddr;
196 QhHw->EpSpeed = Ep->DevSpeed;
197 QhHw->DtCtrl = 0;
198 QhHw->ReclaimHead = 0;
199 QhHw->MaxPacketLen = (UINT32) Ep->MaxPacket;
200 QhHw->CtrlEp = 0;
201 QhHw->NakReload = QH_NAK_RELOAD;
202 QhHw->HubAddr = Ep->HubAddr;
203 QhHw->PortNum = Ep->HubPort;
204 QhHw->Multiplier = 1;
205 QhHw->DataToggle = Ep->Toggle;
206
207 if (Ep->DevSpeed != EFI_USB_SPEED_HIGH) {
208 QhHw->Status |= QTD_STAT_DO_SS;
209 }
210
211 switch (Ep->Type) {
212 case EHC_CTRL_TRANSFER:
213 //
214 // Special initialization for the control transfer:
215 // 1. Control transfer initialize data toggle from each QTD
216 // 2. Set the Control Endpoint Flag (C) for low/full speed endpoint.
217 //
218 QhHw->DtCtrl = 1;
219
220 if (Ep->DevSpeed != EFI_USB_SPEED_HIGH) {
221 QhHw->CtrlEp = 1;
222 }
223 break;
224
225 case EHC_INT_TRANSFER_ASYNC:
226 case EHC_INT_TRANSFER_SYNC:
227 //
228 // Special initialization for the interrupt transfer
229 // to set the S-Mask and C-Mask
230 //
231 QhHw->NakReload = 0;
232 EhcInitIntQh (Ep, QhHw);
233 break;
234
235 case EHC_BULK_TRANSFER:
236 if ((Ep->DevSpeed == EFI_USB_SPEED_HIGH) && (Ep->Direction == EfiUsbDataOut)) {
237 QhHw->Status |= QTD_STAT_DO_PING;
238 }
239
240 break;
241 }
242
243 return Qh;
244 }
245
246
247 /**
248 Convert the poll interval from application to that
249 be used by EHCI interface data structure. Only need
250 to get the max 2^n that is less than interval. UEFI
251 can't support high speed endpoint with a interval less
252 than 8 microframe because interval is specified in
253 the unit of ms (millisecond).
254
255 @param Interval The interval to convert.
256
257 @return The converted interval.
258
259 **/
260 UINTN
261 EhcConvertPollRate (
262 IN UINTN Interval
263 )
264 {
265 UINTN BitCount;
266
267 if (Interval == 0) {
268 return 1;
269 }
270
271 //
272 // Find the index (1 based) of the highest non-zero bit
273 //
274 BitCount = 0;
275
276 while (Interval != 0) {
277 Interval >>= 1;
278 BitCount++;
279 }
280
281 return (UINTN)1 << (BitCount - 1);
282 }
283
284
285 /**
286 Free a list of QTDs.
287
288 @param Ehc The EHCI device.
289 @param Qtds The list head of the QTD.
290
291 **/
292 VOID
293 EhcFreeQtds (
294 IN USB2_HC_DEV *Ehc,
295 IN LIST_ENTRY *Qtds
296 )
297 {
298 LIST_ENTRY *Entry;
299 LIST_ENTRY *Next;
300 EHC_QTD *Qtd;
301
302 EFI_LIST_FOR_EACH_SAFE (Entry, Next, Qtds) {
303 Qtd = EFI_LIST_CONTAINER (Entry, EHC_QTD, QtdList);
304
305 RemoveEntryList (&Qtd->QtdList);
306 UsbHcFreeMem (Ehc->MemPool, Qtd, sizeof (EHC_QTD));
307 }
308 }
309
310
311 /**
312 Free an allocated URB. It is possible for it to be partially inited.
313
314 @param Ehc The EHCI device.
315 @param Urb The URB to free.
316
317 **/
318 VOID
319 EhcFreeUrb (
320 IN USB2_HC_DEV *Ehc,
321 IN URB *Urb
322 )
323 {
324 EFI_PCI_IO_PROTOCOL *PciIo;
325
326 PciIo = Ehc->PciIo;
327
328 if (Urb->RequestPhy != NULL) {
329 PciIo->Unmap (PciIo, Urb->RequestMap);
330 }
331
332 if (Urb->DataMap != NULL) {
333 PciIo->Unmap (PciIo, Urb->DataMap);
334 }
335
336 if (Urb->Qh != NULL) {
337 //
338 // Ensure that this queue head has been unlinked from the
339 // schedule data structures. Free all the associated QTDs
340 //
341 EhcFreeQtds (Ehc, &Urb->Qh->Qtds);
342 UsbHcFreeMem (Ehc->MemPool, Urb->Qh, sizeof (EHC_QH));
343 }
344
345 gBS->FreePool (Urb);
346 }
347
348
349 /**
350 Create a list of QTDs for the URB.
351
352 @param Ehc The EHCI device.
353 @param Urb The URB to create QTDs for.
354
355 @retval EFI_OUT_OF_RESOURCES Failed to allocate resource for QTD.
356 @retval EFI_SUCCESS The QTDs are allocated for the URB.
357
358 **/
359 EFI_STATUS
360 EhcCreateQtds (
361 IN USB2_HC_DEV *Ehc,
362 IN URB *Urb
363 )
364 {
365 USB_ENDPOINT *Ep;
366 EHC_QH *Qh;
367 EHC_QTD *Qtd;
368 EHC_QTD *StatusQtd;
369 EHC_QTD *NextQtd;
370 LIST_ENTRY *Entry;
371 UINT32 AlterNext;
372 UINT8 Toggle;
373 UINTN Len;
374 UINT8 Pid;
375 EFI_PHYSICAL_ADDRESS PhyAddr;
376
377 ASSERT ((Urb != NULL) && (Urb->Qh != NULL));
378
379 //
380 // EHCI follows the alternet next QTD pointer if it meets
381 // a short read and the AlterNext pointer is valid. UEFI
382 // EHCI driver should terminate the transfer except the
383 // control transfer.
384 //
385 Toggle = 0;
386 Qh = Urb->Qh;
387 Ep = &Urb->Ep;
388 StatusQtd = NULL;
389 AlterNext = QTD_LINK (NULL, TRUE);
390
391 PhyAddr = UsbHcGetPciAddressForHostMem (Ehc->MemPool, Ehc->ShortReadStop, sizeof (EHC_QTD));
392 if (Ep->Direction == EfiUsbDataIn) {
393 AlterNext = QTD_LINK (PhyAddr, FALSE);
394 }
395
396 //
397 // Build the Setup and status packets for control transfer
398 //
399 if (Urb->Ep.Type == EHC_CTRL_TRANSFER) {
400 Len = sizeof (EFI_USB_DEVICE_REQUEST);
401 Qtd = EhcCreateQtd (Ehc, (UINT8 *)Urb->Request, (UINT8 *)Urb->RequestPhy, Len, QTD_PID_SETUP, 0, Ep->MaxPacket);
402
403 if (Qtd == NULL) {
404 return EFI_OUT_OF_RESOURCES;
405 }
406
407 InsertTailList (&Qh->Qtds, &Qtd->QtdList);
408
409 //
410 // Create the status packet now. Set the AlterNext to it. So, when
411 // EHCI meets a short control read, it can resume at the status stage.
412 // Use the opposite direction of the data stage, or IN if there is
413 // no data stage.
414 //
415 if (Ep->Direction == EfiUsbDataIn) {
416 Pid = QTD_PID_OUTPUT;
417 } else {
418 Pid = QTD_PID_INPUT;
419 }
420
421 StatusQtd = EhcCreateQtd (Ehc, NULL, NULL, 0, Pid, 1, Ep->MaxPacket);
422
423 if (StatusQtd == NULL) {
424 goto ON_ERROR;
425 }
426
427 if (Ep->Direction == EfiUsbDataIn) {
428 PhyAddr = UsbHcGetPciAddressForHostMem (Ehc->MemPool, StatusQtd, sizeof (EHC_QTD));
429 AlterNext = QTD_LINK (PhyAddr, FALSE);
430 }
431
432 Toggle = 1;
433 }
434
435 //
436 // Build the data packets for all the transfers
437 //
438 if (Ep->Direction == EfiUsbDataIn) {
439 Pid = QTD_PID_INPUT;
440 } else {
441 Pid = QTD_PID_OUTPUT;
442 }
443
444 Qtd = NULL;
445 Len = 0;
446
447 while (Len < Urb->DataLen) {
448 Qtd = EhcCreateQtd (
449 Ehc,
450 (UINT8 *) Urb->Data + Len,
451 (UINT8 *) Urb->DataPhy + Len,
452 Urb->DataLen - Len,
453 Pid,
454 Toggle,
455 Ep->MaxPacket
456 );
457
458 if (Qtd == NULL) {
459 goto ON_ERROR;
460 }
461
462 Qtd->QtdHw.AltNext = AlterNext;
463 InsertTailList (&Qh->Qtds, &Qtd->QtdList);
464
465 //
466 // Switch the Toggle bit if odd number of packets are included in the QTD.
467 //
468 if (((Qtd->DataLen + Ep->MaxPacket - 1) / Ep->MaxPacket) % 2) {
469 Toggle = (UINT8) (1 - Toggle);
470 }
471
472 Len += Qtd->DataLen;
473 }
474
475 //
476 // Insert the status packet for control transfer
477 //
478 if (Ep->Type == EHC_CTRL_TRANSFER) {
479 InsertTailList (&Qh->Qtds, &StatusQtd->QtdList);
480 }
481
482 //
483 // OK, all the QTDs needed are created. Now, fix the NextQtd point
484 //
485 EFI_LIST_FOR_EACH (Entry, &Qh->Qtds) {
486 Qtd = EFI_LIST_CONTAINER (Entry, EHC_QTD, QtdList);
487
488 //
489 // break if it is the last entry on the list
490 //
491 if (Entry->ForwardLink == &Qh->Qtds) {
492 break;
493 }
494
495 NextQtd = EFI_LIST_CONTAINER (Entry->ForwardLink, EHC_QTD, QtdList);
496 PhyAddr = UsbHcGetPciAddressForHostMem (Ehc->MemPool, NextQtd, sizeof (EHC_QTD));
497 Qtd->QtdHw.NextQtd = QTD_LINK (PhyAddr, FALSE);
498 }
499
500 //
501 // Link the QTDs to the queue head
502 //
503 NextQtd = EFI_LIST_CONTAINER (Qh->Qtds.ForwardLink, EHC_QTD, QtdList);
504 PhyAddr = UsbHcGetPciAddressForHostMem (Ehc->MemPool, NextQtd, sizeof (EHC_QTD));
505 Qh->QhHw.NextQtd = QTD_LINK (PhyAddr, FALSE);
506 return EFI_SUCCESS;
507
508 ON_ERROR:
509 EhcFreeQtds (Ehc, &Qh->Qtds);
510 return EFI_OUT_OF_RESOURCES;
511 }
512
513
514 /**
515 Create a new URB and its associated QTD.
516
517 @param Ehc The EHCI device.
518 @param DevAddr The device address.
519 @param EpAddr Endpoint addrress & its direction.
520 @param DevSpeed The device speed.
521 @param Toggle Initial data toggle to use.
522 @param MaxPacket The max packet length of the endpoint.
523 @param Hub The transaction translator to use.
524 @param Type The transaction type.
525 @param Request The standard USB request for control transfer.
526 @param Data The user data to transfer.
527 @param DataLen The length of data buffer.
528 @param Callback The function to call when data is transferred.
529 @param Context The context to the callback.
530 @param Interval The interval for interrupt transfer.
531
532 @return Created URB or NULL.
533
534 **/
535 URB *
536 EhcCreateUrb (
537 IN USB2_HC_DEV *Ehc,
538 IN UINT8 DevAddr,
539 IN UINT8 EpAddr,
540 IN UINT8 DevSpeed,
541 IN UINT8 Toggle,
542 IN UINTN MaxPacket,
543 IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Hub,
544 IN UINTN Type,
545 IN EFI_USB_DEVICE_REQUEST *Request,
546 IN VOID *Data,
547 IN UINTN DataLen,
548 IN EFI_ASYNC_USB_TRANSFER_CALLBACK Callback,
549 IN VOID *Context,
550 IN UINTN Interval
551 )
552 {
553 USB_ENDPOINT *Ep;
554 EFI_PHYSICAL_ADDRESS PhyAddr;
555 EFI_PCI_IO_PROTOCOL_OPERATION MapOp;
556 EFI_PCI_IO_PROTOCOL *PciIo;
557 EFI_STATUS Status;
558 UINTN Len;
559 URB *Urb;
560 VOID *Map;
561
562 Urb = AllocateZeroPool (sizeof (URB));
563
564 if (Urb == NULL) {
565 return NULL;
566 }
567
568 Urb->Signature = EHC_URB_SIG;
569 InitializeListHead (&Urb->UrbList);
570
571 Ep = &Urb->Ep;
572 Ep->DevAddr = DevAddr;
573 Ep->EpAddr = (UINT8) (EpAddr & 0x0F);
574 Ep->Direction = (((EpAddr & 0x80) != 0) ? EfiUsbDataIn : EfiUsbDataOut);
575 Ep->DevSpeed = DevSpeed;
576 Ep->MaxPacket = MaxPacket;
577
578 Ep->HubAddr = 0;
579 Ep->HubPort = 0;
580
581 if (DevSpeed != EFI_USB_SPEED_HIGH) {
582 ASSERT (Hub != NULL);
583
584 Ep->HubAddr = Hub->TranslatorHubAddress;
585 Ep->HubPort = Hub->TranslatorPortNumber;
586 }
587
588 Ep->Toggle = Toggle;
589 Ep->Type = Type;
590 Ep->PollRate = EhcConvertPollRate (Interval);
591
592 Urb->Request = Request;
593 Urb->Data = Data;
594 Urb->DataLen = DataLen;
595 Urb->Callback = Callback;
596 Urb->Context = Context;
597
598 PciIo = Ehc->PciIo;
599 Urb->Qh = EhcCreateQh (Ehc, &Urb->Ep);
600
601 if (Urb->Qh == NULL) {
602 goto ON_ERROR;
603 }
604
605 //
606 // Map the request and user data
607 //
608 if (Request != NULL) {
609 Len = sizeof (EFI_USB_DEVICE_REQUEST);
610 MapOp = EfiPciIoOperationBusMasterRead;
611 Status = PciIo->Map (PciIo, MapOp, Request, &Len, &PhyAddr, &Map);
612
613 if (EFI_ERROR (Status) || (Len != sizeof (EFI_USB_DEVICE_REQUEST))) {
614 goto ON_ERROR;
615 }
616
617 Urb->RequestPhy = (VOID *) ((UINTN) PhyAddr);
618 Urb->RequestMap = Map;
619 }
620
621 if (Data != NULL) {
622 Len = DataLen;
623
624 if (Ep->Direction == EfiUsbDataIn) {
625 MapOp = EfiPciIoOperationBusMasterWrite;
626 } else {
627 MapOp = EfiPciIoOperationBusMasterRead;
628 }
629
630 Status = PciIo->Map (PciIo, MapOp, Data, &Len, &PhyAddr, &Map);
631
632 if (EFI_ERROR (Status) || (Len != DataLen)) {
633 goto ON_ERROR;
634 }
635
636 Urb->DataPhy = (VOID *) ((UINTN) PhyAddr);
637 Urb->DataMap = Map;
638 }
639
640 Status = EhcCreateQtds (Ehc, Urb);
641
642 if (EFI_ERROR (Status)) {
643 goto ON_ERROR;
644 }
645
646 return Urb;
647
648 ON_ERROR:
649 EhcFreeUrb (Ehc, Urb);
650 return NULL;
651 }