ReactOS  0.4.14-dev-297-g23e575c
usb_request.cpp
Go to the documentation of this file.
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:
20 
22  {
24  return m_Ref;
25  }
27  {
29 
30  if (!m_Ref)
31  {
32  delete this;
33  return 0;
34  }
35  return m_Ref;
36  }
37 
38  // com
41 
42  // local functions
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  //
68 
69  //
70  // caller provided irp packet containing URB request
71  //
72  PIRP m_Irp;
73 
74  //
75  // transfer buffer length
76  //
78 
79  //
80  // current transfer length
81  //
83 
84  //
85  // Total Transfer Length
86  //
88 
89  //
90  // transfer buffer MDL
91  //
93 
94  //
95  // caller provided setup packet
96  //
98 
99  //
100  // completion event for callers who initialized request with setup packet
101  //
103 
104  //
105  // device address for callers who initialized it with device address
106  //
108 
109  //
110  // store end point address
111  //
113 
114  //
115  // allocated setup packet from the DMA pool
116  //
119 
120  //
121  // stores the result of the operation
122  //
125 
126  //
127  // store device speed
128  //
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 //----------------------------------------------------------------------------------------
145 {
146  if (m_CompletionEvent != NULL)
147  {
149  }
150 }
151 
152 //----------------------------------------------------------------------------------------
153 NTSTATUS
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,
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;
188  m_DeviceSpeed = Device->GetSpeed();
189 
190  //
191  // Set Length Completed to 0
192  //
194 
195  //
196  // allocate completion event
197  //
199  if (!m_CompletionEvent)
200  {
201  //
202  // failed to allocate completion event
203  //
205  }
206 
207  //
208  // initialize completion event
209  //
211 
212  //
213  // done
214  //
215  return STATUS_SUCCESS;
216 }
217 //----------------------------------------------------------------------------------------
218 NTSTATUS
219 CUSBRequest::InitializeWithIrp(
220  IN PDMAMEMORYMANAGER DmaManager,
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;
235  m_DeviceSpeed = Device->GetSpeed();
236 
237  //
238  // get current irp stack location
239  //
241 
242  //
243  // sanity check
244  //
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  {
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);
291  Urb->UrbBulkOrInterruptTransfer.TransferBufferLength,
292  FALSE,
293  FALSE,
294  NULL);
295 
296  if (!m_TransferBufferMDL)
297  {
298  //
299  // failed to allocate mdl
300  //
302  }
303 
304  //
305  // build mdl for non paged pool
306  // FIXME: Does hub driver already do this when passing MDL?
307  //
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  //
328 
329  //
330  // get endpoint descriptor
331  //
333 
334  //
335  // completed initialization
336  //
337  break;
338  }
339  //
340  // luckily those request have the same structure layout
341  //
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);
366  Urb->UrbBulkOrInterruptTransfer.TransferBufferLength,
367  FALSE,
368  FALSE,
369  NULL);
370 
371  if (!m_TransferBufferMDL)
372  {
373  //
374  // failed to allocate mdl
375  //
377  }
378 
379  //
380  // build mdl for non paged pool
381  // FIXME: Does hub driver already do this when passing MDL?
382  //
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  //
403 
404  //
405  // get endpoint descriptor
406  //
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  //
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
457 {
459  {
460  //
461  // control request
462  //
463  return 0;
464  }
465 
466  ASSERT(m_Irp);
468 
469  //
470  // return max packet size
471  //
473 }
474 
475 UCHAR
476 CUSBRequest::GetInterval()
477 {
480 
481  //
482  // return interrupt interval
483  //
485 }
486 
487 UCHAR
489 {
491  {
492  //
493  // control request
494  //
495  return 0;
496  }
497 
498  ASSERT(m_Irp);
500 
501  //
502  // endpoint number is between 1-15
503  //
505 }
506 
507 //----------------------------------------------------------------------------------------
508 ULONG
510 {
511  ULONG TransferType;
512 
513  //
514  // check if an irp is provided
515  //
516  if (m_Irp)
517  {
519 
520  //
521  // end point is defined in the low byte of bmAttributes
522  //
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
541 {
543  {
544  //
545  // end point direction is highest bit in bEndpointAddress
546  //
548  }
549  else
550  {
551  //
552  // request arrives on the control pipe, extract direction from setup packet
553  //
555  return (m_SetupPacket->bmRequestType.B >> 7);
556  }
557 }
558 
559 
560 //----------------------------------------------------------------------------------------
561 UCHAR
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  //
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 {
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  //
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  //
666 
667  //
668  // wait for the operation to complete
669  //
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
693  OUT PUHCI_TRANSFER_DESCRIPTOR *OutDescriptor,
694  IN UCHAR PidCode,
696 {
700 
701  //
702  // allocate descriptor
703  //
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 
718  {
719  //
720  // isochronous transfer descriptor
721  //
723  }
724  else
725  {
726  //
727  // error count
728  //
729  Descriptor->Status |= TD_CONTROL_3_ERRORS;
730 
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  //
765  }
766  else
767  {
768  //
769  // no buffer magic constant
770  //
772  }
773 
774  //
775  // store address & endpoint number
776  //
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);
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
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;
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  {
835  {
836  //
837  // use endpoint size
838  //
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
959  OUT PUHCI_QUEUE_HEAD *OutQueueHead)
960 {
961  PUHCI_QUEUE_HEAD QueueHead;
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
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  //
1007 }
1008 
1009 NTSTATUS
1011  IN PUHCI_QUEUE_HEAD * OutQueueHead)
1012 {
1013  NTSTATUS Status;
1014  PUHCI_QUEUE_HEAD QueueHead;
1015  PUHCI_TRANSFER_DESCRIPTOR FirstDescriptor, LastDescriptor;
1016  ULONG ChainDescriptorLength;
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
1032 
1033  if (!m_Base)
1034  {
1035  // get buffer base
1037 
1038  // sanity check
1039  ASSERT(m_Base != NULL);
1040  }
1041 
1042  // get new buffer offset
1044 
1045  // FIXME determine buffer limit
1047 
1048  // create descriptor chain
1050  BufferSize,
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
1087  IN PUHCI_QUEUE_HEAD * OutQueueHead)
1088 {
1089  PUHCI_TRANSFER_DESCRIPTOR SetupDescriptor, StatusDescriptor, FirstDescriptor, LastDescriptor;
1090  PUHCI_QUEUE_HEAD QueueHead;
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  //
1112 
1113  //
1114  // build setup descriptor
1115  //
1116  Status = CreateDescriptor(&SetupDescriptor,
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,
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  //
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 
1170  {
1171  //
1172  // create descriptor chain
1173  //
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 }
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  //
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  //
1268 
1269  if (Descriptor->Status & TD_STATUS_ERROR_BUFFER)
1270  {
1271  DPRINT1("[USBUHCI] Buffer Error detected in descriptor %p Index %lu\n", Descriptor, Index);
1273  }
1274  else if (Descriptor->Status & TD_STATUS_ERROR_TIMEOUT)
1275  {
1276  DPRINT1("[USBUHCI] Timeout detected in descriptor %p Index %lu\n", Descriptor, Index);
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);
1283  }
1284  else if (Descriptor->Status & TD_STATUS_ERROR_BITSTUFF)
1285  {
1286  DPRINT1("[USBUHCI] BitStuff detected in descriptor %p Index %lu\n", Descriptor, Index);
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);
1297  }
1298  else
1299  {
1300  //
1301  // stall detected
1302  //
1303  DPRINT1("[USBUHCI] Stall detected Descriptor %p Index %lu\n", Descriptor, Index);
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  //
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
1344  {
1345  // invert last data toggle
1346  m_EndpointDescriptor->DataToggle = (DataToggle == 0);
1347  }
1348 }
1349 
1350 VOID
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  //
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  //
1389  }
1390 
1391  //
1392  // FIXME calculate length
1393  //
1394 
1395  //
1396  // complete request
1397  //
1399  }
1400  else
1401  {
1402  //
1403  // signal completion event
1404  //
1407  }
1408 
1409 }
1410 
1411 
1412 //-----------------------------------------------------------------------------------------
1413 NTSTATUS
1414 NTAPI
1416  PUSBREQUEST *OutRequest)
1417 {
1418  PUSBREQUEST This;
1419 
1420  //
1421  // allocate requests
1422  //
1424  if (!This)
1425  {
1426  //
1427  // failed to allocate
1428  //
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 }
ULONG m_TransferBufferLength
Definition: usb_request.cpp:78
PUSB_ENDPOINT m_EndpointDescriptor
ULONG m_TransferBufferLengthCompleted
Definition: usb_request.cpp:83
IMP_IUSBREQUEST IMP_IEHCIREQUEST ULONG InternalGetTransferType()
#define TD_STATUS_ERROR_NAK
Definition: hardware.h:115
NTSTATUS BuildSetupPacketFromURB()
#define IN
Definition: typedefs.h:38
STDMETHODIMP_(ULONG) AddRef()
Definition: usb_request.cpp:21
#define REFIID
Definition: guiddef.h:118
#define TRUE
Definition: types.h:120
NTSYSAPI VOID NTAPI RtlCopyMemory(VOID UNALIGNED *Destination, CONST VOID UNALIGNED *Source, ULONG Length)
struct _KEVENT * PKEVENT
#define STATUS_INSUFFICIENT_RESOURCES
Definition: udferr_usr.h:158
#define PC_ASSERT(exp)
Definition: usbehci.h:17
_In_ PIRP _In_ PDEVICE_OBJECT Device
Definition: fatprocs.h:2020
#define TD_TOKEN_DATA1
Definition: hardware.h:127
#define IOCTL_INTERNAL_USB_SUBMIT_URB
Definition: usbioctl.h:32
_In_ BOOLEAN Release
Definition: classpnp.h:929
NTSTATUS STDMETHODCALLTYPE BuildTransferDescriptorChain(IN PQUEUE_HEAD QueueHead, IN PVOID TransferBuffer, IN ULONG TransferBufferLength, IN UCHAR PidCode, IN UCHAR InitialDataToggle, OUT PQUEUE_TRANSFER_DESCRIPTOR *OutFirstDescriptor, OUT PQUEUE_TRANSFER_DESCRIPTOR *OutLastDescriptor, OUT PUCHAR OutDataToggle, OUT PULONG OutTransferBufferOffset)
#define MmGetMdlVirtualAddress(_Mdl)
#define TD_TERMINATE
Definition: hardware.h:137
_In_ PIRP Irp
Definition: csq.h:116
#define UNREFERENCED_PARAMETER(P)
Definition: ntbasedef.h:323
#define TD_CONTROL_IOC
Definition: hardware.h:109
unsigned char * PUCHAR
Definition: retypes.h:3
USB_ENDPOINT_DESCRIPTOR EndPointDescriptor
VOID NTAPI MmBuildMdlForNonPagedPool(IN PMDL Mdl)
Definition: mdlsup.c:428
LONG NTSTATUS
Definition: precomp.h:26
NTSTATUS BuildSetupPacket()
#define TD_STATUS_ACTIVE
Definition: hardware.h:111
UCHAR STDMETHODCALLTYPE GetDeviceAddress()
#define USB_ENDPOINT_TYPE_CONTROL
Definition: usb100.h:62
LONG NTAPI KeSetEvent(IN PKEVENT Event, IN KPRIORITY Increment, IN BOOLEAN Wait)
Definition: eventobj.c:159
NTSTATUS NTAPI KeWaitForSingleObject(IN PVOID Object, IN KWAIT_REASON WaitReason, IN KPROCESSOR_MODE WaitMode, IN BOOLEAN Alertable, IN PLARGE_INTEGER Timeout OPTIONAL)
Definition: wait.c:416
#define TD_ERROR_COUNT_MASK
Definition: hardware.h:140
#define USB_ENDPOINT_DIRECTION_MASK
Definition: usb100.h:73
ULONG ElementPhysical
Definition: hardware.h:171
#define TD_STATUS_ERROR_BITSTUFF
Definition: hardware.h:118
#define TD_CONTROL_3_ERRORS
Definition: hardware.h:106
uint32_t ULONG_PTR
Definition: typedefs.h:63
struct _UHCI_TRANSFER_DESCRIPTOR * PUHCI_TRANSFER_DESCRIPTOR
IUSBDevice * PUSBDEVICE
#define IMP_IUSBREQUEST
USB_DEVICE_SPEED m_DeviceSpeed
NTSTATUS(* NTAPI)(IN PFILE_FULL_EA_INFORMATION EaBuffer, IN ULONG EaLength, OUT PULONG ErrorOffset)
Definition: IoEaTest.cpp:117
#define TD_TOKEN_IN
Definition: hardware.h:130
#define TD_ERROR_COUNT_SHIFT
Definition: hardware.h:139
#define USBD_STATUS_BABBLE_DETECTED
Definition: usb.h:188
long LONG
Definition: pedump.c:60
CUSBRequest(IUnknown *OuterUnknown)
_In_ ULONG BufferLength
Definition: usbdlib.h:225
PKEVENT m_CompletionEvent
NTSTATUS BuildControlTransferDescriptor(POHCI_ENDPOINT_DESCRIPTOR *OutEndpointDescriptor)
#define STDMETHODIMP
Definition: basetyps.h:43
unsigned char BOOLEAN
PHYSICAL_ADDRESS m_DescriptorSetupPacket
smooth NULL
Definition: ftsmooth.c:416
static WCHAR Address[46]
Definition: ping.c:68
#define IoCompleteRequest
Definition: irp.c:1240
#define TD_STATUS_ERROR_BUFFER
Definition: hardware.h:113
UCHAR InternalGetPidDirection()
void DPRINT(...)
Definition: polytest.cpp:61
Definition: bufpool.h:45
switch(r->id)
Definition: btrfs.c:2932
PVOID NextElementDescriptor
Definition: hardware.h:177
void * PVOID
Definition: retypes.h:9
NTSTATUS BuildBulkInterruptTransferDescriptor(IN PUHCI_QUEUE_HEAD *OutQueueHead)
PDMAMEMORYMANAGER m_DmaManager
Definition: usb_request.cpp:68
enum _USB_DEVICE_SPEED USB_DEVICE_SPEED
STDMETHODIMP QueryInterface(REFIID InterfaceId, PVOID *Interface)
#define USB_ENDPOINT_TYPE_MASK
Definition: usb100.h:61
PUSB_DEFAULT_PIPE_SETUP_PACKET m_DescriptorPacket
struct _URB_HEADER UrbHeader
Definition: usb.h:531
#define USBD_STATUS_TIMEOUT
Definition: usb.h:209
IN PVOID IN PVOID IN USHORT IN USHORT IN PINTERFACE Interface
Definition: pci.h:359
struct _USB_ENDPOINT * PUSB_ENDPOINT
if(!(yy_init))
Definition: macro.lex.yy.c:714
#define TD_TOKEN_NULL_DATA
Definition: hardware.h:125
#define USBD_STATUS_DATA_BUFFER_ERROR
Definition: usb.h:189
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:32
#define TD_ERROR_MASK
Definition: hardware.h:138
_Inout_ PSIZE_T _In_opt_ PMDLX _In_ MM_ROTATE_DIRECTION Direction
Definition: mmfuncs.h:773
NTSTATUS STDMETHODCALLTYPE CreateDescriptor(PQUEUE_TRANSFER_DESCRIPTOR *OutDescriptor)
static const UCHAR Index[8]
Definition: usbohci.c:18
#define STDMETHODCALLTYPE
Definition: bdasup.h:9
#define BufferSize
Definition: classpnp.h:419
#define IRP_MJ_INTERNAL_DEVICE_CONTROL
VOID FreeDescriptor(POHCI_GENERAL_TD Descriptor)
VOID NTAPI IoFreeMdl(PMDL Mdl)
Definition: iomdl.c:146
#define USB_ENDPOINT_TYPE_ISOCHRONOUS
Definition: usb100.h:63
ASSERT((InvokeOnSuccess||InvokeOnError||InvokeOnCancel) ?(CompletionRoutine !=NULL) :TRUE)
#define STATUS_UNSUCCESSFUL
Definition: udferr_usr.h:132
PUSB_DEFAULT_PIPE_SETUP_PACKET m_SetupPacket
Definition: usb_request.cpp:98
#define ExAllocatePoolWithTag(hernya, size, tag)
Definition: env_spec_w32.h:350
unsigned char UCHAR
Definition: xmlstorage.h:181
#define TD_STATUS_ERROR_TIMEOUT
Definition: hardware.h:117
#define TAG_USBUHCI
Definition: usbuhci.h:26
#define InterlockedDecrement
Definition: armddk.h:52
Definition: arc.h:85
#define PAGE_SIZE
Definition: env_spec_w32.h:49
#define URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE
Definition: usb.h:97
#define USB_ENDPOINT_TYPE_BULK
Definition: usb100.h:64
#define USBD_STATUS_STALL_PID
Definition: usb.h:175
struct _URB * PURB
PMDL m_TransferBufferMDL
Definition: usb_request.cpp:93
#define TD_TOKEN_OUT
Definition: hardware.h:131
Status
Definition: gdiplustypes.h:24
UCHAR m_DeviceAddress
PMDL NTAPI IoAllocateMdl(IN PVOID VirtualAddress, IN ULONG Length, IN BOOLEAN SecondaryBuffer, IN BOOLEAN ChargeQuota, IN PIRP Irp)
Definition: iomdl.c:22
__drv_aliasesMem FORCEINLINE PIO_STACK_LOCATION IoGetCurrentIrpStackLocation(_In_ PIRP Irp)
Definition: iofuncs.h:2745
struct _URB_ISOCH_TRANSFER UrbIsochronousTransfer
Definition: usb.h:544
#define USBD_STATUS_UNEXPECTED_PID
Definition: usb.h:178
#define KeInitializeEvent(pEvt, foo, foo2)
Definition: env_spec_w32.h:477
#define InterlockedIncrement
Definition: armddk.h:53
#define TD_DEPTH_FIRST
Definition: hardware.h:136
Definition: usb.h:529
#define URB_FUNCTION_ISOCH_TRANSFER
Definition: usb.h:96
unsigned short USHORT
Definition: pedump.c:61
IUSBRequest * PUSBREQUEST
#define URB_FUNCTION_CLASS_INTERFACE
Definition: usb.h:113
#define TD_STATUS_ERROR_BABBLE
Definition: hardware.h:114
STDMETHODIMP_(ULONG) Release()
Definition: usb_request.cpp:26
ULONG m_TotalBytesTransferred
Definition: usb_request.cpp:88
unsigned int * PULONG
Definition: retypes.h:1
#define min(a, b)
Definition: monoChain.cc:55
IDMAMemoryManager * PDMAMEMORYMANAGER
UCHAR GetEndpointAddress()
static ULONG WINAPI AddRef(IStream *iface)
Definition: clist.c:90
#define TD_CONTROL_ISOCHRONOUS
Definition: hardware.h:108
#define TD_TOKEN_DEVADDR_SHIFT
Definition: hardware.h:134
#define DPRINT1
Definition: precomp.h:8
#define TD_TOKEN_SETUP
Definition: hardware.h:129
virtual ~CUSBRequest()
#define TD_TOKEN_MAXLEN_SHIFT
Definition: hardware.h:124
NTSTATUS NTAPI InternalCreateUSBRequest(PUSBREQUEST *OutRequest)
#define OUT
Definition: typedefs.h:39
NTSTATUS m_NtStatusCode
#define TD_CONTROL_SPD
Definition: hardware.h:105
struct _URB_BULK_OR_INTERRUPT_TRANSFER UrbBulkOrInterruptTransfer
Definition: usb.h:543
unsigned int ULONG
Definition: retypes.h:1
#define IO_NO_INCREMENT
Definition: iotypes.h:566
#define TD_TOKEN_DATA_TOGGLE_SHIFT
Definition: hardware.h:126
#define TD_CONTROL_LOWSPEED
Definition: hardware.h:107
#define ExFreePoolWithTag(_P, _T)
Definition: module.h:1099
const TCHAR * CompletionCallback(unsigned __int64 &rnIndex, const BOOL *pblnForward, const TCHAR *pszContext, const TCHAR *pszBegin)
Definition: Completion.cpp:439
USHORT GetMaxPacketSize()
struct _NAMED_PIPE_CREATE_PARAMETERS * Parameters
Definition: iotypes.h:2772
NTSTATUS BuildQueueHead(OUT PUHCI_QUEUE_HEAD *OutQueueHead)
IN BOOLEAN OUT PSTR Buffer
Definition: progress.h:34
return STATUS_SUCCESS
Definition: btrfs.c:2966
#define IMP_IUHCIREQUEST
Definition: interfaces.h:91
BM_REQUEST_TYPE bmRequestType
Definition: usb200.h:72
#define TD_TOKEN_ENDPTADDR_SHIFT
Definition: hardware.h:133
ULONG m_UrbStatusCode
#define URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER
Definition: usb.h:95
#define USBD_STATUS_BTSTUFF
Definition: usb.h:173
#define USB_ENDPOINT_TYPE_INTERRUPT
Definition: usb100.h:65
_In_ PSTORAGE_PROPERTY_ID _Outptr_ PSTORAGE_DESCRIPTOR_HEADER * Descriptor
Definition: classpnp.h:966
PULONG MinorVersion OPTIONAL
Definition: CrossNt.h:68