]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Bus/Pci/EhciDxe/EhciUrb.c
Improve coding style in MdeModulePkg.
[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
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 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 *
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
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 *
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
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
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
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
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 *
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 }