[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 virtual NTSTATUS AbortDevicePipe(UCHAR DeviceAddress, IN PUSB_ENDPOINT_DESCRIPTOR EndpointDescriptor);
44
45 // local functions
46 BOOLEAN IsTransferDescriptorInEndpoint(IN POHCI_ENDPOINT_DESCRIPTOR EndpointDescriptor, IN ULONG TransferDescriptorLogicalAddress);
47 BOOLEAN IsTransferDescriptorInIsoEndpoint(IN POHCI_ENDPOINT_DESCRIPTOR EndpointDescriptor, IN ULONG TransferDescriptorLogicalAddress);
48 NTSTATUS FindTransferDescriptorInEndpoint(IN POHCI_ENDPOINT_DESCRIPTOR EndpointDescriptor, IN ULONG TransferDescriptorLogicalAddress, OUT POHCI_ENDPOINT_DESCRIPTOR *OutEndpointDescriptor, OUT POHCI_ENDPOINT_DESCRIPTOR *OutPreviousEndpointDescriptor);
49 NTSTATUS FindTransferDescriptorInInterruptHeadEndpoints(IN ULONG TransferDescriptorLogicalAddress, OUT POHCI_ENDPOINT_DESCRIPTOR *OutEndpointDescriptor, OUT POHCI_ENDPOINT_DESCRIPTOR *OutPreviousEndpointDescriptor);
50 NTSTATUS FindTransferDescriptorInIsochronousHeadEndpoints(IN ULONG TransferDescriptorLogicalAddress, OUT POHCI_ENDPOINT_DESCRIPTOR *OutEndpointDescriptor, OUT POHCI_ENDPOINT_DESCRIPTOR *OutPreviousEndpointDescriptor);
51
52 VOID CleanupEndpointDescriptor(POHCI_ENDPOINT_DESCRIPTOR EndpointDescriptor, POHCI_ENDPOINT_DESCRIPTOR PreviousEndpointDescriptor);
53 POHCI_ENDPOINT_DESCRIPTOR FindInterruptEndpointDescriptor(UCHAR InterruptInterval);
54 VOID PrintEndpointList(POHCI_ENDPOINT_DESCRIPTOR EndpointDescriptor);
55 VOID LinkEndpoint(POHCI_ENDPOINT_DESCRIPTOR HeadEndpointDescriptor, POHCI_ENDPOINT_DESCRIPTOR EndpointDescriptor);
56
57 // constructor / destructor
58 CUSBQueue(IUnknown *OuterUnknown){}
59 virtual ~CUSBQueue(){}
60
61 protected:
62 LONG m_Ref; // reference count
63 KSPIN_LOCK m_Lock; // list lock
64 PUSBHARDWAREDEVICE m_Hardware; // hardware
65 POHCI_ENDPOINT_DESCRIPTOR m_BulkHeadEndpointDescriptor; // bulk head descriptor
66 POHCI_ENDPOINT_DESCRIPTOR m_ControlHeadEndpointDescriptor; // control head descriptor
67 POHCI_ENDPOINT_DESCRIPTOR m_IsoHeadEndpointDescriptor; // isochronous head descriptor
68 POHCI_ENDPOINT_DESCRIPTOR * m_InterruptEndpoints;
69 };
70
71 //=================================================================================================
72 // COM
73 //
74 NTSTATUS
75 STDMETHODCALLTYPE
76 CUSBQueue::QueryInterface(
77 IN REFIID refiid,
78 OUT PVOID* Output)
79 {
80 if (IsEqualGUIDAligned(refiid, IID_IUnknown))
81 {
82 *Output = PVOID(PUNKNOWN(this));
83 PUNKNOWN(*Output)->AddRef();
84 return STATUS_SUCCESS;
85 }
86
87 return STATUS_UNSUCCESSFUL;
88 }
89
90 NTSTATUS
91 CUSBQueue::Initialize(
92 IN PUSBHARDWAREDEVICE Hardware,
93 IN PDMA_ADAPTER AdapterObject,
94 IN PDMAMEMORYMANAGER MemManager,
95 IN OPTIONAL PKSPIN_LOCK Lock)
96 {
97 //
98 // get bulk endpoint descriptor
99 //
100 Hardware->GetBulkHeadEndpointDescriptor(&m_BulkHeadEndpointDescriptor);
101
102 //
103 // get control endpoint descriptor
104 //
105 Hardware->GetControlHeadEndpointDescriptor(&m_ControlHeadEndpointDescriptor);
106
107 //
108 // get isochronous endpoint
109 //
110 Hardware->GetIsochronousHeadEndpointDescriptor(&m_IsoHeadEndpointDescriptor);
111
112 //
113 // get interrupt endpoints
114 //
115 Hardware->GetInterruptEndpointDescriptors(&m_InterruptEndpoints);
116
117 //
118 // initialize spinlock
119 //
120 KeInitializeSpinLock(&m_Lock);
121
122 //
123 // store hardware
124 //
125 m_Hardware = Hardware;
126
127 return STATUS_SUCCESS;
128 }
129
130 ULONG
131 CUSBQueue::GetPendingRequestCount()
132 {
133 //
134 // Loop through the pending list and iterrate one for each QueueHead that
135 // has a IRP to complete.
136 //
137
138 return 0;
139 }
140
141 VOID
142 CUSBQueue::LinkEndpoint(
143 POHCI_ENDPOINT_DESCRIPTOR HeadEndpointDescriptor,
144 POHCI_ENDPOINT_DESCRIPTOR EndpointDescriptor)
145 {
146 POHCI_ENDPOINT_DESCRIPTOR CurrentEndpointDescriptor = HeadEndpointDescriptor;
147
148 //
149 // get last descriptor in queue
150 //
151 while(CurrentEndpointDescriptor->NextDescriptor)
152 {
153 //
154 // move to last descriptor
155 //
156 CurrentEndpointDescriptor = (POHCI_ENDPOINT_DESCRIPTOR)CurrentEndpointDescriptor->NextDescriptor;
157 }
158
159 //
160 // link endpoints
161 //
162 CurrentEndpointDescriptor->NextPhysicalEndpoint = EndpointDescriptor->PhysicalAddress.LowPart;
163 CurrentEndpointDescriptor->NextDescriptor = EndpointDescriptor;
164
165 }
166
167 NTSTATUS
168 CUSBQueue::AddUSBRequest(
169 IUSBRequest * Request)
170 {
171 NTSTATUS Status;
172 ULONG Type;
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 else
293 {
294 //
295 // bad request type
296 //
297 Request->Release();
298 return STATUS_INVALID_PARAMETER;
299 }
300
301 //
302 // set descriptor active
303 //
304 Descriptor->Flags &= ~OHCI_ENDPOINT_SKIP;
305
306 //
307 // insert endpoint at end
308 //
309 LinkEndpoint(HeadDescriptor, Descriptor);
310
311 if (Type == USB_ENDPOINT_TYPE_CONTROL || Type == USB_ENDPOINT_TYPE_BULK)
312 {
313 //
314 // notify hardware of our request
315 //
316 m_Hardware->HeadEndpointDescriptorModified(Type);
317 }
318
319 return STATUS_SUCCESS;
320 }
321
322 NTSTATUS
323 CUSBQueue::CancelRequests()
324 {
325 UNIMPLEMENTED
326 return STATUS_NOT_IMPLEMENTED;
327 }
328
329 NTSTATUS
330 CUSBQueue::CreateUSBRequest(
331 IUSBRequest **OutRequest)
332 {
333 PUSBREQUEST UsbRequest;
334 NTSTATUS Status;
335
336 *OutRequest = NULL;
337 Status = InternalCreateUSBRequest(&UsbRequest);
338
339 if (NT_SUCCESS(Status))
340 {
341 *OutRequest = UsbRequest;
342 }
343
344 return Status;
345 }
346
347 NTSTATUS
348 CUSBQueue::FindTransferDescriptorInEndpoint(
349 IN POHCI_ENDPOINT_DESCRIPTOR EndpointDescriptor,
350 IN ULONG TransferDescriptorLogicalAddress,
351 OUT POHCI_ENDPOINT_DESCRIPTOR *OutEndpointDescriptor,
352 OUT POHCI_ENDPOINT_DESCRIPTOR *OutPreviousEndpointDescriptor)
353 {
354 POHCI_ENDPOINT_DESCRIPTOR LastDescriptor = EndpointDescriptor;
355
356
357 //
358 // skip first endpoint head
359 //
360 EndpointDescriptor = (POHCI_ENDPOINT_DESCRIPTOR)EndpointDescriptor->NextDescriptor;
361
362 while(EndpointDescriptor)
363 {
364 //
365 // check if the transfer descriptor is inside the list
366 //
367 if ((EndpointDescriptor->HeadPhysicalDescriptor & OHCI_ENDPOINT_HEAD_MASK) == EndpointDescriptor->TailPhysicalDescriptor || (EndpointDescriptor->HeadPhysicalDescriptor & OHCI_ENDPOINT_HALTED))
368 {
369 //
370 // found endpoint
371 //
372 *OutEndpointDescriptor = EndpointDescriptor;
373 *OutPreviousEndpointDescriptor = LastDescriptor;
374
375 //
376 // done
377 //
378 return STATUS_SUCCESS;
379 }
380
381 //
382 // store last endpoint
383 //
384 LastDescriptor = EndpointDescriptor;
385
386 //
387 // move to next
388 //
389 EndpointDescriptor = (POHCI_ENDPOINT_DESCRIPTOR)EndpointDescriptor->NextDescriptor;
390 }
391
392 //
393 // failed to endpoint
394 //
395 return STATUS_NOT_FOUND;
396 }
397
398 NTSTATUS
399 CUSBQueue::FindTransferDescriptorInInterruptHeadEndpoints(IN ULONG TransferDescriptorLogicalAddress, OUT POHCI_ENDPOINT_DESCRIPTOR *OutEndpointDescriptor, OUT POHCI_ENDPOINT_DESCRIPTOR *OutPreviousEndpointDescriptor)
400 {
401 ULONG Index;
402 NTSTATUS Status;
403
404 //
405 // search descriptor in endpoint list
406 //
407 for(Index = 0; Index < OHCI_STATIC_ENDPOINT_COUNT; Index++)
408 {
409 //
410 // is it in current endpoint
411 //
412 Status = FindTransferDescriptorInEndpoint(m_InterruptEndpoints[Index], TransferDescriptorLogicalAddress, OutEndpointDescriptor, OutPreviousEndpointDescriptor);
413 if (NT_SUCCESS(Status))
414 {
415 //
416 // found transfer descriptor
417 //
418 return STATUS_SUCCESS;
419 }
420 }
421
422 //
423 // not found
424 //
425 return STATUS_NOT_FOUND;
426 }
427
428 NTSTATUS
429 CUSBQueue::FindTransferDescriptorInIsochronousHeadEndpoints(
430 IN ULONG TransferDescriptorLogicalAddress,
431 OUT POHCI_ENDPOINT_DESCRIPTOR *OutEndpointDescriptor,
432 OUT POHCI_ENDPOINT_DESCRIPTOR *OutPreviousEndpointDescriptor)
433 {
434 POHCI_ENDPOINT_DESCRIPTOR EndpointDescriptor;
435 POHCI_ENDPOINT_DESCRIPTOR LastDescriptor = m_IsoHeadEndpointDescriptor;
436
437
438 //
439 // skip first endpoint head
440 //
441 EndpointDescriptor = (POHCI_ENDPOINT_DESCRIPTOR)m_IsoHeadEndpointDescriptor->NextDescriptor;
442
443 while(EndpointDescriptor)
444 {
445 //
446 // check if the transfer descriptor is inside the list
447 //
448 if (IsTransferDescriptorInIsoEndpoint(EndpointDescriptor, TransferDescriptorLogicalAddress))
449 {
450 //
451 // found endpoint
452 //
453 *OutEndpointDescriptor = EndpointDescriptor;
454 *OutPreviousEndpointDescriptor = LastDescriptor;
455
456 //
457 // done
458 //
459 return STATUS_SUCCESS;
460 }
461
462 //
463 // store last endpoint
464 //
465 LastDescriptor = EndpointDescriptor;
466
467 //
468 // move to next
469 //
470 EndpointDescriptor = (POHCI_ENDPOINT_DESCRIPTOR)EndpointDescriptor->NextDescriptor;
471 }
472
473 //
474 // failed to endpoint
475 //
476 return STATUS_NOT_FOUND;
477 }
478
479 BOOLEAN
480 CUSBQueue::IsTransferDescriptorInIsoEndpoint(
481 IN POHCI_ENDPOINT_DESCRIPTOR EndpointDescriptor,
482 IN ULONG TransferDescriptorLogicalAddress)
483 {
484 POHCI_ISO_TD Descriptor;
485
486 //
487 // get first general transfer descriptor
488 //
489 Descriptor = (POHCI_ISO_TD)EndpointDescriptor->HeadLogicalDescriptor;
490
491 //
492 // sanity check
493 //
494 ASSERT(Descriptor);
495
496 do
497 {
498 if (Descriptor->PhysicalAddress.LowPart == TransferDescriptorLogicalAddress)
499 {
500 //
501 // found descriptor
502 //
503 return TRUE;
504 }
505
506 //
507 // move to next
508 //
509 Descriptor = (POHCI_ISO_TD)Descriptor->NextLogicalDescriptor;
510 }while(Descriptor);
511
512 //
513 // no descriptor found
514 //
515 return FALSE;
516 }
517
518
519 BOOLEAN
520 CUSBQueue::IsTransferDescriptorInEndpoint(
521 IN POHCI_ENDPOINT_DESCRIPTOR EndpointDescriptor,
522 IN ULONG TransferDescriptorLogicalAddress)
523 {
524 POHCI_GENERAL_TD Descriptor;
525
526 //
527 // get first general transfer descriptor
528 //
529 Descriptor = (POHCI_GENERAL_TD)EndpointDescriptor->HeadLogicalDescriptor;
530
531 //
532 // sanity check
533 //
534 ASSERT(Descriptor);
535
536 do
537 {
538 if (Descriptor->PhysicalAddress.LowPart == TransferDescriptorLogicalAddress)
539 {
540 //
541 // found descriptor
542 //
543 return TRUE;
544 }
545
546 //
547 // move to next
548 //
549 Descriptor = (POHCI_GENERAL_TD)Descriptor->NextLogicalDescriptor;
550 }while(Descriptor);
551
552
553 //
554 // no descriptor found
555 //
556 return FALSE;
557 }
558
559 VOID
560 CUSBQueue::CleanupEndpointDescriptor(
561 POHCI_ENDPOINT_DESCRIPTOR EndpointDescriptor,
562 POHCI_ENDPOINT_DESCRIPTOR PreviousEndpointDescriptor)
563 {
564 PUSBREQUEST Request;
565
566 //
567 // FIXME: verify unlinking process
568 //
569 PreviousEndpointDescriptor->NextDescriptor = EndpointDescriptor->NextDescriptor;
570 PreviousEndpointDescriptor->NextPhysicalEndpoint = EndpointDescriptor->NextPhysicalEndpoint;
571
572 //
573 // get corresponding request
574 //
575 Request = PUSBREQUEST(EndpointDescriptor->Request);
576 ASSERT(Request);
577
578 //
579 // notify of completion
580 //
581 Request->CompletionCallback(EndpointDescriptor);
582
583 //
584 // free endpoint descriptor
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 DPRINT("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 CUSBQueue::AbortDevicePipe(
746 IN UCHAR DeviceAddress,
747 IN PUSB_ENDPOINT_DESCRIPTOR EndpointDescriptor)
748 {
749 POHCI_ENDPOINT_DESCRIPTOR HeadDescriptor, CurrentDescriptor, PreviousDescriptor, TempDescriptor;
750 ULONG Type;
751 POHCI_GENERAL_TD TransferDescriptor;
752
753 //
754 // get type
755 //
756 Type = (EndpointDescriptor->bmAttributes & USB_ENDPOINT_TYPE_MASK);
757
758 //
759 // check type
760 //
761 if (Type == USB_ENDPOINT_TYPE_BULK)
762 {
763 //
764 // get head descriptor
765 //
766 HeadDescriptor = m_BulkHeadEndpointDescriptor;
767 }
768 else if (Type == USB_ENDPOINT_TYPE_CONTROL)
769 {
770 //
771 // get head descriptor
772 //
773 HeadDescriptor = m_ControlHeadEndpointDescriptor;
774 }
775 else if (Type == USB_ENDPOINT_TYPE_INTERRUPT)
776 {
777 //
778 // get head descriptor
779 //
780 HeadDescriptor = FindInterruptEndpointDescriptor(EndpointDescriptor->bInterval);
781 ASSERT(HeadDescriptor);
782 }
783 else if (Type == USB_ENDPOINT_TYPE_ISOCHRONOUS)
784 {
785 UNIMPLEMENTED
786 return STATUS_NOT_IMPLEMENTED;
787 }
788
789 //
790 // FIXME should disable list processing
791 //
792
793 //
794 // now remove all endpoints
795 //
796 ASSERT(HeadDescriptor);
797 CurrentDescriptor = (POHCI_ENDPOINT_DESCRIPTOR)HeadDescriptor->NextDescriptor;
798 PreviousDescriptor = (POHCI_ENDPOINT_DESCRIPTOR)HeadDescriptor;
799
800 while(CurrentDescriptor)
801 {
802 if ((CurrentDescriptor->HeadPhysicalDescriptor & OHCI_ENDPOINT_HEAD_MASK) == CurrentDescriptor->TailPhysicalDescriptor || (CurrentDescriptor->HeadPhysicalDescriptor & OHCI_ENDPOINT_HALTED))
803 {
804 //
805 // cleanup endpoint
806 //
807 TempDescriptor = (POHCI_ENDPOINT_DESCRIPTOR)CurrentDescriptor->NextDescriptor;
808 CleanupEndpointDescriptor(CurrentDescriptor, PreviousDescriptor);
809
810 //
811 // use next descriptor
812 //
813 CurrentDescriptor = TempDescriptor;
814 }
815
816 if (!CurrentDescriptor)
817 break;
818
819 if (CurrentDescriptor->HeadPhysicalDescriptor)
820 {
821 TransferDescriptor = (POHCI_GENERAL_TD)CurrentDescriptor->HeadLogicalDescriptor;
822 ASSERT(TransferDescriptor);
823
824 if ((OHCI_ENDPOINT_GET_ENDPOINT_NUMBER(TransferDescriptor->Flags) == (EndpointDescriptor->bEndpointAddress & 0xF)) &&
825 (OHCI_ENDPOINT_GET_DEVICE_ADDRESS(TransferDescriptor->Flags) == DeviceAddress))
826 {
827 //
828 // cleanup endpoint
829 //
830 TempDescriptor = (POHCI_ENDPOINT_DESCRIPTOR)CurrentDescriptor->NextDescriptor;
831 CleanupEndpointDescriptor(CurrentDescriptor, PreviousDescriptor);
832 //
833 // use next descriptor
834 //
835 CurrentDescriptor = TempDescriptor;
836 }
837 }
838
839 if (!CurrentDescriptor)
840 break;
841
842 PreviousDescriptor = CurrentDescriptor;
843 CurrentDescriptor = (POHCI_ENDPOINT_DESCRIPTOR)CurrentDescriptor->NextDescriptor;
844 }
845
846 //
847 // done
848 //
849 return STATUS_SUCCESS;
850 }
851
852
853 NTSTATUS
854 CreateUSBQueue(
855 PUSBQUEUE *OutUsbQueue)
856 {
857 PUSBQUEUE This;
858
859 //
860 // allocate controller
861 //
862 This = new(NonPagedPool, TAG_USBOHCI) CUSBQueue(0);
863 if (!This)
864 {
865 //
866 // failed to allocate
867 //
868 return STATUS_INSUFFICIENT_RESOURCES;
869 }
870
871 //
872 // add reference count
873 //
874 This->AddRef();
875
876 //
877 // return result
878 //
879 *OutUsbQueue = (PUSBQUEUE)This;
880
881 //
882 // done
883 //
884 return STATUS_SUCCESS;
885 }