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.
7 * Michael Martin (michael.martin@reactos.org)
8 * Johannes Anderwald (johannes.anderwald@reactos.org)
14 class CUSBQueue
: public IUSBQueue
17 STDMETHODIMP
QueryInterface( REFIID InterfaceId
, PVOID
* Interface
);
19 STDMETHODIMP_(ULONG
) AddRef()
21 InterlockedIncrement(&m_Ref
);
24 STDMETHODIMP_(ULONG
) Release()
26 InterlockedDecrement(&m_Ref
);
37 virtual NTSTATUS
Initialize(IN PUSBHARDWAREDEVICE Hardware
, PDMA_ADAPTER AdapterObject
, IN PDMAMEMORYMANAGER MemManager
, IN OPTIONAL PKSPIN_LOCK Lock
);
38 virtual ULONG
GetPendingRequestCount();
39 virtual NTSTATUS
AddUSBRequest(IUSBRequest
* Request
);
40 virtual NTSTATUS
CancelRequests();
41 virtual NTSTATUS
CreateUSBRequest(IUSBRequest
**OutRequest
);
42 virtual VOID
TransferDescriptorCompletionCallback(ULONG TransferDescriptorLogicalAddress
);
45 BOOLEAN
IsTransferDescriptorInEndpoint(IN POHCI_ENDPOINT_DESCRIPTOR EndpointDescriptor
, IN ULONG TransferDescriptorLogicalAddress
);
46 NTSTATUS
FindTransferDescriptorInEndpoint(IN POHCI_ENDPOINT_DESCRIPTOR EndpointDescriptor
, IN ULONG TransferDescriptorLogicalAddress
, OUT POHCI_ENDPOINT_DESCRIPTOR
*OutEndpointDescriptor
, OUT POHCI_ENDPOINT_DESCRIPTOR
*OutPreviousEndpointDescriptor
);
48 // constructor / destructor
49 CUSBQueue(IUnknown
*OuterUnknown
){}
50 virtual ~CUSBQueue(){}
53 LONG m_Ref
; // reference count
54 KSPIN_LOCK m_Lock
; // list lock
55 PUSBHARDWAREDEVICE m_Hardware
; // hardware
56 POHCI_ENDPOINT_DESCRIPTOR m_BulkHeadEndpointDescriptor
; // bulk head descriptor
57 POHCI_ENDPOINT_DESCRIPTOR m_ControlHeadEndpointDescriptor
; // control head descriptor
60 //=================================================================================================
65 CUSBQueue::QueryInterface(
69 if (IsEqualGUIDAligned(refiid
, IID_IUnknown
))
71 *Output
= PVOID(PUNKNOWN(this));
72 PUNKNOWN(*Output
)->AddRef();
73 return STATUS_SUCCESS
;
76 return STATUS_UNSUCCESSFUL
;
80 CUSBQueue::Initialize(
81 IN PUSBHARDWAREDEVICE Hardware
,
82 IN PDMA_ADAPTER AdapterObject
,
83 IN PDMAMEMORYMANAGER MemManager
,
84 IN OPTIONAL PKSPIN_LOCK Lock
)
87 // get bulk endpoint descriptor
89 Hardware
->GetBulkHeadEndpointDescriptor(&m_BulkHeadEndpointDescriptor
);
92 // get control endpoint descriptor
94 Hardware
->GetControlHeadEndpointDescriptor(&m_ControlHeadEndpointDescriptor
);
97 // initialize spinlock
99 KeInitializeSpinLock(&m_Lock
);
104 m_Hardware
= Hardware
;
106 return STATUS_SUCCESS
;
110 CUSBQueue::GetPendingRequestCount()
113 // Loop through the pending list and iterrate one for each QueueHead that
114 // has a IRP to complete.
121 CUSBQueue::AddUSBRequest(
122 IUSBRequest
* Request
)
127 POHCI_ENDPOINT_DESCRIPTOR HeadDescriptor
;
128 POHCI_ENDPOINT_DESCRIPTOR Descriptor
;
130 DPRINT1("CUSBQueue::AddUSBRequest\n");
135 ASSERT(Request
!= NULL
);
140 Type
= Request
->GetTransferType();
143 // check if supported
147 case USB_ENDPOINT_TYPE_ISOCHRONOUS
:
148 case USB_ENDPOINT_TYPE_INTERRUPT
:
149 case USB_ENDPOINT_TYPE_BULK
:
150 /* NOT IMPLEMENTED IN QUEUE */
151 Status
= STATUS_NOT_SUPPORTED
;
153 case USB_ENDPOINT_TYPE_CONTROL
:
154 Status
= STATUS_SUCCESS
;
159 Status
= STATUS_NOT_SUPPORTED
;
165 if (!NT_SUCCESS(Status
))
168 // request not supported, please try later
170 DPRINT1("Request Type %x not supported\n", Type
);
176 // add extra reference which is released when the request is completed
181 // get transfer descriptors
183 Status
= Request
->GetEndpointDescriptor(&Descriptor
);
184 if (!NT_SUCCESS(Status
))
187 // failed to get transfer descriptor
189 DPRINT1("CUSBQueue::AddUSBRequest GetEndpointDescriptor failed with %x\n", Status
);
201 if (Type
== USB_ENDPOINT_TYPE_BULK
)
204 // get head descriptor
206 HeadDescriptor
= m_BulkHeadEndpointDescriptor
;
208 else if (Type
== USB_ENDPOINT_TYPE_CONTROL
)
211 // get head descriptor
213 HeadDescriptor
= m_ControlHeadEndpointDescriptor
;
219 Descriptor
->NextPhysicalEndpoint
= HeadDescriptor
->NextPhysicalEndpoint
;
220 Descriptor
->NextDescriptor
= HeadDescriptor
->NextDescriptor
;
222 HeadDescriptor
->NextPhysicalEndpoint
= Descriptor
->PhysicalAddress
.LowPart
;
223 HeadDescriptor
->NextDescriptor
= Descriptor
;
226 // set descriptor active
228 Descriptor
->Flags
&= ~OHCI_ENDPOINT_SKIP
;
229 //HeadDescriptor->Flags &= ~OHCI_ENDPOINT_SKIP;
232 // notify hardware of our request
234 m_Hardware
->HeadEndpointDescriptorModified(Type
);
236 DPRINT1("Request %x %x added to queue\n", Descriptor
, Descriptor
->PhysicalAddress
);
239 return STATUS_SUCCESS
;
243 CUSBQueue::CancelRequests()
246 return STATUS_NOT_IMPLEMENTED
;
250 CUSBQueue::CreateUSBRequest(
251 IUSBRequest
**OutRequest
)
253 PUSBREQUEST UsbRequest
;
257 Status
= InternalCreateUSBRequest(&UsbRequest
);
259 if (NT_SUCCESS(Status
))
261 *OutRequest
= UsbRequest
;
268 CUSBQueue::FindTransferDescriptorInEndpoint(
269 IN POHCI_ENDPOINT_DESCRIPTOR EndpointDescriptor
,
270 IN ULONG TransferDescriptorLogicalAddress
,
271 OUT POHCI_ENDPOINT_DESCRIPTOR
*OutEndpointDescriptor
,
272 OUT POHCI_ENDPOINT_DESCRIPTOR
*OutPreviousEndpointDescriptor
)
274 POHCI_ENDPOINT_DESCRIPTOR LastDescriptor
= EndpointDescriptor
;
278 // skip first endpoint head
280 EndpointDescriptor
= (POHCI_ENDPOINT_DESCRIPTOR
)EndpointDescriptor
->NextDescriptor
;
282 while(EndpointDescriptor
)
285 // check if the transfer descriptor is inside the list
287 if (IsTransferDescriptorInEndpoint(EndpointDescriptor
, TransferDescriptorLogicalAddress
))
292 *OutEndpointDescriptor
= EndpointDescriptor
;
293 *OutPreviousEndpointDescriptor
= LastDescriptor
;
298 return STATUS_SUCCESS
;
302 // store last endpoint
304 LastDescriptor
= EndpointDescriptor
;
309 EndpointDescriptor
= (POHCI_ENDPOINT_DESCRIPTOR
)EndpointDescriptor
->NextDescriptor
;
313 // failed to endpoint
315 return STATUS_NOT_FOUND
;
320 CUSBQueue::IsTransferDescriptorInEndpoint(
321 IN POHCI_ENDPOINT_DESCRIPTOR EndpointDescriptor
,
322 IN ULONG TransferDescriptorLogicalAddress
)
324 POHCI_GENERAL_TD Descriptor
;
327 // get first general transfer descriptor
329 Descriptor
= (POHCI_GENERAL_TD
)EndpointDescriptor
->HeadLogicalDescriptor
;
338 if (Descriptor
->PhysicalAddress
.LowPart
== TransferDescriptorLogicalAddress
)
349 Descriptor
= (POHCI_GENERAL_TD
)Descriptor
->NextLogicalDescriptor
;
354 // no descriptor found
361 CUSBQueue::TransferDescriptorCompletionCallback(
362 ULONG TransferDescriptorLogicalAddress
)
364 POHCI_ENDPOINT_DESCRIPTOR EndpointDescriptor
, PreviousEndpointDescriptor
;
369 // find transfer descriptor in control list
371 Status
= FindTransferDescriptorInEndpoint(m_ControlHeadEndpointDescriptor
, TransferDescriptorLogicalAddress
, &EndpointDescriptor
, &PreviousEndpointDescriptor
);
372 if (NT_SUCCESS(Status
))
375 // FIXME: make sure this is ok
378 PreviousEndpointDescriptor
->NextDescriptor
= EndpointDescriptor
->NextDescriptor
;
379 PreviousEndpointDescriptor
->NextPhysicalEndpoint
= EndpointDescriptor
->NextPhysicalEndpoint
;
382 // get corresponding request
384 Request
= PUSBREQUEST(EndpointDescriptor
->Request
);
387 // notify of completion
389 Request
->CompletionCallback(EndpointDescriptor
);
392 // FIXME: check if complete
394 ASSERT(Request
->IsRequestComplete());
406 PUSBQUEUE
*OutUsbQueue
)
411 // allocate controller
413 This
= new(NonPagedPool
, TAG_USBOHCI
) CUSBQueue(0);
417 // failed to allocate
419 return STATUS_INSUFFICIENT_RESOURCES
;
423 // add reference count
430 *OutUsbQueue
= (PUSBQUEUE
)This
;
435 return STATUS_SUCCESS
;