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