[FREELDR]
[reactos.git] / reactos / drivers / usb / usbehci / hwiface.c
1 /*
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
6 Transfer Descriptors.
7 * TODO: Periodic Frame List, Isochronous Transaction Descriptors
8 and Split-transaction ITD.
9 * PROGRAMMERS:
10 * Michael Martin (michael.martin@reactos.org)
11 */
12
13 #include "hwiface.h"
14 #include "physmem.h"
15 #define NDEBUG
16 #include <debug.h>
17
18 /* Queue Element Transfer Descriptors */
19
20 PQUEUE_TRANSFER_DESCRIPTOR
21 CreateDescriptor(PEHCI_HOST_CONTROLLER hcd, UCHAR PIDCode, ULONG TotalBytesToTransfer)
22 {
23 PQUEUE_TRANSFER_DESCRIPTOR Descriptor;
24 ULONG PhysicalAddress;
25 UCHAR i;
26 KIRQL OldIrql;
27
28 KeAcquireSpinLock(&hcd->Lock, &OldIrql);
29
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;
40 for (i=0;i<5;i++)
41 Descriptor->BufferPointer[i] = 0;
42
43 KeReleaseSpinLock(&hcd->Lock, OldIrql);
44
45 return Descriptor;
46 }
47
48 VOID
49 FreeDescriptor(PEHCI_HOST_CONTROLLER hcd, PQUEUE_TRANSFER_DESCRIPTOR Descriptor)
50 {
51 ReleaseMemory(hcd, (ULONG)Descriptor);
52 }
53
54 /* Queue Head */
55
56 VOID
57 DumpQueueHeadList(PEHCI_HOST_CONTROLLER hcd)
58 {
59 KIRQL OldIrql;
60
61 KeAcquireSpinLock(&hcd->Lock, &OldIrql);
62
63 PQUEUE_HEAD QueueHead = (PQUEUE_HEAD)hcd->CommonBufferVA;
64 PQUEUE_HEAD FirstQueueHead = QueueHead;
65 DPRINT1("Dumping QueueHead List!!!!!!!!!!!!!\n");
66 while (1)
67 {
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;
76 }
77 DPRINT1("-----------------------------------\n");
78 KeReleaseSpinLock(&hcd->Lock, OldIrql);
79 }
80
81 PQUEUE_HEAD
82 CreateQueueHead(PEHCI_HOST_CONTROLLER hcd)
83 {
84 PQUEUE_HEAD CurrentQH;
85 ULONG PhysicalAddress , i;
86 KIRQL OldIrql;
87
88 KeAcquireSpinLock(&hcd->Lock, &OldIrql);
89 CurrentQH = (PQUEUE_HEAD)AllocateMemory(hcd, sizeof(QUEUE_HEAD), &PhysicalAddress);
90 RtlZeroMemory(CurrentQH, sizeof(QUEUE_HEAD));
91
92 ASSERT(CurrentQH);
93 CurrentQH->PhysicalAddr = PhysicalAddress;
94 CurrentQH->HorizontalLinkPointer = TERMINATE_POINTER;
95 CurrentQH->AlternateNextPointer = TERMINATE_POINTER;
96 CurrentQH->NextPointer = TERMINATE_POINTER;
97
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;
102
103 /* Set NakCountReload to max value possible */
104 CurrentQH->EndPointCharacteristics.NakCountReload = 0xF;
105
106 /* Get the Initial Data Toggle from the QEDT */
107 CurrentQH->EndPointCharacteristics.QEDTDataToggleControl = FALSE;
108
109 /* High Speed Device */
110 CurrentQH->EndPointCharacteristics.EndPointSpeed = QH_ENDPOINT_HIGHSPEED;
111
112 CurrentQH->EndPointCapabilities.NumberOfTransactionPerFrame = 0x03;
113
114 CurrentQH->Token.DWord = 0;
115 CurrentQH->NextQueueHead = NULL;
116 CurrentQH->PreviousQueueHead = NULL;
117 for (i=0; i<5; i++)
118 CurrentQH->BufferPointer[i] = 0;
119
120 CurrentQH->Token.Bits.InterruptOnComplete = FALSE;
121
122 KeReleaseSpinLock(&hcd->Lock, OldIrql);
123 return CurrentQH;
124 }
125
126 VOID
127 LinkQueueHead(PEHCI_HOST_CONTROLLER hcd, PQUEUE_HEAD QueueHead)
128 {
129 KIRQL OldIrql;
130 PQUEUE_HEAD CurrentHead = (PQUEUE_HEAD)hcd->AsyncListQueue;
131 PQUEUE_HEAD PreviousHead;
132
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;
139
140 QueueHead->HorizontalLinkPointer = (CurrentHead->HorizontalLinkPointer | QH_TYPE_QH) & ~TERMINATE_POINTER;
141 PreviousHead->HorizontalLinkPointer = QueueHead->PhysicalAddr| QH_TYPE_QH;
142
143 KeReleaseSpinLock(&hcd->Lock, OldIrql);
144 }
145
146 VOID
147 UnlinkQueueHead(PEHCI_HOST_CONTROLLER hcd, PQUEUE_HEAD QueueHead)
148 {
149 KIRQL OldIrql;
150 PQUEUE_HEAD PreviousHead;
151 PQUEUE_HEAD NextHead;
152 KeAcquireSpinLock(&hcd->Lock, &OldIrql);
153
154 PreviousHead = QueueHead->PreviousQueueHead;
155 NextHead = QueueHead->NextQueueHead;
156
157 PreviousHead->NextQueueHead = NextHead;
158 NextHead->PreviousQueueHead = PreviousHead;
159
160 PreviousHead->HorizontalLinkPointer = NextHead->HorizontalLinkPointer;
161 KeReleaseSpinLock(&hcd->Lock, OldIrql);
162 }
163
164 VOID
165 LinkQueueHeadToCompletedList(PEHCI_HOST_CONTROLLER hcd, PQUEUE_HEAD QueueHead)
166 {
167 KIRQL OldIrql;
168 PQUEUE_HEAD CurrentHead = (PQUEUE_HEAD)hcd->CompletedListQueue;
169 PQUEUE_HEAD PreviousHead;
170
171 KeAcquireSpinLock(&hcd->Lock, &OldIrql);
172
173 PreviousHead = CurrentHead->PreviousQueueHead;
174 QueueHead->NextQueueHead = CurrentHead;
175 QueueHead->PreviousQueueHead = PreviousHead;
176 PreviousHead->NextQueueHead = QueueHead;
177 CurrentHead->PreviousQueueHead = QueueHead;
178
179 KeReleaseSpinLock(&hcd->Lock, OldIrql);
180
181 }
182
183 VOID
184 DeleteQueueHead(PEHCI_HOST_CONTROLLER hcd, PQUEUE_HEAD QueueHead)
185 {
186 ReleaseMemory(hcd, (ULONG)QueueHead);
187 }
188
189 VOID
190 CleanupAsyncList(PEHCI_HOST_CONTROLLER hcd)
191 {
192 PQUEUE_TRANSFER_DESCRIPTOR Descriptor;
193 PQUEUE_HEAD QueueHead;
194 KIRQL OldIrql;
195
196 KeAcquireSpinLock(&hcd->Lock, &OldIrql);
197
198 QueueHead = hcd->CompletedListQueue;
199 QueueHead = QueueHead->NextQueueHead;
200
201 while (QueueHead != hcd->CompletedListQueue)
202 {
203 Descriptor = QueueHead->FirstTransferDescriptor;
204 while (Descriptor)
205 {
206 if (Descriptor->Token.Bits.PIDCode == PID_CODE_SETUP_TOKEN)
207 ReleaseMemory(hcd, Descriptor->BufferPointerVA[0]);
208 FreeDescriptor(hcd, Descriptor);
209 Descriptor = Descriptor->NextDescriptor;
210 }
211
212 if (QueueHead->FreeMdl)
213 {
214 DPRINT("Freeing Mdl %x, StartVA %x\n", QueueHead->Mdl, QueueHead->Mdl->StartVa);
215 IoFreeMdl(QueueHead->Mdl);
216 }
217
218 QueueHead = QueueHead->NextQueueHead;
219 }
220
221 hcd->CompletedListQueue->NextQueueHead = hcd->CompletedListQueue;
222 hcd->CompletedListQueue->PreviousQueueHead = hcd->CompletedListQueue;
223
224 KeReleaseSpinLock(&hcd->Lock, OldIrql);
225 }
226