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