2 * PROJECT: ReactOS Universal Serial Bus Bulk Enhanced Host Controller Interface
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: drivers/usb/usbehci/hwiface.c
5 * PURPOSE: EHCI Interface routines: Queue Heads and Queue Element
7 * TODO: Periodic Frame List, Isochronous Transaction Descriptors
8 and Split-transaction ITD.
10 * Michael Martin (michael.martin@reactos.org)
18 /* Queue Element Transfer Descriptors */
20 PQUEUE_TRANSFER_DESCRIPTOR
21 CreateDescriptor(PEHCI_HOST_CONTROLLER hcd
, UCHAR PIDCode
, ULONG TotalBytesToTransfer
)
23 PQUEUE_TRANSFER_DESCRIPTOR Descriptor
;
24 ULONG PhysicalAddress
;
28 KeAcquireSpinLock(&hcd
->Lock
, &OldIrql
);
30 Descriptor
= (PQUEUE_TRANSFER_DESCRIPTOR
)AllocateMemory(hcd
, sizeof(QUEUE_TRANSFER_DESCRIPTOR
), &PhysicalAddress
);
31 RtlZeroMemory(Descriptor
, sizeof(QUEUE_TRANSFER_DESCRIPTOR
));
32 Descriptor
->NextPointer
= TERMINATE_POINTER
;
33 Descriptor
->AlternateNextPointer
= TERMINATE_POINTER
;
34 Descriptor
->Token
.Bits
.DataToggle
= TRUE
;
35 Descriptor
->Token
.Bits
.ErrorCounter
= 0x03;
36 Descriptor
->Token
.Bits
.Active
= TRUE
;
37 Descriptor
->Token
.Bits
.PIDCode
= PIDCode
;
38 Descriptor
->Token
.Bits
.TotalBytesToTransfer
= TotalBytesToTransfer
;
39 Descriptor
->PhysicalAddr
= PhysicalAddress
;
41 Descriptor
->BufferPointer
[i
] = 0;
43 KeReleaseSpinLock(&hcd
->Lock
, OldIrql
);
49 FreeDescriptor(PEHCI_HOST_CONTROLLER hcd
, PQUEUE_TRANSFER_DESCRIPTOR Descriptor
)
51 ReleaseMemory(hcd
, (ULONG
)Descriptor
);
57 DumpQueueHeadList(PEHCI_HOST_CONTROLLER hcd
)
61 KeAcquireSpinLock(&hcd
->Lock
, &OldIrql
);
63 PQUEUE_HEAD QueueHead
= (PQUEUE_HEAD
)hcd
->CommonBufferVA
;
64 PQUEUE_HEAD FirstQueueHead
= QueueHead
;
65 DPRINT1("Dumping QueueHead List!!!!!!!!!!!!!\n");
68 DPRINT1("QueueHead Address %x\n", QueueHead
);
69 DPRINT1("QueueHead->PreviousQueueHead = %x\n", QueueHead
->PreviousQueueHead
);
70 DPRINT1("QueueHead->NextQueueHead = %x\n", QueueHead
->NextQueueHead
);
71 DPRINT1(" ---> PhysicalAddress %x\n", (ULONG
)MmGetPhysicalAddress(QueueHead
).LowPart
);
72 DPRINT1("QueueHead->HorizontalLinkPointer %x\n", QueueHead
->HorizontalLinkPointer
);
73 QueueHead
= QueueHead
->NextQueueHead
;
74 DPRINT1("Next QueueHead %x\n", QueueHead
);
75 if (QueueHead
== FirstQueueHead
) break;
77 DPRINT1("-----------------------------------\n");
78 KeReleaseSpinLock(&hcd
->Lock
, OldIrql
);
82 CreateQueueHead(PEHCI_HOST_CONTROLLER hcd
)
84 PQUEUE_HEAD CurrentQH
;
85 ULONG PhysicalAddress
, i
;
88 KeAcquireSpinLock(&hcd
->Lock
, &OldIrql
);
89 CurrentQH
= (PQUEUE_HEAD
)AllocateMemory(hcd
, sizeof(QUEUE_HEAD
), &PhysicalAddress
);
90 RtlZeroMemory(CurrentQH
, sizeof(QUEUE_HEAD
));
93 CurrentQH
->PhysicalAddr
= PhysicalAddress
;
94 CurrentQH
->HorizontalLinkPointer
= TERMINATE_POINTER
;
95 CurrentQH
->AlternateNextPointer
= TERMINATE_POINTER
;
96 CurrentQH
->NextPointer
= TERMINATE_POINTER
;
98 /* 1 for non high speed, 0 for high speed device */
99 CurrentQH
->EndPointCharacteristics
.ControlEndPointFlag
= 0;
100 CurrentQH
->EndPointCharacteristics
.HeadOfReclamation
= FALSE
;
101 CurrentQH
->EndPointCharacteristics
.MaximumPacketLength
= 64;
103 /* Set NakCountReload to max value possible */
104 CurrentQH
->EndPointCharacteristics
.NakCountReload
= 0xF;
106 /* Get the Initial Data Toggle from the QEDT */
107 CurrentQH
->EndPointCharacteristics
.QEDTDataToggleControl
= FALSE
;
109 /* High Speed Device */
110 CurrentQH
->EndPointCharacteristics
.EndPointSpeed
= QH_ENDPOINT_HIGHSPEED
;
112 CurrentQH
->EndPointCapabilities
.NumberOfTransactionPerFrame
= 0x03;
114 CurrentQH
->Token
.DWord
= 0;
115 CurrentQH
->NextQueueHead
= NULL
;
116 CurrentQH
->PreviousQueueHead
= NULL
;
118 CurrentQH
->BufferPointer
[i
] = 0;
120 CurrentQH
->Token
.Bits
.InterruptOnComplete
= FALSE
;
122 KeReleaseSpinLock(&hcd
->Lock
, OldIrql
);
127 LinkQueueHead(PEHCI_HOST_CONTROLLER hcd
, PQUEUE_HEAD QueueHead
)
130 PQUEUE_HEAD CurrentHead
= (PQUEUE_HEAD
)hcd
->AsyncListQueue
;
131 PQUEUE_HEAD PreviousHead
;
133 KeAcquireSpinLock(&hcd
->Lock
, &OldIrql
);
134 PreviousHead
= CurrentHead
->PreviousQueueHead
;
135 QueueHead
->NextQueueHead
= CurrentHead
;
136 QueueHead
->PreviousQueueHead
= PreviousHead
;
137 PreviousHead
->NextQueueHead
= QueueHead
;
138 CurrentHead
->PreviousQueueHead
= QueueHead
;
140 QueueHead
->HorizontalLinkPointer
= (CurrentHead
->HorizontalLinkPointer
| QH_TYPE_QH
) & ~TERMINATE_POINTER
;
141 PreviousHead
->HorizontalLinkPointer
= QueueHead
->PhysicalAddr
| QH_TYPE_QH
;
143 KeReleaseSpinLock(&hcd
->Lock
, OldIrql
);
147 UnlinkQueueHead(PEHCI_HOST_CONTROLLER hcd
, PQUEUE_HEAD QueueHead
)
150 PQUEUE_HEAD PreviousHead
;
151 PQUEUE_HEAD NextHead
;
152 KeAcquireSpinLock(&hcd
->Lock
, &OldIrql
);
154 PreviousHead
= QueueHead
->PreviousQueueHead
;
155 NextHead
= QueueHead
->NextQueueHead
;
157 PreviousHead
->NextQueueHead
= NextHead
;
158 NextHead
->PreviousQueueHead
= PreviousHead
;
160 PreviousHead
->HorizontalLinkPointer
= NextHead
->HorizontalLinkPointer
;
161 KeReleaseSpinLock(&hcd
->Lock
, OldIrql
);
165 LinkQueueHeadToCompletedList(PEHCI_HOST_CONTROLLER hcd
, PQUEUE_HEAD QueueHead
)
168 PQUEUE_HEAD CurrentHead
= (PQUEUE_HEAD
)hcd
->CompletedListQueue
;
169 PQUEUE_HEAD PreviousHead
;
171 KeAcquireSpinLock(&hcd
->Lock
, &OldIrql
);
173 PreviousHead
= CurrentHead
->PreviousQueueHead
;
174 QueueHead
->NextQueueHead
= CurrentHead
;
175 QueueHead
->PreviousQueueHead
= PreviousHead
;
176 PreviousHead
->NextQueueHead
= QueueHead
;
177 CurrentHead
->PreviousQueueHead
= QueueHead
;
179 KeReleaseSpinLock(&hcd
->Lock
, OldIrql
);
184 DeleteQueueHead(PEHCI_HOST_CONTROLLER hcd
, PQUEUE_HEAD QueueHead
)
186 ReleaseMemory(hcd
, (ULONG
)QueueHead
);
190 CleanupAsyncList(PEHCI_HOST_CONTROLLER hcd
)
192 PQUEUE_TRANSFER_DESCRIPTOR Descriptor
;
193 PQUEUE_HEAD QueueHead
;
196 KeAcquireSpinLock(&hcd
->Lock
, &OldIrql
);
198 QueueHead
= hcd
->CompletedListQueue
;
199 QueueHead
= QueueHead
->NextQueueHead
;
201 while (QueueHead
!= hcd
->CompletedListQueue
)
203 Descriptor
= QueueHead
->FirstTransferDescriptor
;
206 if (Descriptor
->Token
.Bits
.PIDCode
== PID_CODE_SETUP_TOKEN
)
207 ReleaseMemory(hcd
, Descriptor
->BufferPointerVA
[0]);
208 FreeDescriptor(hcd
, Descriptor
);
209 Descriptor
= Descriptor
->NextDescriptor
;
212 if (QueueHead
->FreeMdl
)
214 DPRINT("Freeing Mdl %x, StartVA %x\n", QueueHead
->Mdl
, QueueHead
->Mdl
->StartVa
);
215 IoFreeMdl(QueueHead
->Mdl
);
218 QueueHead
= QueueHead
->NextQueueHead
;
221 hcd
->CompletedListQueue
->NextQueueHead
= hcd
->CompletedListQueue
;
222 hcd
->CompletedListQueue
->PreviousQueueHead
= hcd
->CompletedListQueue
;
224 KeReleaseSpinLock(&hcd
->Lock
, OldIrql
);