[USB-BRINGUP]
[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 // com
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);
43
44 // local functions
45 BOOLEAN IsTransferDescriptorInEndpoint(IN POHCI_ENDPOINT_DESCRIPTOR EndpointDescriptor, IN ULONG TransferDescriptorLogicalAddress);
46 BOOLEAN IsTransferDescriptorInIsoEndpoint(IN POHCI_ENDPOINT_DESCRIPTOR EndpointDescriptor, IN ULONG TransferDescriptorLogicalAddress);
47 NTSTATUS FindTransferDescriptorInEndpoint(IN POHCI_ENDPOINT_DESCRIPTOR EndpointDescriptor, IN ULONG TransferDescriptorLogicalAddress, OUT POHCI_ENDPOINT_DESCRIPTOR *OutEndpointDescriptor, OUT POHCI_ENDPOINT_DESCRIPTOR *OutPreviousEndpointDescriptor);
48 NTSTATUS FindTransferDescriptorInInterruptHeadEndpoints(IN ULONG TransferDescriptorLogicalAddress, OUT POHCI_ENDPOINT_DESCRIPTOR *OutEndpointDescriptor, OUT POHCI_ENDPOINT_DESCRIPTOR *OutPreviousEndpointDescriptor);
49 NTSTATUS FindTransferDescriptorInIsochronousHeadEndpoints(IN ULONG TransferDescriptorLogicalAddress, OUT POHCI_ENDPOINT_DESCRIPTOR *OutEndpointDescriptor, OUT POHCI_ENDPOINT_DESCRIPTOR *OutPreviousEndpointDescriptor);
50
51 VOID CleanupEndpointDescriptor(POHCI_ENDPOINT_DESCRIPTOR EndpointDescriptor, POHCI_ENDPOINT_DESCRIPTOR PreviousEndpointDescriptor);
52 POHCI_ENDPOINT_DESCRIPTOR FindInterruptEndpointDescriptor(UCHAR InterruptInterval);
53 VOID PrintEndpointList(POHCI_ENDPOINT_DESCRIPTOR EndpointDescriptor);
54 VOID LinkEndpoint(POHCI_ENDPOINT_DESCRIPTOR HeadEndpointDescriptor, POHCI_ENDPOINT_DESCRIPTOR EndpointDescriptor);
55
56 // constructor / destructor
57 CUSBQueue(IUnknown *OuterUnknown){}
58 virtual ~CUSBQueue(){}
59
60 protected:
61 LONG m_Ref; // reference count
62 KSPIN_LOCK m_Lock; // list lock
63 PUSBHARDWAREDEVICE m_Hardware; // hardware
64 POHCI_ENDPOINT_DESCRIPTOR m_BulkHeadEndpointDescriptor; // bulk head descriptor
65 POHCI_ENDPOINT_DESCRIPTOR m_ControlHeadEndpointDescriptor; // control head descriptor
66 POHCI_ENDPOINT_DESCRIPTOR m_IsoHeadEndpointDescriptor; // isochronous head descriptor
67 POHCI_ENDPOINT_DESCRIPTOR * m_InterruptEndpoints;
68 };
69
70 //=================================================================================================
71 // COM
72 //
73 NTSTATUS
74 STDMETHODCALLTYPE
75 CUSBQueue::QueryInterface(
76 IN REFIID refiid,
77 OUT PVOID* Output)
78 {
79 if (IsEqualGUIDAligned(refiid, IID_IUnknown))
80 {
81 *Output = PVOID(PUNKNOWN(this));
82 PUNKNOWN(*Output)->AddRef();
83 return STATUS_SUCCESS;
84 }
85
86 return STATUS_UNSUCCESSFUL;
87 }
88
89 NTSTATUS
90 CUSBQueue::Initialize(
91 IN PUSBHARDWAREDEVICE Hardware,
92 IN PDMA_ADAPTER AdapterObject,
93 IN PDMAMEMORYMANAGER MemManager,
94 IN OPTIONAL PKSPIN_LOCK Lock)
95 {
96 //
97 // get bulk endpoint descriptor
98 //
99 Hardware->GetBulkHeadEndpointDescriptor(&m_BulkHeadEndpointDescriptor);
100
101 //
102 // get control endpoint descriptor
103 //
104 Hardware->GetControlHeadEndpointDescriptor(&m_ControlHeadEndpointDescriptor);
105
106 //
107 // get isochronous endpoint
108 //
109 Hardware->GetIsochronousHeadEndpointDescriptor(&m_IsoHeadEndpointDescriptor);
110
111 //
112 // get interrupt endpoints
113 //
114 Hardware->GetInterruptEndpointDescriptors(&m_InterruptEndpoints);
115
116 //
117 // initialize spinlock
118 //
119 KeInitializeSpinLock(&m_Lock);
120
121 //
122 // store hardware
123 //
124 m_Hardware = Hardware;
125
126 return STATUS_SUCCESS;
127 }
128
129 ULONG
130 CUSBQueue::GetPendingRequestCount()
131 {
132 //
133 // Loop through the pending list and iterrate one for each QueueHead that
134 // has a IRP to complete.
135 //
136
137 return 0;
138 }
139
140 VOID
141 CUSBQueue::LinkEndpoint(
142 POHCI_ENDPOINT_DESCRIPTOR HeadEndpointDescriptor,
143 POHCI_ENDPOINT_DESCRIPTOR EndpointDescriptor)
144 {
145 POHCI_ENDPOINT_DESCRIPTOR CurrentEndpointDescriptor = HeadEndpointDescriptor;
146
147 //
148 // get last descriptor in queue
149 //
150 while(CurrentEndpointDescriptor->NextDescriptor)
151 {
152 //
153 // move to last descriptor
154 //
155 CurrentEndpointDescriptor = (POHCI_ENDPOINT_DESCRIPTOR)CurrentEndpointDescriptor->NextDescriptor;
156 }
157
158 //
159 // link endpoints
160 //
161 CurrentEndpointDescriptor->NextPhysicalEndpoint = EndpointDescriptor->PhysicalAddress.LowPart;
162 CurrentEndpointDescriptor->NextDescriptor = EndpointDescriptor;
163
164 }
165
166 NTSTATUS
167 CUSBQueue::AddUSBRequest(
168 IUSBRequest * Request)
169 {
170 NTSTATUS Status;
171 ULONG Type;
172 KIRQL OldLevel;
173 POHCI_ENDPOINT_DESCRIPTOR HeadDescriptor;
174 POHCI_ENDPOINT_DESCRIPTOR Descriptor;
175 POHCI_ISO_TD CurrentDescriptor;
176 ULONG FrameNumber;
177 USHORT Frame;
178
179 DPRINT("CUSBQueue::AddUSBRequest\n");
180
181 //
182 // sanity check
183 //
184 ASSERT(Request != NULL);
185
186 //
187 // get request type
188 //
189 Type = Request->GetTransferType();
190
191 //
192 // add extra reference which is released when the request is completed
193 //
194 Request->AddRef();
195
196 //
197 // get transfer descriptors
198 //
199 Status = Request->GetEndpointDescriptor(&Descriptor);
200 if (!NT_SUCCESS(Status))
201 {
202 //
203 // failed to get transfer descriptor
204 //
205 DPRINT1("CUSBQueue::AddUSBRequest GetEndpointDescriptor failed with %x\n", Status);
206
207 //
208 // release reference
209 //
210 Request->Release();
211 return Status;
212 }
213
214 //
215 // check type
216 //
217 if (Type == USB_ENDPOINT_TYPE_BULK)
218 {
219 //
220 // get head descriptor
221 //
222 HeadDescriptor = m_BulkHeadEndpointDescriptor;
223 }
224 else if (Type == USB_ENDPOINT_TYPE_CONTROL)
225 {
226 //
227 // get head descriptor
228 //
229 HeadDescriptor = m_ControlHeadEndpointDescriptor;
230 }
231 else if (Type == USB_ENDPOINT_TYPE_INTERRUPT)
232 {
233 //
234 // get head descriptor
235 //
236 HeadDescriptor = FindInterruptEndpointDescriptor(Request->GetInterval());
237 ASSERT(HeadDescriptor);
238 }
239 else if (Type == USB_ENDPOINT_TYPE_ISOCHRONOUS)
240 {
241 //
242 // get head descriptor
243 //
244 HeadDescriptor = m_IsoHeadEndpointDescriptor;
245
246 //
247 // get current frame number
248 //
249 m_Hardware->GetCurrentFrameNumber(&FrameNumber);
250
251 //
252 // FIXME: increment frame number
253 //
254 FrameNumber += 300;
255
256 //
257 // apply frame number to iso transfer descriptors
258 //
259 CurrentDescriptor = (POHCI_ISO_TD)Descriptor->HeadLogicalDescriptor;
260
261 DPRINT1("ISO: NextFrameNumber %x\n", FrameNumber);
262 Frame = (FrameNumber & 0xFFFF);
263
264 while(CurrentDescriptor)
265 {
266 //
267 // set current frame number
268 //
269 CurrentDescriptor->Flags |= OHCI_ITD_SET_STARTING_FRAME(Frame);
270
271 //
272 // move to next frame number
273 //
274 Frame += OHCI_ITD_GET_FRAME_COUNT(CurrentDescriptor->Flags);
275
276 //
277 // move to next descriptor
278 //
279 CurrentDescriptor = CurrentDescriptor->NextLogicalDescriptor;
280 }
281
282 //
283 // get current frame number
284 //
285 m_Hardware->GetCurrentFrameNumber(&FrameNumber);
286
287 DPRINT1("Hardware 1ms %p Iso %p\n",m_InterruptEndpoints[0], m_IsoHeadEndpointDescriptor);
288 ASSERT(m_InterruptEndpoints[0]->NextPhysicalEndpoint == m_IsoHeadEndpointDescriptor->PhysicalAddress.LowPart);
289
290 PrintEndpointList(m_IsoHeadEndpointDescriptor);
291 }
292
293 //
294 // set descriptor active
295 //
296 Descriptor->Flags &= ~OHCI_ENDPOINT_SKIP;
297
298 //
299 // insert endpoint at end
300 //
301 LinkEndpoint(HeadDescriptor, Descriptor);
302
303 if (Type == USB_ENDPOINT_TYPE_CONTROL || Type == USB_ENDPOINT_TYPE_BULK)
304 {
305 //
306 // notify hardware of our request
307 //
308 m_Hardware->HeadEndpointDescriptorModified(Type);
309 }
310
311
312 return STATUS_SUCCESS;
313 }
314
315 NTSTATUS
316 CUSBQueue::CancelRequests()
317 {
318 UNIMPLEMENTED
319 return STATUS_NOT_IMPLEMENTED;
320 }
321
322 NTSTATUS
323 CUSBQueue::CreateUSBRequest(
324 IUSBRequest **OutRequest)
325 {
326 PUSBREQUEST UsbRequest;
327 NTSTATUS Status;
328
329 *OutRequest = NULL;
330 Status = InternalCreateUSBRequest(&UsbRequest);
331
332 if (NT_SUCCESS(Status))
333 {
334 *OutRequest = UsbRequest;
335 }
336
337 return Status;
338 }
339
340 NTSTATUS
341 CUSBQueue::FindTransferDescriptorInEndpoint(
342 IN POHCI_ENDPOINT_DESCRIPTOR EndpointDescriptor,
343 IN ULONG TransferDescriptorLogicalAddress,
344 OUT POHCI_ENDPOINT_DESCRIPTOR *OutEndpointDescriptor,
345 OUT POHCI_ENDPOINT_DESCRIPTOR *OutPreviousEndpointDescriptor)
346 {
347 POHCI_ENDPOINT_DESCRIPTOR LastDescriptor = EndpointDescriptor;
348
349
350 //
351 // skip first endpoint head
352 //
353 EndpointDescriptor = (POHCI_ENDPOINT_DESCRIPTOR)EndpointDescriptor->NextDescriptor;
354
355 while(EndpointDescriptor)
356 {
357 //
358 // check if the transfer descriptor is inside the list
359 //
360 if (IsTransferDescriptorInEndpoint(EndpointDescriptor, TransferDescriptorLogicalAddress))
361 {
362 //
363 // found endpoint
364 //
365 *OutEndpointDescriptor = EndpointDescriptor;
366 *OutPreviousEndpointDescriptor = LastDescriptor;
367
368 //
369 // done
370 //
371 return STATUS_SUCCESS;
372 }
373
374 //
375 // store last endpoint
376 //
377 LastDescriptor = EndpointDescriptor;
378
379 //
380 // move to next
381 //
382 EndpointDescriptor = (POHCI_ENDPOINT_DESCRIPTOR)EndpointDescriptor->NextDescriptor;
383 }
384
385 //
386 // failed to endpoint
387 //
388 return STATUS_NOT_FOUND;
389 }
390
391 NTSTATUS
392 CUSBQueue::FindTransferDescriptorInInterruptHeadEndpoints(IN ULONG TransferDescriptorLogicalAddress, OUT POHCI_ENDPOINT_DESCRIPTOR *OutEndpointDescriptor, OUT POHCI_ENDPOINT_DESCRIPTOR *OutPreviousEndpointDescriptor)
393 {
394 ULONG Index;
395 NTSTATUS Status;
396
397 //
398 // search descriptor in endpoint list
399 //
400 for(Index = 0; Index < OHCI_STATIC_ENDPOINT_COUNT; Index++)
401 {
402 //
403 // is it in current endpoint
404 //
405 Status = FindTransferDescriptorInEndpoint(m_InterruptEndpoints[Index], TransferDescriptorLogicalAddress, OutEndpointDescriptor, OutPreviousEndpointDescriptor);
406 if (NT_SUCCESS(Status))
407 {
408 //
409 // found transfer descriptor
410 //
411 return STATUS_SUCCESS;
412 }
413 }
414
415 //
416 // not found
417 //
418 return STATUS_NOT_FOUND;
419 }
420
421 NTSTATUS
422 CUSBQueue::FindTransferDescriptorInIsochronousHeadEndpoints(
423 IN ULONG TransferDescriptorLogicalAddress,
424 OUT POHCI_ENDPOINT_DESCRIPTOR *OutEndpointDescriptor,
425 OUT POHCI_ENDPOINT_DESCRIPTOR *OutPreviousEndpointDescriptor)
426 {
427 POHCI_ENDPOINT_DESCRIPTOR EndpointDescriptor;
428 POHCI_ENDPOINT_DESCRIPTOR LastDescriptor = m_IsoHeadEndpointDescriptor;
429
430
431 //
432 // skip first endpoint head
433 //
434 EndpointDescriptor = (POHCI_ENDPOINT_DESCRIPTOR)m_IsoHeadEndpointDescriptor->NextDescriptor;
435
436 while(EndpointDescriptor)
437 {
438 //
439 // check if the transfer descriptor is inside the list
440 //
441 if (IsTransferDescriptorInIsoEndpoint(EndpointDescriptor, TransferDescriptorLogicalAddress))
442 {
443 //
444 // found endpoint
445 //
446 *OutEndpointDescriptor = EndpointDescriptor;
447 *OutPreviousEndpointDescriptor = LastDescriptor;
448
449 //
450 // done
451 //
452 return STATUS_SUCCESS;
453 }
454
455 //
456 // store last endpoint
457 //
458 LastDescriptor = EndpointDescriptor;
459
460 //
461 // move to next
462 //
463 EndpointDescriptor = (POHCI_ENDPOINT_DESCRIPTOR)EndpointDescriptor->NextDescriptor;
464 }
465
466 //
467 // failed to endpoint
468 //
469 return STATUS_NOT_FOUND;
470 }
471
472 BOOLEAN
473 CUSBQueue::IsTransferDescriptorInIsoEndpoint(
474 IN POHCI_ENDPOINT_DESCRIPTOR EndpointDescriptor,
475 IN ULONG TransferDescriptorLogicalAddress)
476 {
477 POHCI_ISO_TD Descriptor;
478
479 //
480 // get first general transfer descriptor
481 //
482 Descriptor = (POHCI_ISO_TD)EndpointDescriptor->HeadLogicalDescriptor;
483
484 //
485 // sanity check
486 //
487 ASSERT(Descriptor);
488
489 do
490 {
491 if (Descriptor->PhysicalAddress.LowPart == TransferDescriptorLogicalAddress)
492 {
493 //
494 // found descriptor
495 //
496 return TRUE;
497 }
498
499 //
500 // move to next
501 //
502 Descriptor = (POHCI_ISO_TD)Descriptor->NextLogicalDescriptor;
503 }while(Descriptor);
504
505 //
506 // no descriptor found
507 //
508 return FALSE;
509 }
510
511
512 BOOLEAN
513 CUSBQueue::IsTransferDescriptorInEndpoint(
514 IN POHCI_ENDPOINT_DESCRIPTOR EndpointDescriptor,
515 IN ULONG TransferDescriptorLogicalAddress)
516 {
517 POHCI_GENERAL_TD Descriptor;
518
519 //
520 // get first general transfer descriptor
521 //
522 Descriptor = (POHCI_GENERAL_TD)EndpointDescriptor->HeadLogicalDescriptor;
523
524 //
525 // sanity check
526 //
527 ASSERT(Descriptor);
528
529 do
530 {
531 if (Descriptor->PhysicalAddress.LowPart == TransferDescriptorLogicalAddress)
532 {
533 //
534 // found descriptor
535 //
536 return TRUE;
537 }
538
539 //
540 // move to next
541 //
542 Descriptor = (POHCI_GENERAL_TD)Descriptor->NextLogicalDescriptor;
543 }while(Descriptor);
544
545
546 //
547 // no descriptor found
548 //
549 return FALSE;
550 }
551
552 VOID
553 CUSBQueue::CleanupEndpointDescriptor(
554 POHCI_ENDPOINT_DESCRIPTOR EndpointDescriptor,
555 POHCI_ENDPOINT_DESCRIPTOR PreviousEndpointDescriptor)
556 {
557 PUSBREQUEST Request;
558
559 //
560 // FIXME: verify unlinking process
561 //
562 PreviousEndpointDescriptor->NextDescriptor = EndpointDescriptor->NextDescriptor;
563 PreviousEndpointDescriptor->NextPhysicalEndpoint = EndpointDescriptor->NextPhysicalEndpoint;
564
565 //
566 // get corresponding request
567 //
568 Request = PUSBREQUEST(EndpointDescriptor->Request);
569 ASSERT(Request);
570
571 //
572 // notify of completion
573 //
574 Request->CompletionCallback(EndpointDescriptor);
575
576 //
577 // free endpoint descriptor
578 //
579 Request->FreeEndpointDescriptor(EndpointDescriptor);
580
581 //
582 // FIXME: check if complete
583 //
584 //ASSERT(Request->IsRequestComplete());
585
586 Request->FreeEndpointDescriptor(EndpointDescriptor);
587
588 //
589 // release request
590 //
591 Request->Release();
592
593 }
594 VOID
595 CUSBQueue::PrintEndpointList(
596 POHCI_ENDPOINT_DESCRIPTOR EndpointDescriptor)
597 {
598 DPRINT1("CUSBQueue::PrintEndpointList HeadEndpoint %p Logical %x\n", EndpointDescriptor, EndpointDescriptor->PhysicalAddress.LowPart);
599
600 //
601 // get first general transfer descriptor
602 //
603 EndpointDescriptor = (POHCI_ENDPOINT_DESCRIPTOR)EndpointDescriptor->NextDescriptor;
604
605 while(EndpointDescriptor)
606 {
607 DPRINT1(" CUSBQueue::PrintEndpointList Endpoint %p Logical %x\n", EndpointDescriptor, EndpointDescriptor->PhysicalAddress.LowPart);
608
609 //
610 // move to next
611 //
612 EndpointDescriptor = (POHCI_ENDPOINT_DESCRIPTOR)EndpointDescriptor->NextDescriptor;
613 }
614 }
615
616 VOID
617 CUSBQueue::TransferDescriptorCompletionCallback(
618 ULONG TransferDescriptorLogicalAddress)
619 {
620 POHCI_ENDPOINT_DESCRIPTOR EndpointDescriptor, PreviousEndpointDescriptor;
621 NTSTATUS Status;
622
623 DPRINT1("CUSBQueue::TransferDescriptorCompletionCallback transfer descriptor %x\n", TransferDescriptorLogicalAddress);
624
625 //
626 // find transfer descriptor in control list
627 //
628 Status = FindTransferDescriptorInEndpoint(m_ControlHeadEndpointDescriptor, TransferDescriptorLogicalAddress, &EndpointDescriptor, &PreviousEndpointDescriptor);
629 if (NT_SUCCESS(Status))
630 {
631 //
632 // cleanup endpoint
633 //
634 CleanupEndpointDescriptor(EndpointDescriptor, PreviousEndpointDescriptor);
635
636 //
637 // done
638 //
639 return;
640 }
641
642 //
643 // find transfer descriptor in bulk list
644 //
645 Status = FindTransferDescriptorInEndpoint(m_BulkHeadEndpointDescriptor, TransferDescriptorLogicalAddress, &EndpointDescriptor, &PreviousEndpointDescriptor);
646 if (NT_SUCCESS(Status))
647 {
648 //
649 // cleanup endpoint
650 //
651 CleanupEndpointDescriptor(EndpointDescriptor, PreviousEndpointDescriptor);
652
653 //
654 // done
655 //
656 return;
657 }
658
659 //
660 // find transfer descriptor in interrupt list
661 //
662 Status = FindTransferDescriptorInInterruptHeadEndpoints(TransferDescriptorLogicalAddress, &EndpointDescriptor, &PreviousEndpointDescriptor);
663 if (NT_SUCCESS(Status))
664 {
665 //
666 // cleanup endpoint
667 //
668 CleanupEndpointDescriptor(EndpointDescriptor, PreviousEndpointDescriptor);
669
670 //
671 // done
672 //
673 return;
674 }
675
676 //
677 // last try: find the descriptor in isochronous list
678 //
679 Status = FindTransferDescriptorInIsochronousHeadEndpoints(TransferDescriptorLogicalAddress, &EndpointDescriptor, &PreviousEndpointDescriptor);
680 if (NT_SUCCESS(Status))
681 {
682 //
683 // cleanup endpoint
684 //
685 DPRINT1("ISO endpoint complete\n");
686 ASSERT(FALSE);
687 CleanupEndpointDescriptor(EndpointDescriptor, PreviousEndpointDescriptor);
688
689 //
690 // done
691 //
692 return;
693 }
694
695 //
696 // hardware reported dead endpoint completed
697 //
698 DPRINT1("CUSBQueue::TransferDescriptorCompletionCallback invalid transfer descriptor %x\n", TransferDescriptorLogicalAddress);
699 ASSERT(FALSE);
700 }
701
702 POHCI_ENDPOINT_DESCRIPTOR
703 CUSBQueue::FindInterruptEndpointDescriptor(
704 UCHAR InterruptInterval)
705 {
706 ULONG Index = 0;
707 ULONG Power = 1;
708
709 //
710 // sanity check
711 //
712 ASSERT(InterruptInterval <= OHCI_BIGGEST_INTERVAL);
713
714 //
715 // find interrupt index
716 //
717 while (Power <= OHCI_BIGGEST_INTERVAL / 2)
718 {
719 //
720 // is current interval greater
721 //
722 if (Power * 2 > InterruptInterval)
723 break;
724
725 //
726 // increment power
727 //
728 Power *= 2;
729
730 //
731 // move to next interrupt
732 //
733 Index++;
734 }
735
736 DPRINT("InterruptInterval %lu Selected InterruptIndex %lu Choosen Interval %lu\n", InterruptInterval, Index, Power);
737
738 //
739 // return endpoint
740 //
741 return m_InterruptEndpoints[Index];
742 }
743
744 NTSTATUS
745 CreateUSBQueue(
746 PUSBQUEUE *OutUsbQueue)
747 {
748 PUSBQUEUE This;
749
750 //
751 // allocate controller
752 //
753 This = new(NonPagedPool, TAG_USBOHCI) CUSBQueue(0);
754 if (!This)
755 {
756 //
757 // failed to allocate
758 //
759 return STATUS_INSUFFICIENT_RESOURCES;
760 }
761
762 //
763 // add reference count
764 //
765 This->AddRef();
766
767 //
768 // return result
769 //
770 *OutUsbQueue = (PUSBQUEUE)This;
771
772 //
773 // done
774 //
775 return STATUS_SUCCESS;
776 }