[USBEHCI][USBOHCI][USBUHCI]
[reactos.git] / reactos / drivers / usb / usbuhci / usb_request.cpp
1 /*
2 * PROJECT: ReactOS Universal Serial Bus Host Controller Interface
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: drivers/usb/usbuhci/usb_request.cpp
5 * PURPOSE: USB UHCI device driver.
6 * PROGRAMMERS:
7 * Michael Martin (michael.martin@reactos.org)
8 * Johannes Anderwald (johannes.anderwald@reactos.org)
9 */
10
11 #include "usbuhci.h"
12
13 #define NDEBUG
14 #include <debug.h>
15
16 class CUSBRequest : public IUHCIRequest
17 {
18 public:
19 STDMETHODIMP QueryInterface( REFIID InterfaceId, PVOID* Interface);
20
21 STDMETHODIMP_(ULONG) AddRef()
22 {
23 InterlockedIncrement(&m_Ref);
24 return m_Ref;
25 }
26 STDMETHODIMP_(ULONG) Release()
27 {
28 InterlockedDecrement(&m_Ref);
29
30 if (!m_Ref)
31 {
32 delete this;
33 return 0;
34 }
35 return m_Ref;
36 }
37
38 // com
39 IMP_IUSBREQUEST
40 IMP_IUHCIREQUEST
41
42 // local functions
43 ULONG InternalGetTransferType();
44 UCHAR InternalGetPidDirection();
45 UCHAR GetDeviceAddress();
46 NTSTATUS BuildSetupPacket();
47 NTSTATUS BuildSetupPacketFromURB();
48 UCHAR GetEndpointAddress();
49 USHORT GetMaxPacketSize();
50 NTSTATUS CreateDescriptor(PUHCI_TRANSFER_DESCRIPTOR *OutDescriptor, IN UCHAR PidCode, ULONG BufferLength);
51 NTSTATUS BuildControlTransferDescriptor(IN PUHCI_QUEUE_HEAD * OutQueueHead);
52 NTSTATUS BuildBulkInterruptTransferDescriptor(IN PUHCI_QUEUE_HEAD * OutQueueHead);
53 NTSTATUS BuildQueueHead(OUT PUHCI_QUEUE_HEAD *OutQueueHead);
54 VOID FreeDescriptor(IN PUHCI_TRANSFER_DESCRIPTOR Descriptor);
55 NTSTATUS BuildTransferDescriptorChain(IN PVOID TransferBuffer, IN ULONG TransferBufferLength, IN UCHAR PidCode, IN UCHAR InitialDataToggle, OUT PUHCI_TRANSFER_DESCRIPTOR * OutFirstDescriptor, OUT PUHCI_TRANSFER_DESCRIPTOR * OutLastDescriptor, OUT PULONG OutTransferBufferOffset, OUT PUCHAR OutDataToggle);
56
57 // constructor / destructor
58 CUSBRequest(IUnknown *OuterUnknown);
59 virtual ~CUSBRequest();
60
61 protected:
62 LONG m_Ref;
63
64 //
65 // memory manager for allocating setup packet / queue head / transfer descriptors
66 //
67 PDMAMEMORYMANAGER m_DmaManager;
68
69 //
70 // caller provided irp packet containing URB request
71 //
72 PIRP m_Irp;
73
74 //
75 // transfer buffer length
76 //
77 ULONG m_TransferBufferLength;
78
79 //
80 // current transfer length
81 //
82 ULONG m_TransferBufferLengthCompleted;
83
84 //
85 // Total Transfer Length
86 //
87 ULONG m_TotalBytesTransferred;
88
89 //
90 // transfer buffer MDL
91 //
92 PMDL m_TransferBufferMDL;
93
94 //
95 // caller provided setup packet
96 //
97 PUSB_DEFAULT_PIPE_SETUP_PACKET m_SetupPacket;
98
99 //
100 // completion event for callers who initialized request with setup packet
101 //
102 PKEVENT m_CompletionEvent;
103
104 //
105 // device address for callers who initialized it with device address
106 //
107 UCHAR m_DeviceAddress;
108
109 //
110 // store end point address
111 //
112 PUSB_ENDPOINT m_EndpointDescriptor;
113
114 //
115 // allocated setup packet from the DMA pool
116 //
117 PUSB_DEFAULT_PIPE_SETUP_PACKET m_DescriptorPacket;
118 PHYSICAL_ADDRESS m_DescriptorSetupPacket;
119
120 //
121 // stores the result of the operation
122 //
123 NTSTATUS m_NtStatusCode;
124 ULONG m_UrbStatusCode;
125
126 //
127 // store device speed
128 //
129 USB_DEVICE_SPEED m_DeviceSpeed;
130
131 // base
132 PVOID m_Base;
133
134 };
135
136 //----------------------------------------------------------------------------------------
137 CUSBRequest::CUSBRequest(IUnknown *OuterUnknown) :
138 m_CompletionEvent(NULL)
139 {
140 UNREFERENCED_PARAMETER(OuterUnknown);
141 }
142
143 //----------------------------------------------------------------------------------------
144 CUSBRequest::~CUSBRequest()
145 {
146 if (m_CompletionEvent != NULL)
147 {
148 ExFreePoolWithTag(m_CompletionEvent, TAG_USBUHCI);
149 }
150 }
151
152 //----------------------------------------------------------------------------------------
153 NTSTATUS
154 STDMETHODCALLTYPE
155 CUSBRequest::QueryInterface(
156 IN REFIID refiid,
157 OUT PVOID* Output)
158 {
159 return STATUS_UNSUCCESSFUL;
160 }
161
162 //----------------------------------------------------------------------------------------
163 NTSTATUS
164 CUSBRequest::InitializeWithSetupPacket(
165 IN PDMAMEMORYMANAGER DmaManager,
166 IN PUSB_DEFAULT_PIPE_SETUP_PACKET SetupPacket,
167 IN PUSBDEVICE Device,
168 IN OPTIONAL struct _USB_ENDPOINT * EndpointDescriptor,
169 IN OUT ULONG TransferBufferLength,
170 IN OUT PMDL TransferBuffer)
171 {
172 //
173 // sanity checks
174 //
175 PC_ASSERT(DmaManager);
176 PC_ASSERT(SetupPacket);
177
178 //
179 // initialize packet
180 //
181 m_DmaManager = DmaManager;
182 m_SetupPacket = SetupPacket;
183 m_TransferBufferLength = TransferBufferLength;
184 m_TransferBufferMDL = TransferBuffer;
185 m_DeviceAddress = Device->GetDeviceAddress();
186 m_EndpointDescriptor = EndpointDescriptor;
187 m_TotalBytesTransferred = 0;
188 m_DeviceSpeed = Device->GetSpeed();
189
190 //
191 // Set Length Completed to 0
192 //
193 m_TransferBufferLengthCompleted = 0;
194
195 //
196 // allocate completion event
197 //
198 m_CompletionEvent = (PKEVENT)ExAllocatePoolWithTag(NonPagedPool, sizeof(KEVENT), TAG_USBUHCI);
199 if (!m_CompletionEvent)
200 {
201 //
202 // failed to allocate completion event
203 //
204 return STATUS_INSUFFICIENT_RESOURCES;
205 }
206
207 //
208 // initialize completion event
209 //
210 KeInitializeEvent(m_CompletionEvent, NotificationEvent, FALSE);
211
212 //
213 // done
214 //
215 return STATUS_SUCCESS;
216 }
217 //----------------------------------------------------------------------------------------
218 NTSTATUS
219 CUSBRequest::InitializeWithIrp(
220 IN PDMAMEMORYMANAGER DmaManager,
221 IN PUSBDEVICE Device,
222 IN OUT PIRP Irp)
223 {
224 PIO_STACK_LOCATION IoStack;
225 PURB Urb;
226
227 //
228 // sanity checks
229 //
230 PC_ASSERT(DmaManager);
231 PC_ASSERT(Irp);
232
233 m_DmaManager = DmaManager;
234 m_TotalBytesTransferred = 0;
235 m_DeviceSpeed = Device->GetSpeed();
236
237 //
238 // get current irp stack location
239 //
240 IoStack = IoGetCurrentIrpStackLocation(Irp);
241
242 //
243 // sanity check
244 //
245 PC_ASSERT(IoStack->MajorFunction == IRP_MJ_INTERNAL_DEVICE_CONTROL);
246 PC_ASSERT(IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_INTERNAL_USB_SUBMIT_URB);
247 PC_ASSERT(IoStack->Parameters.Others.Argument1 != 0);
248
249 //
250 // get urb
251 //
252 Urb = (PURB)IoStack->Parameters.Others.Argument1;
253
254 //
255 // store irp
256 //
257 m_Irp = Irp;
258
259 //
260 // check function type
261 //
262 switch (Urb->UrbHeader.Function)
263 {
264 case URB_FUNCTION_ISOCH_TRANSFER:
265 {
266 //
267 // there must be at least one packet
268 //
269 ASSERT(Urb->UrbIsochronousTransfer.NumberOfPackets);
270
271 //
272 // is there data to be transferred
273 //
274 if (Urb->UrbIsochronousTransfer.TransferBufferLength)
275 {
276 //
277 // Check if there is a MDL
278 //
279 if (!Urb->UrbBulkOrInterruptTransfer.TransferBufferMDL)
280 {
281 //
282 // sanity check
283 //
284 PC_ASSERT(Urb->UrbBulkOrInterruptTransfer.TransferBuffer);
285
286 //
287 // Create one using TransferBuffer
288 //
289 DPRINT("Creating Mdl from Urb Buffer %p Length %lu\n", Urb->UrbBulkOrInterruptTransfer.TransferBuffer, Urb->UrbBulkOrInterruptTransfer.TransferBufferLength);
290 m_TransferBufferMDL = IoAllocateMdl(Urb->UrbBulkOrInterruptTransfer.TransferBuffer,
291 Urb->UrbBulkOrInterruptTransfer.TransferBufferLength,
292 FALSE,
293 FALSE,
294 NULL);
295
296 if (!m_TransferBufferMDL)
297 {
298 //
299 // failed to allocate mdl
300 //
301 return STATUS_INSUFFICIENT_RESOURCES;
302 }
303
304 //
305 // build mdl for non paged pool
306 // FIXME: Does hub driver already do this when passing MDL?
307 //
308 MmBuildMdlForNonPagedPool(m_TransferBufferMDL);
309 }
310 else
311 {
312 //
313 // use provided mdl
314 //
315 m_TransferBufferMDL = Urb->UrbIsochronousTransfer.TransferBufferMDL;
316 }
317 }
318
319 //
320 // save buffer length
321 //
322 m_TransferBufferLength = Urb->UrbIsochronousTransfer.TransferBufferLength;
323
324 //
325 // Set Length Completed to 0
326 //
327 m_TransferBufferLengthCompleted = 0;
328
329 //
330 // get endpoint descriptor
331 //
332 m_EndpointDescriptor = (PUSB_ENDPOINT)Urb->UrbIsochronousTransfer.PipeHandle;
333
334 //
335 // completed initialization
336 //
337 break;
338 }
339 //
340 // luckily those request have the same structure layout
341 //
342 case URB_FUNCTION_CLASS_INTERFACE:
343 case URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE:
344 case URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER:
345 {
346 //
347 // bulk interrupt transfer
348 //
349 if (Urb->UrbBulkOrInterruptTransfer.TransferBufferLength)
350 {
351 //
352 // Check if there is a MDL
353 //
354 if (!Urb->UrbBulkOrInterruptTransfer.TransferBufferMDL)
355 {
356 //
357 // sanity check
358 //
359 PC_ASSERT(Urb->UrbBulkOrInterruptTransfer.TransferBuffer);
360
361 //
362 // Create one using TransferBuffer
363 //
364 DPRINT("Creating Mdl from Urb Buffer %p Length %lu\n", Urb->UrbBulkOrInterruptTransfer.TransferBuffer, Urb->UrbBulkOrInterruptTransfer.TransferBufferLength);
365 m_TransferBufferMDL = IoAllocateMdl(Urb->UrbBulkOrInterruptTransfer.TransferBuffer,
366 Urb->UrbBulkOrInterruptTransfer.TransferBufferLength,
367 FALSE,
368 FALSE,
369 NULL);
370
371 if (!m_TransferBufferMDL)
372 {
373 //
374 // failed to allocate mdl
375 //
376 return STATUS_INSUFFICIENT_RESOURCES;
377 }
378
379 //
380 // build mdl for non paged pool
381 // FIXME: Does hub driver already do this when passing MDL?
382 //
383 MmBuildMdlForNonPagedPool(m_TransferBufferMDL);
384
385 //
386 // Keep that ehci created the MDL and needs to free it.
387 //
388 }
389 else
390 {
391 m_TransferBufferMDL = Urb->UrbBulkOrInterruptTransfer.TransferBufferMDL;
392 }
393
394 //
395 // save buffer length
396 //
397 m_TransferBufferLength = Urb->UrbBulkOrInterruptTransfer.TransferBufferLength;
398
399 //
400 // Set Length Completed to 0
401 //
402 m_TransferBufferLengthCompleted = 0;
403
404 //
405 // get endpoint descriptor
406 //
407 m_EndpointDescriptor = (PUSB_ENDPOINT)Urb->UrbBulkOrInterruptTransfer.PipeHandle;
408
409 }
410 break;
411 }
412 default:
413 DPRINT1("URB Function: not supported %x\n", Urb->UrbHeader.Function);
414 PC_ASSERT(FALSE);
415 }
416
417 //
418 // done
419 //
420 return STATUS_SUCCESS;
421
422 }
423
424 //----------------------------------------------------------------------------------------
425 BOOLEAN
426 CUSBRequest::IsRequestComplete()
427 {
428 //
429 // FIXME: check if request was split
430 //
431
432 //
433 // Check if the transfer was completed, only valid for Bulk Transfers
434 //
435 if ((m_TransferBufferLengthCompleted < m_TransferBufferLength)
436 && (GetTransferType() == USB_ENDPOINT_TYPE_BULK))
437 {
438 //
439 // Transfer not completed
440 //
441 return FALSE;
442 }
443 return TRUE;
444 }
445 //----------------------------------------------------------------------------------------
446 ULONG
447 CUSBRequest::GetTransferType()
448 {
449 //
450 // call internal implementation
451 //
452 return InternalGetTransferType();
453 }
454
455 USHORT
456 CUSBRequest::GetMaxPacketSize()
457 {
458 if (!m_EndpointDescriptor)
459 {
460 //
461 // control request
462 //
463 return 0;
464 }
465
466 ASSERT(m_Irp);
467 ASSERT(m_EndpointDescriptor);
468
469 //
470 // return max packet size
471 //
472 return m_EndpointDescriptor->EndPointDescriptor.wMaxPacketSize;
473 }
474
475 UCHAR
476 CUSBRequest::GetInterval()
477 {
478 ASSERT(m_EndpointDescriptor);
479 ASSERT((m_EndpointDescriptor->EndPointDescriptor.bmAttributes & USB_ENDPOINT_TYPE_MASK) == USB_ENDPOINT_TYPE_INTERRUPT);
480
481 //
482 // return interrupt interval
483 //
484 return m_EndpointDescriptor->EndPointDescriptor.bInterval;
485 }
486
487 UCHAR
488 CUSBRequest::GetEndpointAddress()
489 {
490 if (!m_EndpointDescriptor)
491 {
492 //
493 // control request
494 //
495 return 0;
496 }
497
498 ASSERT(m_Irp);
499 ASSERT(m_EndpointDescriptor);
500
501 //
502 // endpoint number is between 1-15
503 //
504 return (m_EndpointDescriptor->EndPointDescriptor.bEndpointAddress & 0xF);
505 }
506
507 //----------------------------------------------------------------------------------------
508 ULONG
509 CUSBRequest::InternalGetTransferType()
510 {
511 ULONG TransferType;
512
513 //
514 // check if an irp is provided
515 //
516 if (m_Irp)
517 {
518 ASSERT(m_EndpointDescriptor);
519
520 //
521 // end point is defined in the low byte of bmAttributes
522 //
523 TransferType = (m_EndpointDescriptor->EndPointDescriptor.bmAttributes & USB_ENDPOINT_TYPE_MASK);
524 }
525 else
526 {
527 //
528 // initialized with setup packet, must be a control transfer
529 //
530 TransferType = USB_ENDPOINT_TYPE_CONTROL;
531 }
532
533 //
534 // done
535 //
536 return TransferType;
537 }
538
539 UCHAR
540 CUSBRequest::InternalGetPidDirection()
541 {
542 if (m_EndpointDescriptor)
543 {
544 //
545 // end point direction is highest bit in bEndpointAddress
546 //
547 return (m_EndpointDescriptor->EndPointDescriptor.bEndpointAddress & USB_ENDPOINT_DIRECTION_MASK) >> 7;
548 }
549 else
550 {
551 //
552 // request arrives on the control pipe, extract direction from setup packet
553 //
554 ASSERT(m_SetupPacket);
555 return (m_SetupPacket->bmRequestType.B >> 7);
556 }
557 }
558
559
560 //----------------------------------------------------------------------------------------
561 UCHAR
562 CUSBRequest::GetDeviceAddress()
563 {
564 PIO_STACK_LOCATION IoStack;
565 PURB Urb;
566 PUSBDEVICE UsbDevice;
567
568 //
569 // check if there is an irp provided
570 //
571 if (!m_Irp)
572 {
573 //
574 // used provided address
575 //
576 return m_DeviceAddress;
577 }
578
579 //
580 // get current stack location
581 //
582 IoStack = IoGetCurrentIrpStackLocation(m_Irp);
583
584 //
585 // get contained urb
586 //
587 Urb = (PURB)IoStack->Parameters.Others.Argument1;
588
589 //
590 // check if there is a pipe handle provided
591 //
592 if (Urb->UrbHeader.UsbdDeviceHandle)
593 {
594 //
595 // there is a device handle provided
596 //
597 UsbDevice = (PUSBDEVICE)Urb->UrbHeader.UsbdDeviceHandle;
598
599 //
600 // return device address
601 //
602 return UsbDevice->GetDeviceAddress();
603 }
604
605 //
606 // no device handle provided, it is the host root bus
607 //
608 return 0;
609 }
610
611 //----------------------------------------------------------------------------------------
612 NTSTATUS
613 CUSBRequest::GetEndpointDescriptor(
614 struct _UHCI_QUEUE_HEAD ** OutQueueHead)
615 {
616 NTSTATUS Status = STATUS_UNSUCCESSFUL;
617 ULONG TransferType;
618
619 // get transfer type
620 TransferType = InternalGetTransferType();
621
622 if (TransferType == USB_ENDPOINT_TYPE_CONTROL)
623 {
624 //
625 // build queue head
626 //
627 Status = BuildControlTransferDescriptor(OutQueueHead);
628 }
629 else if (TransferType == USB_ENDPOINT_TYPE_INTERRUPT || TransferType == USB_ENDPOINT_TYPE_BULK)
630 {
631 //
632 // build queue head
633 //
634 Status = BuildBulkInterruptTransferDescriptor(OutQueueHead);
635 }
636
637 if (!NT_SUCCESS(Status))
638 {
639 //
640 // failed
641 //
642 return Status;
643 }
644
645 //
646 // store result
647 //
648 (*OutQueueHead)->Request = PVOID(this);
649
650 //
651 // done
652 //
653 return STATUS_SUCCESS;
654 }
655
656 //----------------------------------------------------------------------------------------
657 VOID
658 CUSBRequest::GetResultStatus(
659 OUT OPTIONAL NTSTATUS * NtStatusCode,
660 OUT OPTIONAL PULONG UrbStatusCode)
661 {
662 //
663 // sanity check
664 //
665 PC_ASSERT(m_CompletionEvent);
666
667 //
668 // wait for the operation to complete
669 //
670 KeWaitForSingleObject(m_CompletionEvent, Executive, KernelMode, FALSE, NULL);
671
672 //
673 // copy status
674 //
675 if (NtStatusCode)
676 {
677 *NtStatusCode = m_NtStatusCode;
678 }
679
680 //
681 // copy urb status
682 //
683 if (UrbStatusCode)
684 {
685 *UrbStatusCode = m_UrbStatusCode;
686 }
687
688 }
689
690 //-----------------------------------------------------------------------------------------
691 NTSTATUS
692 CUSBRequest::CreateDescriptor(
693 OUT PUHCI_TRANSFER_DESCRIPTOR *OutDescriptor,
694 IN UCHAR PidCode,
695 ULONG BufferLength)
696 {
697 PUHCI_TRANSFER_DESCRIPTOR Descriptor;
698 PHYSICAL_ADDRESS Address;
699 NTSTATUS Status;
700
701 //
702 // allocate descriptor
703 //
704 Status = m_DmaManager->Allocate(sizeof(UHCI_TRANSFER_DESCRIPTOR), (PVOID*)&Descriptor, &Address);
705 if (!NT_SUCCESS(Status))
706 {
707 DPRINT1("[USBUHCI] Failed to allocate descriptor\n");
708 return Status;
709 }
710
711 //
712 // init descriptor
713 //
714 Descriptor->PhysicalAddress = Address.LowPart;
715 Descriptor->Status = TD_STATUS_ACTIVE;
716
717 if (InternalGetTransferType() == USB_ENDPOINT_TYPE_ISOCHRONOUS)
718 {
719 //
720 // isochronous transfer descriptor
721 //
722 Descriptor->Status |= TD_CONTROL_ISOCHRONOUS;
723 }
724 else
725 {
726 //
727 // error count
728 //
729 Descriptor->Status |= TD_CONTROL_3_ERRORS;
730
731 if (PidCode == TD_TOKEN_IN && (InternalGetTransferType() != USB_ENDPOINT_TYPE_CONTROL))
732 {
733 //
734 // enable short packet detect for bulk & interrupt
735 //
736 Descriptor->Status |= TD_CONTROL_SPD;
737 }
738 }
739
740 //
741 // is it low speed device
742 //
743 if (m_DeviceSpeed == UsbLowSpeed)
744 {
745 //
746 // low speed device
747 //
748 Descriptor->Status |= TD_CONTROL_LOWSPEED;
749 }
750
751 //
752 // store buffer size
753 //
754 Descriptor->BufferSize = BufferLength;
755
756 //
757 // is there a buffer
758 //
759 if(BufferLength)
760 {
761 //
762 // store buffer length
763 //
764 Descriptor->Token = (BufferLength - 1) << TD_TOKEN_MAXLEN_SHIFT;
765 }
766 else
767 {
768 //
769 // no buffer magic constant
770 //
771 Descriptor->Token = TD_TOKEN_NULL_DATA;
772 }
773
774 //
775 // store address & endpoint number
776 //
777 Descriptor->Token |= GetEndpointAddress() << TD_TOKEN_ENDPTADDR_SHIFT;
778 Descriptor->Token |= GetDeviceAddress() << TD_TOKEN_DEVADDR_SHIFT | PidCode;
779
780 if (BufferLength)
781 {
782 //
783 // allocate buffer for descriptor
784 //
785 Status = m_DmaManager->Allocate(BufferLength, (PVOID*)&Descriptor->BufferLogical, &Address);
786 if (!NT_SUCCESS(Status))
787 {
788 DPRINT1("[USBUHCI] Failed to allocate descriptor buffer length %lu\n", BufferLength);
789 m_DmaManager->Release(Descriptor, sizeof(UHCI_TRANSFER_DESCRIPTOR));
790 return Status;
791 }
792
793 //
794 // store address
795 //
796 Descriptor->BufferPhysical = Address.LowPart;
797 }
798
799 //
800 // done
801 //
802 *OutDescriptor = Descriptor;
803 return STATUS_SUCCESS;
804 }
805
806 NTSTATUS
807 CUSBRequest::BuildTransferDescriptorChain(
808 IN PVOID TransferBuffer,
809 IN ULONG TransferBufferLength,
810 IN UCHAR PidCode,
811 IN UCHAR InitialDataToggle,
812 OUT PUHCI_TRANSFER_DESCRIPTOR * OutFirstDescriptor,
813 OUT PUHCI_TRANSFER_DESCRIPTOR * OutLastDescriptor,
814 OUT PULONG OutTransferBufferOffset,
815 OUT PUCHAR OutDataToggle)
816 {
817 PUHCI_TRANSFER_DESCRIPTOR FirstDescriptor = NULL, CurrentDescriptor, LastDescriptor = NULL;
818 ULONG TransferBufferOffset = 0;
819 NTSTATUS Status;
820 ULONG MaxPacketSize, CurrentBufferSize;
821
822 //
823 // FIXME FIXME FIXME FIXME FIXME
824 //
825 if (GetDeviceSpeed() == UsbLowSpeed)
826 {
827 //
828 // low speed use max 8 bytes
829 //
830 MaxPacketSize = 8;
831 }
832 else
833 {
834 if (m_EndpointDescriptor)
835 {
836 //
837 // use endpoint size
838 //
839 MaxPacketSize = m_EndpointDescriptor->EndPointDescriptor.wMaxPacketSize;
840 }
841 else
842 {
843 //
844 // use max 64 bytes
845 //
846 MaxPacketSize = 64;
847 }
848 }
849
850 do
851 {
852 //
853 // determine current packet size
854 //
855 CurrentBufferSize = min(MaxPacketSize, TransferBufferLength - TransferBufferOffset);
856
857 //
858 // allocate descriptor
859 //
860 Status = CreateDescriptor(&CurrentDescriptor, PidCode, CurrentBufferSize);
861 if (!NT_SUCCESS(Status))
862 {
863 //
864 // failed to allocate queue head
865 //
866 DPRINT1("[UHCI] Failed to create descriptor\n");
867 ASSERT(FALSE);
868 return Status;
869 }
870
871 if (PidCode == TD_TOKEN_OUT)
872 {
873 //
874 // copy buffer
875 //
876 RtlCopyMemory(CurrentDescriptor->BufferLogical, (PVOID)((ULONG_PTR)TransferBuffer + TransferBufferOffset), CurrentBufferSize);
877 }
878 else
879 {
880 //
881 // store user buffer
882 //
883 CurrentDescriptor->UserBuffer = (PVOID)((ULONG_PTR)TransferBuffer + TransferBufferOffset);
884 }
885
886 if (!FirstDescriptor)
887 {
888 //
889 // first descriptor
890 //
891 FirstDescriptor = CurrentDescriptor;
892 }
893 else
894 {
895 //
896 // link descriptor
897 //
898 LastDescriptor->LinkPhysical = CurrentDescriptor->PhysicalAddress | TD_DEPTH_FIRST;
899 LastDescriptor->NextLogicalDescriptor = (PVOID)CurrentDescriptor;
900 }
901
902 if (InitialDataToggle)
903 {
904 //
905 // apply data toggle
906 //
907 CurrentDescriptor->Token |= TD_TOKEN_DATA1;
908 }
909
910 //
911 // re-run
912 //
913 LastDescriptor = CurrentDescriptor;
914 TransferBufferOffset += CurrentBufferSize;
915 InitialDataToggle = !InitialDataToggle;
916
917 }while(TransferBufferOffset < TransferBufferLength);
918
919 if (OutTransferBufferOffset)
920 {
921 //
922 // store transfer buffer length
923 //
924 *OutTransferBufferOffset = TransferBufferOffset;
925 }
926
927 if (OutFirstDescriptor)
928 {
929 //
930 // store first descriptor
931 //
932 *OutFirstDescriptor = FirstDescriptor;
933 }
934
935 if (OutLastDescriptor)
936 {
937 //
938 // store last descriptor
939 //
940 *OutLastDescriptor = CurrentDescriptor;
941 }
942
943 if (OutDataToggle)
944 {
945 //
946 // store data toggle
947 //
948 *OutDataToggle = InitialDataToggle;
949 }
950
951 //
952 // done
953 //
954 return STATUS_SUCCESS;
955 }
956
957 NTSTATUS
958 CUSBRequest::BuildQueueHead(
959 OUT PUHCI_QUEUE_HEAD *OutQueueHead)
960 {
961 PUHCI_QUEUE_HEAD QueueHead;
962 NTSTATUS Status;
963 PHYSICAL_ADDRESS Address;
964
965 //
966 // allocate queue head
967 //
968 Status = m_DmaManager->Allocate(sizeof(UHCI_QUEUE_HEAD), (PVOID*)&QueueHead, &Address);
969 if (!NT_SUCCESS(Status))
970 {
971 //
972 // failed to allocate queue head
973 //
974 DPRINT1("[UHCI] Failed to create queue head\n");
975 return Status;
976 }
977
978 //
979 // store address
980 //
981 QueueHead->PhysicalAddress = Address.LowPart;
982 QueueHead->ElementPhysical = Address.LowPart;
983
984 //
985 // store result
986 //
987 *OutQueueHead = QueueHead;
988 return STATUS_SUCCESS;
989 }
990
991 VOID
992 CUSBRequest::FreeDescriptor(
993 IN PUHCI_TRANSFER_DESCRIPTOR Descriptor)
994 {
995 if (Descriptor->BufferLogical)
996 {
997 //
998 // free buffer
999 //
1000 m_DmaManager->Release(Descriptor->BufferLogical, Descriptor->BufferSize);
1001 }
1002
1003 //
1004 // free descriptors
1005 //
1006 m_DmaManager->Release(Descriptor, sizeof(UHCI_TRANSFER_DESCRIPTOR));
1007 }
1008
1009 NTSTATUS
1010 CUSBRequest::BuildBulkInterruptTransferDescriptor(
1011 IN PUHCI_QUEUE_HEAD * OutQueueHead)
1012 {
1013 NTSTATUS Status;
1014 PUHCI_QUEUE_HEAD QueueHead;
1015 PUHCI_TRANSFER_DESCRIPTOR FirstDescriptor, LastDescriptor;
1016 ULONG ChainDescriptorLength;
1017 BOOLEAN Direction;
1018 PVOID Buffer;
1019 ULONG BufferSize;
1020
1021 // create queue head
1022 Status = BuildQueueHead(&QueueHead);
1023 if (!NT_SUCCESS(Status))
1024 {
1025 // failed to allocate queue head
1026 DPRINT1("[UHCI] Failed to create queue head\n");
1027 return Status;
1028 }
1029
1030 // get direction
1031 Direction = InternalGetPidDirection();
1032
1033 if (!m_Base)
1034 {
1035 // get buffer base
1036 m_Base = MmGetMdlVirtualAddress(m_TransferBufferMDL);
1037
1038 // sanity check
1039 ASSERT(m_Base != NULL);
1040 }
1041
1042 // get new buffer offset
1043 Buffer = (PVOID)((ULONG_PTR)m_Base + m_TransferBufferLengthCompleted);
1044
1045 // FIXME determine buffer limit
1046 BufferSize = min(m_TransferBufferLength - m_TransferBufferLengthCompleted, PAGE_SIZE);
1047
1048 // create descriptor chain
1049 Status = BuildTransferDescriptorChain(Buffer,
1050 BufferSize,
1051 Direction ? TD_TOKEN_IN : TD_TOKEN_OUT,
1052 m_EndpointDescriptor->DataToggle,
1053 &FirstDescriptor,
1054 &LastDescriptor,
1055 &ChainDescriptorLength,
1056 NULL);
1057 if (!NT_SUCCESS(Status))
1058 {
1059 //
1060 // failed to allocate descriptor
1061 //
1062 DPRINT1("[UHCI] Failed to create descriptor chain\n");
1063 m_DmaManager->Release(QueueHead, sizeof(UHCI_QUEUE_HEAD));
1064 return Status;
1065 }
1066
1067 // adjust buffer offset
1068 m_TransferBufferLengthCompleted += ChainDescriptorLength;
1069
1070 // fire interrupt when the last descriptor is complete
1071 LastDescriptor->Status |= TD_CONTROL_IOC;
1072 LastDescriptor->LinkPhysical = TD_TERMINATE;
1073 LastDescriptor->NextLogicalDescriptor = NULL;
1074
1075 // link queue head with first data descriptor descriptor
1076 QueueHead->NextElementDescriptor = (PVOID)FirstDescriptor;
1077 QueueHead->ElementPhysical = FirstDescriptor->PhysicalAddress;
1078
1079 // store result
1080 *OutQueueHead = QueueHead;
1081 return STATUS_SUCCESS;
1082 }
1083
1084
1085 NTSTATUS
1086 CUSBRequest::BuildControlTransferDescriptor(
1087 IN PUHCI_QUEUE_HEAD * OutQueueHead)
1088 {
1089 PUHCI_TRANSFER_DESCRIPTOR SetupDescriptor, StatusDescriptor, FirstDescriptor, LastDescriptor;
1090 PUHCI_QUEUE_HEAD QueueHead;
1091 BOOLEAN Direction;
1092 NTSTATUS Status;
1093 ULONG ChainDescriptorLength;
1094
1095 //
1096 // create queue head
1097 //
1098 Status = BuildQueueHead(&QueueHead);
1099 if (!NT_SUCCESS(Status))
1100 {
1101 //
1102 // failed to allocate queue head
1103 //
1104 DPRINT1("[UHCI] Failed to create queue head\n");
1105 return Status;
1106 }
1107
1108 //
1109 // get direction
1110 //
1111 Direction = InternalGetPidDirection();
1112
1113 //
1114 // build setup descriptor
1115 //
1116 Status = CreateDescriptor(&SetupDescriptor,
1117 TD_TOKEN_SETUP,
1118 sizeof(USB_DEFAULT_PIPE_SETUP_PACKET));
1119 if (!NT_SUCCESS(Status))
1120 {
1121 //
1122 // failed to allocate descriptor
1123 //
1124 DPRINT1("[UHCI] Failed to create setup descriptor\n");
1125 m_DmaManager->Release(QueueHead, sizeof(UHCI_QUEUE_HEAD));
1126 return Status;
1127 }
1128
1129 //
1130 // build status descriptor
1131 //
1132 Status = CreateDescriptor(&StatusDescriptor,
1133 Direction ? TD_TOKEN_OUT : TD_TOKEN_IN,
1134 0);
1135 if (!NT_SUCCESS(Status))
1136 {
1137 //
1138 // failed to allocate descriptor
1139 //
1140 DPRINT1("[UHCI] Failed to create status descriptor\n");
1141 FreeDescriptor(SetupDescriptor);
1142 m_DmaManager->Release(QueueHead, sizeof(UHCI_QUEUE_HEAD));
1143 return Status;
1144 }
1145
1146 if (m_SetupPacket)
1147 {
1148 //
1149 // copy setup packet
1150 //
1151 RtlCopyMemory(SetupDescriptor->BufferLogical, m_SetupPacket, sizeof(USB_DEFAULT_PIPE_SETUP_PACKET));
1152 }
1153 else
1154 {
1155 //
1156 // generate setup packet from urb
1157 //
1158 ASSERT(FALSE);
1159 }
1160
1161 //
1162 // init status descriptor
1163 //
1164 StatusDescriptor->Status |= TD_CONTROL_IOC;
1165 StatusDescriptor->Token |= TD_TOKEN_DATA1;
1166 StatusDescriptor->LinkPhysical = TD_TERMINATE;
1167 StatusDescriptor->NextLogicalDescriptor = NULL;
1168
1169 if (m_TransferBufferLength)
1170 {
1171 //
1172 // create descriptor chain
1173 //
1174 Status = BuildTransferDescriptorChain(MmGetMdlVirtualAddress(m_TransferBufferMDL),
1175 m_TransferBufferLength,
1176 Direction ? TD_TOKEN_IN : TD_TOKEN_OUT,
1177 TRUE,
1178 &FirstDescriptor,
1179 &LastDescriptor,
1180 &ChainDescriptorLength,
1181 NULL);
1182 if (!NT_SUCCESS(Status))
1183 {
1184 //
1185 // failed to allocate descriptor
1186 //
1187 DPRINT1("[UHCI] Failed to create descriptor chain\n");
1188 FreeDescriptor(SetupDescriptor);
1189 FreeDescriptor(StatusDescriptor);
1190 m_DmaManager->Release(QueueHead, sizeof(UHCI_QUEUE_HEAD));
1191 return Status;
1192 }
1193
1194 //
1195 // link setup descriptor to first data descriptor
1196 //
1197 SetupDescriptor->LinkPhysical = FirstDescriptor->PhysicalAddress | TD_DEPTH_FIRST;
1198 SetupDescriptor->NextLogicalDescriptor = (PVOID)FirstDescriptor;
1199
1200 //
1201 // link last data descriptor to status descriptor
1202 //
1203 LastDescriptor->LinkPhysical = StatusDescriptor->PhysicalAddress | TD_DEPTH_FIRST;
1204 LastDescriptor->NextLogicalDescriptor = (PVOID)StatusDescriptor;
1205 }
1206 else
1207 {
1208 //
1209 // directly link setup to status descriptor
1210 //
1211 SetupDescriptor->LinkPhysical = StatusDescriptor->PhysicalAddress | TD_DEPTH_FIRST;
1212 SetupDescriptor->NextLogicalDescriptor = (PVOID)StatusDescriptor;
1213 }
1214
1215 //
1216 // link queue head with setup descriptor
1217 //
1218 QueueHead->NextElementDescriptor = (PVOID)SetupDescriptor;
1219 QueueHead->ElementPhysical = SetupDescriptor->PhysicalAddress;
1220
1221 //
1222 // store result
1223 //
1224 *OutQueueHead = QueueHead;
1225 return STATUS_SUCCESS;
1226 }
1227 USB_DEVICE_SPEED
1228 CUSBRequest::GetDeviceSpeed()
1229 {
1230 return m_DeviceSpeed;
1231 }
1232
1233 VOID
1234 CUSBRequest::FreeEndpointDescriptor(
1235 struct _UHCI_QUEUE_HEAD * OutDescriptor)
1236 {
1237 PUHCI_TRANSFER_DESCRIPTOR Descriptor, NextDescriptor;
1238 ULONG ErrorCount;
1239 UCHAR DataToggle = 0;
1240 ULONG Index = 0;
1241
1242 //
1243 // grab first transfer descriptor
1244 //
1245 Descriptor = (PUHCI_TRANSFER_DESCRIPTOR)OutDescriptor->NextElementDescriptor;
1246 while(Descriptor)
1247 {
1248 // get data toggle
1249 DataToggle = (Descriptor->Token >> TD_TOKEN_DATA_TOGGLE_SHIFT) & 0x01;
1250
1251 if (Descriptor->Status & TD_ERROR_MASK)
1252 {
1253 //
1254 // error happened
1255 //
1256 DPRINT1("[USBUHCI] Error detected at descriptor %p Physical %x\n", Descriptor, Descriptor->PhysicalAddress);
1257
1258 //
1259 // get error count
1260 //
1261 ErrorCount = (Descriptor->Status >> TD_ERROR_COUNT_SHIFT) & TD_ERROR_COUNT_MASK;
1262 if (ErrorCount == 0)
1263 {
1264 //
1265 // error retry count elapsed
1266 //
1267 m_NtStatusCode = STATUS_UNSUCCESSFUL;
1268
1269 if (Descriptor->Status & TD_STATUS_ERROR_BUFFER)
1270 {
1271 DPRINT1("[USBUHCI] Buffer Error detected in descriptor %p Index %lu\n", Descriptor, Index);
1272 m_UrbStatusCode = USBD_STATUS_DATA_BUFFER_ERROR;
1273 }
1274 else if (Descriptor->Status & TD_STATUS_ERROR_TIMEOUT)
1275 {
1276 DPRINT1("[USBUHCI] Timeout detected in descriptor %p Index %lu\n", Descriptor, Index);
1277 m_UrbStatusCode = USBD_STATUS_TIMEOUT;
1278 }
1279 else if (Descriptor->Status & TD_STATUS_ERROR_NAK)
1280 {
1281 DPRINT1("[USBUHCI] Unexpected pid detected in descriptor %p Index %lu\n", Descriptor, Index);
1282 m_UrbStatusCode = USBD_STATUS_UNEXPECTED_PID;
1283 }
1284 else if (Descriptor->Status & TD_STATUS_ERROR_BITSTUFF)
1285 {
1286 DPRINT1("[USBUHCI] BitStuff detected in descriptor %p Index %lu\n", Descriptor, Index);
1287 m_UrbStatusCode = USBD_STATUS_BTSTUFF;
1288 }
1289 }
1290 else if (Descriptor->Status & TD_STATUS_ERROR_BABBLE)
1291 {
1292 //
1293 // babble error
1294 //
1295 DPRINT1("[USBUHCI] Babble detected in descriptor %p Index %lu\n", Descriptor, Index);
1296 m_UrbStatusCode = USBD_STATUS_BABBLE_DETECTED;
1297 }
1298 else
1299 {
1300 //
1301 // stall detected
1302 //
1303 DPRINT1("[USBUHCI] Stall detected Descriptor %p Index %lu\n", Descriptor, Index);
1304 m_UrbStatusCode = USBD_STATUS_STALL_PID;
1305 }
1306 }
1307 else
1308 {
1309 //
1310 // FIXME detect actual length
1311 //
1312 if (Descriptor->UserBuffer)
1313 {
1314 //
1315 // copy contents back
1316 //
1317 RtlCopyMemory(Descriptor->UserBuffer, Descriptor->BufferLogical, Descriptor->BufferSize);
1318 }
1319 }
1320 //
1321 // move to next descriptor
1322 //
1323 NextDescriptor = (PUHCI_TRANSFER_DESCRIPTOR)Descriptor->NextLogicalDescriptor;
1324
1325 //
1326 // free endpoint descriptor
1327 //
1328 FreeDescriptor(Descriptor);
1329
1330 //
1331 // move to next
1332 //
1333 Descriptor = NextDescriptor;
1334 Index++;
1335 }
1336
1337 //
1338 // now free queue head
1339 //
1340 m_DmaManager->Release(OutDescriptor, sizeof(UHCI_QUEUE_HEAD));
1341
1342 // is there an endpoint descriptor
1343 if (m_EndpointDescriptor)
1344 {
1345 // invert last data toggle
1346 m_EndpointDescriptor->DataToggle = (DataToggle == 0);
1347 }
1348 }
1349
1350 VOID
1351 CUSBRequest::CompletionCallback()
1352 {
1353 PIO_STACK_LOCATION IoStack;
1354 PURB Urb;
1355
1356 DPRINT("CUSBRequest::CompletionCallback\n");
1357
1358 if (m_Irp)
1359 {
1360 //
1361 // set irp completion status
1362 //
1363 m_Irp->IoStatus.Status = m_NtStatusCode;
1364
1365 //
1366 // get current irp stack location
1367 //
1368 IoStack = IoGetCurrentIrpStackLocation(m_Irp);
1369
1370 //
1371 // get urb
1372 //
1373 Urb = (PURB)IoStack->Parameters.Others.Argument1;
1374
1375 //
1376 // store urb status
1377 //
1378 Urb->UrbHeader.Status = m_UrbStatusCode;
1379
1380 //
1381 // Check if the MDL was created
1382 //
1383 if (!Urb->UrbBulkOrInterruptTransfer.TransferBufferMDL)
1384 {
1385 //
1386 // Free Mdl
1387 //
1388 IoFreeMdl(m_TransferBufferMDL);
1389 }
1390
1391 //
1392 // FIXME calculate length
1393 //
1394
1395 //
1396 // complete request
1397 //
1398 IoCompleteRequest(m_Irp, IO_NO_INCREMENT);
1399 }
1400 else
1401 {
1402 //
1403 // signal completion event
1404 //
1405 PC_ASSERT(m_CompletionEvent);
1406 KeSetEvent(m_CompletionEvent, 0, FALSE);
1407 }
1408
1409 }
1410
1411
1412 //-----------------------------------------------------------------------------------------
1413 NTSTATUS
1414 NTAPI
1415 InternalCreateUSBRequest(
1416 PUSBREQUEST *OutRequest)
1417 {
1418 PUSBREQUEST This;
1419
1420 //
1421 // allocate requests
1422 //
1423 This = new(NonPagedPool, TAG_USBUHCI) CUSBRequest(0);
1424 if (!This)
1425 {
1426 //
1427 // failed to allocate
1428 //
1429 return STATUS_INSUFFICIENT_RESOURCES;
1430 }
1431
1432 //
1433 // add reference count
1434 //
1435 This->AddRef();
1436
1437 //
1438 // return result
1439 //
1440 *OutRequest = (PUSBREQUEST)This;
1441
1442 //
1443 // done
1444 //
1445 return STATUS_SUCCESS;
1446 }