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