[USBEHCI]
[reactos.git] / reactos / drivers / usb / usbehci / usb_request.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/usbehci/usb_request.cpp
5 * PURPOSE: USB EHCI device driver.
6 * PROGRAMMERS:
7 * Michael Martin (michael.martin@reactos.org)
8 * Johannes Anderwald (johannes.anderwald@reactos.org)
9 */
10
11 #include "usbehci.h"
12
13 #define NDEBUG
14 #include <debug.h>
15
16 class CUSBRequest : public IEHCIRequest
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 // IUSBRequest interface functions
39 IMP_IUSBREQUEST
40 // IEHCI Request interface functions
41 IMP_IEHCIREQUEST
42
43 // local functions
44 ULONG InternalGetTransferType();
45 UCHAR InternalGetPidDirection();
46 NTSTATUS BuildControlTransferQueueHead(PQUEUE_HEAD * OutHead);
47 NTSTATUS BuildBulkInterruptTransferQueueHead(PQUEUE_HEAD * OutHead);
48 NTSTATUS STDMETHODCALLTYPE CreateDescriptor(PQUEUE_TRANSFER_DESCRIPTOR *OutDescriptor);
49 NTSTATUS CreateQueueHead(PQUEUE_HEAD *OutQueueHead);
50 UCHAR STDMETHODCALLTYPE GetDeviceAddress();
51 NTSTATUS BuildSetupPacket();
52 NTSTATUS BuildSetupPacketFromURB();
53 ULONG InternalCalculateTransferLength();
54 NTSTATUS STDMETHODCALLTYPE BuildTransferDescriptorChain(IN PQUEUE_HEAD QueueHead, IN PVOID TransferBuffer, IN ULONG TransferBufferLength, IN UCHAR PidCode, IN UCHAR InitialDataToggle, OUT PQUEUE_TRANSFER_DESCRIPTOR * OutFirstDescriptor, OUT PQUEUE_TRANSFER_DESCRIPTOR * OutLastDescriptor, OUT PUCHAR OutDataToggle, OUT PULONG OutTransferBufferOffset);
55 VOID STDMETHODCALLTYPE InitDescriptor(IN PQUEUE_TRANSFER_DESCRIPTOR CurrentDescriptor, IN PVOID TransferBuffer, IN ULONG TransferBufferLength, IN UCHAR PidCode, IN UCHAR DataToggle, OUT PULONG OutDescriptorLength);
56 VOID DumpQueueHead(IN PQUEUE_HEAD QueueHead);
57
58 // constructor / destructor
59 CUSBRequest(IUnknown *OuterUnknown){}
60 virtual ~CUSBRequest(){}
61
62 protected:
63 LONG m_Ref;
64
65 //
66 // memory manager for allocating setup packet / queue head / transfer descriptors
67 //
68 PDMAMEMORYMANAGER m_DmaManager;
69
70 //
71 // caller provided irp packet containing URB request
72 //
73 PIRP m_Irp;
74
75 //
76 // transfer buffer length
77 //
78 ULONG m_TransferBufferLength;
79
80 //
81 // current transfer length
82 //
83 ULONG m_TransferBufferLengthCompleted;
84
85 //
86 // Total Transfer Length
87 //
88 ULONG m_TotalBytesTransferred;
89
90 //
91 // transfer buffer MDL
92 //
93 PMDL m_TransferBufferMDL;
94
95 //
96 // caller provided setup packet
97 //
98 PUSB_DEFAULT_PIPE_SETUP_PACKET m_SetupPacket;
99
100 //
101 // completion event for callers who initialized request with setup packet
102 //
103 PKEVENT m_CompletionEvent;
104
105 //
106 // device address for callers who initialized it with device address
107 //
108 UCHAR m_DeviceAddress;
109
110 //
111 // store end point address
112 //
113 PUSB_ENDPOINT m_EndpointDescriptor;
114
115 //
116 // DMA queue head
117 //
118 PQUEUE_HEAD m_QueueHead;
119
120 //
121 // allocated setup packet from the DMA pool
122 //
123 PUSB_DEFAULT_PIPE_SETUP_PACKET m_DescriptorPacket;
124 PHYSICAL_ADDRESS m_DescriptorSetupPacket;
125
126 //
127 // stores the result of the operation
128 //
129 NTSTATUS m_NtStatusCode;
130 ULONG m_UrbStatusCode;
131
132 // buffer base address
133 PVOID m_Base;
134
135 // device speed
136 USB_DEVICE_SPEED m_Speed;
137
138 };
139
140 //----------------------------------------------------------------------------------------
141 NTSTATUS
142 STDMETHODCALLTYPE
143 CUSBRequest::QueryInterface(
144 IN REFIID refiid,
145 OUT PVOID* Output)
146 {
147 return STATUS_UNSUCCESSFUL;
148 }
149
150 //----------------------------------------------------------------------------------------
151 NTSTATUS
152 STDMETHODCALLTYPE
153 CUSBRequest::InitializeWithSetupPacket(
154 IN PDMAMEMORYMANAGER DmaManager,
155 IN PUSB_DEFAULT_PIPE_SETUP_PACKET SetupPacket,
156 IN PUSBDEVICE Device,
157 IN OPTIONAL PUSB_ENDPOINT EndpointDescriptor,
158 IN OUT ULONG TransferBufferLength,
159 IN OUT PMDL TransferBuffer)
160 {
161 //
162 // sanity checks
163 //
164 PC_ASSERT(DmaManager);
165 PC_ASSERT(SetupPacket);
166
167 //
168 // initialize packet
169 //
170 m_DmaManager = DmaManager;
171 m_SetupPacket = SetupPacket;
172 m_TransferBufferLength = TransferBufferLength;
173 m_TransferBufferMDL = TransferBuffer;
174 m_DeviceAddress = Device->GetDeviceAddress();
175 m_Speed = Device->GetSpeed();
176 m_EndpointDescriptor = EndpointDescriptor;
177 m_TotalBytesTransferred = 0;
178
179 //
180 // Set Length Completed to 0
181 //
182 m_TransferBufferLengthCompleted = 0;
183
184 //
185 // allocate completion event
186 //
187 m_CompletionEvent = (PKEVENT)ExAllocatePoolWithTag(NonPagedPool, sizeof(KEVENT), TAG_USBEHCI);
188 if (!m_CompletionEvent)
189 {
190 //
191 // failed to allocate completion event
192 //
193 return STATUS_INSUFFICIENT_RESOURCES;
194 }
195
196 //
197 // initialize completion event
198 //
199 KeInitializeEvent(m_CompletionEvent, NotificationEvent, FALSE);
200
201 //
202 // done
203 //
204 return STATUS_SUCCESS;
205 }
206 //----------------------------------------------------------------------------------------
207 NTSTATUS
208 STDMETHODCALLTYPE
209 CUSBRequest::InitializeWithIrp(
210 IN PDMAMEMORYMANAGER DmaManager,
211 IN PUSBDEVICE Device,
212 IN OUT PIRP Irp)
213 {
214 PIO_STACK_LOCATION IoStack;
215 PURB Urb;
216
217 //
218 // sanity checks
219 //
220 PC_ASSERT(DmaManager);
221 PC_ASSERT(Irp);
222
223 m_DmaManager = DmaManager;
224 m_TotalBytesTransferred = 0;
225 m_Speed = Device->GetSpeed();
226
227 //
228 // get current irp stack location
229 //
230 IoStack = IoGetCurrentIrpStackLocation(Irp);
231
232 //
233 // sanity check
234 //
235 PC_ASSERT(IoStack->MajorFunction == IRP_MJ_INTERNAL_DEVICE_CONTROL);
236 PC_ASSERT(IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_INTERNAL_USB_SUBMIT_URB);
237 PC_ASSERT(IoStack->Parameters.Others.Argument1 != 0);
238
239 //
240 // get urb
241 //
242 Urb = (PURB)IoStack->Parameters.Others.Argument1;
243
244 //
245 // store irp
246 //
247 m_Irp = Irp;
248
249 //
250 // check function type
251 //
252 switch (Urb->UrbHeader.Function)
253 {
254 //
255 // luckily those request have the same structure layout
256 //
257 case URB_FUNCTION_CLASS_INTERFACE:
258 case URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE:
259 case URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER:
260 {
261 //
262 // bulk interrupt transfer
263 //
264 if (Urb->UrbBulkOrInterruptTransfer.TransferBufferLength)
265 {
266 //
267 // Check if there is a MDL
268 //
269 if (!Urb->UrbBulkOrInterruptTransfer.TransferBufferMDL)
270 {
271 //
272 // sanity check
273 //
274 PC_ASSERT(Urb->UrbBulkOrInterruptTransfer.TransferBuffer);
275
276 //
277 // Create one using TransferBuffer
278 //
279 DPRINT("Creating Mdl from Urb Buffer %p Length %lu\n", Urb->UrbBulkOrInterruptTransfer.TransferBuffer, Urb->UrbBulkOrInterruptTransfer.TransferBufferLength);
280 m_TransferBufferMDL = IoAllocateMdl(Urb->UrbBulkOrInterruptTransfer.TransferBuffer,
281 Urb->UrbBulkOrInterruptTransfer.TransferBufferLength,
282 FALSE,
283 FALSE,
284 NULL);
285
286 if (!m_TransferBufferMDL)
287 {
288 //
289 // failed to allocate mdl
290 //
291 return STATUS_INSUFFICIENT_RESOURCES;
292 }
293
294 //
295 // build mdl for non paged pool
296 // FIXME: Does hub driver already do this when passing MDL?
297 //
298 MmBuildMdlForNonPagedPool(m_TransferBufferMDL);
299
300 //
301 // Keep that ehci created the MDL and needs to free it.
302 //
303 }
304 else
305 {
306 m_TransferBufferMDL = Urb->UrbBulkOrInterruptTransfer.TransferBufferMDL;
307 }
308
309 //
310 // save buffer length
311 //
312 m_TransferBufferLength = Urb->UrbBulkOrInterruptTransfer.TransferBufferLength;
313
314 //
315 // Set Length Completed to 0
316 //
317 m_TransferBufferLengthCompleted = 0;
318
319 //
320 // get endpoint descriptor
321 //
322 m_EndpointDescriptor = (PUSB_ENDPOINT)Urb->UrbBulkOrInterruptTransfer.PipeHandle;
323
324 }
325 break;
326 }
327 default:
328 DPRINT1("URB Function: not supported %x\n", Urb->UrbHeader.Function);
329 //ASSERT(FALSE);
330 }
331
332 //
333 // done
334 //
335 return STATUS_SUCCESS;
336
337 }
338
339 //----------------------------------------------------------------------------------------
340 VOID
341 STDMETHODCALLTYPE
342 CUSBRequest::CompletionCallback(
343 IN NTSTATUS NtStatusCode,
344 IN ULONG UrbStatusCode,
345 IN struct _QUEUE_HEAD *QueueHead)
346 {
347 PIO_STACK_LOCATION IoStack;
348 PURB Urb;
349
350 //
351 // FIXME: support linked queue heads
352 //
353
354 //
355 // store completion code
356 //
357 m_NtStatusCode = NtStatusCode;
358 m_UrbStatusCode = UrbStatusCode;
359
360 if (m_Irp)
361 {
362 //
363 // set irp completion status
364 //
365 m_Irp->IoStatus.Status = NtStatusCode;
366
367 //
368 // get current irp stack location
369 //
370 IoStack = IoGetCurrentIrpStackLocation(m_Irp);
371
372 //
373 // get urb
374 //
375 Urb = (PURB)IoStack->Parameters.Others.Argument1;
376
377 //
378 // store urb status
379 //
380 Urb->UrbHeader.Status = UrbStatusCode;
381
382 //
383 // Check if the MDL was created
384 //
385 if (!Urb->UrbBulkOrInterruptTransfer.TransferBufferMDL)
386 {
387 //
388 // Free Mdl
389 //
390 IoFreeMdl(m_TransferBufferMDL);
391 }
392
393 //
394 // check if the request was successfull
395 //
396 if (!NT_SUCCESS(NtStatusCode))
397 {
398 //
399 // set returned length to zero in case of error
400 //
401 Urb->UrbHeader.Length = 0;
402 }
403 else
404 {
405 //
406 // calculate transfer length
407 //
408 Urb->UrbBulkOrInterruptTransfer.TransferBufferLength = InternalCalculateTransferLength();
409 }
410
411 DPRINT("Request %p Completing Irp %p NtStatusCode %x UrbStatusCode %x Transferred Length %lu\n", this, m_Irp, NtStatusCode, UrbStatusCode, Urb->UrbBulkOrInterruptTransfer.TransferBufferLength);
412
413 //
414 // FIXME: check if the transfer was split
415 // if yes dont complete irp yet
416 //
417 IoCompleteRequest(m_Irp, IO_NO_INCREMENT);
418 }
419 else
420 {
421 //
422 // signal completion event
423 //
424 PC_ASSERT(m_CompletionEvent);
425 KeSetEvent(m_CompletionEvent, 0, FALSE);
426 }
427 }
428
429 //----------------------------------------------------------------------------------------
430 NTSTATUS
431 STDMETHODCALLTYPE
432 CUSBRequest::GetQueueHead(
433 struct _QUEUE_HEAD ** OutHead)
434 {
435 ULONG TransferType;
436 NTSTATUS Status;
437
438 //
439 // first get transfer type
440 //
441 TransferType = InternalGetTransferType();
442
443 //
444 // build request depending on type
445 //
446 switch(TransferType)
447 {
448 case USB_ENDPOINT_TYPE_CONTROL:
449 Status = BuildControlTransferQueueHead(OutHead);
450 break;
451 case USB_ENDPOINT_TYPE_INTERRUPT:
452 case USB_ENDPOINT_TYPE_BULK:
453 Status = BuildBulkInterruptTransferQueueHead(OutHead);
454 break;
455 case USB_ENDPOINT_TYPE_ISOCHRONOUS:
456 DPRINT1("USB_ENDPOINT_TYPE_ISOCHRONOUS not implemented\n");
457 Status = STATUS_NOT_IMPLEMENTED;
458 break;
459 default:
460 PC_ASSERT(FALSE);
461 Status = STATUS_NOT_IMPLEMENTED;
462 break;
463 }
464
465 if (NT_SUCCESS(Status))
466 {
467 //
468 // store queue head
469 //
470 m_QueueHead = *OutHead;
471
472 //
473 // store request object
474 //
475 (*OutHead)->Request = PVOID(this);
476 }
477
478 //
479 // done
480 //
481 return Status;
482 }
483
484 //----------------------------------------------------------------------------------------
485 BOOLEAN
486 STDMETHODCALLTYPE
487 CUSBRequest::IsRequestComplete()
488 {
489 //
490 // FIXME: check if request was split
491 //
492
493 //
494 // Check if the transfer was completed, only valid for Bulk Transfers
495 //
496 if ((m_TransferBufferLengthCompleted < m_TransferBufferLength)
497 && (GetTransferType() == USB_ENDPOINT_TYPE_BULK))
498 {
499 //
500 // Transfer not completed
501 //
502 return FALSE;
503 }
504 return TRUE;
505 }
506 //----------------------------------------------------------------------------------------
507 ULONG
508 STDMETHODCALLTYPE
509 CUSBRequest::GetTransferType()
510 {
511 //
512 // call internal implementation
513 //
514 return InternalGetTransferType();
515 }
516
517 //----------------------------------------------------------------------------------------
518 ULONG
519 CUSBRequest::InternalGetTransferType()
520 {
521 ULONG TransferType;
522
523 //
524 // check if an irp is provided
525 //
526 if (m_Irp)
527 {
528 ASSERT(m_EndpointDescriptor);
529
530 //
531 // end point is defined in the low byte of bmAttributes
532 //
533 TransferType = (m_EndpointDescriptor->EndPointDescriptor.bmAttributes & USB_ENDPOINT_TYPE_MASK);
534 }
535 else
536 {
537 //
538 // initialized with setup packet, must be a control transfer
539 //
540 TransferType = USB_ENDPOINT_TYPE_CONTROL;
541 ASSERT(m_EndpointDescriptor == NULL);
542 }
543
544 //
545 // done
546 //
547 return TransferType;
548 }
549
550 UCHAR
551 CUSBRequest::InternalGetPidDirection()
552 {
553 if (m_EndpointDescriptor)
554 {
555 //
556 // end point direction is highest bit in bEndpointAddress
557 //
558 return (m_EndpointDescriptor->EndPointDescriptor.bEndpointAddress & USB_ENDPOINT_DIRECTION_MASK) >> 7;
559 }
560 else
561 {
562 //
563 // request arrives on the control pipe, extract direction from setup packet
564 //
565 ASSERT(m_DescriptorPacket);
566 return (m_DescriptorPacket->bmRequestType.B >> 7);
567 }
568 }
569
570 VOID
571 STDMETHODCALLTYPE
572 CUSBRequest::InitDescriptor(
573 IN PQUEUE_TRANSFER_DESCRIPTOR CurrentDescriptor,
574 IN PVOID TransferBuffer,
575 IN ULONG TransferBufferLength,
576 IN UCHAR PidCode,
577 IN UCHAR DataToggle,
578 OUT PULONG OutDescriptorLength)
579 {
580 ULONG Index, Length = 0, PageOffset, BufferLength;
581 PHYSICAL_ADDRESS Address;
582
583 //
584 // init transfer descriptor
585 //
586 CurrentDescriptor->Token.Bits.PIDCode = PidCode;
587 CurrentDescriptor->Token.Bits.TotalBytesToTransfer = 0;
588 CurrentDescriptor->Token.Bits.DataToggle = DataToggle;
589
590 //
591 // sanity check
592 //
593 ASSERT(TransferBufferLength);
594
595 //
596 // store buffers
597 //
598 Index = 0;
599 do
600 {
601 //
602 // get address
603 //
604 Address = MmGetPhysicalAddress(TransferBuffer);
605
606 //
607 // use physical address
608 //
609 CurrentDescriptor->BufferPointer[Index] = Address.LowPart;
610 CurrentDescriptor->ExtendedBufferPointer[Index] = Address.HighPart;
611
612 //
613 // Get the offset from page size
614 //
615 PageOffset = BYTE_OFFSET(CurrentDescriptor->BufferPointer[Index]);
616 if (PageOffset != 0)
617 {
618 //
619 // move to next page
620 //
621 TransferBuffer = (PVOID)ROUND_TO_PAGES(TransferBuffer);
622 }
623 else
624 {
625 //
626 // move to next page
627 //
628 TransferBuffer = (PVOID)((ULONG_PTR)TransferBuffer + PAGE_SIZE);
629 }
630
631 //
632 // calculate buffer length
633 //
634 BufferLength = min(TransferBufferLength, PAGE_SIZE - PageOffset);
635
636 //
637 // increment transfer bytes
638 //
639 CurrentDescriptor->Token.Bits.TotalBytesToTransfer += BufferLength;
640 CurrentDescriptor->TotalBytesToTransfer += BufferLength;
641 Length += BufferLength;
642 DPRINT("Index %lu TransferBufferLength %lu PageOffset %x BufferLength %lu Buffer Phy %p TransferBuffer %p\n", Index, TransferBufferLength, PageOffset, BufferLength, CurrentDescriptor->BufferPointer[Index], TransferBuffer);
643
644 //
645 // decrement available byte count
646 //
647 TransferBufferLength -= BufferLength;
648 if (TransferBufferLength == 0)
649 {
650 //
651 // end reached
652 //
653 break;
654 }
655
656 //
657 // sanity check
658 //
659 if (Index > 1)
660 {
661 //
662 // no equal buffers
663 //
664 ASSERT(CurrentDescriptor->BufferPointer[Index] != CurrentDescriptor->BufferPointer[Index-1]);
665 }
666
667 //
668 // next descriptor index
669 //
670 Index++;
671 }while(Index < 5);
672
673 //
674 // store result
675 //
676 *OutDescriptorLength = Length;
677 }
678
679 NTSTATUS
680 STDMETHODCALLTYPE
681 CUSBRequest::BuildTransferDescriptorChain(
682 IN PQUEUE_HEAD QueueHead,
683 IN PVOID TransferBuffer,
684 IN ULONG TransferBufferLength,
685 IN UCHAR PidCode,
686 IN UCHAR InitialDataToggle,
687 OUT PQUEUE_TRANSFER_DESCRIPTOR * OutFirstDescriptor,
688 OUT PQUEUE_TRANSFER_DESCRIPTOR * OutLastDescriptor,
689 OUT PUCHAR OutDataToggle,
690 OUT PULONG OutTransferBufferOffset)
691 {
692 PQUEUE_TRANSFER_DESCRIPTOR FirstDescriptor = NULL, CurrentDescriptor, LastDescriptor = NULL;
693 NTSTATUS Status;
694 ULONG DescriptorLength, TransferBufferOffset = 0;
695 ULONG MaxPacketSize = 0, TransferSize;
696
697 //
698 // is there an endpoint descriptor
699 //
700 if (m_EndpointDescriptor)
701 {
702 //
703 // use endpoint packet size
704 //
705 MaxPacketSize = m_EndpointDescriptor->EndPointDescriptor.wMaxPacketSize;
706 }
707
708 do
709 {
710 //
711 // allocate transfer descriptor
712 //
713 Status = CreateDescriptor(&CurrentDescriptor);
714 if (!NT_SUCCESS(Status))
715 {
716 //
717 // failed to allocate transfer descriptor
718 //
719 return STATUS_INSUFFICIENT_RESOURCES;
720 }
721
722 if (MaxPacketSize)
723 {
724 //
725 // transfer size is minimum available buffer or endpoint size
726 //
727 TransferSize = min(TransferBufferLength - TransferBufferOffset, MaxPacketSize);
728 }
729 else
730 {
731 //
732 // use available buffer
733 //
734 TransferSize = TransferBufferLength - TransferBufferOffset;
735 }
736
737 //
738 // now init the descriptor
739 //
740 InitDescriptor(CurrentDescriptor,
741 (PVOID)((ULONG_PTR)TransferBuffer + TransferBufferOffset),
742 TransferSize,
743 PidCode,
744 InitialDataToggle,
745 &DescriptorLength);
746
747 //
748 // insert into queue head
749 //
750 InsertTailList(&QueueHead->TransferDescriptorListHead, &CurrentDescriptor->DescriptorEntry);
751
752 //
753 // adjust offset
754 //
755 TransferBufferOffset += DescriptorLength;
756
757 if (LastDescriptor)
758 {
759 //
760 // link to current descriptor
761 //
762 LastDescriptor->NextPointer = CurrentDescriptor->PhysicalAddr;
763 LastDescriptor = CurrentDescriptor;
764 }
765 else
766 {
767 //
768 // first descriptor in chain
769 //
770 LastDescriptor = FirstDescriptor = CurrentDescriptor;
771 }
772
773 //
774 // flip data toggle
775 //
776 InitialDataToggle = !InitialDataToggle;
777
778 if(TransferBufferLength == TransferBufferOffset)
779 {
780 //
781 // end reached
782 //
783 break;
784 }
785
786 }while(TRUE);
787
788 if (OutFirstDescriptor)
789 {
790 //
791 // store first descriptor
792 //
793 *OutFirstDescriptor = FirstDescriptor;
794 }
795
796 if (OutLastDescriptor)
797 {
798 //
799 // store last descriptor
800 //
801 *OutLastDescriptor = CurrentDescriptor;
802 }
803
804 if (OutDataToggle)
805 {
806 //
807 // store result data toggle
808 //
809 *OutDataToggle = InitialDataToggle;
810 }
811
812 if (OutTransferBufferOffset)
813 {
814 //
815 // store offset
816 //
817 *OutTransferBufferOffset = TransferBufferOffset;
818 }
819
820 //
821 // done
822 //
823 return STATUS_SUCCESS;
824 }
825
826 //----------------------------------------------------------------------------------------
827 NTSTATUS
828 CUSBRequest::BuildControlTransferQueueHead(
829 PQUEUE_HEAD * OutHead)
830 {
831 NTSTATUS Status;
832 ULONG DescriptorChainLength;
833 PQUEUE_HEAD QueueHead;
834 PQUEUE_TRANSFER_DESCRIPTOR SetupDescriptor, StatusDescriptor, FirstDescriptor, LastDescriptor;
835
836 //
837 // first allocate the queue head
838 //
839 Status = CreateQueueHead(&QueueHead);
840 if (!NT_SUCCESS(Status))
841 {
842 //
843 // failed to allocate queue head
844 //
845 return STATUS_INSUFFICIENT_RESOURCES;
846 }
847
848 //
849 // sanity check
850 //
851 PC_ASSERT(QueueHead);
852
853 //
854 // create setup packet
855 //
856 Status = BuildSetupPacket();
857 if (!NT_SUCCESS(Status))
858 {
859 //
860 // failed to allocate setup packet
861 //
862 ASSERT(FALSE);
863 return STATUS_INSUFFICIENT_RESOURCES;
864 }
865
866 //
867 // create setup descriptor
868 //
869 Status = CreateDescriptor(&SetupDescriptor);
870 if (!NT_SUCCESS(Status))
871 {
872 //
873 // failed to allocate transfer descriptor
874 //
875 ASSERT(FALSE);
876 return Status;
877 }
878
879 //
880 // create status descriptor
881 //
882 Status = CreateDescriptor(&StatusDescriptor);
883 if (!NT_SUCCESS(Status))
884 {
885 //
886 // failed to allocate transfer descriptor
887 //
888 ASSERT(FALSE);
889 return Status;
890 }
891
892 //
893 // now initialize the queue head
894 //
895 QueueHead->EndPointCharacteristics.DeviceAddress = GetDeviceAddress();
896
897 ASSERT(m_EndpointDescriptor == FALSE);
898
899 //
900 // init setup descriptor
901 //
902 SetupDescriptor->Token.Bits.PIDCode = PID_CODE_SETUP_TOKEN;
903 SetupDescriptor->Token.Bits.TotalBytesToTransfer = sizeof(USB_DEFAULT_PIPE_SETUP_PACKET);
904 SetupDescriptor->Token.Bits.DataToggle = FALSE;
905 SetupDescriptor->BufferPointer[0] = m_DescriptorSetupPacket.LowPart;
906 SetupDescriptor->ExtendedBufferPointer[0] = m_DescriptorSetupPacket.HighPart;
907 InsertTailList(&QueueHead->TransferDescriptorListHead, &SetupDescriptor->DescriptorEntry);
908
909
910 //
911 // init status descriptor
912 //
913 StatusDescriptor->Token.Bits.TotalBytesToTransfer = 0;
914 StatusDescriptor->Token.Bits.DataToggle = TRUE;
915 StatusDescriptor->Token.Bits.InterruptOnComplete = TRUE;
916
917 //
918 // is there data
919 //
920 if (m_TransferBufferLength)
921 {
922 Status = BuildTransferDescriptorChain(QueueHead,
923 MmGetMdlVirtualAddress(m_TransferBufferMDL),
924 m_TransferBufferLength,
925 InternalGetPidDirection(),
926 TRUE,
927 &FirstDescriptor,
928 &LastDescriptor,
929 NULL,
930 &DescriptorChainLength);
931
932 //
933 // FIXME handle errors
934 //
935 ASSERT(Status == STATUS_SUCCESS);
936 if (m_TransferBufferLength != DescriptorChainLength)
937 {
938 DPRINT1("DescriptorChainLength %x\n", DescriptorChainLength);
939 DPRINT1("m_TransferBufferLength %x\n", m_TransferBufferLength);
940 ASSERT(FALSE);
941 }
942
943 //
944 // now link the descriptors
945 //
946 SetupDescriptor->NextPointer = FirstDescriptor->PhysicalAddr;
947 SetupDescriptor->AlternateNextPointer = FirstDescriptor->PhysicalAddr;
948 LastDescriptor->NextPointer = StatusDescriptor->PhysicalAddr;
949 LastDescriptor->AlternateNextPointer = StatusDescriptor->PhysicalAddr;
950
951
952 //
953 // pid code is flipped for ops with data stage
954 //
955 StatusDescriptor->Token.Bits.PIDCode = !InternalGetPidDirection();
956 }
957 else
958 {
959 //
960 // direct link
961 //
962 SetupDescriptor->NextPointer = StatusDescriptor->PhysicalAddr;
963 SetupDescriptor->AlternateNextPointer = StatusDescriptor->PhysicalAddr;
964
965 //
966 // retrieve result of operation
967 //
968 StatusDescriptor->Token.Bits.PIDCode = PID_CODE_IN_TOKEN;
969 }
970
971 //
972 // insert status descriptor
973 //
974 InsertTailList(&QueueHead->TransferDescriptorListHead, &StatusDescriptor->DescriptorEntry);
975
976
977 //
978 // link transfer descriptors to queue head
979 //
980 QueueHead->NextPointer = SetupDescriptor->PhysicalAddr;
981
982 //
983 // store result
984 //
985 *OutHead = QueueHead;
986
987 //
988 // displays the current request
989 //
990 //DumpQueueHead(QueueHead);
991
992 DPRINT("BuildControlTransferQueueHead done\n");
993 //
994 // done
995 //
996 return STATUS_SUCCESS;
997 }
998
999 VOID
1000 CUSBRequest::DumpQueueHead(
1001 IN PQUEUE_HEAD QueueHead)
1002 {
1003 PLIST_ENTRY Entry;
1004 PQUEUE_TRANSFER_DESCRIPTOR Descriptor;
1005 ULONG Index = 0;
1006
1007 DPRINT1("QueueHead %p Addr %x\n", QueueHead, QueueHead->PhysicalAddr);
1008 DPRINT1("QueueHead AlternateNextPointer %x\n", QueueHead->AlternateNextPointer);
1009 DPRINT1("QueueHead NextPointer %x\n", QueueHead->NextPointer);
1010
1011 DPRINT1("QueueHead HubAddr %x\n", QueueHead->EndPointCharacteristics.ControlEndPointFlag);
1012 DPRINT1("QueueHead DeviceAddress %x\n", QueueHead->EndPointCharacteristics.DeviceAddress);
1013 DPRINT1("QueueHead EndPointNumber %x\n", QueueHead->EndPointCharacteristics.EndPointNumber);
1014 DPRINT1("QueueHead EndPointSpeed %x\n", QueueHead->EndPointCharacteristics.EndPointSpeed);
1015 DPRINT1("QueueHead HeadOfReclamation %x\n", QueueHead->EndPointCharacteristics.HeadOfReclamation);
1016 DPRINT1("QueueHead InactiveOnNextTransaction %x\n", QueueHead->EndPointCharacteristics.InactiveOnNextTransaction);
1017 DPRINT1("QueueHead MaximumPacketLength %x\n", QueueHead->EndPointCharacteristics.MaximumPacketLength);
1018 DPRINT1("QueueHead NakCountReload %x\n", QueueHead->EndPointCharacteristics.NakCountReload);
1019 DPRINT1("QueueHead QEDTDataToggleControl %x\n", QueueHead->EndPointCharacteristics.QEDTDataToggleControl);
1020 DPRINT1("QueueHead HubAddr %x\n", QueueHead->EndPointCapabilities.HubAddr);
1021 DPRINT1("QueueHead InterruptScheduleMask %x\n", QueueHead->EndPointCapabilities.InterruptScheduleMask);
1022 DPRINT1("QueueHead NumberOfTransactionPerFrame %x\n", QueueHead->EndPointCapabilities.NumberOfTransactionPerFrame);
1023 DPRINT1("QueueHead PortNumber %x\n", QueueHead->EndPointCapabilities.PortNumber);
1024 DPRINT1("QueueHead SplitCompletionMask %x\n", QueueHead->EndPointCapabilities.SplitCompletionMask);
1025
1026 Entry = QueueHead->TransferDescriptorListHead.Flink;
1027 while(Entry != &QueueHead->TransferDescriptorListHead)
1028 {
1029 //
1030 // get transfer descriptor
1031 //
1032 Descriptor = (PQUEUE_TRANSFER_DESCRIPTOR)CONTAINING_RECORD(Entry, QUEUE_TRANSFER_DESCRIPTOR, DescriptorEntry);
1033
1034 DPRINT1("TransferDescriptor %lu Addr %x\n", Index, Descriptor->PhysicalAddr);
1035 DPRINT1("TransferDescriptor %lu Next %x\n", Index, Descriptor->NextPointer);
1036 DPRINT1("TransferDescriptor %lu AlternateNextPointer %x\n", Index, Descriptor->AlternateNextPointer);
1037 DPRINT1("TransferDescriptor %lu Active %lu\n", Index, Descriptor->Token.Bits.Active);
1038 DPRINT1("TransferDescriptor %lu BabbleDetected %lu\n", Index, Descriptor->Token.Bits.BabbleDetected);
1039 DPRINT1("TransferDescriptor %lu CurrentPage %lu\n", Index, Descriptor->Token.Bits.CurrentPage);
1040 DPRINT1("TransferDescriptor %lu DataBufferError %lu\n", Index, Descriptor->Token.Bits.DataBufferError);
1041 DPRINT1("TransferDescriptor %lu DataToggle %lu\n", Index, Descriptor->Token.Bits.DataToggle);
1042 DPRINT1("TransferDescriptor %lu ErrorCounter %lu\n", Index, Descriptor->Token.Bits.ErrorCounter);
1043 DPRINT1("TransferDescriptor %lu Halted %lu\n", Index, Descriptor->Token.Bits.Halted);
1044 DPRINT1("TransferDescriptor %lu InterruptOnComplete %x\n", Index, Descriptor->Token.Bits.InterruptOnComplete);
1045 DPRINT1("TransferDescriptor %lu MissedMicroFrame %lu\n", Index, Descriptor->Token.Bits.MissedMicroFrame);
1046 DPRINT1("TransferDescriptor %lu PIDCode %lu\n", Index, Descriptor->Token.Bits.PIDCode);
1047 DPRINT1("TransferDescriptor %lu PingState %lu\n", Index, Descriptor->Token.Bits.PingState);
1048 DPRINT1("TransferDescriptor %lu SplitTransactionState %lu\n", Index, Descriptor->Token.Bits.SplitTransactionState);
1049 DPRINT1("TransferDescriptor %lu TotalBytesToTransfer %lu\n", Index, Descriptor->Token.Bits.TotalBytesToTransfer);
1050 DPRINT1("TransferDescriptor %lu TransactionError %lu\n", Index, Descriptor->Token.Bits.TransactionError);
1051
1052 DPRINT1("TransferDescriptor %lu Buffer Pointer 0 %x\n", Index, Descriptor->BufferPointer[0]);
1053 DPRINT1("TransferDescriptor %lu Buffer Pointer 1 %x\n", Index, Descriptor->BufferPointer[1]);
1054 DPRINT1("TransferDescriptor %lu Buffer Pointer 2 %x\n", Index, Descriptor->BufferPointer[2]);
1055 DPRINT1("TransferDescriptor %lu Buffer Pointer 3 %x\n", Index, Descriptor->BufferPointer[3]);
1056 DPRINT1("TransferDescriptor %lu Buffer Pointer 4 %x\n", Index, Descriptor->BufferPointer[4]);
1057 Entry = Entry->Flink;
1058 Index++;
1059 }
1060 }
1061
1062
1063 //----------------------------------------------------------------------------------------
1064 NTSTATUS
1065 CUSBRequest::BuildBulkInterruptTransferQueueHead(
1066 PQUEUE_HEAD * OutHead)
1067 {
1068 NTSTATUS Status;
1069 PQUEUE_HEAD QueueHead;
1070 PVOID Base;
1071 ULONG ChainDescriptorLength;
1072 PQUEUE_TRANSFER_DESCRIPTOR FirstDescriptor, LastDescriptor;
1073
1074 //
1075 // Allocate the queue head
1076 //
1077 Status = CreateQueueHead(&QueueHead);
1078
1079 if (!NT_SUCCESS(Status))
1080 {
1081 //
1082 // failed to allocate queue heads
1083 //
1084 return STATUS_INSUFFICIENT_RESOURCES;
1085 }
1086
1087 //
1088 // sanity checks
1089 //
1090 PC_ASSERT(QueueHead);
1091 PC_ASSERT(m_TransferBufferLength);
1092
1093 if (!m_Base)
1094 {
1095 //
1096 // get virtual base of mdl
1097 //
1098 m_Base = MmGetSystemAddressForMdlSafe(m_TransferBufferMDL, NormalPagePriority);
1099 }
1100
1101 //
1102 // Increase the size of last transfer, 0 in case this is the first
1103 //
1104 Base = (PVOID)((ULONG_PTR)m_Base + m_TransferBufferLengthCompleted);
1105
1106 PC_ASSERT(m_EndpointDescriptor);
1107 PC_ASSERT(Base);
1108
1109 //
1110 // sanity check
1111 //
1112 ASSERT(m_EndpointDescriptor);
1113
1114 //
1115 // use 4 * PAGE_SIZE at max for each new request
1116 //
1117 ULONG MaxTransferLength = min(4 * PAGE_SIZE, m_TransferBufferLength - m_TransferBufferLengthCompleted);
1118
1119 //
1120 // build bulk transfer descriptor chain
1121 //
1122 Status = BuildTransferDescriptorChain(QueueHead,
1123 Base,
1124 MaxTransferLength,
1125 InternalGetPidDirection(),
1126 m_EndpointDescriptor->DataToggle,
1127 &FirstDescriptor,
1128 &LastDescriptor,
1129 &m_EndpointDescriptor->DataToggle,
1130 &ChainDescriptorLength);
1131
1132 //
1133 // move to next offset
1134 //
1135 m_TransferBufferLengthCompleted += ChainDescriptorLength;
1136
1137 ASSERT(Status == STATUS_SUCCESS);
1138
1139 //
1140 // init queue head
1141 //
1142 QueueHead->EndPointCharacteristics.DeviceAddress = GetDeviceAddress();
1143 QueueHead->EndPointCharacteristics.EndPointNumber = m_EndpointDescriptor->EndPointDescriptor.bEndpointAddress & 0x0F;
1144 QueueHead->EndPointCharacteristics.MaximumPacketLength = m_EndpointDescriptor->EndPointDescriptor.wMaxPacketSize;
1145 QueueHead->NextPointer = FirstDescriptor->PhysicalAddr;
1146 QueueHead->CurrentLinkPointer = FirstDescriptor->PhysicalAddr;
1147 QueueHead->AlternateNextPointer = TERMINATE_POINTER;
1148
1149 ASSERT(QueueHead->EndPointCharacteristics.DeviceAddress);
1150 ASSERT(QueueHead->EndPointCharacteristics.EndPointNumber);
1151 ASSERT(QueueHead->EndPointCharacteristics.MaximumPacketLength);
1152 ASSERT(QueueHead->NextPointer);
1153
1154 //
1155 // interrupt on last descriptor
1156 //
1157 LastDescriptor->Token.Bits.InterruptOnComplete = TRUE;
1158
1159 //
1160 // store result
1161 //
1162 *OutHead = QueueHead;
1163
1164 //
1165 // dump status
1166 //
1167 //DumpQueueHead(QueueHead);
1168
1169 //
1170 // done
1171 //
1172 return STATUS_SUCCESS;
1173 }
1174
1175 //----------------------------------------------------------------------------------------
1176 NTSTATUS
1177 STDMETHODCALLTYPE
1178 CUSBRequest::CreateDescriptor(
1179 PQUEUE_TRANSFER_DESCRIPTOR *OutDescriptor)
1180 {
1181 PQUEUE_TRANSFER_DESCRIPTOR Descriptor;
1182 NTSTATUS Status;
1183 PHYSICAL_ADDRESS TransferDescriptorPhysicalAddress;
1184
1185 //
1186 // allocate descriptor
1187 //
1188 Status = m_DmaManager->Allocate(sizeof(QUEUE_TRANSFER_DESCRIPTOR), (PVOID*)&Descriptor, &TransferDescriptorPhysicalAddress);
1189 if (!NT_SUCCESS(Status))
1190 {
1191 //
1192 // failed to allocate transfer descriptor
1193 //
1194 return STATUS_INSUFFICIENT_RESOURCES;
1195 }
1196
1197 //
1198 // initialize transfer descriptor
1199 //
1200 Descriptor->NextPointer = TERMINATE_POINTER;
1201 Descriptor->AlternateNextPointer = TERMINATE_POINTER;
1202 Descriptor->Token.Bits.DataToggle = TRUE;
1203 Descriptor->Token.Bits.ErrorCounter = 0x03;
1204 Descriptor->Token.Bits.Active = TRUE;
1205 Descriptor->PhysicalAddr = TransferDescriptorPhysicalAddress.LowPart;
1206
1207 //
1208 // store result
1209 //
1210 *OutDescriptor = Descriptor;
1211
1212 //
1213 // done
1214 //
1215 return Status;
1216 }
1217
1218 //----------------------------------------------------------------------------------------
1219 NTSTATUS
1220 CUSBRequest::CreateQueueHead(
1221 PQUEUE_HEAD *OutQueueHead)
1222 {
1223 PQUEUE_HEAD QueueHead;
1224 PHYSICAL_ADDRESS QueueHeadPhysicalAddress;
1225 NTSTATUS Status;
1226
1227 //
1228 // allocate queue head
1229 //
1230 Status = m_DmaManager->Allocate(sizeof(QUEUE_HEAD), (PVOID*)&QueueHead, &QueueHeadPhysicalAddress);
1231
1232 if (!NT_SUCCESS(Status))
1233 {
1234 //
1235 // failed to allocate queue head
1236 //
1237 return STATUS_INSUFFICIENT_RESOURCES;
1238 }
1239
1240 //
1241 // initialize queue head
1242 //
1243 QueueHead->HorizontalLinkPointer = TERMINATE_POINTER;
1244 QueueHead->AlternateNextPointer = TERMINATE_POINTER;
1245 QueueHead->NextPointer = TERMINATE_POINTER;
1246 InitializeListHead(&QueueHead->TransferDescriptorListHead);
1247
1248 //
1249 // 1 for non high speed, 0 for high speed device
1250 //
1251 QueueHead->EndPointCharacteristics.ControlEndPointFlag = 0;
1252 QueueHead->EndPointCharacteristics.HeadOfReclamation = FALSE;
1253 QueueHead->EndPointCharacteristics.MaximumPacketLength = 64;
1254
1255 //
1256 // Set NakCountReload to max value possible
1257 //
1258 QueueHead->EndPointCharacteristics.NakCountReload = 0x3;
1259
1260 //
1261 // Get the Initial Data Toggle from the QEDT
1262 //
1263 QueueHead->EndPointCharacteristics.QEDTDataToggleControl = TRUE;
1264
1265 //
1266 // FIXME: check if High Speed Device
1267 //
1268 QueueHead->EndPointCharacteristics.EndPointSpeed = QH_ENDPOINT_HIGHSPEED;
1269 QueueHead->EndPointCapabilities.NumberOfTransactionPerFrame = 0x01;
1270 QueueHead->Token.DWord = 0;
1271 QueueHead->Token.Bits.InterruptOnComplete = FALSE;
1272
1273 //
1274 // store address
1275 //
1276 QueueHead->PhysicalAddr = QueueHeadPhysicalAddress.LowPart;
1277
1278 //
1279 // output queue head
1280 //
1281 *OutQueueHead = QueueHead;
1282
1283 //
1284 // done
1285 //
1286 return STATUS_SUCCESS;
1287 }
1288
1289 //----------------------------------------------------------------------------------------
1290 UCHAR
1291 STDMETHODCALLTYPE
1292 CUSBRequest::GetDeviceAddress()
1293 {
1294 PIO_STACK_LOCATION IoStack;
1295 PURB Urb;
1296 PUSBDEVICE UsbDevice;
1297
1298 //
1299 // check if there is an irp provided
1300 //
1301 if (!m_Irp)
1302 {
1303 //
1304 // used provided address
1305 //
1306 return m_DeviceAddress;
1307 }
1308
1309 //
1310 // get current stack location
1311 //
1312 IoStack = IoGetCurrentIrpStackLocation(m_Irp);
1313
1314 //
1315 // get contained urb
1316 //
1317 Urb = (PURB)IoStack->Parameters.Others.Argument1;
1318
1319 //
1320 // check if there is a pipe handle provided
1321 //
1322 if (Urb->UrbHeader.UsbdDeviceHandle)
1323 {
1324 //
1325 // there is a device handle provided
1326 //
1327 UsbDevice = (PUSBDEVICE)Urb->UrbHeader.UsbdDeviceHandle;
1328
1329 //
1330 // return device address
1331 //
1332 return UsbDevice->GetDeviceAddress();
1333 }
1334
1335 //
1336 // no device handle provided, it is the host root bus
1337 //
1338 return 0;
1339 }
1340
1341 //----------------------------------------------------------------------------------------
1342 NTSTATUS
1343 CUSBRequest::BuildSetupPacket()
1344 {
1345 NTSTATUS Status;
1346
1347 //
1348 // allocate common buffer setup packet
1349 //
1350 Status = m_DmaManager->Allocate(sizeof(USB_DEFAULT_PIPE_SETUP_PACKET), (PVOID*)&m_DescriptorPacket, &m_DescriptorSetupPacket);
1351 if (!NT_SUCCESS(Status))
1352 {
1353 //
1354 // no memory
1355 //
1356 return Status;
1357 }
1358
1359 if (m_SetupPacket)
1360 {
1361 //
1362 // copy setup packet
1363 //
1364 RtlCopyMemory(m_DescriptorPacket, m_SetupPacket, sizeof(USB_DEFAULT_PIPE_SETUP_PACKET));
1365 }
1366 else
1367 {
1368 //
1369 // build setup packet from urb
1370 //
1371 Status = BuildSetupPacketFromURB();
1372 }
1373
1374 //
1375 // done
1376 //
1377 return Status;
1378 }
1379
1380
1381 NTSTATUS
1382 CUSBRequest::BuildSetupPacketFromURB()
1383 {
1384 PIO_STACK_LOCATION IoStack;
1385 PURB Urb;
1386 NTSTATUS Status = STATUS_NOT_IMPLEMENTED;
1387
1388 //
1389 // sanity checks
1390 //
1391 PC_ASSERT(m_Irp);
1392 PC_ASSERT(m_DescriptorPacket);
1393
1394 //
1395 // get stack location
1396 //
1397 IoStack = IoGetCurrentIrpStackLocation(m_Irp);
1398
1399 //
1400 // get urb
1401 //
1402 Urb = (PURB)IoStack->Parameters.Others.Argument1;
1403
1404 //
1405 // zero descriptor packet
1406 //
1407 RtlZeroMemory(m_DescriptorPacket, sizeof(USB_DEFAULT_PIPE_SETUP_PACKET));
1408
1409
1410 switch (Urb->UrbHeader.Function)
1411 {
1412 /* CLEAR FEATURE */
1413 case URB_FUNCTION_CLEAR_FEATURE_TO_DEVICE:
1414 case URB_FUNCTION_CLEAR_FEATURE_TO_INTERFACE:
1415 case URB_FUNCTION_CLEAR_FEATURE_TO_ENDPOINT:
1416 UNIMPLEMENTED
1417 break;
1418
1419 /* GET CONFIG */
1420 case URB_FUNCTION_GET_CONFIGURATION:
1421 m_DescriptorPacket->bRequest = USB_REQUEST_GET_CONFIGURATION;
1422 m_DescriptorPacket->bmRequestType.B = 0x80;
1423 m_DescriptorPacket->wLength = 1;
1424 break;
1425
1426 /* GET DESCRIPTOR */
1427 case URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE:
1428 m_DescriptorPacket->bRequest = USB_REQUEST_GET_DESCRIPTOR;
1429 m_DescriptorPacket->wValue.LowByte = Urb->UrbControlDescriptorRequest.Index;
1430 m_DescriptorPacket->wValue.HiByte = Urb->UrbControlDescriptorRequest.DescriptorType;
1431 m_DescriptorPacket->wIndex.W = Urb->UrbControlDescriptorRequest.LanguageId;
1432 m_DescriptorPacket->wLength = (USHORT)Urb->UrbControlDescriptorRequest.TransferBufferLength;
1433 m_DescriptorPacket->bmRequestType.B = 0x80;
1434 break;
1435
1436 /* GET INTERFACE */
1437 case URB_FUNCTION_GET_INTERFACE:
1438 m_DescriptorPacket->bRequest = USB_REQUEST_GET_CONFIGURATION;
1439 m_DescriptorPacket->wIndex.W = Urb->UrbControlGetStatusRequest.Index;
1440 m_DescriptorPacket->bmRequestType.B = 0x80;
1441 m_DescriptorPacket->wLength = 1;
1442 break;
1443
1444 /* GET STATUS */
1445 case URB_FUNCTION_GET_STATUS_FROM_DEVICE:
1446 m_DescriptorPacket->bRequest = USB_REQUEST_GET_STATUS;
1447 ASSERT(Urb->UrbControlGetStatusRequest.Index == 0);
1448 m_DescriptorPacket->wIndex.W = Urb->UrbControlGetStatusRequest.Index;
1449 m_DescriptorPacket->bmRequestType.B = 0x80;
1450 m_DescriptorPacket->wLength = 2;
1451 break;
1452
1453 case URB_FUNCTION_GET_STATUS_FROM_INTERFACE:
1454 m_DescriptorPacket->bRequest = USB_REQUEST_GET_STATUS;
1455 ASSERT(Urb->UrbControlGetStatusRequest.Index != 0);
1456 m_DescriptorPacket->wIndex.W = Urb->UrbControlGetStatusRequest.Index;
1457 m_DescriptorPacket->bmRequestType.B = 0x81;
1458 m_DescriptorPacket->wLength = 2;
1459 break;
1460
1461 case URB_FUNCTION_GET_STATUS_FROM_ENDPOINT:
1462 m_DescriptorPacket->bRequest = USB_REQUEST_GET_STATUS;
1463 ASSERT(Urb->UrbControlGetStatusRequest.Index != 0);
1464 m_DescriptorPacket->wIndex.W = Urb->UrbControlGetStatusRequest.Index;
1465 m_DescriptorPacket->bmRequestType.B = 0x82;
1466 m_DescriptorPacket->wLength = 2;
1467 break;
1468
1469 /* SET ADDRESS */
1470
1471 /* SET CONFIG */
1472 case URB_FUNCTION_SELECT_CONFIGURATION:
1473 m_DescriptorPacket->bRequest = USB_REQUEST_SET_CONFIGURATION;
1474 m_DescriptorPacket->wValue.W = Urb->UrbSelectConfiguration.ConfigurationDescriptor->bConfigurationValue;
1475 m_DescriptorPacket->wIndex.W = 0;
1476 m_DescriptorPacket->wLength = 0;
1477 m_DescriptorPacket->bmRequestType.B = 0x00;
1478 break;
1479
1480 /* SET DESCRIPTOR */
1481 case URB_FUNCTION_SET_DESCRIPTOR_TO_DEVICE:
1482 case URB_FUNCTION_SET_DESCRIPTOR_TO_INTERFACE:
1483 case URB_FUNCTION_SET_DESCRIPTOR_TO_ENDPOINT:
1484 UNIMPLEMENTED
1485 break;
1486
1487 /* SET FEATURE */
1488 case URB_FUNCTION_SET_FEATURE_TO_DEVICE:
1489 m_DescriptorPacket->bRequest = USB_REQUEST_SET_FEATURE;
1490 ASSERT(Urb->UrbControlGetStatusRequest.Index == 0);
1491 m_DescriptorPacket->wIndex.W = Urb->UrbControlGetStatusRequest.Index;
1492 m_DescriptorPacket->bmRequestType.B = 0x80;
1493 break;
1494
1495 case URB_FUNCTION_SET_FEATURE_TO_INTERFACE:
1496 m_DescriptorPacket->bRequest = USB_REQUEST_SET_FEATURE;
1497 ASSERT(Urb->UrbControlGetStatusRequest.Index == 0);
1498 m_DescriptorPacket->wIndex.W = Urb->UrbControlGetStatusRequest.Index;
1499 m_DescriptorPacket->bmRequestType.B = 0x81;
1500 break;
1501
1502 case URB_FUNCTION_SET_FEATURE_TO_ENDPOINT:
1503 m_DescriptorPacket->bRequest = USB_REQUEST_SET_FEATURE;
1504 ASSERT(Urb->UrbControlGetStatusRequest.Index == 0);
1505 m_DescriptorPacket->wIndex.W = Urb->UrbControlGetStatusRequest.Index;
1506 m_DescriptorPacket->bmRequestType.B = 0x82;
1507 break;
1508
1509 /* SET INTERFACE*/
1510 case URB_FUNCTION_SELECT_INTERFACE:
1511 m_DescriptorPacket->bRequest = USB_REQUEST_SET_INTERFACE;
1512 m_DescriptorPacket->wValue.W = Urb->UrbSelectInterface.Interface.AlternateSetting;
1513 m_DescriptorPacket->wIndex.W = Urb->UrbSelectInterface.Interface.InterfaceNumber;
1514 m_DescriptorPacket->wLength = 0;
1515 m_DescriptorPacket->bmRequestType.B = 0x01;
1516 break;
1517
1518 /* SYNC FRAME */
1519 case URB_FUNCTION_SYNC_RESET_PIPE_AND_CLEAR_STALL:
1520 UNIMPLEMENTED
1521 break;
1522 default:
1523 UNIMPLEMENTED
1524 break;
1525 }
1526
1527 return Status;
1528 }
1529
1530 //----------------------------------------------------------------------------------------
1531 VOID
1532 STDMETHODCALLTYPE
1533 CUSBRequest::GetResultStatus(
1534 OUT OPTIONAL NTSTATUS * NtStatusCode,
1535 OUT OPTIONAL PULONG UrbStatusCode)
1536 {
1537 //
1538 // sanity check
1539 //
1540 PC_ASSERT(m_CompletionEvent);
1541
1542 //
1543 // wait for the operation to complete
1544 //
1545 KeWaitForSingleObject(m_CompletionEvent, Executive, KernelMode, FALSE, NULL);
1546
1547 //
1548 // copy status
1549 //
1550 if (NtStatusCode)
1551 {
1552 *NtStatusCode = m_NtStatusCode;
1553 }
1554
1555 //
1556 // copy urb status
1557 //
1558 if (UrbStatusCode)
1559 {
1560 *UrbStatusCode = m_UrbStatusCode;
1561 }
1562
1563 }
1564
1565 //-----------------------------------------------------------------------------------------
1566 BOOLEAN
1567 STDMETHODCALLTYPE
1568 CUSBRequest::ShouldReleaseRequestAfterCompletion()
1569 {
1570 if (m_Irp)
1571 {
1572 //
1573 // the request is completed, release it
1574 //
1575 return TRUE;
1576 }
1577 else
1578 {
1579 //
1580 // created with an setup packet, don't release
1581 //
1582 return FALSE;
1583 }
1584 }
1585
1586 //-----------------------------------------------------------------------------------------
1587 VOID
1588 STDMETHODCALLTYPE
1589 CUSBRequest::FreeQueueHead(
1590 IN struct _QUEUE_HEAD * QueueHead)
1591 {
1592 PLIST_ENTRY Entry;
1593 PQUEUE_TRANSFER_DESCRIPTOR Descriptor;
1594
1595 //
1596 // sanity checks
1597 //
1598 ASSERT(m_DmaManager);
1599 ASSERT(QueueHead);
1600 ASSERT(!IsListEmpty(&QueueHead->TransferDescriptorListHead));
1601
1602 do
1603 {
1604 //
1605 // get transfer descriptors
1606 //
1607 Entry = RemoveHeadList(&QueueHead->TransferDescriptorListHead);
1608 ASSERT(Entry);
1609
1610 //
1611 // obtain descriptor from entry
1612 //
1613 Descriptor = (PQUEUE_TRANSFER_DESCRIPTOR)CONTAINING_RECORD(Entry, QUEUE_TRANSFER_DESCRIPTOR, DescriptorEntry);
1614 ASSERT(Descriptor);
1615
1616 //
1617 // add transfer count
1618 //
1619 m_TotalBytesTransferred += (Descriptor->TotalBytesToTransfer - Descriptor->Token.Bits.TotalBytesToTransfer);
1620 DPRINT("TotalBytes Transferred in Descriptor %p Phys Addr %x TotalBytesSoftware %lu Length %lu\n", Descriptor, Descriptor->PhysicalAddr, Descriptor->TotalBytesToTransfer, Descriptor->TotalBytesToTransfer - Descriptor->Token.Bits.TotalBytesToTransfer);
1621
1622 //
1623 // release transfer descriptors
1624 //
1625 m_DmaManager->Release(Descriptor, sizeof(QUEUE_TRANSFER_DESCRIPTOR));
1626
1627 }while(!IsListEmpty(&QueueHead->TransferDescriptorListHead));
1628
1629 if (m_DescriptorPacket)
1630 {
1631 //
1632 // release packet descriptor
1633 //
1634 m_DmaManager->Release(m_DescriptorPacket, sizeof(USB_DEFAULT_PIPE_SETUP_PACKET));
1635 }
1636
1637 //
1638 // release queue head
1639 //
1640 m_DmaManager->Release(QueueHead, sizeof(QUEUE_HEAD));
1641
1642 //
1643 // nullify pointers
1644 //
1645 m_QueueHead = 0;
1646 m_DescriptorPacket = 0;
1647 }
1648
1649 //-----------------------------------------------------------------------------------------
1650 BOOLEAN
1651 STDMETHODCALLTYPE
1652 CUSBRequest::IsQueueHeadComplete(
1653 struct _QUEUE_HEAD * QueueHead)
1654 {
1655 PLIST_ENTRY Entry;
1656 PQUEUE_TRANSFER_DESCRIPTOR Descriptor;
1657
1658 //
1659 // first check - is the queue head currently active
1660 //
1661 if (QueueHead->Token.Bits.Active)
1662 {
1663 //
1664 // queue head is active (currently processed)
1665 //
1666 return FALSE;
1667 }
1668
1669 if (QueueHead->Token.Bits.Halted)
1670 {
1671 //
1672 // error occured
1673 //
1674 DPRINT1("Found halted queue head %p\n", QueueHead);
1675 DumpQueueHead(QueueHead);
1676 //ASSERT(FALSE);
1677 return TRUE;
1678 }
1679
1680 //
1681 // loop list and see if there are any active descriptors
1682 //
1683 Entry = QueueHead->TransferDescriptorListHead.Flink;
1684 while(Entry != &QueueHead->TransferDescriptorListHead)
1685 {
1686 //
1687 // obtain descriptor from entry
1688 //
1689 Descriptor = (PQUEUE_TRANSFER_DESCRIPTOR)CONTAINING_RECORD(Entry, QUEUE_TRANSFER_DESCRIPTOR, DescriptorEntry);
1690 ASSERT(Descriptor);
1691 if (Descriptor->Token.Bits.Active)
1692 {
1693 //
1694 // descriptor is still active
1695 //
1696 return FALSE;
1697 }
1698
1699 //
1700 // move to next entry
1701 //
1702 Entry = Entry->Flink;
1703 }
1704
1705 DPRINT("QueueHead %p Addr %x is complete\n", QueueHead, QueueHead->PhysicalAddr);
1706
1707 //
1708 // no active descriptors found, queue head is finished
1709 //
1710 return TRUE;
1711 }
1712
1713 //-----------------------------------------------------------------------------------------
1714 ULONG
1715 CUSBRequest::InternalCalculateTransferLength()
1716 {
1717 if (!m_Irp)
1718 {
1719 //
1720 // FIXME: get length for control request
1721 //
1722 return m_TransferBufferLength;
1723 }
1724
1725 //
1726 // sanity check
1727 //
1728 ASSERT(m_EndpointDescriptor);
1729 if (USB_ENDPOINT_DIRECTION_IN(m_EndpointDescriptor->EndPointDescriptor.bEndpointAddress))
1730 {
1731 //
1732 // bulk in request
1733 // HACK: Properly determine transfer length
1734 //
1735 return m_TransferBufferLength;//m_TotalBytesTransferred;
1736 }
1737
1738 //
1739 // bulk out transfer
1740 //
1741 return m_TransferBufferLength;
1742 }
1743
1744 USB_DEVICE_SPEED
1745 CUSBRequest::GetSpeed()
1746 {
1747 return m_Speed;
1748 }
1749
1750 UCHAR
1751 CUSBRequest::GetInterval()
1752 {
1753 if (!m_EndpointDescriptor)
1754 return 0;
1755
1756 return m_EndpointDescriptor->EndPointDescriptor.bInterval;
1757 }
1758
1759 //-----------------------------------------------------------------------------------------
1760 NTSTATUS
1761 NTAPI
1762 InternalCreateUSBRequest(
1763 PUSBREQUEST *OutRequest)
1764 {
1765 PUSBREQUEST This;
1766
1767 //
1768 // allocate requests
1769 //
1770 This = new(NonPagedPool, TAG_USBEHCI) CUSBRequest(0);
1771 if (!This)
1772 {
1773 //
1774 // failed to allocate
1775 //
1776 return STATUS_INSUFFICIENT_RESOURCES;
1777 }
1778
1779 //
1780 // add reference count
1781 //
1782 This->AddRef();
1783
1784 //
1785 // return result
1786 //
1787 *OutRequest = (PUSBREQUEST)This;
1788
1789 //
1790 // done
1791 //
1792 return STATUS_SUCCESS;
1793 }