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