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