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