3009975ede5a23dee34cdd9a5cc0cadbf8b0d640
[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 IMP_IUSBQUEUE
38 IMP_IUSBOHCIQUEUE
39
40 // local functions
41 BOOLEAN IsTransferDescriptorInEndpoint(IN POHCI_ENDPOINT_DESCRIPTOR EndpointDescriptor, IN ULONG TransferDescriptorLogicalAddress);
42 BOOLEAN IsTransferDescriptorInIsoEndpoint(IN POHCI_ENDPOINT_DESCRIPTOR EndpointDescriptor, IN ULONG TransferDescriptorLogicalAddress);
43 NTSTATUS FindTransferDescriptorInEndpoint(IN POHCI_ENDPOINT_DESCRIPTOR EndpointDescriptor, IN ULONG TransferDescriptorLogicalAddress, OUT POHCI_ENDPOINT_DESCRIPTOR *OutEndpointDescriptor, OUT POHCI_ENDPOINT_DESCRIPTOR *OutPreviousEndpointDescriptor);
44 NTSTATUS FindTransferDescriptorInInterruptHeadEndpoints(IN ULONG TransferDescriptorLogicalAddress, OUT POHCI_ENDPOINT_DESCRIPTOR *OutEndpointDescriptor, OUT POHCI_ENDPOINT_DESCRIPTOR *OutPreviousEndpointDescriptor);
45 NTSTATUS FindTransferDescriptorInIsochronousHeadEndpoints(IN ULONG TransferDescriptorLogicalAddress, OUT POHCI_ENDPOINT_DESCRIPTOR *OutEndpointDescriptor, OUT POHCI_ENDPOINT_DESCRIPTOR *OutPreviousEndpointDescriptor);
46
47 VOID CleanupEndpointDescriptor(POHCI_ENDPOINT_DESCRIPTOR EndpointDescriptor, POHCI_ENDPOINT_DESCRIPTOR PreviousEndpointDescriptor);
48 POHCI_ENDPOINT_DESCRIPTOR FindInterruptEndpointDescriptor(UCHAR InterruptInterval);
49 VOID PrintEndpointList(POHCI_ENDPOINT_DESCRIPTOR EndpointDescriptor);
50 VOID LinkEndpoint(POHCI_ENDPOINT_DESCRIPTOR HeadEndpointDescriptor, POHCI_ENDPOINT_DESCRIPTOR EndpointDescriptor);
51 VOID AddEndpointDescriptor(IN POHCI_ENDPOINT_DESCRIPTOR Descriptor);
52
53
54 // constructor / destructor
55 CUSBQueue(IUnknown *OuterUnknown){}
56 virtual ~CUSBQueue(){}
57
58 protected:
59 LONG m_Ref; // reference count
60 KSPIN_LOCK m_Lock; // list lock
61 POHCIHARDWAREDEVICE m_Hardware; // hardware
62 POHCI_ENDPOINT_DESCRIPTOR m_BulkHeadEndpointDescriptor; // bulk head descriptor
63 POHCI_ENDPOINT_DESCRIPTOR m_ControlHeadEndpointDescriptor; // control head descriptor
64 POHCI_ENDPOINT_DESCRIPTOR m_IsoHeadEndpointDescriptor; // isochronous head descriptor
65 POHCI_ENDPOINT_DESCRIPTOR * m_InterruptEndpoints;
66 LIST_ENTRY m_PendingRequestList; // pending request list
67 };
68
69 //=================================================================================================
70 // COM
71 //
72 NTSTATUS
73 STDMETHODCALLTYPE
74 CUSBQueue::QueryInterface(
75 IN REFIID refiid,
76 OUT PVOID* Output)
77 {
78 if (IsEqualGUIDAligned(refiid, IID_IUnknown))
79 {
80 *Output = PVOID(PUNKNOWN(this));
81 PUNKNOWN(*Output)->AddRef();
82 return STATUS_SUCCESS;
83 }
84
85 return STATUS_UNSUCCESSFUL;
86 }
87
88 NTSTATUS
89 CUSBQueue::Initialize(
90 IN PUSBHARDWAREDEVICE Hardware,
91 IN PDMA_ADAPTER AdapterObject,
92 IN PDMAMEMORYMANAGER MemManager,
93 IN OPTIONAL PKSPIN_LOCK Lock)
94 {
95 //
96 // store hardware
97 //
98 m_Hardware = POHCIHARDWAREDEVICE(Hardware);
99
100
101 //
102 // get bulk endpoint descriptor
103 //
104 m_Hardware->GetBulkHeadEndpointDescriptor(&m_BulkHeadEndpointDescriptor);
105
106 //
107 // get control endpoint descriptor
108 //
109 m_Hardware->GetControlHeadEndpointDescriptor(&m_ControlHeadEndpointDescriptor);
110
111 //
112 // get isochronous endpoint
113 //
114 m_Hardware->GetIsochronousHeadEndpointDescriptor(&m_IsoHeadEndpointDescriptor);
115
116 //
117 // get interrupt endpoints
118 //
119 m_Hardware->GetInterruptEndpointDescriptors(&m_InterruptEndpoints);
120
121 //
122 // initialize spinlock
123 //
124 KeInitializeSpinLock(&m_Lock);
125
126 //
127 // init list
128 //
129 InitializeListHead(&m_PendingRequestList);
130
131 return STATUS_SUCCESS;
132 }
133
134 VOID
135 CUSBQueue::LinkEndpoint(
136 POHCI_ENDPOINT_DESCRIPTOR HeadEndpointDescriptor,
137 POHCI_ENDPOINT_DESCRIPTOR EndpointDescriptor)
138 {
139 POHCI_ENDPOINT_DESCRIPTOR CurrentEndpointDescriptor = HeadEndpointDescriptor;
140
141 //
142 // get last descriptor in queue
143 //
144 while(CurrentEndpointDescriptor->NextDescriptor)
145 {
146 //
147 // move to last descriptor
148 //
149 CurrentEndpointDescriptor = (POHCI_ENDPOINT_DESCRIPTOR)CurrentEndpointDescriptor->NextDescriptor;
150 }
151
152 //
153 // link endpoints
154 //
155 CurrentEndpointDescriptor->NextPhysicalEndpoint = EndpointDescriptor->PhysicalAddress.LowPart;
156 CurrentEndpointDescriptor->NextDescriptor = EndpointDescriptor;
157
158 }
159
160 VOID
161 CUSBQueue::AddEndpointDescriptor(
162 IN POHCI_ENDPOINT_DESCRIPTOR Descriptor)
163 {
164 IOHCIRequest *Request;
165 ULONG Type;
166 POHCI_ENDPOINT_DESCRIPTOR HeadDescriptor;
167 POHCI_ISO_TD CurrentDescriptor;
168 ULONG FrameNumber;
169 USHORT Frame;
170
171
172 //
173 // sanity check
174 //
175 ASSERT(Descriptor->Request);
176 Request = (IOHCIRequest*)Descriptor->Request;
177
178 //
179 // get request type
180 //
181 Type = Request->GetTransferType();
182
183 //
184 // check type
185 //
186 if (Type == USB_ENDPOINT_TYPE_BULK)
187 {
188 //
189 // get head descriptor
190 //
191 HeadDescriptor = m_BulkHeadEndpointDescriptor;
192 }
193 else if (Type == USB_ENDPOINT_TYPE_CONTROL)
194 {
195 //
196 // get head descriptor
197 //
198 HeadDescriptor = m_ControlHeadEndpointDescriptor;
199 }
200 else if (Type == USB_ENDPOINT_TYPE_INTERRUPT)
201 {
202 //
203 // get head descriptor
204 //
205 HeadDescriptor = FindInterruptEndpointDescriptor(Request->GetInterval());
206 ASSERT(HeadDescriptor);
207 }
208 else if (Type == USB_ENDPOINT_TYPE_ISOCHRONOUS)
209 {
210 //
211 // get head descriptor
212 //
213 HeadDescriptor = m_IsoHeadEndpointDescriptor;
214
215 //
216 // get current frame number
217 //
218 m_Hardware->GetCurrentFrameNumber(&FrameNumber);
219
220 //
221 // FIXME: increment frame number
222 //
223 FrameNumber += 300;
224
225 //
226 // apply frame number to iso transfer descriptors
227 //
228 CurrentDescriptor = (POHCI_ISO_TD)Descriptor->HeadLogicalDescriptor;
229
230 DPRINT("ISO: NextFrameNumber %x\n", FrameNumber);
231 Frame = (FrameNumber & 0xFFFF);
232
233 while(CurrentDescriptor)
234 {
235 //
236 // set current frame number
237 //
238 CurrentDescriptor->Flags |= OHCI_ITD_SET_STARTING_FRAME(Frame);
239
240 //
241 // move to next frame number
242 //
243 Frame += OHCI_ITD_GET_FRAME_COUNT(CurrentDescriptor->Flags);
244
245 //
246 // move to next descriptor
247 //
248 CurrentDescriptor = CurrentDescriptor->NextLogicalDescriptor;
249 }
250
251 //
252 // get current frame number
253 //
254 m_Hardware->GetCurrentFrameNumber(&FrameNumber);
255
256 DPRINT("Hardware 1ms %p Iso %p\n",m_InterruptEndpoints[0], m_IsoHeadEndpointDescriptor);
257 ASSERT(m_InterruptEndpoints[0]->NextPhysicalEndpoint == m_IsoHeadEndpointDescriptor->PhysicalAddress.LowPart);
258
259 PrintEndpointList(m_IsoHeadEndpointDescriptor);
260 }
261 else
262 {
263 //
264 // bad request type
265 //
266 ASSERT(FALSE);
267 return;
268 }
269
270 //
271 // set descriptor active
272 //
273 Descriptor->Flags &= ~OHCI_ENDPOINT_SKIP;
274
275 //
276 // insert endpoint at end
277 //
278 LinkEndpoint(HeadDescriptor, Descriptor);
279
280 if (Type == USB_ENDPOINT_TYPE_CONTROL || Type == USB_ENDPOINT_TYPE_BULK)
281 {
282 //
283 // notify hardware of our request
284 //
285 m_Hardware->HeadEndpointDescriptorModified(Type);
286 }
287 }
288
289
290 NTSTATUS
291 CUSBQueue::AddUSBRequest(
292 IUSBRequest * Req)
293 {
294 NTSTATUS Status;
295 IN POHCI_ENDPOINT_DESCRIPTOR Descriptor;
296 POHCIREQUEST Request;
297
298 DPRINT("CUSBQueue::AddUSBRequest\n");
299
300 // get request
301 Request = POHCIREQUEST(Req);
302
303
304 //
305 // sanity check
306 //
307 ASSERT(Request != NULL);
308
309 //
310 // add extra reference which is released when the request is completed
311 //
312 Request->AddRef();
313
314 //
315 // get transfer descriptors
316 //
317 Status = Request->GetEndpointDescriptor(&Descriptor);
318 if (!NT_SUCCESS(Status))
319 {
320 //
321 // failed to get transfer descriptor
322 //
323 DPRINT1("CUSBQueue::AddUSBRequest GetEndpointDescriptor failed with %x\n", Status);
324
325 //
326 // release reference
327 //
328 Request->Release();
329 return Status;
330 }
331
332 //
333 // add the request
334 //
335 AddEndpointDescriptor(Descriptor);
336 return STATUS_SUCCESS;
337 }
338
339 NTSTATUS
340 CUSBQueue::CreateUSBRequest(
341 IUSBRequest **OutRequest)
342 {
343 PUSBREQUEST UsbRequest;
344 NTSTATUS Status;
345
346 *OutRequest = NULL;
347 Status = InternalCreateUSBRequest(&UsbRequest);
348
349 if (NT_SUCCESS(Status))
350 {
351 *OutRequest = UsbRequest;
352 }
353
354 return Status;
355 }
356
357 NTSTATUS
358 CUSBQueue::FindTransferDescriptorInEndpoint(
359 IN POHCI_ENDPOINT_DESCRIPTOR EndpointDescriptor,
360 IN ULONG TransferDescriptorLogicalAddress,
361 OUT POHCI_ENDPOINT_DESCRIPTOR *OutEndpointDescriptor,
362 OUT POHCI_ENDPOINT_DESCRIPTOR *OutPreviousEndpointDescriptor)
363 {
364 POHCI_ENDPOINT_DESCRIPTOR LastDescriptor = EndpointDescriptor;
365
366
367 //
368 // skip first endpoint head
369 //
370 EndpointDescriptor = (POHCI_ENDPOINT_DESCRIPTOR)EndpointDescriptor->NextDescriptor;
371
372 while(EndpointDescriptor)
373 {
374 //
375 // check if the transfer descriptor is inside the list
376 //
377 if ((EndpointDescriptor->HeadPhysicalDescriptor & OHCI_ENDPOINT_HEAD_MASK) == EndpointDescriptor->TailPhysicalDescriptor || (EndpointDescriptor->HeadPhysicalDescriptor & OHCI_ENDPOINT_HALTED))
378 {
379 //
380 // found endpoint
381 //
382 *OutEndpointDescriptor = EndpointDescriptor;
383 *OutPreviousEndpointDescriptor = LastDescriptor;
384
385 //
386 // done
387 //
388 return STATUS_SUCCESS;
389 }
390
391 //
392 // store last endpoint
393 //
394 LastDescriptor = EndpointDescriptor;
395
396 //
397 // move to next
398 //
399 EndpointDescriptor = (POHCI_ENDPOINT_DESCRIPTOR)EndpointDescriptor->NextDescriptor;
400 }
401
402 //
403 // failed to endpoint
404 //
405 return STATUS_NOT_FOUND;
406 }
407
408 NTSTATUS
409 CUSBQueue::FindTransferDescriptorInInterruptHeadEndpoints(IN ULONG TransferDescriptorLogicalAddress, OUT POHCI_ENDPOINT_DESCRIPTOR *OutEndpointDescriptor, OUT POHCI_ENDPOINT_DESCRIPTOR *OutPreviousEndpointDescriptor)
410 {
411 ULONG Index;
412 NTSTATUS Status;
413
414 //
415 // search descriptor in endpoint list
416 //
417 for(Index = 0; Index < OHCI_STATIC_ENDPOINT_COUNT; Index++)
418 {
419 //
420 // is it in current endpoint
421 //
422 Status = FindTransferDescriptorInEndpoint(m_InterruptEndpoints[Index], TransferDescriptorLogicalAddress, OutEndpointDescriptor, OutPreviousEndpointDescriptor);
423 if (NT_SUCCESS(Status))
424 {
425 //
426 // found transfer descriptor
427 //
428 return STATUS_SUCCESS;
429 }
430 }
431
432 //
433 // not found
434 //
435 return STATUS_NOT_FOUND;
436 }
437
438 NTSTATUS
439 CUSBQueue::FindTransferDescriptorInIsochronousHeadEndpoints(
440 IN ULONG TransferDescriptorLogicalAddress,
441 OUT POHCI_ENDPOINT_DESCRIPTOR *OutEndpointDescriptor,
442 OUT POHCI_ENDPOINT_DESCRIPTOR *OutPreviousEndpointDescriptor)
443 {
444 POHCI_ENDPOINT_DESCRIPTOR EndpointDescriptor;
445 POHCI_ENDPOINT_DESCRIPTOR LastDescriptor = m_IsoHeadEndpointDescriptor;
446
447
448 //
449 // skip first endpoint head
450 //
451 EndpointDescriptor = (POHCI_ENDPOINT_DESCRIPTOR)m_IsoHeadEndpointDescriptor->NextDescriptor;
452
453 while(EndpointDescriptor)
454 {
455 //
456 // check if the transfer descriptor is inside the list
457 //
458 if (IsTransferDescriptorInIsoEndpoint(EndpointDescriptor, TransferDescriptorLogicalAddress))
459 {
460 //
461 // found endpoint
462 //
463 *OutEndpointDescriptor = EndpointDescriptor;
464 *OutPreviousEndpointDescriptor = LastDescriptor;
465
466 //
467 // done
468 //
469 return STATUS_SUCCESS;
470 }
471
472 //
473 // store last endpoint
474 //
475 LastDescriptor = EndpointDescriptor;
476
477 //
478 // move to next
479 //
480 EndpointDescriptor = (POHCI_ENDPOINT_DESCRIPTOR)EndpointDescriptor->NextDescriptor;
481 }
482
483 //
484 // failed to endpoint
485 //
486 return STATUS_NOT_FOUND;
487 }
488
489 BOOLEAN
490 CUSBQueue::IsTransferDescriptorInIsoEndpoint(
491 IN POHCI_ENDPOINT_DESCRIPTOR EndpointDescriptor,
492 IN ULONG TransferDescriptorLogicalAddress)
493 {
494 POHCI_ISO_TD Descriptor;
495
496 //
497 // get first general transfer descriptor
498 //
499 Descriptor = (POHCI_ISO_TD)EndpointDescriptor->HeadLogicalDescriptor;
500
501 //
502 // sanity check
503 //
504 ASSERT(Descriptor);
505
506 do
507 {
508 if (Descriptor->PhysicalAddress.LowPart == TransferDescriptorLogicalAddress)
509 {
510 //
511 // found descriptor
512 //
513 return TRUE;
514 }
515
516 //
517 // move to next
518 //
519 Descriptor = (POHCI_ISO_TD)Descriptor->NextLogicalDescriptor;
520 }while(Descriptor);
521
522 //
523 // no descriptor found
524 //
525 return FALSE;
526 }
527
528
529 BOOLEAN
530 CUSBQueue::IsTransferDescriptorInEndpoint(
531 IN POHCI_ENDPOINT_DESCRIPTOR EndpointDescriptor,
532 IN ULONG TransferDescriptorLogicalAddress)
533 {
534 POHCI_GENERAL_TD Descriptor;
535
536 //
537 // get first general transfer descriptor
538 //
539 Descriptor = (POHCI_GENERAL_TD)EndpointDescriptor->HeadLogicalDescriptor;
540
541 //
542 // sanity check
543 //
544 ASSERT(Descriptor);
545
546 do
547 {
548 if (Descriptor->PhysicalAddress.LowPart == TransferDescriptorLogicalAddress)
549 {
550 //
551 // found descriptor
552 //
553 return TRUE;
554 }
555
556 //
557 // move to next
558 //
559 Descriptor = (POHCI_GENERAL_TD)Descriptor->NextLogicalDescriptor;
560 }while(Descriptor);
561
562
563 //
564 // no descriptor found
565 //
566 return FALSE;
567 }
568
569 VOID
570 CUSBQueue::CleanupEndpointDescriptor(
571 POHCI_ENDPOINT_DESCRIPTOR EndpointDescriptor,
572 POHCI_ENDPOINT_DESCRIPTOR PreviousEndpointDescriptor)
573 {
574 POHCIREQUEST Request;
575 POHCI_ENDPOINT_DESCRIPTOR NewEndpointDescriptor;
576 USBD_STATUS UrbStatus;
577 KIRQL OldLevel;
578
579 //
580 // FIXME: verify unlinking process
581 //
582 PreviousEndpointDescriptor->NextDescriptor = EndpointDescriptor->NextDescriptor;
583 PreviousEndpointDescriptor->NextPhysicalEndpoint = EndpointDescriptor->NextPhysicalEndpoint;
584
585 //
586 // get corresponding request
587 //
588 Request = POHCIREQUEST(EndpointDescriptor->Request);
589 ASSERT(Request);
590
591 //
592 // check for errors
593 //
594 if (EndpointDescriptor->HeadPhysicalDescriptor & OHCI_ENDPOINT_HALTED)
595 {
596 //
597 // the real error will processed by IUSBRequest
598 //
599 UrbStatus = USBD_STATUS_STALL_PID;
600 }
601 else
602 {
603 //
604 // well done ;)
605 //
606 UrbStatus = USBD_STATUS_SUCCESS;
607 }
608
609 //
610 // Check if the transfer was completed and if UrbStatus is ok
611 //
612 if ((Request->IsRequestComplete() == FALSE) && (UrbStatus == USBD_STATUS_SUCCESS))
613 {
614 //
615 // request is incomplete, get new queue head
616 //
617 if (Request->GetEndpointDescriptor(&NewEndpointDescriptor) == STATUS_SUCCESS)
618 {
619 //
620 // notify of completion
621 //
622 Request->FreeEndpointDescriptor(EndpointDescriptor);
623
624 //
625 // first acquire request lock
626 //
627 KeAcquireSpinLock(&m_Lock, &OldLevel);
628
629 //
630 // add to pending list
631 //
632 InsertTailList(&m_PendingRequestList, &NewEndpointDescriptor->DescriptorListEntry);
633
634 //
635 // release queue head
636 //
637 KeReleaseSpinLock(&m_Lock, OldLevel);
638
639 //
640 // Done for now
641 //
642 return;
643 }
644 DPRINT1("Unable to create a new QueueHead\n");
645 //ASSERT(FALSE);
646
647 //
648 // Else there was a problem
649 // FIXME: Find better return
650 UrbStatus = USBD_STATUS_INSUFFICIENT_RESOURCES;
651 }
652
653 if (UrbStatus != USBD_STATUS_SUCCESS)
654 {
655 DPRINT1("URB failed with status 0x%x\n", UrbStatus);
656 //PC_ASSERT(FALSE);
657 }
658
659 //
660 // free endpoint descriptor
661 //
662 Request->FreeEndpointDescriptor(EndpointDescriptor);
663
664 //
665 // notify of completion
666 //
667 Request->CompletionCallback();
668
669
670 //
671 // release request
672 //
673 Request->Release();
674 }
675
676 VOID
677 CUSBQueue::PrintEndpointList(
678 POHCI_ENDPOINT_DESCRIPTOR EndpointDescriptor)
679 {
680 DPRINT1("CUSBQueue::PrintEndpointList HeadEndpoint %p Logical %x\n", EndpointDescriptor, EndpointDescriptor->PhysicalAddress.LowPart);
681
682 //
683 // get first general transfer descriptor
684 //
685 EndpointDescriptor = (POHCI_ENDPOINT_DESCRIPTOR)EndpointDescriptor->NextDescriptor;
686
687 while(EndpointDescriptor)
688 {
689 DPRINT1(" CUSBQueue::PrintEndpointList Endpoint %p Logical %x\n", EndpointDescriptor, EndpointDescriptor->PhysicalAddress.LowPart);
690
691 //
692 // move to next
693 //
694 EndpointDescriptor = (POHCI_ENDPOINT_DESCRIPTOR)EndpointDescriptor->NextDescriptor;
695 }
696 }
697
698 VOID
699 CUSBQueue::TransferDescriptorCompletionCallback(
700 ULONG TransferDescriptorLogicalAddress)
701 {
702 POHCI_ENDPOINT_DESCRIPTOR EndpointDescriptor, PreviousEndpointDescriptor;
703 PLIST_ENTRY Entry;
704 NTSTATUS Status;
705
706 DPRINT("CUSBQueue::TransferDescriptorCompletionCallback transfer descriptor %x\n", TransferDescriptorLogicalAddress);
707
708 do
709 {
710 //
711 // find transfer descriptor in control list
712 //
713 Status = FindTransferDescriptorInEndpoint(m_ControlHeadEndpointDescriptor, TransferDescriptorLogicalAddress, &EndpointDescriptor, &PreviousEndpointDescriptor);
714 if (NT_SUCCESS(Status))
715 {
716 //
717 // cleanup endpoint
718 //
719 CleanupEndpointDescriptor(EndpointDescriptor, PreviousEndpointDescriptor);
720
721 //
722 // done
723 //
724 continue;
725 }
726
727 //
728 // find transfer descriptor in bulk list
729 //
730 Status = FindTransferDescriptorInEndpoint(m_BulkHeadEndpointDescriptor, TransferDescriptorLogicalAddress, &EndpointDescriptor, &PreviousEndpointDescriptor);
731 if (NT_SUCCESS(Status))
732 {
733 //
734 // cleanup endpoint
735 //
736 CleanupEndpointDescriptor(EndpointDescriptor, PreviousEndpointDescriptor);
737
738 //
739 // done
740 //
741 continue;
742 }
743
744 //
745 // find transfer descriptor in interrupt list
746 //
747 Status = FindTransferDescriptorInInterruptHeadEndpoints(TransferDescriptorLogicalAddress, &EndpointDescriptor, &PreviousEndpointDescriptor);
748 if (NT_SUCCESS(Status))
749 {
750 //
751 // cleanup endpoint
752 //
753 CleanupEndpointDescriptor(EndpointDescriptor, PreviousEndpointDescriptor);
754
755 //
756 // done
757 //
758 continue;
759 }
760
761 //
762 // last try: find the descriptor in isochronous list
763 //
764 Status = FindTransferDescriptorInIsochronousHeadEndpoints(TransferDescriptorLogicalAddress, &EndpointDescriptor, &PreviousEndpointDescriptor);
765 if (NT_SUCCESS(Status))
766 {
767 //
768 // cleanup endpoint
769 //
770 DPRINT("ISO endpoint complete\n");
771 //ASSERT(FALSE);
772 CleanupEndpointDescriptor(EndpointDescriptor, PreviousEndpointDescriptor);
773
774 //
775 // done
776 //
777 continue;
778 }
779
780 //
781 // no more completed descriptors found
782 //
783 break;
784
785 }while(TRUE);
786
787
788 //
789 // acquire spin lock
790 //
791 KeAcquireSpinLockAtDpcLevel(&m_Lock);
792
793 //
794 // is there a pending list item
795 //
796 if (!IsListEmpty(&m_PendingRequestList))
797 {
798 //
799 // get list entry
800 //
801 Entry = RemoveHeadList(&m_PendingRequestList);
802
803 //
804 // get entry
805 //
806 EndpointDescriptor = (POHCI_ENDPOINT_DESCRIPTOR)CONTAINING_RECORD(Entry, OHCI_ENDPOINT_DESCRIPTOR, DescriptorListEntry);
807
808 //
809 // add entry
810 //
811 AddEndpointDescriptor(EndpointDescriptor);
812 }
813
814 //
815 // release lock
816 //
817 KeReleaseSpinLockFromDpcLevel(&m_Lock);
818 }
819
820 POHCI_ENDPOINT_DESCRIPTOR
821 CUSBQueue::FindInterruptEndpointDescriptor(
822 UCHAR InterruptInterval)
823 {
824 ULONG Index = 0;
825 ULONG Power = 1;
826
827 //
828 // sanity check
829 //
830 ASSERT(InterruptInterval <= OHCI_BIGGEST_INTERVAL);
831
832 //
833 // find interrupt index
834 //
835 while (Power <= OHCI_BIGGEST_INTERVAL / 2)
836 {
837 //
838 // is current interval greater
839 //
840 if (Power * 2 > InterruptInterval)
841 break;
842
843 //
844 // increment power
845 //
846 Power *= 2;
847
848 //
849 // move to next interrupt
850 //
851 Index++;
852 }
853
854 DPRINT("InterruptInterval %lu Selected InterruptIndex %lu Choosen Interval %lu\n", InterruptInterval, Index, Power);
855
856 //
857 // return endpoint
858 //
859 return m_InterruptEndpoints[Index];
860 }
861
862 NTSTATUS
863 CUSBQueue::AbortDevicePipe(
864 IN UCHAR DeviceAddress,
865 IN PUSB_ENDPOINT_DESCRIPTOR EndpointDescriptor)
866 {
867 POHCI_ENDPOINT_DESCRIPTOR HeadDescriptor, CurrentDescriptor, PreviousDescriptor, TempDescriptor;
868 ULONG Type;
869 POHCI_GENERAL_TD TransferDescriptor;
870
871 //
872 // get type
873 //
874 Type = (EndpointDescriptor->bmAttributes & USB_ENDPOINT_TYPE_MASK);
875
876 //
877 // check type
878 //
879 if (Type == USB_ENDPOINT_TYPE_BULK)
880 {
881 //
882 // get head descriptor
883 //
884 HeadDescriptor = m_BulkHeadEndpointDescriptor;
885 }
886 else if (Type == USB_ENDPOINT_TYPE_CONTROL)
887 {
888 //
889 // get head descriptor
890 //
891 HeadDescriptor = m_ControlHeadEndpointDescriptor;
892 }
893 else if (Type == USB_ENDPOINT_TYPE_INTERRUPT)
894 {
895 //
896 // get head descriptor
897 //
898 HeadDescriptor = FindInterruptEndpointDescriptor(EndpointDescriptor->bInterval);
899 ASSERT(HeadDescriptor);
900 }
901 else
902 {
903 //
904 // IMPLEMENT me
905 //
906 ASSERT(Type == USB_ENDPOINT_TYPE_ISOCHRONOUS);
907 UNIMPLEMENTED
908 return STATUS_NOT_IMPLEMENTED;
909 }
910
911 //
912 // FIXME should disable list processing
913 //
914
915 //
916 // now remove all endpoints
917 //
918 ASSERT(HeadDescriptor);
919 CurrentDescriptor = (POHCI_ENDPOINT_DESCRIPTOR)HeadDescriptor->NextDescriptor;
920 PreviousDescriptor = (POHCI_ENDPOINT_DESCRIPTOR)HeadDescriptor;
921
922 while(CurrentDescriptor)
923 {
924 if ((CurrentDescriptor->HeadPhysicalDescriptor & OHCI_ENDPOINT_HEAD_MASK) == CurrentDescriptor->TailPhysicalDescriptor || (CurrentDescriptor->HeadPhysicalDescriptor & OHCI_ENDPOINT_HALTED))
925 {
926 //
927 // cleanup endpoint
928 //
929 TempDescriptor = (POHCI_ENDPOINT_DESCRIPTOR)CurrentDescriptor->NextDescriptor;
930 CleanupEndpointDescriptor(CurrentDescriptor, PreviousDescriptor);
931
932 //
933 // use next descriptor
934 //
935 CurrentDescriptor = TempDescriptor;
936 }
937
938 if (!CurrentDescriptor)
939 break;
940
941 if (CurrentDescriptor->HeadPhysicalDescriptor)
942 {
943 TransferDescriptor = (POHCI_GENERAL_TD)CurrentDescriptor->HeadLogicalDescriptor;
944 ASSERT(TransferDescriptor);
945
946 if ((OHCI_ENDPOINT_GET_ENDPOINT_NUMBER(TransferDescriptor->Flags) == (EndpointDescriptor->bEndpointAddress & 0xF)) &&
947 (OHCI_ENDPOINT_GET_DEVICE_ADDRESS(TransferDescriptor->Flags) == DeviceAddress))
948 {
949 //
950 // cleanup endpoint
951 //
952 TempDescriptor = (POHCI_ENDPOINT_DESCRIPTOR)CurrentDescriptor->NextDescriptor;
953 CleanupEndpointDescriptor(CurrentDescriptor, PreviousDescriptor);
954 //
955 // use next descriptor
956 //
957 CurrentDescriptor = TempDescriptor;
958 }
959 }
960
961 if (!CurrentDescriptor)
962 break;
963
964 PreviousDescriptor = CurrentDescriptor;
965 CurrentDescriptor = (POHCI_ENDPOINT_DESCRIPTOR)CurrentDescriptor->NextDescriptor;
966 }
967
968 //
969 // done
970 //
971 return STATUS_SUCCESS;
972 }
973
974
975 NTSTATUS
976 CreateUSBQueue(
977 PUSBQUEUE *OutUsbQueue)
978 {
979 PUSBQUEUE This;
980
981 //
982 // allocate controller
983 //
984 This = new(NonPagedPool, TAG_USBOHCI) CUSBQueue(0);
985 if (!This)
986 {
987 //
988 // failed to allocate
989 //
990 return STATUS_INSUFFICIENT_RESOURCES;
991 }
992
993 //
994 // add reference count
995 //
996 This->AddRef();
997
998 //
999 // return result
1000 //
1001 *OutUsbQueue = (PUSBQUEUE)This;
1002
1003 //
1004 // done
1005 //
1006 return STATUS_SUCCESS;
1007 }