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