[BRANCHES]
[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 descriptor
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
1044 // adjust buffer offset
1045 m_TransferBufferLengthCompleted += ChainDescriptorLength;
1046
1047 // fire interrupt when the last descriptor is complete
1048 LastDescriptor->Status |= TD_CONTROL_IOC;
1049 LastDescriptor->LinkPhysical = TD_TERMINATE;
1050 LastDescriptor->NextLogicalDescriptor = NULL;
1051
1052 // link queue head with first data descriptor descriptor
1053 QueueHead->NextElementDescriptor = (PVOID)FirstDescriptor;
1054 QueueHead->ElementPhysical = FirstDescriptor->PhysicalAddress;
1055
1056 // store result
1057 *OutQueueHead = QueueHead;
1058 return STATUS_SUCCESS;
1059 }
1060
1061
1062 NTSTATUS
1063 CUSBRequest::BuildControlTransferDescriptor(
1064 IN PUHCI_QUEUE_HEAD * OutQueueHead)
1065 {
1066 PUHCI_TRANSFER_DESCRIPTOR SetupDescriptor, StatusDescriptor, FirstDescriptor, LastDescriptor;
1067 PUHCI_QUEUE_HEAD QueueHead;
1068 BOOLEAN Direction;
1069 NTSTATUS Status;
1070 ULONG ChainDescriptorLength;
1071
1072 //
1073 // create queue head
1074 //
1075 Status = BuildQueueHead(&QueueHead);
1076 if (!NT_SUCCESS(Status))
1077 {
1078 //
1079 // failed to allocate descriptor
1080 //
1081 DPRINT1("[UHCI] Failed to create queue head\n");
1082 return Status;
1083 }
1084
1085 //
1086 // get direction
1087 //
1088 Direction = InternalGetPidDirection();
1089
1090 //
1091 // build setup descriptor
1092 //
1093 Status = CreateDescriptor(&SetupDescriptor,
1094 TD_TOKEN_SETUP,
1095 sizeof(USB_DEFAULT_PIPE_SETUP_PACKET));
1096 if (!NT_SUCCESS(Status))
1097 {
1098 //
1099 // failed to allocate descriptor
1100 //
1101 DPRINT1("[UHCI] Failed to create setup descriptor\n");
1102 m_DmaManager->Release(QueueHead, sizeof(UHCI_QUEUE_HEAD));
1103 return Status;
1104 }
1105
1106 //
1107 // build status descriptor
1108 //
1109 Status = CreateDescriptor(&StatusDescriptor,
1110 Direction ? TD_TOKEN_OUT : TD_TOKEN_IN,
1111 0);
1112 if (!NT_SUCCESS(Status))
1113 {
1114 //
1115 // failed to allocate descriptor
1116 //
1117 DPRINT1("[UHCI] Failed to create status descriptor\n");
1118 FreeDescriptor(SetupDescriptor);
1119 m_DmaManager->Release(QueueHead, sizeof(UHCI_QUEUE_HEAD));
1120 return Status;
1121 }
1122
1123 if (m_SetupPacket)
1124 {
1125 //
1126 // copy setup packet
1127 //
1128 RtlCopyMemory(SetupDescriptor->BufferLogical, m_SetupPacket, sizeof(USB_DEFAULT_PIPE_SETUP_PACKET));
1129 }
1130 else
1131 {
1132 //
1133 // generate setup packet from urb
1134 //
1135 ASSERT(FALSE);
1136 }
1137
1138 //
1139 // init status descriptor
1140 //
1141 StatusDescriptor->Status |= TD_CONTROL_IOC;
1142 StatusDescriptor->Token |= TD_TOKEN_DATA1;
1143 StatusDescriptor->LinkPhysical = TD_TERMINATE;
1144 StatusDescriptor->NextLogicalDescriptor = NULL;
1145
1146 if (m_TransferBufferLength)
1147 {
1148 //
1149 // create descriptor chain
1150 //
1151 Status = BuildTransferDescriptorChain(MmGetMdlVirtualAddress(m_TransferBufferMDL),
1152 m_TransferBufferLength,
1153 Direction ? TD_TOKEN_IN : TD_TOKEN_OUT,
1154 TRUE,
1155 &FirstDescriptor,
1156 &LastDescriptor,
1157 &ChainDescriptorLength,
1158 NULL);
1159 if (!NT_SUCCESS(Status))
1160 {
1161 //
1162 // failed to allocate descriptor
1163 //
1164 DPRINT1("[UHCI] Failed to create descriptor chain\n");
1165 FreeDescriptor(SetupDescriptor);
1166 FreeDescriptor(StatusDescriptor);
1167 m_DmaManager->Release(QueueHead, sizeof(UHCI_QUEUE_HEAD));
1168 return Status;
1169 }
1170
1171 //
1172 // link setup descriptor to first data descriptor
1173 //
1174 SetupDescriptor->LinkPhysical = FirstDescriptor->PhysicalAddress | TD_DEPTH_FIRST;
1175 SetupDescriptor->NextLogicalDescriptor = (PVOID)FirstDescriptor;
1176
1177 //
1178 // link last data descriptor to status descriptor
1179 //
1180 LastDescriptor->LinkPhysical = StatusDescriptor->PhysicalAddress | TD_DEPTH_FIRST;
1181 LastDescriptor->NextLogicalDescriptor = (PVOID)StatusDescriptor;
1182 }
1183 else
1184 {
1185 //
1186 // directly link setup to status descriptor
1187 //
1188 SetupDescriptor->LinkPhysical = StatusDescriptor->PhysicalAddress | TD_DEPTH_FIRST;
1189 SetupDescriptor->NextLogicalDescriptor = (PVOID)StatusDescriptor;
1190 }
1191
1192 //
1193 // link queue head with setup descriptor
1194 //
1195 QueueHead->NextElementDescriptor = (PVOID)SetupDescriptor;
1196 QueueHead->ElementPhysical = SetupDescriptor->PhysicalAddress;
1197
1198 //
1199 // store result
1200 //
1201 *OutQueueHead = QueueHead;
1202 return STATUS_SUCCESS;
1203 }
1204 USB_DEVICE_SPEED
1205 CUSBRequest::GetDeviceSpeed()
1206 {
1207 return m_DeviceSpeed;
1208 }
1209
1210 VOID
1211 CUSBRequest::FreeEndpointDescriptor(
1212 struct _UHCI_QUEUE_HEAD * OutDescriptor)
1213 {
1214 PUHCI_TRANSFER_DESCRIPTOR Descriptor, NextDescriptor;
1215 ULONG ErrorCount;
1216 UCHAR DataToggle = 0;
1217 ULONG Index = 0;
1218
1219 //
1220 // grab first transfer descriptor
1221 //
1222 Descriptor = (PUHCI_TRANSFER_DESCRIPTOR)OutDescriptor->NextElementDescriptor;
1223 while(Descriptor)
1224 {
1225 // get data toggle
1226 DataToggle = (Descriptor->Token >> TD_TOKEN_DATA_TOGGLE_SHIFT) & 0x01;
1227
1228 if (Descriptor->Status & TD_ERROR_MASK)
1229 {
1230 //
1231 // error happened
1232 //
1233 DPRINT1("[USBUHCI] Error detected at descriptor %p Physical %x\n", Descriptor, Descriptor->PhysicalAddress);
1234
1235 //
1236 // get error count
1237 //
1238 ErrorCount = (Descriptor->Status >> TD_ERROR_COUNT_SHIFT) & TD_ERROR_COUNT_MASK;
1239 if (ErrorCount == 0)
1240 {
1241 //
1242 // error retry count elapsed
1243 //
1244 m_NtStatusCode = STATUS_UNSUCCESSFUL;
1245
1246 if (Descriptor->Status & TD_STATUS_ERROR_BUFFER)
1247 {
1248 DPRINT1("[USBUHCI] Buffer Error detected in descriptor %p Index %lu\n", Descriptor, Index);
1249 m_UrbStatusCode = USBD_STATUS_DATA_BUFFER_ERROR;
1250 }
1251 else if (Descriptor->Status & TD_STATUS_ERROR_TIMEOUT)
1252 {
1253 DPRINT1("[USBUHCI] Timeout detected in descriptor %p Index %lu\n", Descriptor, Index);
1254 m_UrbStatusCode = USBD_STATUS_TIMEOUT;
1255 }
1256 else if (Descriptor->Status & TD_STATUS_ERROR_NAK)
1257 {
1258 DPRINT1("[USBUHCI] Unexpected pid detected in descriptor %p Index %lu\n", Descriptor, Index);
1259 m_UrbStatusCode = USBD_STATUS_UNEXPECTED_PID;
1260 }
1261 else if (Descriptor->Status & TD_STATUS_ERROR_BITSTUFF)
1262 {
1263 DPRINT1("[USBUHCI] BitStuff detected in descriptor %p Index %lu\n", Descriptor, Index);
1264 m_UrbStatusCode = USBD_STATUS_BTSTUFF;
1265 }
1266 }
1267 else if (Descriptor->Status & TD_STATUS_ERROR_BABBLE)
1268 {
1269 //
1270 // babble error
1271 //
1272 DPRINT1("[USBUHCI] Babble detected in descriptor %p Index %lu\n", Descriptor, Index);
1273 m_UrbStatusCode = USBD_STATUS_BABBLE_DETECTED;
1274 }
1275 else
1276 {
1277 //
1278 // stall detected
1279 //
1280 DPRINT1("[USBUHCI] Stall detected Descriptor %p Index %lu\n", Descriptor, Index);
1281 m_UrbStatusCode = USBD_STATUS_STALL_PID;
1282 }
1283 }
1284 else
1285 {
1286 //
1287 // FIXME detect actual length
1288 //
1289 if (Descriptor->UserBuffer)
1290 {
1291 //
1292 // copy contents back
1293 //
1294 RtlCopyMemory(Descriptor->UserBuffer, Descriptor->BufferLogical, Descriptor->BufferSize);
1295 }
1296 }
1297 //
1298 // move to next descriptor
1299 //
1300 NextDescriptor = (PUHCI_TRANSFER_DESCRIPTOR)Descriptor->NextLogicalDescriptor;
1301
1302 //
1303 // free endpoint descriptor
1304 //
1305 FreeDescriptor(Descriptor);
1306
1307 //
1308 // move to next
1309 //
1310 Descriptor = NextDescriptor;
1311 Index++;
1312 }
1313
1314 //
1315 // now free queue head
1316 //
1317 m_DmaManager->Release(OutDescriptor, sizeof(UHCI_QUEUE_HEAD));
1318
1319 // is there an endpoint descriptor
1320 if (m_EndpointDescriptor)
1321 {
1322 // invert last data toggle
1323 m_EndpointDescriptor->DataToggle = (DataToggle == 0);
1324 }
1325 }
1326
1327 VOID
1328 CUSBRequest::CompletionCallback()
1329 {
1330 PIO_STACK_LOCATION IoStack;
1331 PURB Urb;
1332
1333 DPRINT("CUSBRequest::CompletionCallback\n");
1334
1335 if (m_Irp)
1336 {
1337 //
1338 // set irp completion status
1339 //
1340 m_Irp->IoStatus.Status = m_NtStatusCode;
1341
1342 //
1343 // get current irp stack location
1344 //
1345 IoStack = IoGetCurrentIrpStackLocation(m_Irp);
1346
1347 //
1348 // get urb
1349 //
1350 Urb = (PURB)IoStack->Parameters.Others.Argument1;
1351
1352 //
1353 // store urb status
1354 //
1355 Urb->UrbHeader.Status = m_UrbStatusCode;
1356
1357 //
1358 // Check if the MDL was created
1359 //
1360 if (!Urb->UrbBulkOrInterruptTransfer.TransferBufferMDL)
1361 {
1362 //
1363 // Free Mdl
1364 //
1365 IoFreeMdl(m_TransferBufferMDL);
1366 }
1367
1368 //
1369 // FIXME calculate length
1370 //
1371
1372 //
1373 // complete request
1374 //
1375 IoCompleteRequest(m_Irp, IO_NO_INCREMENT);
1376 }
1377 else
1378 {
1379 //
1380 // signal completion event
1381 //
1382 PC_ASSERT(m_CompletionEvent);
1383 KeSetEvent(m_CompletionEvent, 0, FALSE);
1384 }
1385
1386 }
1387
1388
1389 //-----------------------------------------------------------------------------------------
1390 NTSTATUS
1391 NTAPI
1392 InternalCreateUSBRequest(
1393 PUSBREQUEST *OutRequest)
1394 {
1395 PUSBREQUEST This;
1396
1397 //
1398 // allocate requests
1399 //
1400 This = new(NonPagedPool, TAG_USBUHCI) CUSBRequest(0);
1401 if (!This)
1402 {
1403 //
1404 // failed to allocate
1405 //
1406 return STATUS_INSUFFICIENT_RESOURCES;
1407 }
1408
1409 //
1410 // add reference count
1411 //
1412 This->AddRef();
1413
1414 //
1415 // return result
1416 //
1417 *OutRequest = (PUSBREQUEST)This;
1418
1419 //
1420 // done
1421 //
1422 return STATUS_SUCCESS;
1423 }