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