[USBOHCI]
[reactos.git] / reactos / 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 DPRINT("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 DPRINT("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 do
626 {
627 //
628 // find transfer descriptor in control list
629 //
630 Status = FindTransferDescriptorInEndpoint(m_ControlHeadEndpointDescriptor, TransferDescriptorLogicalAddress, &EndpointDescriptor, &PreviousEndpointDescriptor);
631 if (NT_SUCCESS(Status))
632 {
633 //
634 // cleanup endpoint
635 //
636 CleanupEndpointDescriptor(EndpointDescriptor, PreviousEndpointDescriptor);
637
638 //
639 // done
640 //
641 continue;
642 }
643
644 //
645 // find transfer descriptor in bulk list
646 //
647 Status = FindTransferDescriptorInEndpoint(m_BulkHeadEndpointDescriptor, TransferDescriptorLogicalAddress, &EndpointDescriptor, &PreviousEndpointDescriptor);
648 if (NT_SUCCESS(Status))
649 {
650 //
651 // cleanup endpoint
652 //
653 CleanupEndpointDescriptor(EndpointDescriptor, PreviousEndpointDescriptor);
654
655 //
656 // done
657 //
658 continue;
659 }
660
661 //
662 // find transfer descriptor in interrupt list
663 //
664 Status = FindTransferDescriptorInInterruptHeadEndpoints(TransferDescriptorLogicalAddress, &EndpointDescriptor, &PreviousEndpointDescriptor);
665 if (NT_SUCCESS(Status))
666 {
667 //
668 // cleanup endpoint
669 //
670 CleanupEndpointDescriptor(EndpointDescriptor, PreviousEndpointDescriptor);
671
672 //
673 // done
674 //
675 continue;
676 }
677
678 //
679 // last try: find the descriptor in isochronous list
680 //
681 Status = FindTransferDescriptorInIsochronousHeadEndpoints(TransferDescriptorLogicalAddress, &EndpointDescriptor, &PreviousEndpointDescriptor);
682 if (NT_SUCCESS(Status))
683 {
684 //
685 // cleanup endpoint
686 //
687 DPRINT("ISO endpoint complete\n");
688 //ASSERT(FALSE);
689 CleanupEndpointDescriptor(EndpointDescriptor, PreviousEndpointDescriptor);
690
691 //
692 // done
693 //
694 continue;
695 }
696
697 //
698 // no more completed descriptors found
699 //
700 return;
701
702 }while(TRUE);
703
704 //
705 // hardware reported dead endpoint completed
706 //
707 DPRINT1("CUSBQueue::TransferDescriptorCompletionCallback invalid transfer descriptor %x\n", TransferDescriptorLogicalAddress);
708 ASSERT(FALSE);
709 }
710
711 POHCI_ENDPOINT_DESCRIPTOR
712 CUSBQueue::FindInterruptEndpointDescriptor(
713 UCHAR InterruptInterval)
714 {
715 ULONG Index = 0;
716 ULONG Power = 1;
717
718 //
719 // sanity check
720 //
721 ASSERT(InterruptInterval <= OHCI_BIGGEST_INTERVAL);
722
723 //
724 // find interrupt index
725 //
726 while (Power <= OHCI_BIGGEST_INTERVAL / 2)
727 {
728 //
729 // is current interval greater
730 //
731 if (Power * 2 > InterruptInterval)
732 break;
733
734 //
735 // increment power
736 //
737 Power *= 2;
738
739 //
740 // move to next interrupt
741 //
742 Index++;
743 }
744
745 DPRINT("InterruptInterval %lu Selected InterruptIndex %lu Choosen Interval %lu\n", InterruptInterval, Index, Power);
746
747 //
748 // return endpoint
749 //
750 return m_InterruptEndpoints[Index];
751 }
752
753 NTSTATUS
754 CUSBQueue::AbortDevicePipe(
755 IN UCHAR DeviceAddress,
756 IN PUSB_ENDPOINT_DESCRIPTOR EndpointDescriptor)
757 {
758 POHCI_ENDPOINT_DESCRIPTOR HeadDescriptor, CurrentDescriptor, PreviousDescriptor, TempDescriptor;
759 ULONG Type;
760 POHCI_GENERAL_TD TransferDescriptor;
761
762 //
763 // get type
764 //
765 Type = (EndpointDescriptor->bmAttributes & USB_ENDPOINT_TYPE_MASK);
766
767 //
768 // check type
769 //
770 if (Type == USB_ENDPOINT_TYPE_BULK)
771 {
772 //
773 // get head descriptor
774 //
775 HeadDescriptor = m_BulkHeadEndpointDescriptor;
776 }
777 else if (Type == USB_ENDPOINT_TYPE_CONTROL)
778 {
779 //
780 // get head descriptor
781 //
782 HeadDescriptor = m_ControlHeadEndpointDescriptor;
783 }
784 else if (Type == USB_ENDPOINT_TYPE_INTERRUPT)
785 {
786 //
787 // get head descriptor
788 //
789 HeadDescriptor = FindInterruptEndpointDescriptor(EndpointDescriptor->bInterval);
790 ASSERT(HeadDescriptor);
791 }
792 else if (Type == USB_ENDPOINT_TYPE_ISOCHRONOUS)
793 {
794 UNIMPLEMENTED
795 return STATUS_NOT_IMPLEMENTED;
796 }
797
798 //
799 // FIXME should disable list processing
800 //
801
802 //
803 // now remove all endpoints
804 //
805 ASSERT(HeadDescriptor);
806 CurrentDescriptor = (POHCI_ENDPOINT_DESCRIPTOR)HeadDescriptor->NextDescriptor;
807 PreviousDescriptor = (POHCI_ENDPOINT_DESCRIPTOR)HeadDescriptor;
808
809 while(CurrentDescriptor)
810 {
811 if ((CurrentDescriptor->HeadPhysicalDescriptor & OHCI_ENDPOINT_HEAD_MASK) == CurrentDescriptor->TailPhysicalDescriptor || (CurrentDescriptor->HeadPhysicalDescriptor & OHCI_ENDPOINT_HALTED))
812 {
813 //
814 // cleanup endpoint
815 //
816 TempDescriptor = (POHCI_ENDPOINT_DESCRIPTOR)CurrentDescriptor->NextDescriptor;
817 CleanupEndpointDescriptor(CurrentDescriptor, PreviousDescriptor);
818
819 //
820 // use next descriptor
821 //
822 CurrentDescriptor = TempDescriptor;
823 }
824
825 if (!CurrentDescriptor)
826 break;
827
828 if (CurrentDescriptor->HeadPhysicalDescriptor)
829 {
830 TransferDescriptor = (POHCI_GENERAL_TD)CurrentDescriptor->HeadLogicalDescriptor;
831 ASSERT(TransferDescriptor);
832
833 if ((OHCI_ENDPOINT_GET_ENDPOINT_NUMBER(TransferDescriptor->Flags) == (EndpointDescriptor->bEndpointAddress & 0xF)) &&
834 (OHCI_ENDPOINT_GET_DEVICE_ADDRESS(TransferDescriptor->Flags) == DeviceAddress))
835 {
836 //
837 // cleanup endpoint
838 //
839 TempDescriptor = (POHCI_ENDPOINT_DESCRIPTOR)CurrentDescriptor->NextDescriptor;
840 CleanupEndpointDescriptor(CurrentDescriptor, PreviousDescriptor);
841 //
842 // use next descriptor
843 //
844 CurrentDescriptor = TempDescriptor;
845 }
846 }
847
848 if (!CurrentDescriptor)
849 break;
850
851 PreviousDescriptor = CurrentDescriptor;
852 CurrentDescriptor = (POHCI_ENDPOINT_DESCRIPTOR)CurrentDescriptor->NextDescriptor;
853 }
854
855 //
856 // done
857 //
858 return STATUS_SUCCESS;
859 }
860
861
862 NTSTATUS
863 CreateUSBQueue(
864 PUSBQUEUE *OutUsbQueue)
865 {
866 PUSBQUEUE This;
867
868 //
869 // allocate controller
870 //
871 This = new(NonPagedPool, TAG_USBOHCI) CUSBQueue(0);
872 if (!This)
873 {
874 //
875 // failed to allocate
876 //
877 return STATUS_INSUFFICIENT_RESOURCES;
878 }
879
880 //
881 // add reference count
882 //
883 This->AddRef();
884
885 //
886 // return result
887 //
888 *OutUsbQueue = (PUSBQUEUE)This;
889
890 //
891 // done
892 //
893 return STATUS_SUCCESS;
894 }