[HIDCLASS]
[reactos.git] / drivers / usb / usbehci_new / 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_DESCRIPTOR 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
66 // constructor / destructor
67 CUSBRequest(IUnknown *OuterUnknown){}
68 virtual ~CUSBRequest(){}
69
70 protected:
71 LONG m_Ref;
72
73 //
74 // memory manager for allocating setup packet / queue head / transfer descriptors
75 //
76 PDMAMEMORYMANAGER m_DmaManager;
77
78 //
79 // caller provided irp packet containing URB request
80 //
81 PIRP m_Irp;
82
83 //
84 // transfer buffer length
85 //
86 ULONG m_TransferBufferLength;
87
88 //
89 // current transfer length
90 //
91 ULONG m_TransferBufferLengthCompleted;
92
93 //
94 // Total Transfer Length
95 //
96 ULONG m_TotalBytesTransferred;
97
98 //
99 // transfer buffer MDL
100 //
101 PMDL m_TransferBufferMDL;
102
103 //
104 // caller provided setup packet
105 //
106 PUSB_DEFAULT_PIPE_SETUP_PACKET m_SetupPacket;
107
108 //
109 // completion event for callers who initialized request with setup packet
110 //
111 PKEVENT m_CompletionEvent;
112
113 //
114 // device address for callers who initialized it with device address
115 //
116 UCHAR m_DeviceAddress;
117
118 //
119 // store end point address
120 //
121 PUSB_ENDPOINT_DESCRIPTOR m_EndpointDescriptor;
122
123 //
124 // DMA queue head
125 //
126 PQUEUE_HEAD m_QueueHead;
127
128 //
129 // DMA transfer descriptors linked to the queue head
130 //
131 PQUEUE_TRANSFER_DESCRIPTOR m_TransferDescriptors[3];
132
133 //
134 // allocated setup packet from the DMA pool
135 //
136 PUSB_DEFAULT_PIPE_SETUP_PACKET m_DescriptorPacket;
137 PHYSICAL_ADDRESS m_DescriptorSetupPacket;
138
139 //
140 // stores the result of the operation
141 //
142 NTSTATUS m_NtStatusCode;
143 ULONG m_UrbStatusCode;
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_DESCRIPTOR 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_DESCRIPTOR)Urb->UrbBulkOrInterruptTransfer.PipeHandle;
325
326 }
327 break;
328 }
329 default:
330 DPRINT1("URB Function: not supported %x\n", Urb->UrbHeader.Function);
331 PC_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->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 }
599
600 //
601 // done
602 //
603 return TransferType;
604 }
605
606 UCHAR
607 CUSBRequest::InternalGetPidDirection()
608 {
609 ASSERT(m_Irp);
610 ASSERT(m_EndpointDescriptor);
611
612 //
613 // end point is defined in the low byte of bEndpointAddress
614 //
615 return (m_EndpointDescriptor->bEndpointAddress & USB_ENDPOINT_DIRECTION_MASK) >> 7;
616 }
617
618 //----------------------------------------------------------------------------------------
619 NTSTATUS
620 CUSBRequest::BuildControlTransferQueueHead(
621 PQUEUE_HEAD * OutHead)
622 {
623 NTSTATUS Status;
624 ULONG NumTransferDescriptors, Index;
625 PQUEUE_HEAD QueueHead;
626
627 //
628 // first allocate the queue head
629 //
630 Status = CreateQueueHead(&QueueHead);
631 if (!NT_SUCCESS(Status))
632 {
633 //
634 // failed to allocate queue head
635 //
636 return STATUS_INSUFFICIENT_RESOURCES;
637 }
638
639 //
640 // sanity check
641 //
642 PC_ASSERT(QueueHead);
643
644 //
645 // create setup packet
646 //
647 Status = BuildSetupPacket();
648 if (!NT_SUCCESS(Status))
649 {
650 //
651 // failed to allocate setup packet
652 //
653 return STATUS_INSUFFICIENT_RESOURCES;
654 }
655
656 //
657 // calculate num of transfer descriptors
658 //
659 NumTransferDescriptors = m_TransferBufferMDL != 0 ? 3 : 2;
660
661 //
662 // allocate transfer descriptors
663 //
664 for(Index = 0; Index < NumTransferDescriptors; Index++)
665 {
666 //
667 // allocate transfer descriptor
668 //
669 Status = CreateDescriptor(&m_TransferDescriptors[Index]);
670 if (!NT_SUCCESS(Status))
671 {
672 //
673 // failed to allocate transfer descriptor
674 //
675 return Status;
676 }
677 }
678
679 //
680 // now initialize the queue head
681 //
682 QueueHead->EndPointCharacteristics.DeviceAddress = GetDeviceAddress();
683
684 if (m_EndpointDescriptor)
685 {
686 //
687 // set endpoint address and max packet length
688 //
689 QueueHead->EndPointCharacteristics.EndPointNumber = m_EndpointDescriptor->bEndpointAddress & 0x0F;
690 QueueHead->EndPointCharacteristics.MaximumPacketLength = m_EndpointDescriptor->wMaxPacketSize;
691 }
692
693 QueueHead->Token.Bits.DataToggle = TRUE;
694
695 //
696 // setup descriptors
697 //
698 m_TransferDescriptors[0]->Token.Bits.PIDCode = PID_CODE_SETUP_TOKEN;
699 m_TransferDescriptors[0]->Token.Bits.TotalBytesToTransfer = sizeof(USB_DEFAULT_PIPE_SETUP_PACKET);
700 m_TransferDescriptors[0]->Token.Bits.DataToggle = FALSE;
701
702 if (m_TransferBufferMDL)
703 {
704 //
705 // setup in descriptor
706 //
707 m_TransferDescriptors[1]->Token.Bits.PIDCode = PID_CODE_IN_TOKEN;
708 m_TransferDescriptors[1]->Token.Bits.TotalBytesToTransfer = m_TransferBufferLength;
709
710 //
711 // FIXME: check if the request spawns over a page -> fill other members
712 //
713 PC_ASSERT(m_TransferBufferLength <= PAGE_SIZE);
714 m_TransferDescriptors[1]->BufferPointer[0] = MmGetPhysicalAddress(MmGetMdlVirtualAddress(m_TransferBufferMDL)).LowPart;
715
716 //
717 // setup out descriptor
718 //
719 m_TransferDescriptors[2]->Token.Bits.PIDCode = PID_CODE_OUT_TOKEN;
720 m_TransferDescriptors[2]->Token.Bits.TotalBytesToTransfer = 0;
721
722 //
723 // link descriptors
724 //
725 m_TransferDescriptors[0]->NextPointer = m_TransferDescriptors[1]->PhysicalAddr;
726
727 //
728 // special case, setup alternative next descriptor in case of error
729 // HAIKU links to dead descriptor
730 //
731 m_TransferDescriptors[0]->AlternateNextPointer = m_TransferDescriptors[2]->PhysicalAddr;
732 m_TransferDescriptors[1]->NextPointer = m_TransferDescriptors[2]->PhysicalAddr;
733 m_TransferDescriptors[1]->AlternateNextPointer = m_TransferDescriptors[2]->PhysicalAddr;
734
735 //
736 // interrupt on completion
737 //
738 m_TransferDescriptors[2]->Token.Bits.InterruptOnComplete = TRUE;
739
740 }
741 else
742 {
743 //
744 // no buffer, setup in descriptor
745 //
746 m_TransferDescriptors[1]->Token.Bits.PIDCode = PID_CODE_OUT_TOKEN;
747 m_TransferDescriptors[1]->Token.Bits.TotalBytesToTransfer = 0;
748
749 //
750 // link descriptors
751 //
752 m_TransferDescriptors[0]->NextPointer = m_TransferDescriptors[1]->PhysicalAddr;
753 m_TransferDescriptors[0]->AlternateNextPointer = m_TransferDescriptors[1]->PhysicalAddr;
754
755 //
756 // interrupt on completion
757 //
758 m_TransferDescriptors[1]->Token.Bits.InterruptOnComplete = TRUE;
759 }
760
761 //
762 // link setup packet into buffer - Physical Address!!!
763 //
764 m_TransferDescriptors[0]->BufferPointer[0] = (ULONG)PtrToUlong(m_DescriptorSetupPacket.LowPart);
765
766 //
767 // link transfer descriptors to queue head
768 //
769 QueueHead->NextPointer = m_TransferDescriptors[0]->PhysicalAddr;
770 /*
771 if (m_TransferBufferMDL)
772 QueueHead->AlternateNextPointer = m_TransferDescriptors[2]->PhysicalAddr;
773 else
774 QueueHead->AlternateNextPointer = m_TransferDescriptors[1]->PhysicalAddr;
775
776 QueueHead->EndPointCapabilities.InterruptScheduleMask = 0x0;
777 */
778 //
779 // store result
780 //
781 *OutHead = QueueHead;
782
783 //
784 // done
785 //
786 return STATUS_SUCCESS;
787 }
788
789 //----------------------------------------------------------------------------------------
790 NTSTATUS
791 CUSBRequest::BuildBulkTransferQueueHead(
792 PQUEUE_HEAD * OutHead)
793 {
794 NTSTATUS Status;
795 PQUEUE_HEAD QueueHead;
796 ULONG TransferDescriptorCount, Index;
797 ULONG BytesAvailable, BufferIndex;
798 PVOID Base;
799 ULONG PageOffset, CurrentTransferBufferLength;
800
801 //
802 // Allocate the queue head
803 //
804 Status = CreateQueueHead(&QueueHead);
805
806 if (!NT_SUCCESS(Status))
807 {
808 //
809 // failed to allocate queue heads
810 //
811 return STATUS_INSUFFICIENT_RESOURCES;
812 }
813
814 //
815 // sanity checks
816 //
817 PC_ASSERT(QueueHead);
818 PC_ASSERT(m_TransferBufferLength);
819
820 //
821 // Max default of 3 descriptors
822 //
823 TransferDescriptorCount = 3;
824
825 //
826 // get virtual base of mdl
827 //
828 Base = MmGetSystemAddressForMdlSafe(m_TransferBufferMDL, NormalPagePriority);
829
830 //
831 // Increase the size of last transfer, 0 in case this is the first
832 //
833 Base = (PVOID)((ULONG_PTR)Base + m_TransferBufferLengthCompleted);
834
835 PC_ASSERT(m_EndpointDescriptor);
836 PC_ASSERT(Base);
837
838 //
839 // Get the offset from page size
840 //
841 PageOffset = BYTE_OFFSET(Base);
842
843 //
844 // PageOffset should only be > 0 if this is the first transfer for this requests
845 //
846 if ((PageOffset != 0) && (m_TransferBufferLengthCompleted != 0))
847 {
848 ASSERT(FALSE);
849 }
850
851 //
852 // Calculate the size of this transfer
853 //
854 if ((PageOffset != 0) && ((m_TransferBufferLength - m_TransferBufferLengthCompleted) >= (PAGE_SIZE * 4) + PageOffset))
855 {
856 CurrentTransferBufferLength = (PAGE_SIZE * 4) + PageOffset;
857 }
858 else if ((m_TransferBufferLength - m_TransferBufferLengthCompleted) >= PAGE_SIZE * 5)
859 {
860 CurrentTransferBufferLength = PAGE_SIZE * 5;
861 }
862 else
863 CurrentTransferBufferLength = (m_TransferBufferLength - m_TransferBufferLengthCompleted);
864
865 //
866 // Add current transfer length to transfer length completed
867 //
868 m_TransferBufferLengthCompleted += CurrentTransferBufferLength;
869 BytesAvailable = CurrentTransferBufferLength;
870 DPRINT("CurrentTransferBufferLength %x, m_TransferBufferLengthCompleted %x\n", CurrentTransferBufferLength, m_TransferBufferLengthCompleted);
871
872 DPRINT("EndPointAddress %x\n", m_EndpointDescriptor->bEndpointAddress);
873 DPRINT("EndPointDirection %x\n", USB_ENDPOINT_DIRECTION_IN(m_EndpointDescriptor->bEndpointAddress));
874
875 DPRINT("Request %p Base Address %p TransferBytesLength %lu MDL %p\n", this, Base, BytesAvailable, m_TransferBufferMDL);
876 DPRINT("InternalGetPidDirection() %d EndPointAddress %x\n", InternalGetPidDirection(), m_EndpointDescriptor->bEndpointAddress & 0x0F);
877 DPRINT("Irp %p QueueHead %p\n", m_Irp, QueueHead);
878
879 //PC_ASSERT(InternalGetPidDirection() == USB_ENDPOINT_DIRECTION_IN(m_EndpointDescriptor->bEndpointAddress));
880
881 //
882 // Allocated transfer descriptors
883 //
884 for (Index = 0; Index < TransferDescriptorCount; Index++)
885 {
886 Status = CreateDescriptor(&m_TransferDescriptors[Index]);
887 if (!NT_SUCCESS(Status))
888 {
889 //
890 // Failed to allocate transfer descriptors
891 //
892
893 //
894 // Free QueueHead
895 //
896 FreeQueueHead(QueueHead);
897
898 //
899 // Free Descriptors
900 // FIXME: Implement FreeDescriptors
901 //
902 return Status;
903 }
904
905 //
906 // sanity check
907 //
908 PC_ASSERT(BytesAvailable);
909
910 //
911 // now setup transfer buffers
912 //
913 for(BufferIndex = 0; BufferIndex < 5; BufferIndex++)
914 {
915 //
916 // If this is the first buffer of the first descriptor and there is a PageOffset
917 //
918 if ((BufferIndex == 0) && (PageOffset != 0) && (Index == 0))
919 {
920 //
921 // use physical address
922 //
923 m_TransferDescriptors[Index]->BufferPointer[0] = MmGetPhysicalAddress(Base).LowPart;
924
925 //
926 // move to next page
927 //
928 Base = (PVOID)ROUND_TO_PAGES(Base);
929
930 //
931 // increment transfer bytes
932 //
933 if (CurrentTransferBufferLength > PAGE_SIZE - PageOffset)
934 m_TransferDescriptors[Index]->Token.Bits.TotalBytesToTransfer = PAGE_SIZE - PageOffset;
935 else
936 m_TransferDescriptors[Index]->Token.Bits.TotalBytesToTransfer = CurrentTransferBufferLength;
937
938 //
939 // decrement available byte count
940 //
941 BytesAvailable -= m_TransferDescriptors[Index]->Token.Bits.TotalBytesToTransfer;
942
943 DPRINT("TransferDescriptor %p BufferPointer %p BufferIndex %lu TotalBytes %lu Remaining %lu\n", m_TransferDescriptors[Index], m_TransferDescriptors[Index]->BufferPointer[BufferIndex],
944 BufferIndex, m_TransferDescriptors[Index]->Token.Bits.TotalBytesToTransfer, BytesAvailable);
945 }
946 else
947 {
948 //
949 // the following pages always start on byte zero of each page
950 //
951 PC_ASSERT(((ULONG_PTR)Base & (PAGE_SIZE-1)) == 0);
952
953 if (BytesAvailable >= PAGE_SIZE)
954 {
955 //
956 // store address
957 //
958 m_TransferDescriptors[Index]->BufferPointer[BufferIndex] = MmGetPhysicalAddress(Base).LowPart;
959
960 //
961 // move to next page
962 //
963 Base = (PVOID)((ULONG_PTR)Base + PAGE_SIZE);
964
965 //
966 // increment transfer descriptor bytes
967 //
968 m_TransferDescriptors[Index]->Token.Bits.TotalBytesToTransfer += PAGE_SIZE;
969
970 //
971 // decrement available byte count
972 //
973 BytesAvailable -= PAGE_SIZE;
974
975 DPRINT("TransferDescriptor %p BufferPointer %p BufferIndex %lu TotalBytes %lu Remaining %lu\n", m_TransferDescriptors[Index], m_TransferDescriptors[Index]->BufferPointer[BufferIndex],
976 BufferIndex, m_TransferDescriptors[Index]->Token.Bits.TotalBytesToTransfer, BytesAvailable);
977 }
978 else
979 {
980 PC_ASSERT(BytesAvailable);
981
982 //
983 // store address
984 //
985 m_TransferDescriptors[Index]->BufferPointer[BufferIndex] = MmGetPhysicalAddress(Base).LowPart;
986
987 //
988 // increment transfer descriptor bytes
989 //
990 m_TransferDescriptors[Index]->Token.Bits.TotalBytesToTransfer += BytesAvailable;
991
992 //
993 // decrement available byte count
994 //
995 BytesAvailable -= BytesAvailable;
996
997 //
998 // done as this is the last partial or full page
999 //
1000 DPRINT("TransferDescriptor %p BufferPointer %p BufferIndex %lu TotalBytes %lu Remaining %lu\n", m_TransferDescriptors[Index], m_TransferDescriptors[Index]->BufferPointer[BufferIndex],
1001 BufferIndex, m_TransferDescriptors[Index]->Token.Bits.TotalBytesToTransfer, BytesAvailable);
1002
1003 break;
1004 }
1005 }
1006
1007 //
1008 // Check if all bytes have been consumed
1009 //
1010 if (BytesAvailable == 0)
1011 break;
1012 }
1013
1014 //
1015 // store transfer bytes of descriptor
1016 //
1017 m_TransferDescriptors[Index]->TotalBytesToTransfer = m_TransferDescriptors[Index]->Token.Bits.TotalBytesToTransfer;
1018
1019 //
1020 // Go ahead and link descriptors
1021 //
1022 if (Index > 0)
1023 {
1024 m_TransferDescriptors[Index - 1]->NextPointer = m_TransferDescriptors[Index]->PhysicalAddr;
1025 }
1026
1027 //
1028 // setup direction
1029 //
1030 m_TransferDescriptors[Index]->Token.Bits.PIDCode = InternalGetPidDirection();
1031
1032 //
1033 // FIXME: performance penality?
1034 //
1035 m_TransferDescriptors[Index]->Token.Bits.InterruptOnComplete = TRUE;
1036
1037 //
1038 // FIXME need dead queue transfer descriptor?
1039 //
1040
1041 //
1042 // Check if all bytes have been consumed
1043 //
1044 if (BytesAvailable == 0)
1045 break;
1046 }
1047
1048 //
1049 // all bytes should have been consumed
1050 //
1051 PC_ASSERT(BytesAvailable == 0);
1052
1053 //
1054 // Initialize the QueueHead
1055 //
1056 QueueHead->EndPointCharacteristics.DeviceAddress = GetDeviceAddress();
1057
1058 if (m_EndpointDescriptor)
1059 {
1060 //
1061 // Set endpoint address and max packet length
1062 //
1063 QueueHead->EndPointCharacteristics.EndPointNumber = m_EndpointDescriptor->bEndpointAddress & 0x0F;
1064 QueueHead->EndPointCharacteristics.MaximumPacketLength = m_EndpointDescriptor->wMaxPacketSize;
1065 }
1066
1067 QueueHead->Token.Bits.DataToggle = TRUE;
1068
1069 //
1070 // link descriptor with queue head
1071 //
1072 QueueHead->NextPointer = m_TransferDescriptors[0]->PhysicalAddr;
1073
1074 //
1075 // store result
1076 //
1077 *OutHead = QueueHead;
1078
1079 //
1080 // done
1081 //
1082 return STATUS_SUCCESS;
1083 }
1084
1085 //----------------------------------------------------------------------------------------
1086 NTSTATUS
1087 CUSBRequest::CreateDescriptor(
1088 PQUEUE_TRANSFER_DESCRIPTOR *OutDescriptor)
1089 {
1090 PQUEUE_TRANSFER_DESCRIPTOR Descriptor;
1091 NTSTATUS Status;
1092 PHYSICAL_ADDRESS TransferDescriptorPhysicalAddress;
1093
1094 //
1095 // allocate descriptor
1096 //
1097 Status = m_DmaManager->Allocate(sizeof(QUEUE_TRANSFER_DESCRIPTOR), (PVOID*)&Descriptor, &TransferDescriptorPhysicalAddress);
1098 if (!NT_SUCCESS(Status))
1099 {
1100 //
1101 // failed to allocate transfer descriptor
1102 //
1103 return STATUS_INSUFFICIENT_RESOURCES;
1104 }
1105
1106 //
1107 // initialize transfer descriptor
1108 //
1109 Descriptor->NextPointer = TERMINATE_POINTER;
1110 Descriptor->AlternateNextPointer = TERMINATE_POINTER;
1111 Descriptor->Token.Bits.DataToggle = TRUE;
1112 Descriptor->Token.Bits.ErrorCounter = 0x03;
1113 Descriptor->Token.Bits.Active = TRUE;
1114 Descriptor->PhysicalAddr = TransferDescriptorPhysicalAddress.LowPart;
1115
1116 //
1117 // store result
1118 //
1119 *OutDescriptor = Descriptor;
1120
1121 //
1122 // done
1123 //
1124 return Status;
1125 }
1126
1127 //----------------------------------------------------------------------------------------
1128 NTSTATUS
1129 CUSBRequest::CreateQueueHead(
1130 PQUEUE_HEAD *OutQueueHead)
1131 {
1132 PQUEUE_HEAD QueueHead;
1133 PHYSICAL_ADDRESS QueueHeadPhysicalAddress;
1134 NTSTATUS Status;
1135
1136 //
1137 // allocate queue head
1138 //
1139 Status = m_DmaManager->Allocate(sizeof(QUEUE_HEAD), (PVOID*)&QueueHead, &QueueHeadPhysicalAddress);
1140
1141 if (!NT_SUCCESS(Status))
1142 {
1143 //
1144 // failed to allocate queue head
1145 //
1146 return STATUS_INSUFFICIENT_RESOURCES;
1147 }
1148
1149 //
1150 // initialize queue head
1151 //
1152 QueueHead->HorizontalLinkPointer = TERMINATE_POINTER;
1153 QueueHead->AlternateNextPointer = TERMINATE_POINTER;
1154 QueueHead->NextPointer = TERMINATE_POINTER;
1155
1156 //
1157 // 1 for non high speed, 0 for high speed device
1158 //
1159 QueueHead->EndPointCharacteristics.ControlEndPointFlag = 0;
1160 QueueHead->EndPointCharacteristics.HeadOfReclamation = FALSE;
1161 QueueHead->EndPointCharacteristics.MaximumPacketLength = 64;
1162
1163 //
1164 // Set NakCountReload to max value possible
1165 //
1166 QueueHead->EndPointCharacteristics.NakCountReload = 0xF;
1167
1168 //
1169 // Get the Initial Data Toggle from the QEDT
1170 //
1171 QueueHead->EndPointCharacteristics.QEDTDataToggleControl = FALSE;
1172
1173 //
1174 // FIXME: check if High Speed Device
1175 //
1176 QueueHead->EndPointCharacteristics.EndPointSpeed = QH_ENDPOINT_HIGHSPEED;
1177 QueueHead->EndPointCapabilities.NumberOfTransactionPerFrame = 0x03;
1178 QueueHead->Token.DWord = 0;
1179 QueueHead->Token.Bits.InterruptOnComplete = FALSE;
1180
1181 //
1182 // FIXME check if that is really needed
1183 //
1184 QueueHead->PhysicalAddr = QueueHeadPhysicalAddress.LowPart;
1185
1186 //
1187 // output queue head
1188 //
1189 *OutQueueHead = QueueHead;
1190
1191 //
1192 // done
1193 //
1194 return STATUS_SUCCESS;
1195 }
1196
1197 //----------------------------------------------------------------------------------------
1198 UCHAR
1199 CUSBRequest::GetDeviceAddress()
1200 {
1201 PIO_STACK_LOCATION IoStack;
1202 PURB Urb;
1203 PUSBDEVICE UsbDevice;
1204
1205 //
1206 // check if there is an irp provided
1207 //
1208 if (!m_Irp)
1209 {
1210 //
1211 // used provided address
1212 //
1213 return m_DeviceAddress;
1214 }
1215
1216 //
1217 // get current stack location
1218 //
1219 IoStack = IoGetCurrentIrpStackLocation(m_Irp);
1220
1221 //
1222 // get contained urb
1223 //
1224 Urb = (PURB)IoStack->Parameters.Others.Argument1;
1225
1226 //
1227 // check if there is a pipe handle provided
1228 //
1229 if (Urb->UrbHeader.UsbdDeviceHandle)
1230 {
1231 //
1232 // there is a device handle provided
1233 //
1234 UsbDevice = (PUSBDEVICE)Urb->UrbHeader.UsbdDeviceHandle;
1235
1236 //
1237 // return device address
1238 //
1239 return UsbDevice->GetDeviceAddress();
1240 }
1241
1242 //
1243 // no device handle provided, it is the host root bus
1244 //
1245 return 0;
1246 }
1247
1248 //----------------------------------------------------------------------------------------
1249 NTSTATUS
1250 CUSBRequest::BuildSetupPacket()
1251 {
1252 NTSTATUS Status;
1253
1254 //
1255 // allocate common buffer setup packet
1256 //
1257 Status = m_DmaManager->Allocate(sizeof(USB_DEFAULT_PIPE_SETUP_PACKET), (PVOID*)&m_DescriptorPacket, &m_DescriptorSetupPacket);
1258 if (!NT_SUCCESS(Status))
1259 {
1260 //
1261 // no memory
1262 //
1263 return Status;
1264 }
1265
1266 if (m_SetupPacket)
1267 {
1268 //
1269 // copy setup packet
1270 //
1271 RtlCopyMemory(m_DescriptorPacket, m_SetupPacket, sizeof(USB_DEFAULT_PIPE_SETUP_PACKET));
1272 }
1273 else
1274 {
1275 //
1276 // build setup packet from urb
1277 //
1278 Status = BuildSetupPacketFromURB();
1279 }
1280
1281 //
1282 // done
1283 //
1284 return Status;
1285 }
1286
1287
1288 NTSTATUS
1289 CUSBRequest::BuildSetupPacketFromURB()
1290 {
1291 PIO_STACK_LOCATION IoStack;
1292 PURB Urb;
1293 NTSTATUS Status = STATUS_NOT_IMPLEMENTED;
1294
1295 //
1296 // sanity checks
1297 //
1298 PC_ASSERT(m_Irp);
1299 PC_ASSERT(m_DescriptorPacket);
1300
1301 //
1302 // get stack location
1303 //
1304 IoStack = IoGetCurrentIrpStackLocation(m_Irp);
1305
1306 //
1307 // get urb
1308 //
1309 Urb = (PURB)IoStack->Parameters.Others.Argument1;
1310
1311 //
1312 // zero descriptor packet
1313 //
1314 RtlZeroMemory(m_DescriptorPacket, sizeof(USB_DEFAULT_PIPE_SETUP_PACKET));
1315
1316
1317 switch (Urb->UrbHeader.Function)
1318 {
1319 /* CLEAR FEATURE */
1320 case URB_FUNCTION_CLEAR_FEATURE_TO_DEVICE:
1321 case URB_FUNCTION_CLEAR_FEATURE_TO_INTERFACE:
1322 case URB_FUNCTION_CLEAR_FEATURE_TO_ENDPOINT:
1323 UNIMPLEMENTED
1324 break;
1325
1326 /* GET CONFIG */
1327 case URB_FUNCTION_GET_CONFIGURATION:
1328 m_DescriptorPacket->bRequest = USB_REQUEST_GET_CONFIGURATION;
1329 m_DescriptorPacket->bmRequestType.B = 0x80;
1330 m_DescriptorPacket->wLength = 1;
1331 break;
1332
1333 /* GET DESCRIPTOR */
1334 case URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE:
1335 m_DescriptorPacket->bRequest = USB_REQUEST_GET_DESCRIPTOR;
1336 m_DescriptorPacket->wValue.LowByte = Urb->UrbControlDescriptorRequest.Index;
1337 m_DescriptorPacket->wValue.HiByte = Urb->UrbControlDescriptorRequest.DescriptorType;
1338 m_DescriptorPacket->wIndex.W = Urb->UrbControlDescriptorRequest.LanguageId;
1339 m_DescriptorPacket->wLength = Urb->UrbControlDescriptorRequest.TransferBufferLength;
1340 m_DescriptorPacket->bmRequestType.B = 0x80;
1341 break;
1342
1343 /* GET INTERFACE */
1344 case URB_FUNCTION_GET_INTERFACE:
1345 m_DescriptorPacket->bRequest = USB_REQUEST_GET_CONFIGURATION;
1346 m_DescriptorPacket->wIndex.W = Urb->UrbControlGetStatusRequest.Index;
1347 m_DescriptorPacket->bmRequestType.B = 0x80;
1348 m_DescriptorPacket->wLength = 1;
1349 break;
1350
1351 /* GET STATUS */
1352 case URB_FUNCTION_GET_STATUS_FROM_DEVICE:
1353 m_DescriptorPacket->bRequest = USB_REQUEST_GET_STATUS;
1354 ASSERT(Urb->UrbControlGetStatusRequest.Index == 0);
1355 m_DescriptorPacket->wIndex.W = Urb->UrbControlGetStatusRequest.Index;
1356 m_DescriptorPacket->bmRequestType.B = 0x80;
1357 m_DescriptorPacket->wLength = 2;
1358 break;
1359
1360 case URB_FUNCTION_GET_STATUS_FROM_INTERFACE:
1361 m_DescriptorPacket->bRequest = USB_REQUEST_GET_STATUS;
1362 ASSERT(Urb->UrbControlGetStatusRequest.Index != 0);
1363 m_DescriptorPacket->wIndex.W = Urb->UrbControlGetStatusRequest.Index;
1364 m_DescriptorPacket->bmRequestType.B = 0x81;
1365 m_DescriptorPacket->wLength = 2;
1366 break;
1367
1368 case URB_FUNCTION_GET_STATUS_FROM_ENDPOINT:
1369 m_DescriptorPacket->bRequest = USB_REQUEST_GET_STATUS;
1370 ASSERT(Urb->UrbControlGetStatusRequest.Index != 0);
1371 m_DescriptorPacket->wIndex.W = Urb->UrbControlGetStatusRequest.Index;
1372 m_DescriptorPacket->bmRequestType.B = 0x82;
1373 m_DescriptorPacket->wLength = 2;
1374 break;
1375
1376 /* SET ADDRESS */
1377
1378 /* SET CONFIG */
1379 case URB_FUNCTION_SELECT_CONFIGURATION:
1380 m_DescriptorPacket->bRequest = USB_REQUEST_SET_CONFIGURATION;
1381 m_DescriptorPacket->wValue.W = Urb->UrbSelectConfiguration.ConfigurationDescriptor->bConfigurationValue;
1382 m_DescriptorPacket->wIndex.W = 0;
1383 m_DescriptorPacket->wLength = 0;
1384 m_DescriptorPacket->bmRequestType.B = 0x00;
1385 break;
1386
1387 /* SET DESCRIPTOR */
1388 case URB_FUNCTION_SET_DESCRIPTOR_TO_DEVICE:
1389 case URB_FUNCTION_SET_DESCRIPTOR_TO_INTERFACE:
1390 case URB_FUNCTION_SET_DESCRIPTOR_TO_ENDPOINT:
1391 UNIMPLEMENTED
1392 break;
1393
1394 /* SET FEATURE */
1395 case URB_FUNCTION_SET_FEATURE_TO_DEVICE:
1396 m_DescriptorPacket->bRequest = USB_REQUEST_SET_FEATURE;
1397 ASSERT(Urb->UrbControlGetStatusRequest.Index == 0);
1398 m_DescriptorPacket->wIndex.W = Urb->UrbControlGetStatusRequest.Index;
1399 m_DescriptorPacket->bmRequestType.B = 0x80;
1400 break;
1401
1402 case URB_FUNCTION_SET_FEATURE_TO_INTERFACE:
1403 m_DescriptorPacket->bRequest = USB_REQUEST_SET_FEATURE;
1404 ASSERT(Urb->UrbControlGetStatusRequest.Index == 0);
1405 m_DescriptorPacket->wIndex.W = Urb->UrbControlGetStatusRequest.Index;
1406 m_DescriptorPacket->bmRequestType.B = 0x81;
1407 break;
1408
1409 case URB_FUNCTION_SET_FEATURE_TO_ENDPOINT:
1410 m_DescriptorPacket->bRequest = USB_REQUEST_SET_FEATURE;
1411 ASSERT(Urb->UrbControlGetStatusRequest.Index == 0);
1412 m_DescriptorPacket->wIndex.W = Urb->UrbControlGetStatusRequest.Index;
1413 m_DescriptorPacket->bmRequestType.B = 0x82;
1414 break;
1415
1416 /* SET INTERFACE*/
1417 case URB_FUNCTION_SELECT_INTERFACE:
1418 m_DescriptorPacket->bRequest = USB_REQUEST_SET_INTERFACE;
1419 m_DescriptorPacket->wValue.W = Urb->UrbSelectInterface.Interface.AlternateSetting;
1420 m_DescriptorPacket->wIndex.W = Urb->UrbSelectInterface.Interface.InterfaceNumber;
1421 m_DescriptorPacket->wLength = 0;
1422 m_DescriptorPacket->bmRequestType.B = 0x01;
1423 break;
1424
1425 /* SYNC FRAME */
1426 case URB_FUNCTION_SYNC_RESET_PIPE_AND_CLEAR_STALL:
1427 UNIMPLEMENTED
1428 break;
1429 default:
1430 UNIMPLEMENTED
1431 break;
1432 }
1433
1434 return Status;
1435 }
1436
1437 //----------------------------------------------------------------------------------------
1438 VOID
1439 CUSBRequest::GetResultStatus(
1440 OUT OPTIONAL NTSTATUS * NtStatusCode,
1441 OUT OPTIONAL PULONG UrbStatusCode)
1442 {
1443 //
1444 // sanity check
1445 //
1446 PC_ASSERT(m_CompletionEvent);
1447
1448 //
1449 // wait for the operation to complete
1450 //
1451 KeWaitForSingleObject(m_CompletionEvent, Executive, KernelMode, FALSE, NULL);
1452
1453 //
1454 // copy status
1455 //
1456 if (NtStatusCode)
1457 {
1458 *NtStatusCode = m_NtStatusCode;
1459 }
1460
1461 //
1462 // copy urb status
1463 //
1464 if (UrbStatusCode)
1465 {
1466 *UrbStatusCode = m_UrbStatusCode;
1467 }
1468
1469 }
1470
1471
1472 //-----------------------------------------------------------------------------------------
1473 BOOLEAN
1474 CUSBRequest::IsRequestInitialized()
1475 {
1476 if (m_Irp || m_SetupPacket)
1477 {
1478 //
1479 // request is initialized
1480 //
1481 return TRUE;
1482 }
1483
1484 //
1485 // request is not initialized
1486 //
1487 return FALSE;
1488 }
1489
1490 //-----------------------------------------------------------------------------------------
1491 BOOLEAN
1492 CUSBRequest::ShouldReleaseRequestAfterCompletion()
1493 {
1494 if (m_Irp)
1495 {
1496 //
1497 // the request is completed, release it
1498 //
1499 return TRUE;
1500 }
1501 else
1502 {
1503 //
1504 // created with an setup packet, don't release
1505 //
1506 return FALSE;
1507 }
1508 }
1509
1510 //-----------------------------------------------------------------------------------------
1511 VOID
1512 CUSBRequest::FreeQueueHead(
1513 IN struct _QUEUE_HEAD * QueueHead)
1514 {
1515 LONG DescriptorCount;
1516
1517 //
1518 // FIXME: support chained queue heads
1519 //
1520 //PC_ASSERT(QueueHead == m_QueueHead);
1521
1522 //
1523 // release queue head
1524 //
1525 m_DmaManager->Release(QueueHead, sizeof(QUEUE_HEAD));
1526
1527 //
1528 // nullify pointer
1529 //
1530 m_QueueHead = 0;
1531
1532 //
1533 // release transfer descriptors
1534 //
1535 for (DescriptorCount = 0; DescriptorCount < 3; DescriptorCount++)
1536 {
1537 if (m_TransferDescriptors[DescriptorCount])
1538 {
1539 //
1540 // Calculate Total Bytes Transferred
1541 // FIXME: Is this the correct method of determine bytes transferred?
1542 //
1543 if (USB_ENDPOINT_TYPE_BULK == GetTransferType())
1544 {
1545 //
1546 // sanity check
1547 //
1548 ASSERT(m_EndpointDescriptor);
1549
1550 if (USB_ENDPOINT_DIRECTION_IN(m_EndpointDescriptor->bEndpointAddress))
1551 {
1552 DPRINT("m_TotalBytesTransferred %x, %x - %x\n",
1553 m_TotalBytesTransferred,
1554 m_TransferDescriptors[DescriptorCount]->TotalBytesToTransfer,
1555 m_TransferDescriptors[DescriptorCount]->Token.Bits.TotalBytesToTransfer);
1556
1557 m_TotalBytesTransferred +=
1558 m_TransferDescriptors[DescriptorCount]->TotalBytesToTransfer -
1559 m_TransferDescriptors[DescriptorCount]->Token.Bits.TotalBytesToTransfer;
1560 }
1561 }
1562
1563 //
1564 // release transfer descriptors
1565 //
1566 m_DmaManager->Release(m_TransferDescriptors[DescriptorCount], sizeof(QUEUE_TRANSFER_DESCRIPTOR));
1567 m_TransferDescriptors[DescriptorCount] = 0;
1568 }
1569 }
1570
1571 if (m_DescriptorPacket)
1572 {
1573 //
1574 // release packet descriptor
1575 //
1576 m_DmaManager->Release(m_DescriptorPacket, sizeof(USB_DEFAULT_PIPE_SETUP_PACKET));
1577 m_DescriptorPacket = 0;
1578 }
1579 }
1580
1581 //-----------------------------------------------------------------------------------------
1582 BOOLEAN
1583 CUSBRequest::IsQueueHeadComplete(
1584 struct _QUEUE_HEAD * QueueHead)
1585 {
1586 ULONG Index;
1587
1588 //
1589 // first check - is the queue head currently active
1590 //
1591 if (QueueHead->Token.Bits.Active)
1592 {
1593 //
1594 // queue head is active (currently processed)
1595 //
1596 return FALSE;
1597 }
1598
1599 //
1600 // FIXME: support chained queue heads
1601 //
1602 for(Index = 0; Index < 3; Index++)
1603 {
1604 //
1605 // check transfer descriptors for completion
1606 //
1607 if (m_TransferDescriptors[Index])
1608 {
1609 //
1610 // check for serious error
1611 //
1612 //PC_ASSERT(m_TransferDescriptors[Index]->Token.Bits.Halted == 0);
1613
1614 //
1615 // the transfer descriptor should be in the same state as the queue head
1616 //
1617 //PC_ASSERT(m_TransferDescriptors[Index]->Token.Bits.Active == 0);
1618 }
1619 }
1620
1621 return TRUE;
1622 }
1623
1624 //-----------------------------------------------------------------------------------------
1625 VOID
1626 CUSBRequest::GetTransferBuffer(
1627 OUT PMDL * OutMDL,
1628 OUT PULONG TransferLength)
1629 {
1630 // sanity checks
1631 PC_ASSERT(OutMDL);
1632 PC_ASSERT(TransferLength);
1633
1634 *OutMDL = m_TransferBufferMDL;
1635 *TransferLength = m_TransferBufferLength;
1636 }
1637 //-----------------------------------------------------------------------------------------
1638 ULONG
1639 CUSBRequest::InternalCalculateTransferLength()
1640 {
1641 if (!m_Irp)
1642 {
1643 //
1644 // FIXME: get length for control request
1645 //
1646 return m_TransferBufferLength;
1647 }
1648
1649 //
1650 // sanity check
1651 //
1652 ASSERT(m_EndpointDescriptor);
1653
1654 if (USB_ENDPOINT_DIRECTION_IN(m_EndpointDescriptor->bEndpointAddress))
1655 {
1656 //
1657 // bulk in request
1658 // HACK: Properly determine transfer length
1659 //
1660 return m_TransferBufferLength;//m_TotalBytesTransferred;
1661 }
1662
1663 //
1664 // bulk out transfer
1665 //
1666 return m_TransferBufferLength;
1667 }
1668
1669 //-----------------------------------------------------------------------------------------
1670 NTSTATUS
1671 InternalCreateUSBRequest(
1672 PUSBREQUEST *OutRequest)
1673 {
1674 PUSBREQUEST This;
1675
1676 //
1677 // allocate requests
1678 //
1679 This = new(NonPagedPool, TAG_USBEHCI) CUSBRequest(0);
1680 if (!This)
1681 {
1682 //
1683 // failed to allocate
1684 //
1685 return STATUS_INSUFFICIENT_RESOURCES;
1686 }
1687
1688 //
1689 // add reference count
1690 //
1691 This->AddRef();
1692
1693 //
1694 // return result
1695 //
1696 *OutRequest = (PUSBREQUEST)This;
1697
1698 //
1699 // done
1700 //
1701 return STATUS_SUCCESS;
1702 }