[USBOHCI]
[reactos.git] / drivers / usb / usbohci / usb_request.cpp
1 /*
2 * PROJECT: ReactOS Universal Serial Bus Bulk Enhanced Host Controller Interface
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: drivers/usb/usbohci/usb_request.cpp
5 * PURPOSE: USB OHCI 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 "usbohci.h"
14 #include "hardware.h"
15
16 class CUSBRequest : public IUSBRequest
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 // IUSBRequest interface functions
39 virtual NTSTATUS InitializeWithSetupPacket(IN PDMAMEMORYMANAGER DmaManager, IN PUSB_DEFAULT_PIPE_SETUP_PACKET SetupPacket, IN UCHAR DeviceAddress, IN OPTIONAL PUSB_ENDPOINT_DESCRIPTOR EndpointDescriptor, IN OUT ULONG TransferBufferLength, IN OUT PMDL TransferBuffer);
40 virtual NTSTATUS InitializeWithIrp(IN PDMAMEMORYMANAGER DmaManager, IN OUT PIRP Irp);
41 virtual BOOLEAN IsRequestComplete();
42 virtual ULONG GetTransferType();
43 virtual NTSTATUS GetEndpointDescriptor(struct _OHCI_ENDPOINT_DESCRIPTOR ** OutEndpointDescriptor);
44 virtual VOID GetResultStatus(OUT OPTIONAL NTSTATUS *NtStatusCode, OUT OPTIONAL PULONG UrbStatusCode);
45 virtual BOOLEAN IsRequestInitialized();
46 virtual BOOLEAN IsQueueHeadComplete(struct _QUEUE_HEAD * QueueHead);
47 virtual VOID CompletionCallback(struct _OHCI_ENDPOINT_DESCRIPTOR * OutDescriptor);
48 virtual VOID FreeEndpointDescriptor(struct _OHCI_ENDPOINT_DESCRIPTOR * OutDescriptor);
49
50 // local functions
51 ULONG InternalGetTransferType();
52 UCHAR InternalGetPidDirection();
53 UCHAR GetDeviceAddress();
54 NTSTATUS BuildSetupPacket();
55 NTSTATUS BuildSetupPacketFromURB();
56 NTSTATUS BuildControlTransferDescriptor(POHCI_ENDPOINT_DESCRIPTOR * OutEndpointDescriptor);
57 NTSTATUS BuildBulkInterruptEndpoint(POHCI_ENDPOINT_DESCRIPTOR * OutEndpointDescriptor);
58 NTSTATUS CreateGeneralTransferDescriptor(POHCI_GENERAL_TD* OutDescriptor, ULONG BufferSize);
59 VOID FreeDescriptor(POHCI_GENERAL_TD Descriptor);
60 NTSTATUS AllocateEndpointDescriptor(OUT POHCI_ENDPOINT_DESCRIPTOR *OutDescriptor);
61 UCHAR GetEndpointAddress();
62 USHORT GetMaxPacketSize();
63
64 // constructor / destructor
65 CUSBRequest(IUnknown *OuterUnknown){}
66 virtual ~CUSBRequest(){}
67
68 protected:
69 LONG m_Ref;
70
71 //
72 // memory manager for allocating setup packet / queue head / transfer descriptors
73 //
74 PDMAMEMORYMANAGER m_DmaManager;
75
76 //
77 // caller provided irp packet containing URB request
78 //
79 PIRP m_Irp;
80
81 //
82 // transfer buffer length
83 //
84 ULONG m_TransferBufferLength;
85
86 //
87 // current transfer length
88 //
89 ULONG m_TransferBufferLengthCompleted;
90
91 //
92 // Total Transfer Length
93 //
94 ULONG m_TotalBytesTransferred;
95
96 //
97 // transfer buffer MDL
98 //
99 PMDL m_TransferBufferMDL;
100
101 //
102 // caller provided setup packet
103 //
104 PUSB_DEFAULT_PIPE_SETUP_PACKET m_SetupPacket;
105
106 //
107 // completion event for callers who initialized request with setup packet
108 //
109 PKEVENT m_CompletionEvent;
110
111 //
112 // device address for callers who initialized it with device address
113 //
114 UCHAR m_DeviceAddress;
115
116 //
117 // store end point address
118 //
119 PUSB_ENDPOINT_DESCRIPTOR m_EndpointDescriptor;
120
121 //
122 // allocated setup packet from the DMA pool
123 //
124 PUSB_DEFAULT_PIPE_SETUP_PACKET m_DescriptorPacket;
125 PHYSICAL_ADDRESS m_DescriptorSetupPacket;
126
127 //
128 // stores the result of the operation
129 //
130 NTSTATUS m_NtStatusCode;
131 ULONG m_UrbStatusCode;
132
133 };
134
135 //----------------------------------------------------------------------------------------
136 NTSTATUS
137 STDMETHODCALLTYPE
138 CUSBRequest::QueryInterface(
139 IN REFIID refiid,
140 OUT PVOID* Output)
141 {
142 return STATUS_UNSUCCESSFUL;
143 }
144
145 //----------------------------------------------------------------------------------------
146 NTSTATUS
147 CUSBRequest::InitializeWithSetupPacket(
148 IN PDMAMEMORYMANAGER DmaManager,
149 IN PUSB_DEFAULT_PIPE_SETUP_PACKET SetupPacket,
150 IN UCHAR DeviceAddress,
151 IN OPTIONAL PUSB_ENDPOINT_DESCRIPTOR EndpointDescriptor,
152 IN OUT ULONG TransferBufferLength,
153 IN OUT PMDL TransferBuffer)
154 {
155 //
156 // sanity checks
157 //
158 PC_ASSERT(DmaManager);
159 PC_ASSERT(SetupPacket);
160
161 //
162 // initialize packet
163 //
164 m_DmaManager = DmaManager;
165 m_SetupPacket = SetupPacket;
166 m_TransferBufferLength = TransferBufferLength;
167 m_TransferBufferMDL = TransferBuffer;
168 m_DeviceAddress = DeviceAddress;
169 m_EndpointDescriptor = EndpointDescriptor;
170 m_TotalBytesTransferred = 0;
171
172 //
173 // Set Length Completed to 0
174 //
175 m_TransferBufferLengthCompleted = 0;
176
177 //
178 // allocate completion event
179 //
180 m_CompletionEvent = (PKEVENT)ExAllocatePoolWithTag(NonPagedPool, sizeof(KEVENT), TAG_USBOHCI);
181 if (!m_CompletionEvent)
182 {
183 //
184 // failed to allocate completion event
185 //
186 return STATUS_INSUFFICIENT_RESOURCES;
187 }
188
189 //
190 // initialize completion event
191 //
192 KeInitializeEvent(m_CompletionEvent, NotificationEvent, FALSE);
193
194 //
195 // done
196 //
197 return STATUS_SUCCESS;
198 }
199 //----------------------------------------------------------------------------------------
200 NTSTATUS
201 CUSBRequest::InitializeWithIrp(
202 IN PDMAMEMORYMANAGER DmaManager,
203 IN OUT PIRP Irp)
204 {
205 PIO_STACK_LOCATION IoStack;
206 PURB Urb;
207
208 //
209 // sanity checks
210 //
211 PC_ASSERT(DmaManager);
212 PC_ASSERT(Irp);
213
214 m_DmaManager = DmaManager;
215 m_TotalBytesTransferred = 0;
216
217 //
218 // get current irp stack location
219 //
220 IoStack = IoGetCurrentIrpStackLocation(Irp);
221
222 //
223 // sanity check
224 //
225 PC_ASSERT(IoStack->MajorFunction == IRP_MJ_INTERNAL_DEVICE_CONTROL);
226 PC_ASSERT(IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_INTERNAL_USB_SUBMIT_URB);
227 PC_ASSERT(IoStack->Parameters.Others.Argument1 != 0);
228
229 //
230 // get urb
231 //
232 Urb = (PURB)IoStack->Parameters.Others.Argument1;
233
234 //
235 // store irp
236 //
237 m_Irp = Irp;
238
239 //
240 // check function type
241 //
242 switch (Urb->UrbHeader.Function)
243 {
244 //
245 // luckily those request have the same structure layout
246 //
247 case URB_FUNCTION_CLASS_INTERFACE:
248 case URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE:
249 case URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER:
250 {
251 //
252 // bulk interrupt transfer
253 //
254 if (Urb->UrbBulkOrInterruptTransfer.TransferBufferLength)
255 {
256 //
257 // Check if there is a MDL
258 //
259 if (!Urb->UrbBulkOrInterruptTransfer.TransferBufferMDL)
260 {
261 //
262 // sanity check
263 //
264 PC_ASSERT(Urb->UrbBulkOrInterruptTransfer.TransferBuffer);
265
266 //
267 // Create one using TransferBuffer
268 //
269 DPRINT("Creating Mdl from Urb Buffer %p Length %lu\n", Urb->UrbBulkOrInterruptTransfer.TransferBuffer, Urb->UrbBulkOrInterruptTransfer.TransferBufferLength);
270 m_TransferBufferMDL = IoAllocateMdl(Urb->UrbBulkOrInterruptTransfer.TransferBuffer,
271 Urb->UrbBulkOrInterruptTransfer.TransferBufferLength,
272 FALSE,
273 FALSE,
274 NULL);
275
276 if (!m_TransferBufferMDL)
277 {
278 //
279 // failed to allocate mdl
280 //
281 return STATUS_INSUFFICIENT_RESOURCES;
282 }
283
284 //
285 // build mdl for non paged pool
286 // FIXME: Does hub driver already do this when passing MDL?
287 //
288 MmBuildMdlForNonPagedPool(m_TransferBufferMDL);
289
290 //
291 // Keep that ehci created the MDL and needs to free it.
292 //
293 }
294 else
295 {
296 m_TransferBufferMDL = Urb->UrbBulkOrInterruptTransfer.TransferBufferMDL;
297 }
298
299 //
300 // save buffer length
301 //
302 m_TransferBufferLength = Urb->UrbBulkOrInterruptTransfer.TransferBufferLength;
303
304 //
305 // Set Length Completed to 0
306 //
307 m_TransferBufferLengthCompleted = 0;
308
309 //
310 // get endpoint descriptor
311 //
312 m_EndpointDescriptor = (PUSB_ENDPOINT_DESCRIPTOR)Urb->UrbBulkOrInterruptTransfer.PipeHandle;
313
314 }
315 break;
316 }
317 default:
318 DPRINT1("URB Function: not supported %x\n", Urb->UrbHeader.Function);
319 PC_ASSERT(FALSE);
320 }
321
322 //
323 // done
324 //
325 return STATUS_SUCCESS;
326
327 }
328
329 //----------------------------------------------------------------------------------------
330 BOOLEAN
331 CUSBRequest::IsRequestComplete()
332 {
333 //
334 // FIXME: check if request was split
335 //
336
337 //
338 // Check if the transfer was completed, only valid for Bulk Transfers
339 //
340 if ((m_TransferBufferLengthCompleted < m_TransferBufferLength)
341 && (GetTransferType() == USB_ENDPOINT_TYPE_BULK))
342 {
343 //
344 // Transfer not completed
345 //
346 return FALSE;
347 }
348 return TRUE;
349 }
350 //----------------------------------------------------------------------------------------
351 ULONG
352 CUSBRequest::GetTransferType()
353 {
354 //
355 // call internal implementation
356 //
357 return InternalGetTransferType();
358 }
359
360 USHORT
361 CUSBRequest::GetMaxPacketSize()
362 {
363 if (!m_EndpointDescriptor)
364 {
365 //
366 // control request
367 //
368 return 0;
369 }
370
371 ASSERT(m_Irp);
372 ASSERT(m_EndpointDescriptor);
373
374 //
375 // return max packet size
376 //
377 return m_EndpointDescriptor->wMaxPacketSize;
378 }
379
380 UCHAR
381 CUSBRequest::GetEndpointAddress()
382 {
383 if (!m_EndpointDescriptor)
384 {
385 //
386 // control request
387 //
388 return 0;
389 }
390
391 ASSERT(m_Irp);
392 ASSERT(m_EndpointDescriptor);
393
394 //
395 // endpoint number is between 1-15
396 //
397 return (m_EndpointDescriptor->bEndpointAddress & 0xF);
398 }
399
400 //----------------------------------------------------------------------------------------
401 ULONG
402 CUSBRequest::InternalGetTransferType()
403 {
404 ULONG TransferType;
405
406 //
407 // check if an irp is provided
408 //
409 if (m_Irp)
410 {
411 ASSERT(m_EndpointDescriptor);
412
413 //
414 // end point is defined in the low byte of bmAttributes
415 //
416 TransferType = (m_EndpointDescriptor->bmAttributes & USB_ENDPOINT_TYPE_MASK);
417 }
418 else
419 {
420 //
421 // initialized with setup packet, must be a control transfer
422 //
423 TransferType = USB_ENDPOINT_TYPE_CONTROL;
424 }
425
426 //
427 // done
428 //
429 return TransferType;
430 }
431
432 UCHAR
433 CUSBRequest::InternalGetPidDirection()
434 {
435 ASSERT(m_Irp);
436 ASSERT(m_EndpointDescriptor);
437
438 //
439 // end point is defined in the low byte of bEndpointAddress
440 //
441 return (m_EndpointDescriptor->bEndpointAddress & USB_ENDPOINT_DIRECTION_MASK) >> 7;
442 }
443
444
445 //----------------------------------------------------------------------------------------
446 UCHAR
447 CUSBRequest::GetDeviceAddress()
448 {
449 PIO_STACK_LOCATION IoStack;
450 PURB Urb;
451 PUSBDEVICE UsbDevice;
452
453 //
454 // check if there is an irp provided
455 //
456 if (!m_Irp)
457 {
458 //
459 // used provided address
460 //
461 return m_DeviceAddress;
462 }
463
464 //
465 // get current stack location
466 //
467 IoStack = IoGetCurrentIrpStackLocation(m_Irp);
468
469 //
470 // get contained urb
471 //
472 Urb = (PURB)IoStack->Parameters.Others.Argument1;
473
474 //
475 // check if there is a pipe handle provided
476 //
477 if (Urb->UrbHeader.UsbdDeviceHandle)
478 {
479 //
480 // there is a device handle provided
481 //
482 UsbDevice = (PUSBDEVICE)Urb->UrbHeader.UsbdDeviceHandle;
483
484 //
485 // return device address
486 //
487 return UsbDevice->GetDeviceAddress();
488 }
489
490 //
491 // no device handle provided, it is the host root bus
492 //
493 return 0;
494 }
495
496 VOID
497 CUSBRequest::FreeDescriptor(
498 POHCI_GENERAL_TD Descriptor)
499 {
500 if (Descriptor->BufferSize)
501 {
502 //
503 // free buffer
504 //
505 m_DmaManager->Release(Descriptor->BufferLogical, Descriptor->BufferSize);
506 }
507
508 //
509 // release descriptor
510 //
511 m_DmaManager->Release(Descriptor, sizeof(OHCI_GENERAL_TD));
512
513 }
514 //----------------------------------------------------------------------------------------
515 NTSTATUS
516 CUSBRequest::CreateGeneralTransferDescriptor(
517 POHCI_GENERAL_TD* OutDescriptor,
518 ULONG BufferSize)
519 {
520 POHCI_GENERAL_TD Descriptor;
521 PHYSICAL_ADDRESS DescriptorAddress;
522 NTSTATUS Status;
523
524 //
525 // allocate transfer descriptor
526 //
527 Status = m_DmaManager->Allocate(sizeof(OHCI_GENERAL_TD), (PVOID*)&Descriptor, &DescriptorAddress);
528 if (!NT_SUCCESS(Status))
529 {
530 //
531 // no memory
532 //
533 return Status;
534 }
535
536 //
537 // initialize descriptor, hardware part
538 //
539 Descriptor->Flags = 0;
540 Descriptor->BufferPhysical = 0;
541 Descriptor->NextPhysicalDescriptor = 0;
542 Descriptor->LastPhysicalByteAddress = 0;
543
544 //
545 // software part
546 //
547 Descriptor->PhysicalAddress.QuadPart = DescriptorAddress.QuadPart;
548 Descriptor->BufferSize = BufferSize;
549
550 if (BufferSize > 0)
551 {
552 //
553 // allocate buffer from dma
554 //
555 Status = m_DmaManager->Allocate(BufferSize, &Descriptor->BufferLogical, &DescriptorAddress);
556 if (!NT_SUCCESS(Status))
557 {
558 //
559 // no memory
560 //
561 m_DmaManager->Release(Descriptor, sizeof(OHCI_GENERAL_TD));
562 return Status;
563 }
564
565 //
566 // set physical address of buffer
567 //
568 Descriptor->BufferPhysical = DescriptorAddress.LowPart;
569 Descriptor->LastPhysicalByteAddress = Descriptor->BufferPhysical + BufferSize - 1;
570 }
571
572 //
573 // store result
574 //
575 *OutDescriptor = Descriptor;
576
577 //
578 // done
579 //
580 return STATUS_SUCCESS;
581 }
582
583 NTSTATUS
584 CUSBRequest::AllocateEndpointDescriptor(
585 OUT POHCI_ENDPOINT_DESCRIPTOR *OutDescriptor)
586 {
587 POHCI_ENDPOINT_DESCRIPTOR Descriptor;
588 PHYSICAL_ADDRESS DescriptorAddress;
589 NTSTATUS Status;
590
591 //
592 // allocate descriptor
593 //
594 Status = m_DmaManager->Allocate(sizeof(OHCI_ENDPOINT_DESCRIPTOR), (PVOID*)&Descriptor, &DescriptorAddress);
595 if (!NT_SUCCESS(Status))
596 {
597 //
598 // failed to allocate descriptor
599 //
600 return Status;
601 }
602
603 //
604 // intialize descriptor
605 //
606 Descriptor->Flags = OHCI_ENDPOINT_SKIP;
607
608 //
609 // append device address and endpoint number
610 //
611 Descriptor->Flags |= OHCI_ENDPOINT_SET_DEVICE_ADDRESS(GetDeviceAddress());
612 Descriptor->Flags |= OHCI_ENDPOINT_SET_ENDPOINT_NUMBER(GetEndpointAddress());
613 Descriptor->Flags |= OHCI_ENDPOINT_SET_MAX_PACKET_SIZE(GetMaxPacketSize());
614
615 //
616 // is there an endpoint descriptor
617 //
618 if (m_EndpointDescriptor)
619 {
620 //
621 // check direction
622 //
623 if (USB_ENDPOINT_DIRECTION_OUT(m_EndpointDescriptor->bEndpointAddress))
624 {
625 //
626 // direction out
627 //
628 Descriptor->Flags |= OHCI_ENDPOINT_DIRECTION_OUT;
629 }
630 else
631 {
632 //
633 // direction in
634 //
635 Descriptor->Flags |= OHCI_ENDPOINT_DIRECTION_IN;
636 }
637
638 }
639
640
641 //
642 // FIXME: detect type
643 //
644 Descriptor->Flags |= OHCI_ENDPOINT_FULL_SPEED;
645
646 Descriptor->HeadPhysicalDescriptor = 0;
647 Descriptor->NextPhysicalEndpoint = 0;
648 Descriptor->TailPhysicalDescriptor = 0;
649 Descriptor->PhysicalAddress.QuadPart = DescriptorAddress.QuadPart;
650
651 //
652 // store result
653 //
654 *OutDescriptor = Descriptor;
655
656 //
657 // done
658 //
659 return STATUS_SUCCESS;
660 }
661
662 NTSTATUS
663 CUSBRequest::BuildBulkInterruptEndpoint(
664 POHCI_ENDPOINT_DESCRIPTOR * OutEndpointDescriptor)
665 {
666 POHCI_GENERAL_TD FirstDescriptor, PreviousDescriptor = NULL, CurrentDescriptor, LastDescriptor;
667 POHCI_ENDPOINT_DESCRIPTOR EndpointDescriptor;
668 ULONG BufferSize, CurrentSize, Direction, MaxLengthInPage;
669 NTSTATUS Status;
670 PVOID Buffer;
671
672 //
673 // allocate endpoint descriptor
674 //
675 Status = AllocateEndpointDescriptor(&EndpointDescriptor);
676 if (!NT_SUCCESS(Status))
677 {
678 //
679 // failed to create setup descriptor
680 //
681 return Status;
682 }
683
684 //
685 // allocate transfer descriptor for last descriptor
686 //
687 Status = CreateGeneralTransferDescriptor(&LastDescriptor, 0);
688 if (!NT_SUCCESS(Status))
689 {
690 //
691 // failed to create transfer descriptor
692 //
693 m_DmaManager->Release(EndpointDescriptor, sizeof(OHCI_ENDPOINT_DESCRIPTOR));
694 return Status;
695 }
696
697 //
698 // get buffer size
699 //
700 BufferSize = m_TransferBufferLength;
701 ASSERT(BufferSize);
702 ASSERT(m_TransferBufferMDL);
703
704 //
705 // get buffer
706 //
707 Buffer = MmGetSystemAddressForMdlSafe(m_TransferBufferMDL, NormalPagePriority);
708 ASSERT(Buffer);
709
710 if (InternalGetPidDirection())
711 {
712 //
713 // input direction
714 //
715 Direction = OHCI_TD_DIRECTION_PID_IN;
716 }
717 else
718 {
719 //
720 // output direction
721 //
722 Direction = OHCI_TD_DIRECTION_PID_OUT;
723 }
724
725 do
726 {
727 //
728 // get current buffersize
729 //
730 CurrentSize = min(8192, BufferSize);
731
732 //
733 // get page offset
734 //
735 MaxLengthInPage = PAGE_SIZE - BYTE_OFFSET(Buffer);
736
737 //
738 // get minimum from current page size
739 //
740 CurrentSize = min(CurrentSize, MaxLengthInPage);
741 ASSERT(CurrentSize);
742
743 //
744 // allocate transfer descriptor
745 //
746 Status = CreateGeneralTransferDescriptor(&CurrentDescriptor, 0);
747 if (!NT_SUCCESS(Status))
748 {
749 //
750 // failed to create transfer descriptor
751 // TODO: cleanup
752 //
753 ASSERT(FALSE);
754 m_DmaManager->Release(EndpointDescriptor, sizeof(OHCI_ENDPOINT_DESCRIPTOR));
755 FreeDescriptor(LastDescriptor);
756 return Status;
757 }
758
759 //
760 // initialize descriptor
761 //
762 CurrentDescriptor->Flags = Direction | OHCI_TD_BUFFER_ROUNDING | OHCI_TD_SET_CONDITION_CODE(OHCI_TD_CONDITION_NOT_ACCESSED) | OHCI_TD_SET_DELAY_INTERRUPT(OHCI_TD_INTERRUPT_NONE) | OHCI_TD_TOGGLE_CARRY;
763
764 //
765 // store physical address of buffer
766 //
767 CurrentDescriptor->BufferPhysical = MmGetPhysicalAddress(Buffer).LowPart;
768 CurrentDescriptor->LastPhysicalByteAddress = CurrentDescriptor->BufferPhysical + CurrentSize - 1;
769
770 //
771 // is there a previous descriptor
772 //
773 if (PreviousDescriptor)
774 {
775 //
776 // link descriptors
777 //
778 PreviousDescriptor->NextLogicalDescriptor = (PVOID)CurrentDescriptor;
779 PreviousDescriptor->NextPhysicalDescriptor = CurrentDescriptor->PhysicalAddress.LowPart;
780 }
781 else
782 {
783 //
784 // it is the first descriptor
785 //
786 FirstDescriptor = CurrentDescriptor;
787 }
788
789 DPRINT("PreviousDescriptor %p CurrentDescriptor %p Buffer Logical %p Physical %x Last Physical %x CurrentSize %lu\n", PreviousDescriptor, CurrentDescriptor, CurrentDescriptor->BufferLogical, CurrentDescriptor->BufferPhysical, CurrentDescriptor->LastPhysicalByteAddress, CurrentSize);
790
791 //
792 // set previous descriptor
793 //
794 PreviousDescriptor = CurrentDescriptor;
795
796 //
797 // subtract buffer size
798 //
799 BufferSize -= CurrentSize;
800
801 //
802 // increment buffer offset
803 //
804 Buffer = (PVOID)((ULONG_PTR)Buffer + CurrentSize);
805
806 }while(BufferSize);
807
808 //
809 // first descriptor has no carry bit
810 //
811 FirstDescriptor->Flags &= ~OHCI_TD_TOGGLE_CARRY;
812
813 //
814 // fixme: toggle
815 //
816 FirstDescriptor->Flags |= OHCI_TD_TOGGLE_0;
817
818 //
819 // clear interrupt mask for last transfer descriptor
820 //
821 CurrentDescriptor->Flags &= ~OHCI_TD_INTERRUPT_MASK;
822
823 //
824 // fire interrupt as soon transfer is finished
825 //
826 CurrentDescriptor->Flags |= OHCI_TD_SET_DELAY_INTERRUPT(OHCI_TD_INTERRUPT_IMMEDIATE);
827
828 //
829 // link last data descriptor to last descriptor
830 //
831 CurrentDescriptor->NextLogicalDescriptor = LastDescriptor;
832 CurrentDescriptor->NextPhysicalDescriptor = LastDescriptor->PhysicalAddress.LowPart;
833
834 //
835 // now link descriptor to endpoint
836 //
837 EndpointDescriptor->HeadPhysicalDescriptor = FirstDescriptor->PhysicalAddress.LowPart;
838 EndpointDescriptor->TailPhysicalDescriptor = LastDescriptor->PhysicalAddress.LowPart;
839 EndpointDescriptor->HeadLogicalDescriptor = FirstDescriptor;
840
841 //
842 // store result
843 //
844 *OutEndpointDescriptor = EndpointDescriptor;
845
846 //
847 // done
848 //
849 return STATUS_SUCCESS;
850
851 }
852
853
854 NTSTATUS
855 CUSBRequest::BuildControlTransferDescriptor(
856 POHCI_ENDPOINT_DESCRIPTOR * OutEndpointDescriptor)
857 {
858 POHCI_GENERAL_TD SetupDescriptor, StatusDescriptor, DataDescriptor = NULL, LastDescriptor;
859 POHCI_ENDPOINT_DESCRIPTOR EndpointDescriptor;
860 NTSTATUS Status;
861
862 //
863 // allocate endpoint descriptor
864 //
865 Status = AllocateEndpointDescriptor(&EndpointDescriptor);
866 if (!NT_SUCCESS(Status))
867 {
868 //
869 // failed to create setup descriptor
870 //
871 return Status;
872 }
873
874 //
875 // first allocate setup descriptor
876 //
877 Status = CreateGeneralTransferDescriptor(&SetupDescriptor, sizeof(USB_DEFAULT_PIPE_SETUP_PACKET));
878 if (!NT_SUCCESS(Status))
879 {
880 //
881 // failed to create setup descriptor
882 //
883 m_DmaManager->Release(EndpointDescriptor, sizeof(OHCI_ENDPOINT_DESCRIPTOR));
884 return Status;
885 }
886
887 //
888 // now create the status descriptor
889 //
890 Status = CreateGeneralTransferDescriptor(&StatusDescriptor, 0);
891 if (!NT_SUCCESS(Status))
892 {
893 //
894 // failed to create status descriptor
895 //
896 FreeDescriptor(SetupDescriptor);
897 m_DmaManager->Release(EndpointDescriptor, sizeof(OHCI_ENDPOINT_DESCRIPTOR));
898 return Status;
899 }
900
901 //
902 // finally create the last descriptor
903 //
904 Status = CreateGeneralTransferDescriptor(&LastDescriptor, 0);
905 if (!NT_SUCCESS(Status))
906 {
907 //
908 // failed to create status descriptor
909 //
910 FreeDescriptor(SetupDescriptor);
911 FreeDescriptor(StatusDescriptor);
912 m_DmaManager->Release(EndpointDescriptor, sizeof(OHCI_ENDPOINT_DESCRIPTOR));
913 return Status;
914 }
915
916 if (m_TransferBufferLength)
917 {
918 //
919 // FIXME: support more than one data descriptor
920 //
921 ASSERT(m_TransferBufferLength < 8192);
922
923 //
924 // now create the data descriptor
925 //
926 Status = CreateGeneralTransferDescriptor(&DataDescriptor, 0);
927 if (!NT_SUCCESS(Status))
928 {
929 //
930 // failed to create status descriptor
931 //
932 m_DmaManager->Release(EndpointDescriptor, sizeof(OHCI_ENDPOINT_DESCRIPTOR));
933 FreeDescriptor(SetupDescriptor);
934 FreeDescriptor(StatusDescriptor);
935 FreeDescriptor(LastDescriptor);
936 return Status;
937 }
938
939 //
940 // initialize data descriptor
941 //
942 DataDescriptor->Flags = OHCI_TD_BUFFER_ROUNDING| OHCI_TD_SET_CONDITION_CODE(OHCI_TD_CONDITION_NOT_ACCESSED) | OHCI_TD_SET_DELAY_INTERRUPT(OHCI_TD_INTERRUPT_NONE) | OHCI_TD_TOGGLE_CARRY | OHCI_TD_DIRECTION_PID_IN;
943
944 //
945 // store physical address of buffer
946 //
947 DataDescriptor->BufferPhysical = MmGetPhysicalAddress(MmGetMdlVirtualAddress(m_TransferBufferMDL)).LowPart;
948 DataDescriptor->LastPhysicalByteAddress = DataDescriptor->BufferPhysical + m_TransferBufferLength - 1;
949
950 }
951
952 //
953 // initialize setup descriptor
954 //
955 SetupDescriptor->Flags = OHCI_TD_DIRECTION_PID_SETUP | OHCI_TD_SET_CONDITION_CODE(OHCI_TD_CONDITION_NOT_ACCESSED) | OHCI_TD_TOGGLE_0 | OHCI_TD_SET_DELAY_INTERRUPT(OHCI_TD_INTERRUPT_NONE);
956
957 if (m_SetupPacket)
958 {
959 //
960 // copy setup packet
961 //
962 RtlCopyMemory(SetupDescriptor->BufferLogical, m_SetupPacket, sizeof(USB_DEFAULT_PIPE_SETUP_PACKET));
963 }
964 else
965 {
966 //
967 // generate setup packet from urb
968 //
969 ASSERT(FALSE);
970 }
971
972 //
973 // initialize status descriptor
974 //
975 StatusDescriptor->Flags = OHCI_TD_SET_CONDITION_CODE(OHCI_TD_CONDITION_NOT_ACCESSED) | OHCI_TD_TOGGLE_1 | OHCI_TD_SET_DELAY_INTERRUPT(OHCI_TD_INTERRUPT_IMMEDIATE);
976 if (m_TransferBufferLength == 0)
977 {
978 //
979 // input direction is flipped for the status descriptor
980 //
981 StatusDescriptor->Flags |= OHCI_TD_DIRECTION_PID_IN;
982 }
983 else
984 {
985 //
986 // output direction is flipped for the status descriptor
987 //
988 StatusDescriptor->Flags |= OHCI_TD_DIRECTION_PID_OUT;
989 }
990
991 //
992 // now link the descriptors
993 //
994 if (m_TransferBufferLength)
995 {
996 //
997 // link setup descriptor to data descriptor
998 //
999 SetupDescriptor->NextPhysicalDescriptor = DataDescriptor->PhysicalAddress.LowPart;
1000 SetupDescriptor->NextLogicalDescriptor = DataDescriptor;
1001
1002 //
1003 // link data descriptor to status descriptor
1004 // FIXME: check if there are more data descriptors
1005 //
1006 DataDescriptor->NextPhysicalDescriptor = StatusDescriptor->PhysicalAddress.LowPart;
1007 DataDescriptor->NextLogicalDescriptor = StatusDescriptor;
1008
1009 //
1010 // link status descriptor to last descriptor
1011 //
1012 StatusDescriptor->NextPhysicalDescriptor = LastDescriptor->PhysicalAddress.LowPart;
1013 StatusDescriptor->NextLogicalDescriptor = LastDescriptor;
1014 }
1015 else
1016 {
1017 //
1018 // link setup descriptor to status descriptor
1019 //
1020 SetupDescriptor->NextPhysicalDescriptor = StatusDescriptor->PhysicalAddress.LowPart;
1021 SetupDescriptor->NextLogicalDescriptor = StatusDescriptor;
1022
1023 //
1024 // link status descriptor to last descriptor
1025 //
1026 StatusDescriptor->NextPhysicalDescriptor = LastDescriptor->PhysicalAddress.LowPart;
1027 StatusDescriptor->NextLogicalDescriptor = LastDescriptor;
1028 }
1029
1030 //
1031 // now link descriptor to endpoint
1032 //
1033 EndpointDescriptor->HeadPhysicalDescriptor = SetupDescriptor->PhysicalAddress.LowPart;
1034 EndpointDescriptor->TailPhysicalDescriptor = LastDescriptor->PhysicalAddress.LowPart;
1035 EndpointDescriptor->HeadLogicalDescriptor = SetupDescriptor;
1036
1037 //
1038 // store result
1039 //
1040 *OutEndpointDescriptor = EndpointDescriptor;
1041
1042 //
1043 // done
1044 //
1045 return STATUS_SUCCESS;
1046 }
1047
1048 //----------------------------------------------------------------------------------------
1049 NTSTATUS
1050 CUSBRequest::GetEndpointDescriptor(
1051 struct _OHCI_ENDPOINT_DESCRIPTOR ** OutDescriptor)
1052 {
1053 ULONG TransferType;
1054 NTSTATUS Status;
1055
1056 //
1057 // get transfer type
1058 //
1059 TransferType = InternalGetTransferType();
1060
1061 //
1062 // build request depending on type
1063 //
1064 switch(TransferType)
1065 {
1066 case USB_ENDPOINT_TYPE_CONTROL:
1067 Status = BuildControlTransferDescriptor((POHCI_ENDPOINT_DESCRIPTOR*)OutDescriptor);
1068 break;
1069 case USB_ENDPOINT_TYPE_BULK:
1070 case USB_ENDPOINT_TYPE_INTERRUPT:
1071 Status = BuildBulkInterruptEndpoint(OutDescriptor);
1072 break;
1073 case USB_ENDPOINT_TYPE_ISOCHRONOUS:
1074 DPRINT1("USB_ENDPOINT_TYPE_ISOCHRONOUS not implemented\n");
1075 Status = STATUS_NOT_IMPLEMENTED;
1076 break;
1077 default:
1078 PC_ASSERT(FALSE);
1079 Status = STATUS_NOT_IMPLEMENTED;
1080 break;
1081 }
1082
1083 if (NT_SUCCESS(Status))
1084 {
1085 //
1086 // store queue head
1087 //
1088 //m_QueueHead = *OutDescriptor;
1089
1090 //
1091 // store request object
1092 //
1093 (*OutDescriptor)->Request = PVOID(this);
1094 }
1095
1096 //
1097 // done
1098 //
1099 return Status;
1100 }
1101
1102 //----------------------------------------------------------------------------------------
1103 VOID
1104 CUSBRequest::GetResultStatus(
1105 OUT OPTIONAL NTSTATUS * NtStatusCode,
1106 OUT OPTIONAL PULONG UrbStatusCode)
1107 {
1108 //
1109 // sanity check
1110 //
1111 PC_ASSERT(m_CompletionEvent);
1112
1113 //
1114 // wait for the operation to complete
1115 //
1116 KeWaitForSingleObject(m_CompletionEvent, Executive, KernelMode, FALSE, NULL);
1117
1118 //
1119 // copy status
1120 //
1121 if (NtStatusCode)
1122 {
1123 *NtStatusCode = m_NtStatusCode;
1124 }
1125
1126 //
1127 // copy urb status
1128 //
1129 if (UrbStatusCode)
1130 {
1131 *UrbStatusCode = m_UrbStatusCode;
1132 }
1133
1134 }
1135
1136 VOID
1137 CUSBRequest::FreeEndpointDescriptor(
1138 struct _OHCI_ENDPOINT_DESCRIPTOR * OutDescriptor)
1139 {
1140 POHCI_GENERAL_TD TransferDescriptor, NextTransferDescriptor;
1141
1142 DPRINT("CUSBRequest::FreeEndpointDescriptor EndpointDescriptor %p Logical %x\n", OutDescriptor, OutDescriptor->PhysicalAddress.LowPart);
1143
1144 //
1145 // get first general transfer descriptor
1146 //
1147 TransferDescriptor = (POHCI_GENERAL_TD)OutDescriptor->HeadLogicalDescriptor;
1148
1149 //
1150 // release endpoint descriptor
1151 //
1152 m_DmaManager->Release(OutDescriptor, sizeof(OHCI_ENDPOINT_DESCRIPTOR));
1153
1154 while(TransferDescriptor)
1155 {
1156 //
1157 // get next
1158 //
1159 NextTransferDescriptor = (POHCI_GENERAL_TD)TransferDescriptor->NextLogicalDescriptor;
1160
1161 //
1162 // is there a buffer associated
1163 //
1164 if (TransferDescriptor->BufferSize)
1165 {
1166 //
1167 // release buffer
1168 //
1169 m_DmaManager->Release(TransferDescriptor->BufferLogical, TransferDescriptor->BufferSize);
1170 }
1171
1172 DPRINT("CUSBRequest::FreeEndpointDescriptor Descriptor %p Logical %x Buffer Physical %x EndAddress %x\n", TransferDescriptor, TransferDescriptor->PhysicalAddress.LowPart, TransferDescriptor->BufferPhysical, TransferDescriptor->LastPhysicalByteAddress);
1173
1174 //
1175 // release descriptor
1176 //
1177 m_DmaManager->Release(TransferDescriptor, sizeof(OHCI_GENERAL_TD));
1178
1179 //
1180 // move to next
1181 //
1182 TransferDescriptor = NextTransferDescriptor;
1183 }
1184
1185 }
1186
1187 VOID
1188 CUSBRequest::CompletionCallback(
1189 struct _OHCI_ENDPOINT_DESCRIPTOR * OutDescriptor)
1190 {
1191 POHCI_GENERAL_TD TransferDescriptor, NextTransferDescriptor;
1192 PIO_STACK_LOCATION IoStack;
1193 PURB Urb;
1194
1195 DPRINT("CUSBRequest::CompletionCallback Descriptor %p PhysicalAddress %x\n", OutDescriptor, OutDescriptor->PhysicalAddress.LowPart);
1196
1197 //
1198 // set status code
1199 //
1200 m_NtStatusCode = STATUS_SUCCESS;
1201 m_UrbStatusCode = USBD_STATUS_SUCCESS;
1202
1203 if (m_Irp)
1204 {
1205 //
1206 // set irp completion status
1207 //
1208 m_Irp->IoStatus.Status = STATUS_SUCCESS; //FIXME
1209
1210 //
1211 // get current irp stack location
1212 //
1213 IoStack = IoGetCurrentIrpStackLocation(m_Irp);
1214
1215 //
1216 // get urb
1217 //
1218 Urb = (PURB)IoStack->Parameters.Others.Argument1;
1219
1220 //
1221 // store urb status
1222 //
1223 Urb->UrbHeader.Status = USBD_STATUS_SUCCESS; //FIXME
1224
1225 //
1226 // Check if the MDL was created
1227 //
1228 if (!Urb->UrbBulkOrInterruptTransfer.TransferBufferMDL)
1229 {
1230 //
1231 // Free Mdl
1232 //
1233 IoFreeMdl(m_TransferBufferMDL);
1234 }
1235
1236 //
1237 // FIXME: support status and calculate length
1238 //
1239
1240 //
1241 // FIXME: check if the transfer was split
1242 // if yes dont complete irp yet
1243 //
1244 IoCompleteRequest(m_Irp, IO_NO_INCREMENT);
1245 }
1246 else
1247 {
1248 //
1249 // signal completion event
1250 //
1251 PC_ASSERT(m_CompletionEvent);
1252 KeSetEvent(m_CompletionEvent, 0, FALSE);
1253 }
1254 }
1255
1256
1257 //-----------------------------------------------------------------------------------------
1258 BOOLEAN
1259 CUSBRequest::IsRequestInitialized()
1260 {
1261 if (m_Irp || m_SetupPacket)
1262 {
1263 //
1264 // request is initialized
1265 //
1266 return TRUE;
1267 }
1268
1269 //
1270 // request is not initialized
1271 //
1272 return FALSE;
1273 }
1274
1275 //-----------------------------------------------------------------------------------------
1276 BOOLEAN
1277 CUSBRequest::IsQueueHeadComplete(
1278 struct _QUEUE_HEAD * QueueHead)
1279 {
1280 UNIMPLEMENTED
1281 return TRUE;
1282 }
1283
1284
1285
1286 //-----------------------------------------------------------------------------------------
1287 NTSTATUS
1288 InternalCreateUSBRequest(
1289 PUSBREQUEST *OutRequest)
1290 {
1291 PUSBREQUEST This;
1292
1293 //
1294 // allocate requests
1295 //
1296 This = new(NonPagedPool, TAG_USBOHCI) CUSBRequest(0);
1297 if (!This)
1298 {
1299 //
1300 // failed to allocate
1301 //
1302 return STATUS_INSUFFICIENT_RESOURCES;
1303 }
1304
1305 //
1306 // add reference count
1307 //
1308 This->AddRef();
1309
1310 //
1311 // return result
1312 //
1313 *OutRequest = (PUSBREQUEST)This;
1314
1315 //
1316 // done
1317 //
1318 return STATUS_SUCCESS;
1319 }