Import EhciDxe and UhciDxe into MdeModulePkg.
[mirror_edk2.git] / MdeModulePkg / Bus / Pci / UhciDxe / UhciQueue.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 UhciQueue.c
15
16 Abstract:
17
18 The UHCI register operation routines.
19
20 Revision History
21
22
23 **/
24
25 #include "Uhci.h"
26
27
28 /**
29 Map address of request structure buffer
30
31 @param Uhc The UHCI device
32 @param Request The user request buffer
33 @param MappedAddr Mapped address of request
34 @param Map Identificaion of this mapping to return
35
36 @return EFI_SUCCESS : Success
37 @return EFI_DEVICE_ERROR : Fail to map the user request
38
39 **/
40 EFI_STATUS
41 UhciMapUserRequest (
42 IN USB_HC_DEV *Uhc,
43 IN OUT VOID *Request,
44 OUT UINT8 **MappedAddr,
45 OUT VOID **Map
46 )
47 {
48 EFI_STATUS Status;
49 UINTN Len;
50 EFI_PHYSICAL_ADDRESS PhyAddr;
51
52 Len = sizeof (EFI_USB_DEVICE_REQUEST);
53 Status = Uhc->PciIo->Map (
54 Uhc->PciIo,
55 EfiPciIoOperationBusMasterRead,
56 Request,
57 &Len,
58 &PhyAddr,
59 Map
60 );
61
62 if (!EFI_ERROR (Status)) {
63 *MappedAddr = (UINT8 *) (UINTN) PhyAddr;
64 }
65
66 return Status;
67 }
68
69
70 /**
71 Map address of user data buffer
72
73 @param Uhc The UHCI device
74 @param Direction direction of the data transfer
75 @param Data The user data buffer
76 @param Len Length of the user data
77 @param PktId Packet identificaion
78 @param MappedAddr mapped address to return
79 @param Map identificaion of this mapping to return
80
81 @return EFI_SUCCESS : Success
82 @return EFI_DEVICE_ERROR : Fail to map the user data
83
84 **/
85 EFI_STATUS
86 UhciMapUserData (
87 IN USB_HC_DEV *Uhc,
88 IN EFI_USB_DATA_DIRECTION Direction,
89 IN VOID *Data,
90 IN OUT UINTN *Len,
91 OUT UINT8 *PktId,
92 OUT UINT8 **MappedAddr,
93 OUT VOID **Map
94 )
95 {
96 EFI_STATUS Status;
97 EFI_PHYSICAL_ADDRESS PhyAddr;
98
99 Status = EFI_SUCCESS;
100
101 switch (Direction) {
102 case EfiUsbDataIn:
103 //
104 // BusMasterWrite means cpu read
105 //
106 *PktId = INPUT_PACKET_ID;
107 Status = Uhc->PciIo->Map (
108 Uhc->PciIo,
109 EfiPciIoOperationBusMasterWrite,
110 Data,
111 Len,
112 &PhyAddr,
113 Map
114 );
115
116 if (EFI_ERROR (Status)) {
117 goto EXIT;
118 }
119
120 *MappedAddr = (UINT8 *) (UINTN) PhyAddr;
121 break;
122
123 case EfiUsbDataOut:
124 *PktId = OUTPUT_PACKET_ID;
125 Status = Uhc->PciIo->Map (
126 Uhc->PciIo,
127 EfiPciIoOperationBusMasterRead,
128 Data,
129 Len,
130 &PhyAddr,
131 Map
132 );
133
134 if (EFI_ERROR (Status)) {
135 goto EXIT;
136 }
137
138 *MappedAddr = (UINT8 *) (UINTN) PhyAddr;
139 break;
140
141 case EfiUsbNoData:
142 if ((Len != NULL) && (*Len != 0)) {
143 Status = EFI_INVALID_PARAMETER;
144 goto EXIT;
145 }
146
147 *PktId = OUTPUT_PACKET_ID;
148 *Len = 0;
149 *MappedAddr = NULL;
150 *Map = NULL;
151 break;
152
153 default:
154 Status = EFI_INVALID_PARAMETER;
155 }
156
157 EXIT:
158 return Status;
159 }
160
161
162
163 /**
164 Link the TD To QH
165
166 @param Qh The queue head for the TD to link to
167 @param Td The TD to link
168
169 @return VOID
170
171 **/
172 VOID
173 UhciLinkTdToQh (
174 IN UHCI_QH_SW *Qh,
175 IN UHCI_TD_SW *Td
176 )
177 {
178 ASSERT ((Qh != NULL) && (Td != NULL));
179
180 Qh->QhHw.VerticalLink = QH_VLINK (Td, FALSE);
181 Qh->TDs = (VOID *) Td;
182 }
183
184
185 /**
186 Unlink TD from the QH
187
188 @param Qh The queue head to unlink from
189 @param Td The TD to unlink
190
191 @return VOID
192
193 **/
194 VOID
195 UhciUnlinkTdFromQh (
196 IN UHCI_QH_SW *Qh,
197 IN UHCI_TD_SW *Td
198 )
199 {
200 ASSERT ((Qh != NULL) && (Td != NULL));
201
202 Qh->QhHw.VerticalLink = QH_VLINK (NULL, TRUE);
203 Qh->TDs = NULL;
204 }
205
206
207 /**
208 Append a new TD To the previous TD
209
210 @param PrevTd Previous UHCI_TD_SW to be linked to
211 @param ThisTd TD to link
212
213 @return VOID
214
215 **/
216 STATIC
217 VOID
218 UhciAppendTd (
219 IN UHCI_TD_SW *PrevTd,
220 IN UHCI_TD_SW *ThisTd
221 )
222 {
223 ASSERT ((PrevTd != NULL) && (ThisTd != NULL));
224
225 PrevTd->TdHw.NextLink = TD_LINK (ThisTd, TRUE, FALSE);
226 PrevTd->NextTd = (VOID *) ThisTd;
227 }
228
229
230 /**
231 Delete a list of TDs
232
233 @param Uhc The UHCI device
234 @param FirstTd TD link list head
235
236 @return VOID
237
238 **/
239 VOID
240 UhciDestoryTds (
241 IN USB_HC_DEV *Uhc,
242 IN UHCI_TD_SW *FirstTd
243 )
244 {
245 UHCI_TD_SW *NextTd;
246 UHCI_TD_SW *ThisTd;
247
248 NextTd = FirstTd;
249
250 while (NextTd != NULL) {
251 ThisTd = NextTd;
252 NextTd = ThisTd->NextTd;
253 UsbHcFreeMem (Uhc->MemPool, ThisTd, sizeof (UHCI_TD_SW));
254 }
255 }
256
257
258 /**
259 Create an initialize a new queue head
260
261 @param Uhc The UHCI device
262 @param Interval The polling interval for the queue
263
264 @return The newly created queue header
265
266 **/
267 UHCI_QH_SW *
268 UhciCreateQh (
269 IN USB_HC_DEV *Uhc,
270 IN UINTN Interval
271 )
272 {
273 UHCI_QH_SW *Qh;
274
275 Qh = UsbHcAllocateMem (Uhc->MemPool, sizeof (UHCI_QH_SW));
276
277 if (Qh == NULL) {
278 return NULL;
279 }
280
281 Qh->QhHw.HorizonLink = QH_HLINK (NULL, TRUE);
282 Qh->QhHw.VerticalLink = QH_VLINK (NULL, TRUE);
283 Qh->Interval = Interval;
284 Qh->TDs = NULL;
285 Qh->NextQh = NULL;
286
287 return Qh;
288 }
289
290
291 /**
292 Create and intialize a TD
293
294 @param Uhc The UHCI device
295
296 @return The newly allocated and initialized TD
297
298 **/
299 STATIC
300 UHCI_TD_SW *
301 UhciCreateTd (
302 IN USB_HC_DEV *Uhc
303 )
304 {
305 UHCI_TD_SW *Td;
306
307 Td = UsbHcAllocateMem (Uhc->MemPool, sizeof (UHCI_TD_SW));
308 if (Td == NULL) {
309 return NULL;
310 }
311
312 Td->TdHw.NextLink = TD_LINK (NULL, FALSE, TRUE);
313 Td->NextTd = NULL;
314 Td->Data = NULL;
315 Td->DataLen = 0;
316
317 return Td;
318 }
319
320
321 /**
322 Create and initialize a TD for Setup Stage of a control transfer
323
324 @param Uhc The UHCI device
325 @param DevAddr Device address
326 @param Request Device request
327 @param IsLow Full speed or low speed
328
329 @return The created setup Td Pointer
330
331 **/
332 STATIC
333 UHCI_TD_SW *
334 UhciCreateSetupTd (
335 IN USB_HC_DEV *Uhc,
336 IN UINT8 DevAddr,
337 IN UINT8 *Request,
338 IN BOOLEAN IsLow
339 )
340 {
341 UHCI_TD_SW *Td;
342
343 Td = UhciCreateTd (Uhc);
344
345 if (Td == NULL) {
346 return NULL;
347 }
348
349 Td->TdHw.NextLink = TD_LINK (NULL, TRUE, TRUE);
350 Td->TdHw.ShortPacket = FALSE;
351 Td->TdHw.IsIsoch = FALSE;
352 Td->TdHw.IntOnCpl = FALSE;
353 Td->TdHw.ErrorCount = 0x03;
354 Td->TdHw.Status |= USBTD_ACTIVE;
355 Td->TdHw.DataToggle = 0;
356 Td->TdHw.EndPoint = 0;
357 Td->TdHw.LowSpeed = IsLow ? 1 : 0;
358 Td->TdHw.DeviceAddr = DevAddr & 0x7F;
359 Td->TdHw.MaxPacketLen = (UINT32) (sizeof (EFI_USB_DEVICE_REQUEST) - 1);
360 Td->TdHw.PidCode = SETUP_PACKET_ID;
361 Td->TdHw.DataBuffer = (UINT32) (UINTN) Request;
362
363 Td->Data = Request;
364 Td->DataLen = sizeof (EFI_USB_DEVICE_REQUEST);
365
366 return Td;
367 }
368
369
370 /**
371 Create a TD for data
372
373 @param Uhc The UHCI device
374 @param DevAddr Device address
375 @param Endpoint Endpoint number
376 @param DataPtr Data buffer
377 @param Len Data length
378 @param PktId Packet ID
379 @param Toggle Data toggle value
380 @param IsLow Full speed or low speed
381
382 @return Data Td pointer if success, otherwise NUL
383
384 **/
385 STATIC
386 UHCI_TD_SW *
387 UhciCreateDataTd (
388 IN USB_HC_DEV *Uhc,
389 IN UINT8 DevAddr,
390 IN UINT8 Endpoint,
391 IN UINT8 *DataPtr,
392 IN UINTN Len,
393 IN UINT8 PktId,
394 IN UINT8 Toggle,
395 IN BOOLEAN IsLow
396 )
397 {
398 UHCI_TD_SW *Td;
399
400 //
401 // Code as length - 1, and the max valid length is 0x500
402 //
403 ASSERT (Len <= 0x500);
404
405 Td = UhciCreateTd (Uhc);
406
407 if (Td == NULL) {
408 return NULL;
409 }
410
411 Td->TdHw.NextLink = TD_LINK (NULL, TRUE, TRUE);
412 Td->TdHw.ShortPacket = FALSE;
413 Td->TdHw.IsIsoch = FALSE;
414 Td->TdHw.IntOnCpl = FALSE;
415 Td->TdHw.ErrorCount = 0X03;
416 Td->TdHw.Status = USBTD_ACTIVE;
417 Td->TdHw.LowSpeed = IsLow ? 1 : 0;
418 Td->TdHw.DataToggle = Toggle & 0x01;
419 Td->TdHw.EndPoint = Endpoint & 0x0F;
420 Td->TdHw.DeviceAddr = DevAddr & 0x7F;
421 Td->TdHw.MaxPacketLen = (UINT32) (Len - 1);
422 Td->TdHw.PidCode = (UINT8) PktId;
423 Td->TdHw.DataBuffer = (UINT32) (UINTN) DataPtr;
424
425 Td->Data = DataPtr;
426 Td->DataLen = (UINT16) Len;
427
428 return Td;
429 }
430
431
432 /**
433 Create TD for the Status Stage of control transfer
434
435 @param Uhc The UHCI device
436 @param DevAddr Device address
437 @param PktId Packet ID
438 @param IsLow Full speed or low speed
439
440 @return Status Td Pointer
441
442 **/
443 STATIC
444 UHCI_TD_SW *
445 UhciCreateStatusTd (
446 IN USB_HC_DEV *Uhc,
447 IN UINT8 DevAddr,
448 IN UINT8 PktId,
449 IN BOOLEAN IsLow
450 )
451 {
452 UHCI_TD_SW *Td;
453
454 Td = UhciCreateTd (Uhc);
455
456 if (Td == NULL) {
457 return NULL;
458 }
459
460 Td->TdHw.NextLink = TD_LINK (NULL, TRUE, TRUE);
461 Td->TdHw.ShortPacket = FALSE;
462 Td->TdHw.IsIsoch = FALSE;
463 Td->TdHw.IntOnCpl = FALSE;
464 Td->TdHw.ErrorCount = 0x03;
465 Td->TdHw.Status |= USBTD_ACTIVE;
466 Td->TdHw.MaxPacketLen = 0x7FF; //0x7FF: there is no data (refer to UHCI spec)
467 Td->TdHw.DataToggle = 1;
468 Td->TdHw.EndPoint = 0;
469 Td->TdHw.LowSpeed = IsLow ? 1 : 0;
470 Td->TdHw.DeviceAddr = DevAddr & 0x7F;
471 Td->TdHw.PidCode = (UINT8) PktId;
472 Td->TdHw.DataBuffer = (UINT32) (UINTN) NULL;
473
474 Td->Data = NULL;
475 Td->DataLen = 0;
476
477 return Td;
478 }
479
480
481 /**
482 Create Tds list for Control Transfer
483
484 @param Uhc The UHCI device
485 @param DeviceAddr The device address
486 @param DataPktId Packet Identification of Data Tds
487 @param Request A pointer to request structure buffer to transfer
488 @param Data A pointer to user data buffer to transfer
489 @param DataLen Length of user data to transfer
490 @param MaxPacket Maximum packet size for control transfer
491 @param IsLow Full speed or low speed
492
493 @return The Td list head for the control transfer
494
495 **/
496 UHCI_TD_SW *
497 UhciCreateCtrlTds (
498 IN USB_HC_DEV *Uhc,
499 IN UINT8 DeviceAddr,
500 IN UINT8 DataPktId,
501 IN UINT8 *Request,
502 IN UINT8 *Data,
503 IN UINTN DataLen,
504 IN UINT8 MaxPacket,
505 IN BOOLEAN IsLow
506 )
507 {
508 UHCI_TD_SW *SetupTd;
509 UHCI_TD_SW *FirstDataTd;
510 UHCI_TD_SW *DataTd;
511 UHCI_TD_SW *PrevDataTd;
512 UHCI_TD_SW *StatusTd;
513 UINT8 DataToggle;
514 UINT8 StatusPktId;
515 UINTN ThisTdLen;
516
517
518 DataTd = NULL;
519 SetupTd = NULL;
520 FirstDataTd = NULL;
521 PrevDataTd = NULL;
522 StatusTd = NULL;
523
524 //
525 // Create setup packets for the transfer
526 //
527 SetupTd = UhciCreateSetupTd (Uhc, DeviceAddr, Request, IsLow);
528
529 if (SetupTd == NULL) {
530 return NULL;
531 }
532
533 //
534 // Create data packets for the transfer
535 //
536 DataToggle = 1;
537
538 while (DataLen > 0) {
539 //
540 // PktSize is the data load size in each Td.
541 //
542 ThisTdLen = (DataLen > MaxPacket ? MaxPacket : DataLen);
543
544 DataTd = UhciCreateDataTd (
545 Uhc,
546 DeviceAddr,
547 0,
548 Data,
549 ThisTdLen,
550 DataPktId,
551 DataToggle,
552 IsLow
553 );
554
555 if (DataTd == NULL) {
556 goto FREE_TD;
557 }
558
559 if (FirstDataTd == NULL) {
560 FirstDataTd = DataTd;
561 FirstDataTd->NextTd = NULL;
562 } else {
563 UhciAppendTd (PrevDataTd, DataTd);
564 }
565
566 DataToggle ^= 1;
567 PrevDataTd = DataTd;
568 Data += ThisTdLen;
569 DataLen -= ThisTdLen;
570 }
571
572 //
573 // Status packet is on the opposite direction to data packets
574 //
575 if (OUTPUT_PACKET_ID == DataPktId) {
576 StatusPktId = INPUT_PACKET_ID;
577 } else {
578 StatusPktId = OUTPUT_PACKET_ID;
579 }
580
581 StatusTd = UhciCreateStatusTd (Uhc, DeviceAddr, StatusPktId, IsLow);
582
583 if (StatusTd == NULL) {
584 goto FREE_TD;
585 }
586
587 //
588 // Link setup Td -> data Tds -> status Td together
589 //
590 if (FirstDataTd != NULL) {
591 UhciAppendTd (SetupTd, FirstDataTd);
592 UhciAppendTd (PrevDataTd, StatusTd);
593 } else {
594 UhciAppendTd (SetupTd, StatusTd);
595 }
596
597 return SetupTd;
598
599 FREE_TD:
600 if (SetupTd != NULL) {
601 UhciDestoryTds (Uhc, SetupTd);
602 }
603
604 if (FirstDataTd != NULL) {
605 UhciDestoryTds (Uhc, FirstDataTd);
606 }
607
608 return NULL;
609 }
610
611
612 /**
613 Create Tds list for Bulk/Interrupt Transfer
614
615 @param Uhc USB_HC_DEV
616 @param DevAddr Address of Device
617 @param EndPoint Endpoint Number
618 @param PktId Packet Identification of Data Tds
619 @param Data A pointer to user data buffer to transfer
620 @param DataLen Length of user data to transfer
621 @param DataToggle Data Toggle Pointer
622 @param MaxPacket Maximum packet size for Bulk/Interrupt transfer
623 @param IsLow Is Low Speed Device
624
625 @return The Tds list head for the bulk transfer
626
627 **/
628 UHCI_TD_SW *
629 UhciCreateBulkOrIntTds (
630 IN USB_HC_DEV *Uhc,
631 IN UINT8 DevAddr,
632 IN UINT8 EndPoint,
633 IN UINT8 PktId,
634 IN UINT8 *Data,
635 IN UINTN DataLen,
636 IN OUT UINT8 *DataToggle,
637 IN UINT8 MaxPacket,
638 IN BOOLEAN IsLow
639 )
640 {
641 UHCI_TD_SW *DataTd;
642 UHCI_TD_SW *FirstDataTd;
643 UHCI_TD_SW *PrevDataTd;
644 UINTN ThisTdLen;
645
646 DataTd = NULL;
647 FirstDataTd = NULL;
648 PrevDataTd = NULL;
649
650 //
651 // Create data packets for the transfer
652 //
653 while (DataLen > 0) {
654 //
655 // PktSize is the data load size that each Td.
656 //
657 ThisTdLen = DataLen;
658
659 if (DataLen > MaxPacket) {
660 ThisTdLen = MaxPacket;
661 }
662
663 DataTd = UhciCreateDataTd (
664 Uhc,
665 DevAddr,
666 EndPoint,
667 Data,
668 ThisTdLen,
669 PktId,
670 *DataToggle,
671 IsLow
672 );
673
674 if (DataTd == NULL) {
675 goto FREE_TD;
676 }
677
678 if (PktId == INPUT_PACKET_ID) {
679 DataTd->TdHw.ShortPacket = TRUE;
680 }
681
682 if (FirstDataTd == NULL) {
683 FirstDataTd = DataTd;
684 FirstDataTd->NextTd = NULL;
685 } else {
686 UhciAppendTd (PrevDataTd, DataTd);
687 }
688
689 *DataToggle ^= 1;
690 PrevDataTd = DataTd;
691 Data += ThisTdLen;
692 DataLen -= ThisTdLen;
693 }
694
695 return FirstDataTd;
696
697 FREE_TD:
698 if (FirstDataTd != NULL) {
699 UhciDestoryTds (Uhc, FirstDataTd);
700 }
701
702 return NULL;
703 }