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