[USBOHCI]
[reactos.git] / drivers / usb / usbohci / usb_queue.cpp
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/usbohci/usb_queue.cpp
5 * PURPOSE: USB OHCI device driver.
6 * PROGRAMMERS:
7 * Michael Martin (michael.martin@reactos.org)
8 * Johannes Anderwald (johannes.anderwald@reactos.org)
9 */
10
11 #include "usbohci.h"
12 #include "hardware.h"
13
14 class CUSBQueue : public IUSBQueue
15 {
16 public:
17 STDMETHODIMP QueryInterface( REFIID InterfaceId, PVOID* Interface);
18
19 STDMETHODIMP_(ULONG) AddRef()
20 {
21 InterlockedIncrement(&m_Ref);
22 return m_Ref;
23 }
24 STDMETHODIMP_(ULONG) Release()
25 {
26 InterlockedDecrement(&m_Ref);
27
28 if (!m_Ref)
29 {
30 delete this;
31 return 0;
32 }
33 return m_Ref;
34 }
35
36 virtual NTSTATUS Initialize(IN PUSBHARDWAREDEVICE Hardware, PDMA_ADAPTER AdapterObject, IN PDMAMEMORYMANAGER MemManager, IN OPTIONAL PKSPIN_LOCK Lock);
37 virtual ULONG GetPendingRequestCount();
38 virtual NTSTATUS AddUSBRequest(IUSBRequest * Request);
39 virtual NTSTATUS CancelRequests();
40 virtual NTSTATUS CreateUSBRequest(IUSBRequest **OutRequest);
41
42 // constructor / destructor
43 CUSBQueue(IUnknown *OuterUnknown){}
44 virtual ~CUSBQueue(){}
45
46 protected:
47 LONG m_Ref; // reference count
48 KSPIN_LOCK m_Lock; // list lock
49 PUSBHARDWAREDEVICE m_Hardware; // hardware
50 POHCI_ENDPOINT_DESCRIPTOR m_BulkHeadEndpointDescriptor; // bulk head descriptor
51 POHCI_ENDPOINT_DESCRIPTOR m_ControlHeadEndpointDescriptor; // control head descriptor
52 };
53
54 //=================================================================================================
55 // COM
56 //
57 NTSTATUS
58 STDMETHODCALLTYPE
59 CUSBQueue::QueryInterface(
60 IN REFIID refiid,
61 OUT PVOID* Output)
62 {
63 if (IsEqualGUIDAligned(refiid, IID_IUnknown))
64 {
65 *Output = PVOID(PUNKNOWN(this));
66 PUNKNOWN(*Output)->AddRef();
67 return STATUS_SUCCESS;
68 }
69
70 return STATUS_UNSUCCESSFUL;
71 }
72
73 NTSTATUS
74 CUSBQueue::Initialize(
75 IN PUSBHARDWAREDEVICE Hardware,
76 IN PDMA_ADAPTER AdapterObject,
77 IN PDMAMEMORYMANAGER MemManager,
78 IN OPTIONAL PKSPIN_LOCK Lock)
79 {
80 //
81 // get bulk endpoint descriptor
82 //
83 Hardware->GetBulkHeadEndpointDescriptor(&m_BulkHeadEndpointDescriptor);
84
85 //
86 // get control endpoint descriptor
87 //
88 Hardware->GetControlHeadEndpointDescriptor(&m_ControlHeadEndpointDescriptor);
89
90 //
91 // initialize spinlock
92 //
93 KeInitializeSpinLock(&m_Lock);
94
95 //
96 // store hardware
97 //
98 m_Hardware = Hardware;
99
100 return STATUS_SUCCESS;
101 }
102
103 ULONG
104 CUSBQueue::GetPendingRequestCount()
105 {
106 //
107 // Loop through the pending list and iterrate one for each QueueHead that
108 // has a IRP to complete.
109 //
110
111 return 0;
112 }
113
114 NTSTATUS
115 CUSBQueue::AddUSBRequest(
116 IUSBRequest * Request)
117 {
118 NTSTATUS Status;
119 ULONG Type;
120 KIRQL OldLevel;
121 POHCI_ENDPOINT_DESCRIPTOR HeadDescriptor;
122 POHCI_ENDPOINT_DESCRIPTOR Descriptor;
123
124 DPRINT1("CUSBQueue::AddUSBRequest\n");
125
126 //
127 // sanity check
128 //
129 ASSERT(Request != NULL);
130
131 //
132 // get request type
133 //
134 Type = Request->GetTransferType();
135
136 //
137 // check if supported
138 //
139 switch(Type)
140 {
141 case USB_ENDPOINT_TYPE_ISOCHRONOUS:
142 case USB_ENDPOINT_TYPE_INTERRUPT:
143 /* NOT IMPLEMENTED IN QUEUE */
144 Status = STATUS_NOT_SUPPORTED;
145 break;
146 case USB_ENDPOINT_TYPE_BULK:
147 case USB_ENDPOINT_TYPE_CONTROL:
148 Status = STATUS_SUCCESS;
149 break;
150 default:
151 /* BUG */
152 PC_ASSERT(FALSE);
153 Status = STATUS_NOT_SUPPORTED;
154 }
155
156 //
157 // check for success
158 //
159 if (!NT_SUCCESS(Status))
160 {
161 //
162 // request not supported, please try later
163 //
164 return Status;
165 }
166
167 //
168 // add extra reference which is released when the request is completed
169 //
170 Request->AddRef();
171
172 //
173 // get transfer descriptors
174 //
175 Status = Request->GetEndpointDescriptor(&Descriptor);
176 if (!NT_SUCCESS(Status))
177 {
178 //
179 // failed to get transfer descriptor
180 //
181 DPRINT1("CUSBQueue::AddUSBRequest GetEndpointDescriptor failed with %x\n", Status);
182
183 //
184 // release reference
185 //
186 Request->Release();
187 return Status;
188 }
189
190 //
191 // check type
192 //
193 if (Type == USB_ENDPOINT_TYPE_BULK)
194 {
195 //
196 // get head descriptor
197 //
198 HeadDescriptor = m_BulkHeadEndpointDescriptor;
199 }
200 else if (Type == USB_ENDPOINT_TYPE_CONTROL)
201 {
202 //
203 // get head descriptor
204 //
205 HeadDescriptor = m_ControlHeadEndpointDescriptor;
206 }
207
208 //
209 // link endpoints
210 //
211 Descriptor->NextPhysicalEndpoint = HeadDescriptor->NextPhysicalEndpoint;
212 Descriptor->NextDescriptor = HeadDescriptor->NextDescriptor;
213
214 HeadDescriptor->NextPhysicalEndpoint = Descriptor->PhysicalAddress.LowPart;
215 HeadDescriptor->NextDescriptor = Descriptor;
216
217 //
218 // set descriptor active
219 //
220 Descriptor->Flags &= ~OHCI_ENDPOINT_SKIP;
221
222 //
223 // notify hardware of our request
224 //
225 m_Hardware->HeadEndpointDescriptorModified(Type);
226
227 DPRINT1("Request added to queue\n");
228
229
230 return STATUS_SUCCESS;
231 }
232
233 NTSTATUS
234 CUSBQueue::CancelRequests()
235 {
236 UNIMPLEMENTED
237 return STATUS_NOT_IMPLEMENTED;
238 }
239
240 NTSTATUS
241 CUSBQueue::CreateUSBRequest(
242 IUSBRequest **OutRequest)
243 {
244 PUSBREQUEST UsbRequest;
245 NTSTATUS Status;
246
247 *OutRequest = NULL;
248 Status = InternalCreateUSBRequest(&UsbRequest);
249
250 if (NT_SUCCESS(Status))
251 {
252 *OutRequest = UsbRequest;
253 }
254
255 return Status;
256 }
257
258
259 NTSTATUS
260 CreateUSBQueue(
261 PUSBQUEUE *OutUsbQueue)
262 {
263 PUSBQUEUE This;
264
265 //
266 // allocate controller
267 //
268 This = new(NonPagedPool, TAG_USBOHCI) CUSBQueue(0);
269 if (!This)
270 {
271 //
272 // failed to allocate
273 //
274 return STATUS_INSUFFICIENT_RESOURCES;
275 }
276
277 //
278 // add reference count
279 //
280 This->AddRef();
281
282 //
283 // return result
284 //
285 *OutUsbQueue = (PUSBQUEUE)This;
286
287 //
288 // done
289 //
290 return STATUS_SUCCESS;
291 }