]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Bus/Pci/UhciDxe/UhciQueue.c
Remove some useless EDK_RELEASE_VERSION, EFI_SPECIFICATION_VERSION ,and review VALID_...
[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 *Len = 0;
140 *MappedAddr = NULL;
141 *Map = NULL;
142 break;
143
144 default:
145 Status = EFI_INVALID_PARAMETER;
146 }
147
148 EXIT:
149 return Status;
150 }
151
152
153 /**
154 Link the TD To QH.
155
156 @param Qh The queue head for the TD to link to.
157 @param Td The TD to link.
158
159 @return None.
160
161 **/
162 VOID
163 UhciLinkTdToQh (
164 IN UHCI_QH_SW *Qh,
165 IN UHCI_TD_SW *Td
166 )
167 {
168 ASSERT ((Qh != NULL) && (Td != NULL));
169
170 Qh->QhHw.VerticalLink = QH_VLINK (Td, FALSE);
171 Qh->TDs = (VOID *) Td;
172 }
173
174
175 /**
176 Unlink TD from the QH.
177
178 @param Qh The queue head to unlink from.
179 @param Td The TD to unlink.
180
181 @return None.
182
183 **/
184 VOID
185 UhciUnlinkTdFromQh (
186 IN UHCI_QH_SW *Qh,
187 IN UHCI_TD_SW *Td
188 )
189 {
190 ASSERT ((Qh != NULL) && (Td != NULL));
191
192 Qh->QhHw.VerticalLink = QH_VLINK (NULL, TRUE);
193 Qh->TDs = NULL;
194 }
195
196
197 /**
198 Append a new TD To the previous TD.
199
200 @param PrevTd Previous UHCI_TD_SW to be linked to.
201 @param ThisTd TD to link.
202
203 @return None.
204
205 **/
206 VOID
207 UhciAppendTd (
208 IN UHCI_TD_SW *PrevTd,
209 IN UHCI_TD_SW *ThisTd
210 )
211 {
212 ASSERT ((PrevTd != NULL) && (ThisTd != NULL));
213
214 PrevTd->TdHw.NextLink = TD_LINK (ThisTd, TRUE, FALSE);
215 PrevTd->NextTd = (VOID *) ThisTd;
216 }
217
218
219 /**
220 Delete a list of TDs.
221
222 @param Uhc The UHCI device.
223 @param FirstTd TD link list head.
224
225 @return None.
226
227 **/
228 VOID
229 UhciDestoryTds (
230 IN USB_HC_DEV *Uhc,
231 IN UHCI_TD_SW *FirstTd
232 )
233 {
234 UHCI_TD_SW *NextTd;
235 UHCI_TD_SW *ThisTd;
236
237 NextTd = FirstTd;
238
239 while (NextTd != NULL) {
240 ThisTd = NextTd;
241 NextTd = ThisTd->NextTd;
242 UsbHcFreeMem (Uhc->MemPool, ThisTd, sizeof (UHCI_TD_SW));
243 }
244 }
245
246
247 /**
248 Create an initialize a new queue head.
249
250 @param Uhc The UHCI device.
251 @param Interval The polling interval for the queue.
252
253 @return The newly created queue header.
254
255 **/
256 UHCI_QH_SW *
257 UhciCreateQh (
258 IN USB_HC_DEV *Uhc,
259 IN UINTN Interval
260 )
261 {
262 UHCI_QH_SW *Qh;
263
264 Qh = UsbHcAllocateMem (Uhc->MemPool, sizeof (UHCI_QH_SW));
265
266 if (Qh == NULL) {
267 return NULL;
268 }
269
270 Qh->QhHw.HorizonLink = QH_HLINK (NULL, TRUE);
271 Qh->QhHw.VerticalLink = QH_VLINK (NULL, TRUE);
272 Qh->Interval = UhciConvertPollRate(Interval);
273 Qh->TDs = NULL;
274 Qh->NextQh = NULL;
275
276 return Qh;
277 }
278
279
280 /**
281 Create and intialize a TD.
282
283 @param Uhc The UHCI device.
284
285 @return The newly allocated and initialized TD.
286
287 **/
288 UHCI_TD_SW *
289 UhciCreateTd (
290 IN USB_HC_DEV *Uhc
291 )
292 {
293 UHCI_TD_SW *Td;
294
295 Td = UsbHcAllocateMem (Uhc->MemPool, sizeof (UHCI_TD_SW));
296 if (Td == NULL) {
297 return NULL;
298 }
299
300 Td->TdHw.NextLink = TD_LINK (NULL, FALSE, TRUE);
301 Td->NextTd = NULL;
302 Td->Data = NULL;
303 Td->DataLen = 0;
304
305 return Td;
306 }
307
308
309 /**
310 Create and initialize a TD for Setup Stage of a control transfer.
311
312 @param Uhc The UHCI device.
313 @param DevAddr Device address.
314 @param Request Device request.
315 @param IsLow Full speed or low speed.
316
317 @return The created setup Td Pointer.
318
319 **/
320 UHCI_TD_SW *
321 UhciCreateSetupTd (
322 IN USB_HC_DEV *Uhc,
323 IN UINT8 DevAddr,
324 IN UINT8 *Request,
325 IN BOOLEAN IsLow
326 )
327 {
328 UHCI_TD_SW *Td;
329
330 Td = UhciCreateTd (Uhc);
331
332 if (Td == NULL) {
333 return NULL;
334 }
335
336 Td->TdHw.NextLink = TD_LINK (NULL, TRUE, TRUE);
337 Td->TdHw.ShortPacket = FALSE;
338 Td->TdHw.IsIsoch = FALSE;
339 Td->TdHw.IntOnCpl = FALSE;
340 Td->TdHw.ErrorCount = 0x03;
341 Td->TdHw.Status |= USBTD_ACTIVE;
342 Td->TdHw.DataToggle = 0;
343 Td->TdHw.EndPoint = 0;
344 Td->TdHw.LowSpeed = IsLow ? 1 : 0;
345 Td->TdHw.DeviceAddr = DevAddr & 0x7F;
346 Td->TdHw.MaxPacketLen = (UINT32) (sizeof (EFI_USB_DEVICE_REQUEST) - 1);
347 Td->TdHw.PidCode = SETUP_PACKET_ID;
348 Td->TdHw.DataBuffer = (UINT32) (UINTN) Request;
349
350 Td->Data = Request;
351 Td->DataLen = sizeof (EFI_USB_DEVICE_REQUEST);
352
353 return Td;
354 }
355
356
357 /**
358 Create a TD for data.
359
360 @param Uhc The UHCI device.
361 @param DevAddr Device address.
362 @param Endpoint Endpoint number.
363 @param DataPtr Data buffer.
364 @param Len Data length.
365 @param PktId Packet ID.
366 @param Toggle Data toggle value.
367 @param IsLow Full speed or low speed.
368
369 @return Data Td pointer if success, otherwise NULL.
370
371 **/
372 UHCI_TD_SW *
373 UhciCreateDataTd (
374 IN USB_HC_DEV *Uhc,
375 IN UINT8 DevAddr,
376 IN UINT8 Endpoint,
377 IN UINT8 *DataPtr,
378 IN UINTN Len,
379 IN UINT8 PktId,
380 IN UINT8 Toggle,
381 IN BOOLEAN IsLow
382 )
383 {
384 UHCI_TD_SW *Td;
385
386 //
387 // Code as length - 1, and the max valid length is 0x500
388 //
389 ASSERT (Len <= 0x500);
390
391 Td = UhciCreateTd (Uhc);
392
393 if (Td == NULL) {
394 return NULL;
395 }
396
397 Td->TdHw.NextLink = TD_LINK (NULL, TRUE, TRUE);
398 Td->TdHw.ShortPacket = FALSE;
399 Td->TdHw.IsIsoch = FALSE;
400 Td->TdHw.IntOnCpl = FALSE;
401 Td->TdHw.ErrorCount = 0X03;
402 Td->TdHw.Status = USBTD_ACTIVE;
403 Td->TdHw.LowSpeed = IsLow ? 1 : 0;
404 Td->TdHw.DataToggle = Toggle & 0x01;
405 Td->TdHw.EndPoint = Endpoint & 0x0F;
406 Td->TdHw.DeviceAddr = DevAddr & 0x7F;
407 Td->TdHw.MaxPacketLen = (UINT32) (Len - 1);
408 Td->TdHw.PidCode = (UINT8) PktId;
409 Td->TdHw.DataBuffer = (UINT32) (UINTN) DataPtr;
410
411 Td->Data = DataPtr;
412 Td->DataLen = (UINT16) Len;
413
414 return Td;
415 }
416
417
418 /**
419 Create TD for the Status Stage of control transfer.
420
421 @param Uhc The UHCI device.
422 @param DevAddr Device address.
423 @param PktId Packet ID.
424 @param IsLow Full speed or low speed.
425
426 @return Status Td Pointer.
427
428 **/
429 UHCI_TD_SW *
430 UhciCreateStatusTd (
431 IN USB_HC_DEV *Uhc,
432 IN UINT8 DevAddr,
433 IN UINT8 PktId,
434 IN BOOLEAN IsLow
435 )
436 {
437 UHCI_TD_SW *Td;
438
439 Td = UhciCreateTd (Uhc);
440
441 if (Td == NULL) {
442 return NULL;
443 }
444
445 Td->TdHw.NextLink = TD_LINK (NULL, TRUE, TRUE);
446 Td->TdHw.ShortPacket = FALSE;
447 Td->TdHw.IsIsoch = FALSE;
448 Td->TdHw.IntOnCpl = FALSE;
449 Td->TdHw.ErrorCount = 0x03;
450 Td->TdHw.Status |= USBTD_ACTIVE;
451 Td->TdHw.MaxPacketLen = 0x7FF; //0x7FF: there is no data (refer to UHCI spec)
452 Td->TdHw.DataToggle = 1;
453 Td->TdHw.EndPoint = 0;
454 Td->TdHw.LowSpeed = IsLow ? 1 : 0;
455 Td->TdHw.DeviceAddr = DevAddr & 0x7F;
456 Td->TdHw.PidCode = (UINT8) PktId;
457 Td->TdHw.DataBuffer = (UINT32) (UINTN) NULL;
458
459 Td->Data = NULL;
460 Td->DataLen = 0;
461
462 return Td;
463 }
464
465
466 /**
467 Create Tds list for Control Transfer.
468
469 @param Uhc The UHCI device.
470 @param DeviceAddr The device address.
471 @param DataPktId Packet Identification of Data Tds.
472 @param Request A pointer to request structure buffer to transfer.
473 @param Data A pointer to user data buffer to transfer.
474 @param DataLen Length of user data to transfer.
475 @param MaxPacket Maximum packet size for control transfer.
476 @param IsLow Full speed or low speed.
477
478 @return The Td list head for the control transfer.
479
480 **/
481 UHCI_TD_SW *
482 UhciCreateCtrlTds (
483 IN USB_HC_DEV *Uhc,
484 IN UINT8 DeviceAddr,
485 IN UINT8 DataPktId,
486 IN UINT8 *Request,
487 IN UINT8 *Data,
488 IN UINTN DataLen,
489 IN UINT8 MaxPacket,
490 IN BOOLEAN IsLow
491 )
492 {
493 UHCI_TD_SW *SetupTd;
494 UHCI_TD_SW *FirstDataTd;
495 UHCI_TD_SW *DataTd;
496 UHCI_TD_SW *PrevDataTd;
497 UHCI_TD_SW *StatusTd;
498 UINT8 DataToggle;
499 UINT8 StatusPktId;
500 UINTN ThisTdLen;
501
502
503 DataTd = NULL;
504 SetupTd = NULL;
505 FirstDataTd = NULL;
506 PrevDataTd = NULL;
507 StatusTd = NULL;
508
509 //
510 // Create setup packets for the transfer
511 //
512 SetupTd = UhciCreateSetupTd (Uhc, DeviceAddr, Request, IsLow);
513
514 if (SetupTd == NULL) {
515 return NULL;
516 }
517
518 //
519 // Create data packets for the transfer
520 //
521 DataToggle = 1;
522
523 while (DataLen > 0) {
524 //
525 // PktSize is the data load size in each Td.
526 //
527 ThisTdLen = (DataLen > MaxPacket ? MaxPacket : DataLen);
528
529 DataTd = UhciCreateDataTd (
530 Uhc,
531 DeviceAddr,
532 0,
533 Data,
534 ThisTdLen,
535 DataPktId,
536 DataToggle,
537 IsLow
538 );
539
540 if (DataTd == NULL) {
541 goto FREE_TD;
542 }
543
544 if (FirstDataTd == NULL) {
545 FirstDataTd = DataTd;
546 FirstDataTd->NextTd = NULL;
547 } else {
548 UhciAppendTd (PrevDataTd, DataTd);
549 }
550
551 DataToggle ^= 1;
552 PrevDataTd = DataTd;
553 Data += ThisTdLen;
554 DataLen -= ThisTdLen;
555 }
556
557 //
558 // Status packet is on the opposite direction to data packets
559 //
560 if (OUTPUT_PACKET_ID == DataPktId) {
561 StatusPktId = INPUT_PACKET_ID;
562 } else {
563 StatusPktId = OUTPUT_PACKET_ID;
564 }
565
566 StatusTd = UhciCreateStatusTd (Uhc, DeviceAddr, StatusPktId, IsLow);
567
568 if (StatusTd == NULL) {
569 goto FREE_TD;
570 }
571
572 //
573 // Link setup Td -> data Tds -> status Td together
574 //
575 if (FirstDataTd != NULL) {
576 UhciAppendTd (SetupTd, FirstDataTd);
577 UhciAppendTd (PrevDataTd, StatusTd);
578 } else {
579 UhciAppendTd (SetupTd, StatusTd);
580 }
581
582 return SetupTd;
583
584 FREE_TD:
585 if (SetupTd != NULL) {
586 UhciDestoryTds (Uhc, SetupTd);
587 }
588
589 if (FirstDataTd != NULL) {
590 UhciDestoryTds (Uhc, FirstDataTd);
591 }
592
593 return NULL;
594 }
595
596
597 /**
598 Create Tds list for Bulk/Interrupt Transfer.
599
600 @param Uhc USB_HC_DEV.
601 @param DevAddr Address of Device.
602 @param EndPoint Endpoint Number.
603 @param PktId Packet Identification of Data Tds.
604 @param Data A pointer to user data buffer to transfer.
605 @param DataLen Length of user data to transfer.
606 @param DataToggle Data Toggle Pointer.
607 @param MaxPacket Maximum packet size for Bulk/Interrupt transfer.
608 @param IsLow Is Low Speed Device.
609
610 @return The Tds list head for the bulk transfer.
611
612 **/
613 UHCI_TD_SW *
614 UhciCreateBulkOrIntTds (
615 IN USB_HC_DEV *Uhc,
616 IN UINT8 DevAddr,
617 IN UINT8 EndPoint,
618 IN UINT8 PktId,
619 IN UINT8 *Data,
620 IN UINTN DataLen,
621 IN OUT UINT8 *DataToggle,
622 IN UINT8 MaxPacket,
623 IN BOOLEAN IsLow
624 )
625 {
626 UHCI_TD_SW *DataTd;
627 UHCI_TD_SW *FirstDataTd;
628 UHCI_TD_SW *PrevDataTd;
629 UINTN ThisTdLen;
630
631 DataTd = NULL;
632 FirstDataTd = NULL;
633 PrevDataTd = NULL;
634
635 //
636 // Create data packets for the transfer
637 //
638 while (DataLen > 0) {
639 //
640 // PktSize is the data load size that each Td.
641 //
642 ThisTdLen = DataLen;
643
644 if (DataLen > MaxPacket) {
645 ThisTdLen = MaxPacket;
646 }
647
648 DataTd = UhciCreateDataTd (
649 Uhc,
650 DevAddr,
651 EndPoint,
652 Data,
653 ThisTdLen,
654 PktId,
655 *DataToggle,
656 IsLow
657 );
658
659 if (DataTd == NULL) {
660 goto FREE_TD;
661 }
662
663 if (PktId == INPUT_PACKET_ID) {
664 DataTd->TdHw.ShortPacket = TRUE;
665 }
666
667 if (FirstDataTd == NULL) {
668 FirstDataTd = DataTd;
669 FirstDataTd->NextTd = NULL;
670 } else {
671 UhciAppendTd (PrevDataTd, DataTd);
672 }
673
674 *DataToggle ^= 1;
675 PrevDataTd = DataTd;
676 Data += ThisTdLen;
677 DataLen -= ThisTdLen;
678 }
679
680 return FirstDataTd;
681
682 FREE_TD:
683 if (FirstDataTd != NULL) {
684 UhciDestoryTds (Uhc, FirstDataTd);
685 }
686
687 return NULL;
688 }